From b6ddd795b1569e7b4bd600afdd05922096499a3c Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 9 Oct 2025 20:20:28 +0200 Subject: [PATCH 001/274] Add ModuleContainerPanYOnlyWithScrollCache class Introduced a scroll position cache for the observatory asteroid list, allowing restoration of scroll positions across GUI layouts. fixes observatory scroll reset when selecting asteroid. --- ...oduleContainerPanYOnlyWithScrollCache.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleContainerPanYOnlyWithScrollCache.java diff --git a/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleContainerPanYOnlyWithScrollCache.java b/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleContainerPanYOnlyWithScrollCache.java new file mode 100644 index 000000000..229933deb --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleContainerPanYOnlyWithScrollCache.java @@ -0,0 +1,54 @@ +package zmaster587.advancedRocketry.inventory.modules; + +import zmaster587.libVulpes.inventory.modules.ModuleContainerPanYOnly; +import zmaster587.libVulpes.inventory.modules.ModuleBase; +import net.minecraft.util.ResourceLocation; +import java.util.concurrent.ConcurrentHashMap; +import java.util.Map; +import java.util.List; + +public class ModuleContainerPanYOnlyWithScrollCache extends ModuleContainerPanYOnly { + + /** + * Scroll position cache for the observatory asteroid list. + * - One entry (per GUI layout) per client; cleared on new scan or scroll. + * - Minimal memory use (single Integer per layout). + * - Client-side only; no multiplayer or server impact. + * - Thread-safe for typical GUI use. + * - If reused, ensure cacheKey is unique per list type / GUI layout. + */ + + // Cache: only stores latest scroll position per key + private static final Map scrollCache = new ConcurrentHashMap<>(); + private final String cacheKey; + + public ModuleContainerPanYOnlyWithScrollCache(int offsetX, int offsetY, List moduleList, List staticModules, ResourceLocation backdrop, int screenSizeX, int screenSizeY, int paddingX, int paddingY, int containerSizeX, int containerSizeY) { + super(offsetX, offsetY, moduleList, staticModules, backdrop, screenSizeX, screenSizeY, paddingX, paddingY, containerSizeX, containerSizeY); + + // Create unique cache key + this.cacheKey = "observatory_asteroid_list:" + offsetX + ":" + offsetY + ":" + screenSizeX + ":" + screenSizeY; + + // Restore scroll position if available + Integer cachedPos = scrollCache.get(cacheKey); + if (cachedPos != null) { + super.setOffset2(-cachedPos); + } + } + + @Override + protected void moveContainerInterior(int deltaY) { + super.moveContainerInterior(deltaY); + scrollCache.put(cacheKey, super.getScrollY()); + } + + @Override + public void onScroll(int dwheel) { + super.onScroll(dwheel); + scrollCache.put(cacheKey, super.getScrollY()); + } + + // Public method to clear cache (for new asteroid scans) + public static void clearScrollCache() { + scrollCache.clear(); + } +} From 43d6135c17f9f2a53c2cd115c0e82e060ba91ba5 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 9 Oct 2025 20:23:43 +0200 Subject: [PATCH 002/274] Refactor TileObservatory to use scroll cache module Updated the TileObservatory class to use ModuleContainerPanYOnlyWithScrollCache for asteroid listing and added cache clearing on new data scanning. -fixes scroll reset when selecting asteroid --- .../tile/multiblock/TileObservatory.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java b/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java index 576661819..89f59d102 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java @@ -20,6 +20,7 @@ import zmaster587.advancedRocketry.api.DataStorage.DataType; import zmaster587.advancedRocketry.inventory.TextureResources; import zmaster587.advancedRocketry.inventory.modules.ModuleData; +import zmaster587.advancedRocketry.inventory.modules.ModuleContainerPanYOnlyWithScrollCache; import zmaster587.advancedRocketry.item.ItemAsteroidChip; import zmaster587.advancedRocketry.item.ItemData; import zmaster587.advancedRocketry.tile.hatch.TileDataBus; @@ -405,9 +406,10 @@ public List getModules(int ID, EntityPlayer player) { modules.add(new ModuleScaledImage(baseX, 2 * baseY + sizeY, sizeX, -3, TextureResources.horizontalBar)); } - //Relying on a bug, is this safe? + //listing of asteroids with scrollcaching if (lastSeed != -1) { - ModuleContainerPanYOnly pan = new ModuleContainerPanYOnly(baseX, baseY, list2, new LinkedList<>(), null, sizeX - 2, sizeY, 0, -48, 0, 72); + ModuleContainerPanYOnlyWithScrollCache pan = new ModuleContainerPanYOnlyWithScrollCache( + baseX, baseY, list2, new LinkedList<>(), null, sizeX - 2, sizeY, 0, -48, 0, 72); modules.add(pan); } @@ -499,26 +501,30 @@ public void useNetworkData(EntityPlayer player, Side side, byte id, else if (id == TAB_SWITCH && !world.isRemote) { tabModule.setTab(nbt.getShort("tab")); player.openGui(LibVulpes.instance, GuiHandler.guiId.MODULARNOINV.ordinal(), getWorld(), pos.getX(), pos.getY(), pos.getZ()); - } else if (id == BUTTON_PRESS && !world.isRemote) { + } + else if (id == BUTTON_PRESS && !world.isRemote) { lastButton = nbt.getShort("button"); lastType = buttonType.get(lastButton - LIST_OFFSET); markDirty(); world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 2); player.openGui(LibVulpes.instance, GuiHandler.guiId.MODULARNOINV.ordinal(), getWorld(), pos.getX(), pos.getY(), pos.getZ()); - - } else if (id == SEED_CHANGE) { + } + else if (id == SEED_CHANGE) { if (extractData(dataConsumedPerRefresh, DataType.DISTANCE, EnumFacing.UP, false) >= dataConsumedPerRefresh) { lastSeed = world.getTotalWorldTime() / 100; lastButton = -1; lastType = ""; + + // Clear scroll cache when scanning new data + ModuleContainerPanYOnlyWithScrollCache.clearScrollCache(); + extractData(dataConsumedPerRefresh, DataType.DISTANCE, EnumFacing.UP, true); world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 2); markDirty(); player.openGui(LibVulpes.instance, GuiHandler.guiId.MODULARNOINV.ordinal(), getWorld(), pos.getX(), pos.getY(), pos.getZ()); } - - - } else if (id == PROCESS_CHIP && !world.isRemote) { + } + else if (id == PROCESS_CHIP && !world.isRemote) { if (inv.getStackInSlot(2).isEmpty() && isOpen && hasEnergy(500) && lastButton != -1) { ItemStack stack = inv.decrStackSize(1, 1); From 9783d2728747e0e4f6eb12d1de9697d7af972839 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 9 Oct 2025 23:23:39 +0200 Subject: [PATCH 003/274] Change parent model to cube_all for guidance hatch cleaner logic. (trying to fix transparent texture for blockstate varient14) --- .../models/block/guidancecomputeraccesshatch.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/resources/assets/advancedrocketry/models/block/guidancecomputeraccesshatch.json b/src/main/resources/assets/advancedrocketry/models/block/guidancecomputeraccesshatch.json index 64a7115ed..7c3692ed9 100644 --- a/src/main/resources/assets/advancedrocketry/models/block/guidancecomputeraccesshatch.json +++ b/src/main/resources/assets/advancedrocketry/models/block/guidancecomputeraccesshatch.json @@ -1,8 +1,6 @@ { - "parent": "block/orientable", + "parent": "block/cube_all", "textures": { - "top": "advancedrocketry:blocks/guidancecomputeraccesshatch", - "front": "advancedrocketry:blocks/guidancecomputeraccesshatch", - "side": "advancedrocketry:blocks/guidancecomputeraccesshatch" + "all": "advancedrocketry:blocks/guidancecomputeraccesshatch" } } From 6d46b7de4fc7eb38db9bf65d1c6ffea193580db9 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 10 Oct 2025 01:01:12 +0200 Subject: [PATCH 004/274] guidancecompteraccesshatch render bugfix forcing rendering all sides. fixing transparent texture when varient = 14 --- .../block/multiblock/BlockARHatch.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/multiblock/BlockARHatch.java b/src/main/java/zmaster587/advancedRocketry/block/multiblock/BlockARHatch.java index d45817de4..8fd68b7e7 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/multiblock/BlockARHatch.java +++ b/src/main/java/zmaster587/advancedRocketry/block/multiblock/BlockARHatch.java @@ -35,17 +35,24 @@ public void getSubBlocks(CreativeTabs tab, } @Override - public boolean shouldSideBeRendered(IBlockState blockState, - IBlockAccess blockAccess, BlockPos pos, EnumFacing direction) { + public boolean shouldSideBeRendered(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos, EnumFacing direction) { + int variant = blockState.getValue(VARIANT); + // Always render sides for guidancecomputeraccesshatch variants (6 and 14) + if (variant == 6 || variant == 14) { + return true; + } - boolean isPointer = blockAccess.getTileEntity(pos.offset(direction.getOpposite())) instanceof TilePointer; - if (blockState.getValue(VARIANT) == 8) + // Keep + if (variant == 8) return false; - if (isPointer || blockState.getValue(VARIANT) < 2) + + boolean isPointer = blockAccess.getTileEntity(pos.offset(direction.getOpposite())) instanceof TilePointer; + if (isPointer || variant < 2) return super.shouldSideBeRendered(blockState, blockAccess, pos, direction); - return true; + + return true; } @Override From 2f9d0f3ead0149f51fa08e74897c9e65c221f031 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Tue, 14 Oct 2025 20:02:12 +0200 Subject: [PATCH 005/274] Implement inventory validation for satellite chassis Added inventory validation for satellite modules to ensure only valid items are placed in slots. Fixes crash when player tries to assemble satellite without valid primaryfunction. UX improvement. --- .../advancedRocketry/item/ItemSatellite.java | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java b/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java index 8510fc3f4..61f471d58 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java @@ -17,8 +17,44 @@ public class ItemSatellite extends ItemIdWithName { + //Guarding inventory to ensure only valid items are placed in slots. + public static class SatelliteModuleInventory extends EmbeddedInventory { + public SatelliteModuleInventory() { super(7); } // slots 0-6 embedded from chassis + + @Override + public boolean isItemValidForSlot(int slot, @Nonnull ItemStack stack) { + if (stack.isEmpty()) return false; + + // Registry-driven: only accept items that have SatelliteProperties + SatelliteProperties p = SatelliteRegistry.getSatelliteProperty(stack); + if (p == null) return false; + int f = p.getPropertyFlag(); + + // Slot 0: ONLY primary function meta 0-6 + if (slot == 0) { + return SatelliteProperties.Property.MAIN.isOfType(f); + } + + // Slots 1–6: power gen, battery, or data modules + if (slot >= 1 && slot <= 6) { + return SatelliteProperties.Property.POWER_GEN.isOfType(f) || + SatelliteProperties.Property.BATTERY.isOfType(f) || + SatelliteProperties.Property.DATA.isOfType(f); + } + + return false; + } + + @Override + public void setInventorySlotContents(int index, ItemStack stack) { + if (!stack.isEmpty() && !isItemValidForSlot(index, stack)) return; + super.setInventorySlotContents(index, stack); + } + } + + public EmbeddedInventory readInvFromNBT(@Nonnull ItemStack stackIn) { - EmbeddedInventory inv = new EmbeddedInventory(7); + EmbeddedInventory inv = new SatelliteModuleInventory(); // <-- guarded if (!stackIn.hasTagCompound() || !stackIn.getTagCompound().hasKey("inv")) return inv; From 636c99ce2800a77745b0b3d307e8c9fc781c4ab9 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Tue, 14 Oct 2025 20:32:49 +0200 Subject: [PATCH 006/274] Update comment for EmbeddedInventory initialization Clarify comment regarding EmbeddedInventory instantiation. --- .../java/zmaster587/advancedRocketry/item/ItemSatellite.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java b/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java index 61f471d58..c26b9d0c5 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java @@ -54,7 +54,7 @@ public void setInventorySlotContents(int index, ItemStack stack) { public EmbeddedInventory readInvFromNBT(@Nonnull ItemStack stackIn) { - EmbeddedInventory inv = new SatelliteModuleInventory(); // <-- guarded + EmbeddedInventory inv = new SatelliteModuleInventory(); // slots 0-6 embedded from chassis, guarded by class above if (!stackIn.hasTagCompound() || !stackIn.getTagCompound().hasKey("inv")) return inv; From 2a85aa6a8a7be58ebb2ababaeb22d75ce211c6bc Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 10:03:59 +0200 Subject: [PATCH 007/274] Add German translations for satellite features --- .../resources/assets/advancedrocketry/lang/de_DE.lang | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/resources/assets/advancedrocketry/lang/de_DE.lang b/src/main/resources/assets/advancedrocketry/lang/de_DE.lang index c0dc83148..d832ae4e5 100644 --- a/src/main/resources/assets/advancedrocketry/lang/de_DE.lang +++ b/src/main/resources/assets/advancedrocketry/lang/de_DE.lang @@ -406,4 +406,10 @@ msg.notconnected=Nicht verbunden msg.unprogrammed=Unprogrammiert msg.programfail=Programmierung fehlgeschlagen msg.modules=Module -msg.na=Nicht verfügbar \ No newline at end of file +msg.na=Nicht verfügbar + +jei.sb.satellitepreview=Bereit für den Orbit! +jei.sb.copy.source=Quelle +jei.sb.copy.output=Neue Kopie +jei.sb.assemblyhint=Mindestens ein Solarpanel +jei.sb.copychiphint=Erstelle Sicherungskopien! From 84e95ec8e97bf54490f26df363d83927134d6f50 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 10:04:23 +0200 Subject: [PATCH 008/274] Add new language entries for satellite preview and hints --- src/main/resources/assets/advancedrocketry/lang/en_US.lang | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/resources/assets/advancedrocketry/lang/en_US.lang b/src/main/resources/assets/advancedrocketry/lang/en_US.lang index fc1e8d6b3..502730313 100644 --- a/src/main/resources/assets/advancedrocketry/lang/en_US.lang +++ b/src/main/resources/assets/advancedrocketry/lang/en_US.lang @@ -507,3 +507,10 @@ msg.chat.nostation3=You must be on a space station to be in this dimension, and commands.weather.always_not_clear=This planet is always not clear... commands.weather.cannot_rain=Cannot start a rain here commands.weather.cannot_thunder=Cannot start a thunder here + +jei.sb.satellitepreview=Ready for orbit! +jei.sb.copy.source=Source +jei.sb.copy.output=New Copy +jei.sb.assemblyhint=Atleast one solar panel +jei.sb.copychiphint=Make backups! + From 56e596923ed39450898bc331c36518ee286763fb Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 10:04:45 +0200 Subject: [PATCH 009/274] Add Spanish translations for satellite features Added Spanish translations for satellite preview and hints. --- .../resources/assets/advancedrocketry/lang/es_ES.lang | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/resources/assets/advancedrocketry/lang/es_ES.lang b/src/main/resources/assets/advancedrocketry/lang/es_ES.lang index d17daaf60..76c126f26 100644 --- a/src/main/resources/assets/advancedrocketry/lang/es_ES.lang +++ b/src/main/resources/assets/advancedrocketry/lang/es_ES.lang @@ -131,4 +131,10 @@ fluid.oxygen=Oxígeno fluid.hydrogen=Hidrógeno fluid.rocketFuel=Combustible de cohete -mission.asteroidmining.name=Minería de asteroides \ No newline at end of file +mission.asteroidmining.name=Minería de asteroides + +jei.sb.satellitepreview=¡Listo para la órbita! +jei.sb.copy.source=Fuente +jei.sb.copy.output=Nueva copia +jei.sb.assemblyhint=Al menos un panel solar +jei.sb.copychiphint=¡Haz copias de seguridad! From d553900fed2fd547f56f35b18ebd6f292e6848ab Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 10:05:07 +0200 Subject: [PATCH 010/274] Update Finnish language translations in fi_FI.lang --- .../assets/advancedrocketry/lang/fi_FI.lang | 312 +++++++++--------- 1 file changed, 159 insertions(+), 153 deletions(-) diff --git a/src/main/resources/assets/advancedrocketry/lang/fi_FI.lang b/src/main/resources/assets/advancedrocketry/lang/fi_FI.lang index f5270fc2a..4a741dd86 100644 --- a/src/main/resources/assets/advancedrocketry/lang/fi_FI.lang +++ b/src/main/resources/assets/advancedrocketry/lang/fi_FI.lang @@ -18,34 +18,34 @@ tile.seat.name=Istuin tile.pad.name=Laukaisualusta tile.structuretower.name=Rakennetorni tile.rocketAssembler.name=Raketin Kokoamislaite -tile.turf.name=Kuuply -tile.turfDark.name=Tumma Kuuply +tile.turf.name=Kuupöly +tile.turfDark.name=Tumma Kuupöly tile.cuttingMachine.name=Leikkuulaite -tile.sawBlade.name=Sahanter Kokoonpano -tile.controlComp.name=Tehtvn Ohjaustietokone +tile.sawBlade.name=Sahanterä Kokoonpano +tile.controlComp.name=Tehtävän Ohjaustietokone tile.precisionAssemblingMachine.name=Tarkkuuskokoaja tile.spaceLaser.name=Kiertorata Laser Pora -tile.Crystallizer.name=Kiteyttj -tile.blastBrick.name=Lmmnkestv tiili -tile.blastFurnaceController.name=Lmmnkestvn Uunin Ohjain +tile.Crystallizer.name=Kiteyttäjä +tile.blastBrick.name=Lämmönkestävä tiili +tile.blastFurnaceController.name=Lämmönkestävän Uunin Ohjain tile.fuelStation.name=Tankkausasema -tile.loader.0.name=Datavyl +tile.loader.0.name=Dataväylä tile.loader.1.name=Satelliittiasema tile.loader.2.name=Rakettipurkaja -tile.loader.3.name=Rakettityttj +tile.loader.3.name=Rakettitäyttäjä tile.loader.4.name=Rakettinestepurkaja -tile.loader.5.name=Rakettinestetyttj -tile.loader.6.name=Ohjaustietokoneen psyluukku +tile.loader.5.name=Rakettinestetäyttäjä +tile.loader.6.name=Ohjaustietokoneen pääsyluukku tile.observatory.name=Observatorio tile.satelliteBuilder.name=Satelliittirakentaja tile.rocket.name=Yksiajoaineinen Rakettimoottori tile.bipropellantrocket.name=Kaksiajoaineinen Rakettimoottori -tile.nuclearrocket.name=Ydinlamprakettimoottori +tile.nuclearrocket.name=Ydinlampörakettimoottori tile.fuelTank.name=Yksiajoainetankki tile.bipropellantfueltank.name=Kaksiajoainetankki tile.oxidizerfueltank.name=Hapetinpolttoainetankki -tile.nuclearfueltank.name=Ydinlmptystmisnestetankki -tile.nuclearcore.name=Ydinlmpfissioydin +tile.nuclearfueltank.name=Ydinlämpötyöstämisnestetankki +tile.nuclearcore.name=Ydinlämpöfissioydin tile.monitoringstation.name=Raketin Tarkkailuasema tile.satelliteMonitor.name=Satelliitti Terminaali tile.lightwoodlog.name=Valopuu @@ -56,7 +56,7 @@ tile.chipStorage.name=Satelliitti Id Varasto tile.planetanalyser.name=Avaruusobjekti Data Prosessori tile.lunaranalyser.name=Kuuanalysaattori tile.guidanceComputer.name=Ohjaustietokone -tile.electricArcFurnace.name=Shkinen Valokaariuuni +tile.electricArcFurnace.name=Sähköinen Valokaariuuni tile.hotDryturf.name=Hapetettu rautahiekka tile.concrete.name=Betoni tile.lathe.name=Sorvi @@ -78,35 +78,35 @@ tile.oxygenCharger.name=Kaasulataustyyny tile.dockingPad.name=Telakointialusta tile.stationmonitor.name=Hyperavaruusohjain tile.warpCore.name=Hyperavaruusydin -tile.atmosphereDetector.name=Ilmakehtunnistin +tile.atmosphereDetector.name=Ilmakehätunnistin tile.unlittorch.name=Sammunut Soihtu tile.geode.name=Geodikuutio -tile.electricMushroom.name=Shkinen Sieni +tile.electricMushroom.name=Sähköinen Sieni tile.charcoallog.name=Puuhiilitukki tile.vitrifiedSand.name=Lasittunut Hiekka tile.ruby.name=Punainen Kristallikuutio -tile.emerald.name=Vihre Kristallikuutio +tile.emerald.name=Vihreä Kristallikuutio tile.sapphire.name=Sininen Kristallikuutio tile.citrine.name=Keltainen Kristallikuutio tile.wulfentite.name=Oranssi Kristallikuutio tile.amethyst.name=Violetti Kristallikuutio tile.gravityControl.name=Avaruusaseman Painovoiman Ohjain tile.drill.name=Pora -tile.dataPipe.name=Datakaapeli(Poistettu kytst) -tile.liquidPipe.name=Nesteputki(Poistettu kytst) -tile.rfOutput.name=Redstone Flux Lhtpistoke +tile.dataPipe.name=Datakaapeli(Poistettu käytöstä) +tile.liquidPipe.name=Nesteputki(Poistettu käytöstä) +tile.rfOutput.name=Redstone Flux Lähtöpistoke tile.microwaveReciever.name=Mikroaaltovastaanotin tile.solarPanel.name=Aurinkopaneeli -tile.suitWorkStation.name=Pukutyasema +tile.suitWorkStation.name=Pukutyöasema tile.orientationControl.name=Suuntaohjain tile.biomeScanner.name=Biomiskanneri -tile.atmoshereTerraformer.name=Ilmakehterraformaattori -tile.deployableRocketAssembler.name=Miehittmttomn Kulkuneuvon Kokoaja +tile.atmoshereTerraformer.name=Ilmakehäterraformaattori +tile.deployableRocketAssembler.name=Miehittämättomän Kulkuneuvon Kokoaja tile.pressurizedTank.name=Paineistettu Tankki -tile.gasIntake.name=Kaasun Sisnotto -tile.atmosphereTerraformer.name=Ilmakehterraformaattori +tile.gasIntake.name=Kaasun Sisäänotto +tile.atmosphereTerraformer.name=Ilmakehäterraformaattori tile.circleLight.name=Asemavalo -tile.energyPipe.name=Shkputki(Poistettu kytst) +tile.energyPipe.name=Sähköputki(Poistettu käytöstä) tile.solarGenerator.name=Aurinkogeneraattori tile.stationMarker.name=Asematelakointiportti tile.qcrucible.name=Kvartsi Sulatusastia @@ -116,15 +116,15 @@ tile.advRocket.name=Edistynyt Yksiajoainerakettimoottori tile.advbipropellantRocket.name=Edistynyt Kaksiajoainerakettimoottori tile.planetHoloSelector.name=Holographinen Planeettavalitsin tile.lens.name=Linssi -tile.forceField.name=Voimakentt -tile.forceFieldProjector.name=Voimakenttprojektori -tile.vacuumLaser.name=Suuritehoinen Tyhjikammiolaser +tile.forceField.name=Voimakenttä +tile.forceFieldProjector.name=Voimakenttäprojektori +tile.vacuumLaser.name=Suuritehoinen Tyhjiökammiolaser tile.gravityMachine.name=Aluepainovoimaohjain tile.pipeSeal.name=Putkitiiviste tile.spaceElevatorController.name=Avaruushissi tile.beacon.name=Merkkivalo tile.thermiteTorch.name=Termiittisoihtu -tile.wirelessTransciever.name=Langaton Lhetin-Vastaanotin +tile.wirelessTransciever.name=Langaton Lähetin-Vastaanotin tile.blackholegenerator.name=Musta Aukko Generaattori tile.pump.name=Nestepumppu tile.centrifuge.name=Sentrifugi @@ -146,46 +146,46 @@ item.circuitIC.3.name=Ohjauspiiti item.circuitIC.4.name=Tavara IO Piiri item.circuitIC.5.name=Neste IO Piiri item.OreScanner.name=Malmiskanneri -item.dataUnit.0.name=Datatallennusyksikk -item.sawBlade.0.name=Rautainen Sahanter +item.dataUnit.0.name=Datatallennusyksikkö +item.sawBlade.0.name=Rautainen Sahanterä item.satellite.name=Satelliitti item.satellitePowerSource.0.name=Perusaurinkopaneeli item.satellitePowerSource.1.name=Iso Aurinkopaneeli item.satellitePrimaryFunction.0.name=Optinen Sensori item.satellitePrimaryFunction.1.name=Koostumussensori item.satellitePrimaryFunction.2.name=Massasensori -item.satellitePrimaryFunction.3.name=Mikroaaltolhetin +item.satellitePrimaryFunction.3.name=Mikroaaltolähetin item.satellitePrimaryFunction.4.name=Malmikartoittaja item.satellitePrimaryFunction.5.name=Biomimuuttaja item.satelliteIdChip.name=Satelliitti ID-Siru item.planetIdChip.name=Planeetta ID-Siru item.asteroidChip.name=Asteroidi ID-Siru -item.miscpart.0.name=Kyttliittym +item.miscpart.0.name=Käyttöliittymä item.miscpart.1.name=Hiilitiili item.station.name=Avaruusasemakontti item.stationChip.name=Avaruusasema ID-Siru -item.stationchip.openmenu=Kyyki ja klikkaa hiiren oikeaa nppint avataksesi asetusvalikon -item.spaceHelmet.name=Avaruuspukukypt +item.stationchip.openmenu=Kyyki ja klikkaa hiiren oikeaa näppäintä avataksesi asetusvalikon +item.spaceHelmet.name=Avaruuspukukypätä item.spaceChest.name=Avaruuspukupaita item.spaceLeggings.name=Avaruuspukuhousut -item.spaceBoots.name=Avaruuspukukengt +item.spaceBoots.name=Avaruuspukukengät item.smallAirlock.name=Pieni Ilmalukko-ovi -item.carbonScrubberCartridge.name=Hiilenkeryspatruuna +item.carbonScrubberCartridge.name=Hiilenkeräyspatruuna item.jackhammer.name=Nokkavasara item.sealDetector.name=Vuototunnistin -item.itemUpgrade.0.name=Leijumispivitys -item.itemUpgrade.1.name=Lentonopeuden Ohjauspivitys -item.itemUpgrade.2.name=Bioninen Jalkapivitys -item.itemUpgrade.3.name=Pehmustetut Laskeutumiskengt +item.itemUpgrade.0.name=Leijumispäivitys +item.itemUpgrade.1.name=Lentonopeuden Ohjauspäivitys +item.itemUpgrade.2.name=Bioninen Jalkapäivitys +item.itemUpgrade.3.name=Pehmustetut Laskeutumiskengät item.itemUpgrade.4.name=Sumunestovisiiri item.itemUpgrade.5.name=Maankirkas Visiiri -item.atmAnalyser.name=Ilmakehanalysaattori -item.biomeChanger.name=Biomin vaihtokaukosdin +item.atmAnalyser.name=Ilmakehäanalysaattori +item.biomeChanger.name=Biomin vaihtokaukosäädin item.basicLaserGun.name=Peruslaserpyssy -item.beaconFinder.name=Merkkivalon Lytj +item.beaconFinder.name=Merkkivalon Löytäjä item.thermite.name=Termiitti item.hovercraft.name=Leijualus -item.hovercraft.tooltip=Pitkn kestv dilitiumvoimanlhde. Se el todennkisesti pitempn kuin sin. +item.hovercraft.tooltip=Pitkään kestävä dilitiumvoimanlähde. Se elää todennäköisesti pitempään kuin sinä. item.jetPack.name=Asurakettireppu item.pressureTank.0.name=Matalapainetankki @@ -200,14 +200,14 @@ container.monitoringstation=Tarkkailuasema material.TitaniumAluminide.name=Titaanialuminidi material.TitaniumIridium.name=Titaani-Iridiumseos -enchantment.spaceBreathing=Ilmanpitv Tiiviste +enchantment.spaceBreathing=Ilmanpitävä Tiiviste data.undefined.name=Jotain Satunnaista Dataa -data.distance.name=Etisyys +data.distance.name=Etäisyys data.humidity.name=Ilmankosteus -data.temperature.name=Lmptila +data.temperature.name=Lämpötila data.composition.name=Koostumus -data.atmospheredensity.name=Ilmakehn Tiheys +data.atmospheredensity.name=Ilmakehän Tiheys data.mass.name=Massa fluid.oxygenHappi @@ -217,116 +217,116 @@ fluid.rocketFuel=Rakettipolttoaine fluid.enrichedLava=Rikastettu Laava mission.asteroidmining.name=Asteroidin Louhinta -mission.gascollection.name=Kaasun Kerys +mission.gascollection.name=Kaasun Keräys -error.rocket.cannotGetThere=Mrnp Tavoittamaton -error.rocket.destinationNotExist=Ei voi laukaista: Mrnp ei ole olemassa -error.rocket.notSameSystem=Ei voi laukaista: Mrnp ei ole samassa planeettasysteemiss +error.rocket.cannotGetThere=Määränpää Tavoittamaton +error.rocket.destinationNotExist=Ei voi laukaista: Määränpää ei ole olemassa +error.rocket.notSameSystem=Ei voi laukaista: Määränpää ei ole samassa planeettasysteemissä advancement.holographic=Holografinen advancement.holographic.desc=Rakenna Holo-Projektori -advancement.flattening=Litistv +advancement.flattening=Litistävä advancement.flattening.desc=Rakenna Pieni Levy Puristin -advancement.feelTheHeat=Tunne lmp! +advancement.feelTheHeat=Tunne lämpö! advancement.feelTheHeat.desc=Rakenna Valokaariuuni -advancement.electrifying=Shkistv! +advancement.electrifying=Sähköistävää! advancement.electrifying.desc=Rakenna Elekrolysaattori -advancement.spinDoctor=Pyrimistohtori +advancement.spinDoctor=Pyörimistohtori advancement.spinDoctor.desc=Rakenna Sorvi advancement.rollin=Rullaan advancement.rollin.desc=Rakenna Rullauskone advancement.crystalline=Kiteinen -advancement.crystalline.desc=Rakenna Kiteyttj +advancement.crystalline.desc=Rakenna Kiteyttäjä advancement.warp=Hyperavaruus advancement.warp.desc=Rakenna Hyperavaruusydin advancement.moonLanding=Kuulaskeutuminen! advancement.moonLanding.desc=Laskeudu Kuuhun advancement.oneSmallStep=Yksi Pieni Askel... -advancement.oneSmallStep.desc=Ole ensimminen joka laskeutuu kuuhun! +advancement.oneSmallStep.desc=Ole ensimmäinen joka laskeutuu kuuhun! advancement.weReallyWentToTheMoon=Me Oikeasti Menimme Kuuhun! -advancement.weReallyWentToTheMoon.desc=Lyd Apollo 11:n laskeutumispaikka Kuussa +advancement.weReallyWentToTheMoon.desc=Löydä Apollo 11:n laskeutumispaikka Kuussa advancement.dilithium=Dilitium -advancement.dilithium.desc=Lyd Dilitiummalmia -advancement.givingItAllShesGot=Annetaan kaikki mit hnell on! -advancement.givingItAllShesGot.desc=Lenn Hyperavaruuteen kykenevss aluksessa +advancement.dilithium.desc=Löydä Dilitiummalmia +advancement.givingItAllShesGot=Annetaan kaikki mitä hänellä on! +advancement.givingItAllShesGot.desc=Lennä Hyperavaruuteen kykenevässä aluksessa advancement.flightOfThePhoenix=Feeniksin Lento -advancement.flightOfThePhoenix.desc=Rakenna ja Lenn ensimmist Hyperavaruuteen kykenev alusta +advancement.flightOfThePhoenix.desc=Rakenna ja Lennä ensimmäistä Hyperavaruuteen kykenevää alusta advancement.beerOnTheSun=Aikuisten Juomia Auringossa -advancement.beerOnTheSun.desc=Tulet tarvitsemaan enemmn TNT pstksesi kiertoradalle +advancement.beerOnTheSun.desc=Tulet tarvitsemaan enemmän TNTä päästäksesi kiertoradalle advancement.suitedUp=Pukeutunut -advancement.suitedUp.desc=Pid yllsi kokonaista avaruuspukua +advancement.suitedUp.desc=Pidä ylläsi kokonaista avaruuspukua key.controls.advancedrocketry=Advanced Rocketry key.openRocketUI=Avaa Raketti GUI -key.toggleJetpack=Kynnist/Sammuta Rakettireppu -key.togglercs=Kynnist/Sammuta RCS -key.turnRocketLeft=Knn Kulkuneuvoa Vasemmalle -key.turnRocketRight=Knn Kulkuneuvoa Oikealle -key.turnRocketUp=Nosta Kulkuneuvoa Yls +key.toggleJetpack=Käynnistä/Sammuta Rakettireppu +key.togglercs=Käynnistä/Sammuta RCS +key.turnRocketLeft=Käännä Kulkuneuvoa Vasemmalle +key.turnRocketRight=Käännä Kulkuneuvoa Oikealle +key.turnRocketUp=Nosta Kulkuneuvoa Ylös key.turnRocketDown=Laske Kulkuneuvoa Alas -enchantment.advancedrocketry.spacebreathing.desc=Mahdollistaa haarniskan palan luomaan ilmanpitvn eristeen +enchantment.advancedrocketry.spacebreathing.desc=Mahdollistaa haarniskan palan luomaan ilmanpitävän eristeen machine.tooltip.smallplatepress=Tarvitsee obsidiaani kaksi kuutiota alapuolella toimiakseen msg.crystalliser.gravityTooHigh=Painovoima ei ole tarpeeksi alhainen! -msg.observetory.scan.tooltip=Skannaa uusia asteroideja, kytt 100 etisyys dataa +msg.observetory.scan.tooltip=Skannaa uusia asteroideja, käyttää 100 etäisyys dataa msg.observetory.scan.button=Skannaa! msg.observetory.text.asteroids=Asteroidit msg.observetory.text.composition=Koostumus -msg.observetory.text.processdiscovery=Prosessoi lyt -msg.observetory.text.observabledistance=Havaittava etisyys: -msg.observetory.text.missionTime=Tehtvaika: +msg.observetory.text.processdiscovery=Prosessoi löytö +msg.observetory.text.observabledistance=Havaittava etäisyys: +msg.observetory.text.missionTime=Tehtäväaika: msg.tooltip.data=Data msg.tooltip.asteroidselection=Asteroidivalikko msg.label.name=Nimi -msg.label.clear=Tyhjenn -msg.label.add=Lis Uusi -msg.label.rename=Nime Uudelleen +msg.label.clear=Tyhjennä +msg.label.add=Lisää Uusi +msg.label.rename=Nimeä Uudelleen msg.label.delete=Poista -msg.label.noneSelected=Ei Valittua Mrnpt -msg.label.selectDst=Valitse mrnp -msg.label.destName=Mrnpn nimi +msg.label.noneSelected=Ei Valittua Määränpäätä +msg.label.selectDst=Valitse määränpää +msg.label.destName=Määränpään nimi msg.label.coords=Koordinaatit msg.spaceElevator.button.summon=Luo Kapseli -msg.spaceElevator.sameDimensionError=Ei voi yhdist kahta hissi samalla planeetalla! +msg.spaceElevator.sameDimensionError=Ei voi yhdistää kahta hissiä samalla planeetalla! msg.spaceElevator.linkNotGeostationaryError=Asema ei ole geostationaarisella kiertoradalla! -msg.spaceElevator.tetherWouldBreakError=Aseman tytyy olla oikeinpin ja paikalleen vastaanottaakseen kaapelin! -msg.spaceElevator.linkCannotChangeError=Hissikaapelit eivt voi vaihtaa paikkaa kun ne ovat jo yhdistettyj! +msg.spaceElevator.tetherWouldBreakError=Aseman täytyy olla oikeinpäin ja paikalleen vastaanottaakseen kaapelin! +msg.spaceElevator.linkCannotChangeError=Hissikaapelit eivät voi vaihtaa paikkaa kun ne ovat jo yhdistettyjä! msg.spaceElevator.newDstAdded=Hissikaapeli Yhdistetty! msg.spaceElevator.ascentReady=Valmiina nousuun -msg.spaceElevator.warning.anchored0=Tll hissikaapelilla on +msg.spaceElevator.warning.anchored0=Tällä hissikaapelilla on msg.spaceElevator.warning.anchored1=asema ankkuroituna! -msg.spaceElevator.warning.unanchored=Tll hissill ei ole kaapelia -msg.spaceElevator.turnedOff=Hissi on poissa plt -msg.fuelingStation.link=Sin ohjelmoit yhdistjn tankkausaseman kanssa, joka on koordinaateissa -msg.monitoringStation.missionProgressNA=Tehtvn Edistys: N/A -msg.monitoringStation.link=Sin ohjelmoit yhdistjn tarkkailuaseman kanssa, joka on koordinaateissa +msg.spaceElevator.warning.unanchored=Tällä hissillä ei ole kaapelia +msg.spaceElevator.turnedOff=Hissi on poissa päältä +msg.fuelingStation.link=Sinä ohjelmoit yhdistäjän tankkausaseman kanssa, joka on koordinaateissa +msg.monitoringStation.missionProgressNA=Tehtävän Edistys: N/A +msg.monitoringStation.link=Sinä ohjelmoit yhdistäjän tarkkailuaseman kanssa, joka on koordinaateissa msg.monitoringStation.progress= Edistys: msg.guidanceComputerHatch.loadingState=Lastaustila: -msg.guidanceComputerHatch.ejectonlanding=Poista automaattisesti laskeutumisen jlkeen +msg.guidanceComputerHatch.ejectonlanding=Poista automaattisesti laskeutumisen jälkeen msg.guidanceComputerHatch.ejectonsatlanding=Salli Satelliittisirujen poistaminen msg.guidanceComputerHatch.ejectonplanetlanding=Salli Planeettasirujen poistaminen msg.guidanceComputerHatch.ejectonstationlanding=Salli Asemasirujen poistaminen -msg.guidanceComputerHatch.link=Sin ohjelmoit yhdistjn ohjaustietokoneen psyluukun kanssa, joka on koordinaateissa +msg.guidanceComputerHatch.link=Sinä ohjelmoit yhdistäjän ohjaustietokoneen pääsyluukun kanssa, joka on koordinaateissa msg.fluidLoader.loadingState=Lastaustila: msg.fluidLoader.allowLoading=Salli Lastaus: -msg.fluidLoader.allowredstoneinput=Salli redstone sisntulo +msg.fluidLoader.allowredstoneinput=Salli redstone sisääntulo msg.fluidLoader.allowredstoneoutput=Salli redstone ulosmeno -msg.fluidLoader.none=Ei mitn -msg.fluidLoader.link=Sin ohjelmoit yhdistjn nestelastaajan kanssa, joka on koordinaateissa +msg.fluidLoader.none=Ei mitään +msg.fluidLoader.link=Sinä ohjelmoit yhdistäjän nestelastaajan kanssa, joka on koordinaateissa msg.rocketLoader.loadingState=Lastaustila: msg.rocketLoader.allowLoading=Salli Lastaus: -msg.rocketLoader.allowredstoneinput=Salli redstone sisntulo +msg.rocketLoader.allowredstoneinput=Salli redstone sisääntulo msg.rocketLoader.allowredstoneoutput=Salli redstone ulosmeno -msg.rocketLoader.none=Ei mitn -msg.rocketLoader.link=Sin ohjelmoit yhdistjn rakettilastaajan kanssa, joka on koordinaateissa +msg.rocketLoader.none=Ei mitään +msg.rocketLoader.link=Sinä ohjelmoit yhdistäjän rakettilastaajan kanssa, joka on koordinaateissa msg.microwaverec.notgenerating=Tuottaa 0 FE/t msg.microwaverec.generating=Tuottaa msg.abdp.compositionresearch=Koostumustutkimus -msg.abdp.distanceresearch=Etisyystutkimus +msg.abdp.distanceresearch=Etäisyystutkimus msg.abdp.massresearch=Massatutkimus msg.terraformer.atminc=Nosta Ilmanpainetta msg.terraformer.atmdec=Laske Ilmanpainetta @@ -336,22 +336,22 @@ msg.terraformer.outofgas=Peruutettu: Kaasut loppuivat msg.terraformer.notrunning=Ei toimi msg.terraformer.status=Tila msg.terraformer.pressure=Paine -msg.biomescanner.gas=nyehhh, Kaasuista, eik? +msg.biomescanner.gas=nyehhh, Kaasuista, eikö? msg.biomescanner.star=Jos vain minun sensoreilla olisi aurinkolasit -msg.gravitycontroller.radius=Sde: +msg.gravitycontroller.radius=Säde: msg.gravitycontroller.targetgrav=Tavoitepainovoima: msg.gravitycontroller.none=Asettamaton msg.gravitycontroller.activeset=Aktiivinen: aseta -msg.gravitycontroller.activeadd=Aktiivinen: lis +msg.gravitycontroller.activeadd=Aktiivinen: lisää msg.gravitycontroller.targetdir.1=Kohde-> msg.gravitycontroller.targetdir.2=Suunta msg.railgun.transfermin=Minimi Siirtokoko msg.spacelaser.reset=Nollaa msg.satctrlcenter.toofar=Liian Kaukana -msg.satctrlcenter.nolink=Ei Linkki... +msg.satctrlcenter.nolink=Ei Linkkiä... msg.satctrlcenter.info=Info: msg.satctrlcenter.destroysat=Tuhoa Satelliitti -msg.satctrlcenter.connect=Yhdist! +msg.satctrlcenter.connect=Yhdistä! msg.satbuilder.writesecondchip=Kirjoita toiselle sirulle msg.dockingport.target=Kohde Id msg.dockingport.me=Minun Id @@ -370,113 +370,119 @@ msg.warpmon.tab.tracking=Planeettatarkkailu msg.warpmon.selectplanet=Valitse planeetta msg.warpmon.corestatus=Ytimen Tila: msg.warpmon.anchored=Asema on ankkuroitu! -msg.warpmon.nowhere=Ei ole minnekkn minne menn +msg.warpmon.nowhere=Ei ole minnekkään minne mennä msg.warpmon.missingart=Artefakti Puuttuu msg.warpmon.ready=Valmis! msg.warpmon.notready=Ei ole Valmis msg.warpmon.warp=Hyperavaruus! msg.warpmon.fuelcost=Polttoainekustannus: msg.warpmon.fuel=Polttoaine: -msg.warpmon.dest=Mrnp: +msg.warpmon.dest=Määränpää: msg.warpmon.na=N/A msg.warpmon.search=Etsi planeetta msg.warpmon.chip=Ohjelmoi sirusta -msg.warpmon.datareq=Tarvitaan 100 jokaista datatyyppi +msg.warpmon.datareq=Tarvitaan 100 jokaista datatyyppiä msg.warpmon.artifact=Artefaktit msg.rocketbuilder.success=Valmis laukaisuun! msg.rocketbuilder.nofuel=Ei tarpeeksi polttoainekapasiteettia! msg.rocketbuilder.noseat=Istuin tai satelliittiasema puuttuu! -msg.rocketbuilder.noengines=Sinulla ei ole tarpeeksi tyntvoimaa! +msg.rocketbuilder.noengines=Sinulla ei ole tarpeeksi työntövoimaa! msg.rocketbuilder.noguidance=Ohjaustietokone Puuttuu msg.rocketbuilder.unscanned=Raketti skannaamaton msg.rocketbuilder.success_station=Valmis! -msg.rocketbuilder.empty=Ei mitn tll +msg.rocketbuilder.empty=Ei mitään täällä msg.rocketbuilder.finished=Rakennus Valmis! -msg.rocketbuild.invalidblock=Ptemtn kuutio! +msg.rocketbuild.invalidblock=Pätemätön kuutio! msg.rocketbuilder.incompletestructure=Virheellinen Laukaisualustarakennus! msg.rocketbuilder.nosatellitehatch=Satelliittiasema Puuttuu msg.rocketbuilder.nosatellitechip=Siru Puuttuu msg.rocketbuilder.outputblocked=Ulostulo aukko tukittu -msg.rocketbuilder.thrust=Tyntvoima +msg.rocketbuilder.thrust=Työntövoima msg.rocketbuilder.weight=Paino msg.rocketbuilder.fuel=Polttoaine msg.rocketbuilder.acc=Kiihtyvyys msg.rocketbuilder.build=Rakenna msg.rocketbuilder.scan=Skannaa -msg.rocketbuild.combinedthrust=Polttoainetyyppej ei voi yhdist! -msg.solar.collectingEnergy=Energiankerys: -msg.solar.cannotcollectEnergy=Ei pysty kermn Energiaa +msg.rocketbuild.combinedthrust=Polttoainetyyppejä ei voi yhdistää! +msg.solar.collectingEnergy=Energiankeräys: +msg.solar.cannotcollectEnergy=Ei pysty keräämään Energiaa msg.asteroidChip.asteroid=Asteroidi -msg.atmanal.atmtype=Ilmakehtyyppi: -msg.atmanal.canbreathe=Hengitettv: +msg.atmanal.atmtype=Ilmakehätyyppi: +msg.atmanal.canbreathe=Hengitettävä: msg.biomechanger.scan=Skannaa Biomi -msg.biomechanger.nosat=Satelliitti ei ole viel laukaistu +msg.biomechanger.nosat=Satelliitti ei ole vielä laukaistu msg.biomechanger.selBiome=Valittu Biomi: -msg.biomechanger.numBiome=Skannattujen Biomien Mr: -msg.itemorescanner.nosat=Satelliitti ei ole viel laukaistu +msg.biomechanger.numBiome=Skannattujen Biomien Määrä: +msg.itemorescanner.nosat=Satelliitti ei ole vielä laukaistu msg.itemorescanner.maxzoom=Maksimi zoomaus: msg.itemorescanner.filter=Pystyy suodattamaan malmeja: msg.itemorescanner.value=Arvo: msg.itemplanetidchip.planetname=Planeetan Nimi: msg.itemplanetidchip.stationid=Asema Id: msg.itemplanetidchip.artifacts=Artefaktit: -msg.vent.trace=Happijlki +msg.vent.trace=Happijälki -msg.itemsatellite.pwr=Shkn Varastointi: -msg.itemsatellite.nopwr=Ei Shkn Varastointia -msg.itemsatellite.pwrgen=Shkn Tuotanto: -msg.itemsatellite.nopwrgen=Ei Shkn Tuotantoa! -msg.itemsatellite.microwavestatus=Shkn Kerys +msg.itemsatellite.pwr=Sähkön Varastointi: +msg.itemsatellite.nopwr=Ei Sähkön Varastointia +msg.itemsatellite.pwrgen=Sähkön Tuotanto: +msg.itemsatellite.nopwrgen=Ei Sähkön Tuotantoa! +msg.itemsatellite.microwavestatus=Sähkön Keräys msg.itemsatellite.data=Datan Varastointi: msg.itemsatellite.nodata=Ei Datan Varastointia! -msg.itemsatellite.empty=Tyhj Runko +msg.itemsatellite.empty=Tyhjä Runko msg.itemsatchip.id=ID: msg.itemsatchip.planet=Planeetta: msg.itemsatchip.planetunk=Planeetta: Tuntematon msg.itemsatchip.sat=Satelliitti: msg.itemsatchip.satlost=Satelliitti: Yhteys Menetetty -msg.sealdetector.sealed=Pitisi pit hyvn eristeen. -msg.sealdetector.notsealmat=Materiaali ei pid eristett. -msg.sealdetector.notsealblock=Kuutio ei pid eristett. -msg.sealdetector.notfullblock=Ilma kiert tmn kuution ymprilt. -msg.sealdetector.fluid=Ilma kuplii tmn kuution lpi. -msg.sealdetector.other=Ilma karkaa tmn kuution lpi. +msg.sealdetector.sealed=Pitäisi pitää hyvän eristeen. +msg.sealdetector.notsealmat=Materiaali ei pidä eristettä. +msg.sealdetector.notsealblock=Kuutio ei pidä eristettä. +msg.sealdetector.notfullblock=Ilma kiertää tämän kuution ympäriltä. +msg.sealdetector.fluid=Ilma kuplii tämän kuution läpi. +msg.sealdetector.other=Ilma karkaa tämän kuution läpi. msg.stationchip.sation=Asema -msg.entity.rocket.descend.1=Paina Vlilynti laskeutuaksesi! +msg.entity.rocket.descend.1=Paina Välilyöntiä laskeutuaksesi! msg.entity.rocket.descend.2=Automaattinen laskeutuminen -msg.entity.rocket.ascend.1=Paina Vlilynti laukaisemiseen! -msg.entity.rocket.ascend.2=Mrnp: +msg.entity.rocket.ascend.1=Paina Välilyöntiä laukaisemiseen! +msg.entity.rocket.ascend.2=Määränpää: msg.entity.rocket.launch=Laukaisu T- -msg.entity.rocket.launch2=Paina [Vlilynti] keskeyttksesi +msg.entity.rocket.launch2=Paina [Välilyönti] keskeyttääksesi msg.entity.rocket.station=Asema msg.entity.rocket.pad=Alusta: msg.entity.rocket.disass=Pura -msg.entity.rocket.seldst=Valitse Mrnp -msg.entity.rocket.clear=Tyhjenn +msg.entity.rocket.seldst=Valitse Määränpää +msg.entity.rocket.clear=Tyhjennä msg.entity.rocket.rcs=RCS Moodi msg.entity.rocket.none=Ei Valittu msg.wirelessTransciever.extract=ota talteen msg.powerunit.rfpertick=FE/t -msg.linker.error.firstMachine=Tmn tytyy olla ensimminen yhdistettv laite! -msg.linker.program=Koordinaatit ohjelmoitu yhdistjn +msg.linker.error.firstMachine=Tämän täytyy olla ensimmäinen yhdistettävä laite! +msg.linker.program=Koordinaatit ohjelmoitu yhdistäjään msg.linker.success=Onnistuneesti Yhdistetty -msg.notenoughpower=Ei Tarpeeksi shk! -msg.empty=Tyhj -msg.yes=kyll +msg.notenoughpower=Ei Tarpeeksi sähköä! +msg.empty=Tyhjä +msg.yes=kyllä msg.no=ei msg.connected=yhdistetty msg.notconnected=ei yhdistetty msg.unprogrammed=Ohjelmoimaton -msg.programfail=Ohjelmointi Eponnistui +msg.programfail=Ohjelmointi Epäonnistui msg.modules=moduulit msg.na=N/A -msg.entityDeployedRocket.notGasGiant=Ei Kaasua Tll -msg.noOxygen=Varoitus: Ilmakehss ei ole happea! -msg.tooHot=Varoitus: Ilmakeh liian kuuma! +msg.entityDeployedRocket.notGasGiant=Ei Kaasua Täällä +msg.noOxygen=Varoitus: Ilmakehässä ei ole happea! +msg.tooHot=Varoitus: Ilmakehä liian kuuma! msg.tooDense=Varoitus: Ilmanpaine liian korkea! msg.muchTooDense=Varoitus: Ilmanpaine kriittisen korkea! -msg.chat.nostation1=Sin hert avaruusasemalla viipyvn tunteen kanssa, ett sinun pitkkantoinen avaruuskvely oli jonkun vanhan kettujumalan paheksuma ja ett olisis typer yritt niin uudelleen ja odottaa erilaisia tuloksia -msg.chat.nostation2=Ehk sinun pitisi ajatella ennen kuin ylitt jlleen selkesti loogisia ja absoluuttisia rajoja ja sitten ptt, ett se oli hyv idea eik sinun vikasi, jos asiat menevt pieleen -msg.chat.nostation3=Sinun tytyy olla avaruusasemalla ollaksesi tss ulottuvuudessa, ja yhtn ei ole luotu! \ No newline at end of file +msg.chat.nostation1=Sinä heräät avaruusasemalla viipyvän tunteen kanssa, että sinun pitkäkantoinen avaruuskävely oli jonkun vanhan kettujumalan paheksuma ja että olisis typerää yrittää niin uudelleen ja odottaa erilaisia tuloksia +msg.chat.nostation2=Ehkä sinun pitäisi ajatella ennen kuin ylität jälleen selkeästi loogisia ja absoluuttisia rajoja ja sitten päättää, että se oli hyvä idea eikä sinun vikasi, jos asiat menevät pieleen +msg.chat.nostation3=Sinun täytyy olla avaruusasemalla ollaksesi tässä ulottuvuudessa, ja yhtään ei ole luotu! + +jei.sb.satellitepreview=Valmis kiertoradalle! +jei.sb.copy.source=Lähde +jei.sb.copy.output=Uusi kopio +jei.sb.assemblyhint=Vähintään yksi aurinkopaneeli +jei.sb.copychiphint=Tee varmuuskopiot! From b5bd8629c9f2d32b4ff1da70014b597944ae98d5 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 10:05:31 +0200 Subject: [PATCH 011/274] Add French translations for satellite features --- src/main/resources/assets/advancedrocketry/lang/fr_FR.lang | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/resources/assets/advancedrocketry/lang/fr_FR.lang b/src/main/resources/assets/advancedrocketry/lang/fr_FR.lang index f863c40f0..f06e2f69b 100644 --- a/src/main/resources/assets/advancedrocketry/lang/fr_FR.lang +++ b/src/main/resources/assets/advancedrocketry/lang/fr_FR.lang @@ -260,3 +260,10 @@ msg.spaceElevator.ascentReady=Paré pour l'ascension msg.spaceElevator.turnedOff=L'ascenseur est hors tension. msg.entityDeployedRocket.notGasGiant=Absence de gaz msg.noOxygen=Avertissement: oxygène non détecté! + +jei.sb.satellitepreview=Prêt pour l’orbite ! +jei.sb.copy.source=Source +jei.sb.copy.output=Nouvelle copie +jei.sb.assemblyhint=Au moins un panneau solaire +jei.sb.copychiphint=Faites des sauvegardes ! + From dc0a93aa0abac365b5ce0662d3ab85525425cb60 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 10:05:55 +0200 Subject: [PATCH 012/274] Update pt_br.lang --- .../resources/assets/advancedrocketry/lang/pt_br.lang | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/resources/assets/advancedrocketry/lang/pt_br.lang b/src/main/resources/assets/advancedrocketry/lang/pt_br.lang index 3f63313c3..56020c67a 100644 --- a/src/main/resources/assets/advancedrocketry/lang/pt_br.lang +++ b/src/main/resources/assets/advancedrocketry/lang/pt_br.lang @@ -222,3 +222,11 @@ advancement.suitedUp.desc=Wear a full spacesuit key.controls.advancedrocketry=Advanced Rocketry key.openRocketUI=Open Rocket GUI key.toggleJetpack=Toggle Jetpack + + +jei.sb.satellitepreview=Pronto para a órbita! +jei.sb.copy.source=Fonte +jei.sb.copy.output=Nova cópia +jei.sb.assemblyhint=Pelo menos um painel solar +jei.sb.copychiphint=Faça backups! + From 2139488a55bf75d53808ba2bef5bb72a29532926 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 10:06:14 +0200 Subject: [PATCH 013/274] Add new Russian language entries for commands --- src/main/resources/assets/advancedrocketry/lang/ru_RU.lang | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/resources/assets/advancedrocketry/lang/ru_RU.lang b/src/main/resources/assets/advancedrocketry/lang/ru_RU.lang index 9c25fc9d4..1f5c8ab0e 100644 --- a/src/main/resources/assets/advancedrocketry/lang/ru_RU.lang +++ b/src/main/resources/assets/advancedrocketry/lang/ru_RU.lang @@ -448,3 +448,10 @@ msg.na=Н/Д commands.weather.always_not_clear=На этой планете не бывает сухо... commands.weather.cannot_rain=Невозможно начать дождь, увы... commands.weather.cannot_thunder=Невозможно включить грозу, увы... + + +jei.sb.satellitepreview=Готово к орбите! +jei.sb.copy.source=Источник +jei.sb.copy.output=Новая копия +jei.sb.assemblyhint=Как минимум одна солнечная панель +jei.sb.copychiphint=Делайте резервные копии! From 89509a1067f340f83f0a641fa62ccc0e3774a9ac Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 10:06:32 +0200 Subject: [PATCH 014/274] Add new Ukrainian translations for satellite features --- src/main/resources/assets/advancedrocketry/lang/ua_UA.lang | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/resources/assets/advancedrocketry/lang/ua_UA.lang b/src/main/resources/assets/advancedrocketry/lang/ua_UA.lang index 8c922dfd4..6321d6af0 100644 --- a/src/main/resources/assets/advancedrocketry/lang/ua_UA.lang +++ b/src/main/resources/assets/advancedrocketry/lang/ua_UA.lang @@ -159,3 +159,10 @@ mission.asteroidmining.name=Вивчення астероїдів key.controls.advancedrocketry=Advanced Rocketry key.toggleJetpack=Ввімкнути реактивний ранець + +jei.sb.satellitepreview=Готово до орбіти! +jei.sb.copy.source=Джерело +jei.sb.copy.output=Нова копія +jei.sb.assemblyhint=Щонайменше одна сонячна панель +jei.sb.copychiphint=Робіть резервні копії! + From 8311a04a2910bc9d3c336dc0d4455bdbab7441b2 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 10:06:48 +0200 Subject: [PATCH 015/274] Add new translations to zh_CN.lang --- src/main/resources/assets/advancedrocketry/lang/zh_CN.lang | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/resources/assets/advancedrocketry/lang/zh_CN.lang b/src/main/resources/assets/advancedrocketry/lang/zh_CN.lang index 1f9c728f4..84ccf28ac 100644 --- a/src/main/resources/assets/advancedrocketry/lang/zh_CN.lang +++ b/src/main/resources/assets/advancedrocketry/lang/zh_CN.lang @@ -507,3 +507,9 @@ msg.chat.nostation3=你必须在空间站上才能来到这个时空,而现在 commands.weather.always_not_clear=这个星球的天气总是阴暗... commands.weather.cannot_rain=这里无法启动降雨 commands.weather.cannot_thunder=这里无法启动雷暴 + +jei.sb.satellitepreview=准备进入轨道! +jei.sb.copy.source=来源 +jei.sb.copy.output=新副本 +jei.sb.assemblyhint=至少一个太阳能电池板 +jei.sb.copychiphint=请做好备份! From 436abb2430b746e1b69acfd11d9ffc53b3f05a1b Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 10:32:22 +0200 Subject: [PATCH 016/274] Add Satellite Builder integration to JEI --- .../integration/jei/ARPlugin.java | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/ARPlugin.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/ARPlugin.java index 22a596f1d..e934a949b 100644 --- a/src/main/java/zmaster587/advancedRocketry/integration/jei/ARPlugin.java +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/ARPlugin.java @@ -41,6 +41,9 @@ import zmaster587.advancedRocketry.integration.jei.sawmill.SawMillCategory; import zmaster587.advancedRocketry.integration.jei.sawmill.SawMillRecipeHandler; import zmaster587.advancedRocketry.integration.jei.sawmill.SawMillRecipeMaker; +import zmaster587.advancedRocketry.integration.jei.satelliteBuilder.SatelliteBuilderCategory; +import zmaster587.advancedRocketry.integration.jei.satelliteBuilder.SatelliteBuilderRecipeHandler; +import zmaster587.advancedRocketry.integration.jei.satelliteBuilder.SatelliteBuilderRecipeMaker; import zmaster587.advancedRocketry.tile.multiblock.machine.*; import zmaster587.libVulpes.inventory.GuiModular; @@ -61,6 +64,7 @@ public class ARPlugin implements IModPlugin { public static final String platePresser = "zmaster587.AR.platePresser"; public static final String centrifugeUUID = "zmaster587.AR.centrifuge"; public static final String precisionLaserEngraverUUID = "zmaster587.AR.precisionlaseretcher"; + public static final String satelliteBuilderUUID = "zmaster587.AR.satelliteBuilder"; public static IJeiHelpers jeiHelpers; //AR machines can reload recipes. We still need this for JEI to be up-to-date @@ -74,17 +78,20 @@ public void registerCategories(IRecipeCategoryRegistration registry) { jeiHelpers = registry.getJeiHelpers(); IGuiHelper guiHelper = jeiHelpers.getGuiHelper(); - registry.addRecipeCategories(new RollingMachineCategory(guiHelper), - new LatheCategory(guiHelper), - new PrecisionAssemblerCategory(guiHelper), - new SawMillCategory(guiHelper), - new ChemicalReactorCategory(guiHelper), - new CrystallizerCategory(guiHelper), - new ElectrolyzerCategory(guiHelper), - new ArcFurnaceCategory(guiHelper), - new PlatePressCategory(guiHelper), - new CentrifugeCategory(guiHelper), - new PrecisionLaserEtcherCategory(guiHelper)); + registry.addRecipeCategories( + new RollingMachineCategory(guiHelper), + new LatheCategory(guiHelper), + new PrecisionAssemblerCategory(guiHelper), + new SawMillCategory(guiHelper), + new ChemicalReactorCategory(guiHelper), + new CrystallizerCategory(guiHelper), + new ElectrolyzerCategory(guiHelper), + new ArcFurnaceCategory(guiHelper), + new PlatePressCategory(guiHelper), + new CentrifugeCategory(guiHelper), + new PrecisionLaserEtcherCategory(guiHelper), + new SatelliteBuilderCategory(guiHelper) + ); } @Override @@ -128,7 +135,9 @@ public Object getIngredientUnderMouse(GuiModular guiContainer, new ArcFurnaceRecipeHandler(), new PlatePressRecipeHandler(), new CentrifugeRecipeHandler(), - new PrecisionLaserEtcherRecipeHandler()); + new PrecisionLaserEtcherRecipeHandler(), + new SatelliteBuilderRecipeHandler() + ); registry.addRecipes(RollingMachineRecipeMaker.getMachineRecipes(jeiHelpers, TileRollingMachine.class), rollingMachineUUID); registry.addRecipes(LatheRecipeMaker.getMachineRecipes(jeiHelpers, TileLathe.class), latheUUID); @@ -141,6 +150,7 @@ public Object getIngredientUnderMouse(GuiModular guiContainer, registry.addRecipes(ChemicalReactorRecipeMaker.getMachineRecipes(jeiHelpers, TileChemicalReactor.class), chemicalReactorUUID); registry.addRecipes(CentrifugeRecipeMaker.getMachineRecipes(jeiHelpers, TileCentrifuge.class), centrifugeUUID); registry.addRecipes(PrecisionLaserEtcherRecipeMaker.getMachineRecipes(jeiHelpers, TilePrecisionLaserEtcher.class), precisionLaserEngraverUUID); + registry.addRecipes(SatelliteBuilderRecipeMaker.getMachineRecipes(jeiHelpers, null), satelliteBuilderUUID); registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockRollingMachine), rollingMachineUUID); @@ -154,5 +164,6 @@ public Object getIngredientUnderMouse(GuiModular guiContainer, registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockPlatePress), platePresser); registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockCentrifuge), centrifugeUUID); registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockPrecisionLaserEngraver), precisionLaserEngraverUUID); + registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockSatelliteBuilder), satelliteBuilderUUID); } } From ae69cf0052c604c94e3feb0fca03260c684302f5 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 10:36:58 +0200 Subject: [PATCH 017/274] Add SatelliteBuilderCategory for JEI integration --- .../SatelliteBuilderCategory.java | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/integration/jei/satelliteBuilder/SatelliteBuilderCategory.java diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/satelliteBuilder/SatelliteBuilderCategory.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/satelliteBuilder/SatelliteBuilderCategory.java new file mode 100644 index 000000000..0a303e02f --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/satelliteBuilder/SatelliteBuilderCategory.java @@ -0,0 +1,152 @@ +package zmaster587.advancedRocketry.integration.jei.satelliteBuilder; + +import mezz.jei.api.IGuiHelper; +import mezz.jei.api.gui.IDrawable; +import mezz.jei.api.gui.IRecipeLayout; +import mezz.jei.api.ingredients.IIngredients; +import mezz.jei.api.recipe.IRecipeCategory; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import zmaster587.advancedRocketry.integration.jei.ARPlugin; +import zmaster587.advancedRocketry.inventory.TextureResources; +import zmaster587.libVulpes.LibVulpes; + +import java.util.List; + +public class SatelliteBuilderCategory implements IRecipeCategory { + + private final IDrawable background; + private final IDrawable slotFunctionComponent; + private final IDrawable slotPowerComponent; + private final IDrawable slotIO; + private final IDrawable slotSatellite; + private final IDrawable slotIdChip; + private final IDrawable progressBar; + private final IDrawable vanillaSlot; + private final String uid; + + public SatelliteBuilderCategory(IGuiHelper guiHelper) { + // Use a blank or minimal background (176x90 is enough for the elements) + this.background = guiHelper.createBlankDrawable(176, 90); + + // Slot frames/icons from TextureResources + this.slotFunctionComponent = guiHelper.createDrawable( + new ResourceLocation("libvulpes:textures/gui/maingui.png"), + 212, 18, 18, 18); // functionComponent + + this.slotPowerComponent = guiHelper.createDrawable( + new ResourceLocation("libvulpes:textures/gui/maingui.png"), + 230, 18, 18, 18); // powercomponent + + this.slotIO = guiHelper.createDrawable( + new ResourceLocation("libvulpes:textures/gui/maingui.png"), + 212, 0, 18, 18); // ioSlot + + this.slotSatellite = guiHelper.createDrawable( + new ResourceLocation("advancedrocketry:textures/gui/progressBars/progressBars.png"), + 220, 238, 18, 18); + + this.slotIdChip = guiHelper.createDrawable( + new ResourceLocation("libvulpes:textures/gui/maingui.png"), + 230, 0, 18, 18); // idChip + + this.vanillaSlot = guiHelper.getSlotDrawable(); + + this.progressBar = guiHelper.createDrawable( + new ResourceLocation("advancedrocketry:textures/gui/progressBars/progressBars.png"), + 217, 0, 17, 17); // progressBar + + this.uid = ARPlugin.satelliteBuilderUUID; + } + + @Override + public IDrawable getBackground() { + return background; + } + + @Override + public String getTitle() { + return LibVulpes.proxy.getLocalizedString("tile.satelliteBuilder.name"); + } + + @Override + public String getModName() { + return "Advanced Rocketry"; + } + + @Override + public String getUid() { + return uid; + } + + public Class getRecipeClass() { + return SatelliteBuilderWrapper.class; + } + + + @Override + public void setRecipe(IRecipeLayout recipeLayout, SatelliteBuilderWrapper wrapper, IIngredients ingredients) { + // Place JEI slots at the same coordinates as the modules + // Slot indices: see TileSatelliteBuilder for mapping + // 0: function, 1-6: IO, 7: Output, 8: Chip, 9: Chip, 10: Chip copy 11: chassis + // Function slot 0 + recipeLayout.getItemStacks().init(0, true, 152, 10); + + // Power slots 1-2-3 + recipeLayout.getItemStacks().init(1, true, 116, 30); + recipeLayout.getItemStacks().init(2, true, 134, 30); + recipeLayout.getItemStacks().init(3, true, 152, 30); + recipeLayout.getItemStacks().init(4, true, 116, 50); + recipeLayout.getItemStacks().init(5, true, 134, 50); + recipeLayout.getItemStacks().init(6, true, 152, 50); + + // Output slot 7 + recipeLayout.getItemStacks().init(7, false, 58, 36); + + // ID chip slot 8 + recipeLayout.getItemStacks().init(8, true, 58, 16); + + // Chip copy slot 9 + recipeLayout.getItemStacks().init(9, true, 82, 16); + + // holdingslot slot 10 not used by players + //recipeLayout.getItemStacks().init(10, false, 58, 36); + + // Chassis slot 11 + recipeLayout.getItemStacks().init(11, true, 38, 16); + + recipeLayout.getItemStacks().set(ingredients); + + // Add tooltip cosmetics + wrapper.registerTooltipCallbacks(recipeLayout.getItemStacks()); + } + + @Override + public void drawExtras(Minecraft minecraft) { + FontRenderer fr = minecraft.fontRenderer; + // Draw slot frames and icons at the correct positions + slotFunctionComponent.draw(minecraft, 152, 10); // slot 0 + slotPowerComponent.draw(minecraft, 116, 30); // slot 1 + slotPowerComponent.draw(minecraft, 134, 30); // slot 2 + slotPowerComponent.draw(minecraft, 152, 30); // slot 3 + slotIO.draw(minecraft, 116, 50); // slot 4 + slotIO.draw(minecraft, 134, 50); // slot 5 + slotIO.draw(minecraft, 152, 50); // slot 6 + vanillaSlot.draw(minecraft, 58, 36); // Output slot (slot 7) + slotIdChip.draw(minecraft, 58, 16); // slot 8 + slotIdChip.draw(minecraft, 82, 16); // slot 9 + slotSatellite.draw(minecraft, 38, 16); // Chassis slot (slot 11) + + // Progress bar + progressBar.draw(minecraft, 75, 36); + + } + @Override + public java.util.List getTooltipStrings(int mouseX, int mouseY) { + return java.util.Collections.emptyList(); + } + +} From 6b66c716ace1cb796cc416e6bd9709bae807a632 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 10:37:21 +0200 Subject: [PATCH 018/274] Add SatelliteBuilderRecipeHandler for JEI integration --- .../SatelliteBuilderRecipeHandler.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/integration/jei/satelliteBuilder/SatelliteBuilderRecipeHandler.java diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/satelliteBuilder/SatelliteBuilderRecipeHandler.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/satelliteBuilder/SatelliteBuilderRecipeHandler.java new file mode 100644 index 000000000..adaa2e443 --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/satelliteBuilder/SatelliteBuilderRecipeHandler.java @@ -0,0 +1,28 @@ +package zmaster587.advancedRocketry.integration.jei.satelliteBuilder; + +import mezz.jei.api.recipe.IRecipeHandler; +import mezz.jei.api.recipe.IRecipeWrapper; +import zmaster587.advancedRocketry.integration.jei.ARPlugin; + +public class SatelliteBuilderRecipeHandler implements IRecipeHandler { + + @Override + public Class getRecipeClass() { + return SatelliteBuilderWrapper.class; + } + + @Override + public String getRecipeCategoryUid(SatelliteBuilderWrapper recipe) { + return ARPlugin.satelliteBuilderUUID; + } + + @Override + public IRecipeWrapper getRecipeWrapper(SatelliteBuilderWrapper recipe) { + return recipe; + } + + @Override + public boolean isRecipeValid(SatelliteBuilderWrapper recipe) { + return recipe != null; + } +} From 5414e988c2c96cdab38bbb44efc7ea448d2121ef Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 10:37:48 +0200 Subject: [PATCH 019/274] Add SatelliteBuilderRecipeMaker class for recipe creation Implement SatelliteBuilderRecipeMaker to create recipes for satellite assembly and chip copying. --- .../SatelliteBuilderRecipeMaker.java | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/integration/jei/satelliteBuilder/SatelliteBuilderRecipeMaker.java diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/satelliteBuilder/SatelliteBuilderRecipeMaker.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/satelliteBuilder/SatelliteBuilderRecipeMaker.java new file mode 100644 index 000000000..2827a502f --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/satelliteBuilder/SatelliteBuilderRecipeMaker.java @@ -0,0 +1,168 @@ +package zmaster587.advancedRocketry.integration.jei.satelliteBuilder; + +import mezz.jei.api.gui.ITooltipCallback; +import mezz.jei.api.IJeiHelpers; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import zmaster587.advancedRocketry.api.AdvancedRocketryItems; +import zmaster587.advancedRocketry.integration.jei.satelliteBuilder.SatelliteBuilderWrapper; +import zmaster587.libVulpes.api.LibVulpesItems; +import zmaster587.libVulpes.interfaces.IRecipe; + + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class SatelliteBuilderRecipeMaker { + + public static List getMachineRecipes(IJeiHelpers helpers, Class clazz) { + List recipes = new ArrayList<>(); + + // --- Satellite Assembly Example --- + // Slot mapping: + // 0: Function component (core module) + // 1-6: Module components (power, IO, etc) + // 7: Output slot + // 8: ID chip slot (input) + // 9: Chip copy slot (input) + // 10: Holding slot (ghostslot, not used by player) + // 11: Chassis slot + + + // slot 0 + List coreModules = new ArrayList<>(); + for (int i = 0; i < 7; i++) { + coreModules.add(new ItemStack(AdvancedRocketryItems.itemSatellitePrimaryFunction, 1, i)); + } // slot 0 + + // slots 1-6: power gen, battery, data units + List moduleVariants = Arrays.asList( + new ItemStack(AdvancedRocketryItems.itemSatellitePowerSource, 1, 0), + new ItemStack(AdvancedRocketryItems.itemSatellitePowerSource, 1, 1), + new ItemStack(LibVulpesItems.itemBattery, 1, 0), + new ItemStack(LibVulpesItems.itemBattery, 1, 1), + new ItemStack(AdvancedRocketryItems.itemDataUnit, 1, 0) + ); + + + + // Slot 8: controllers mapped 1:1 to primariry core modules (metas 0-6) + List satelliteControllers = Arrays.asList( + new ItemStack(AdvancedRocketryItems.itemSatelliteIdChip), // 0: Optical + new ItemStack(AdvancedRocketryItems.itemSatelliteIdChip), // 1: Composition + new ItemStack(AdvancedRocketryItems.itemSatelliteIdChip), // 2: Mass Scanner + new ItemStack(AdvancedRocketryItems.itemSatelliteIdChip), // 3: Microwave Energy + new ItemStack(AdvancedRocketryItems.itemOreScanner), // 4: Ore Mapping + new ItemStack(AdvancedRocketryItems.itemBiomeChanger), // 5: Biome Changer (remote) + new ItemStack(AdvancedRocketryItems.itemWeatherController)// 6: Weather Controller (remote) + ); + + + List output = Collections.singletonList(new ItemStack(AdvancedRocketryItems.itemSatellite)); // slot 7 (output) + List chassis = Collections.singletonList(new ItemStack(AdvancedRocketryItems.itemSatellite)); // slot 11 (empty chassis) + + List> inputs = new ArrayList<>(); + inputs.add(coreModules); // slot 0: Function component + inputs.add(moduleVariants); // slot 1: Module component + inputs.add(moduleVariants); // slot 2: Module component + inputs.add(moduleVariants); // slot 3: Module component + inputs.add(moduleVariants); // slot 4: Module component + inputs.add(moduleVariants); // slot 5: Module component + inputs.add(moduleVariants); // slot 6: Module component + //inputs.add(Collections.emptyList()); // slot 7: Output slot (not used as input) + inputs.add(satelliteControllers); // slot 8: ID chip slot + inputs.add(Collections.emptyList()); // slot 9: Chip copy slot (not used in this recipe) + //inputs.add(Collections.emptyList()); // slot 10: Holding slot (ghostslot, not used) + inputs.add(chassis); // slot 11: Chassis slot + + // Anonymous IRecipe implementation + IRecipe assemblyRecipe = new IRecipe() { + @Override + public List getOutput() { return output; } // slot 7 + @Override + public List getFluidOutputs() { return Collections.emptyList(); } + @Override + public List> getIngredients() { return inputs; } + @Override + public List getFluidIngredients() { return Collections.emptyList(); } + @Override + public int getTime() { return 200; } + @Override + public int getPower() { return 0; } + @Override + public String getOreDictString(int var1) { return ""; } + }; + + recipes.add(new SatelliteBuilderWrapper(assemblyRecipe, false)); + + // --- Chip Copy Example --- + // Slot mapping for chip copy: + // 8: Source chip (input) + // 9: Blank chip (input) + // 7: Output slot (copied chip) + + List sourceChips = Arrays.asList( + new ItemStack(AdvancedRocketryItems.itemSatelliteIdChip), + new ItemStack(AdvancedRocketryItems.itemPlanetIdChip), + new ItemStack(AdvancedRocketryItems.itemSpaceStationChip), + new ItemStack(AdvancedRocketryItems.itemOreScanner), + new ItemStack(AdvancedRocketryItems.itemBiomeChanger), + new ItemStack(AdvancedRocketryItems.itemWeatherController), + new ItemStack(AdvancedRocketryItems.itemSpaceElevatorChip) + ); + + // Mirror the source chips for blank chips + List blankChips = sourceChips; + + // The output cycling in mapped order: + List copiedOutputVariants = Arrays.asList( + new ItemStack(AdvancedRocketryItems.itemSatelliteIdChip), + new ItemStack(AdvancedRocketryItems.itemPlanetIdChip), + new ItemStack(AdvancedRocketryItems.itemSpaceStationChip), + new ItemStack(AdvancedRocketryItems.itemOreScanner), + new ItemStack(AdvancedRocketryItems.itemBiomeChanger), + new ItemStack(AdvancedRocketryItems.itemWeatherController), + new ItemStack(AdvancedRocketryItems.itemSpaceElevatorChip) + ); + + List> chipCopyInputs = new ArrayList<>(); + chipCopyInputs.add(Collections.emptyList()); // slot 0: Function component (not used) + chipCopyInputs.add(Collections.emptyList()); // slot 1: Power component (not used) + chipCopyInputs.add(Collections.emptyList()); // slot 2: Power component (not used) + chipCopyInputs.add(Collections.emptyList()); // slot 3: Power component (not used) + chipCopyInputs.add(Collections.emptyList()); // slot 4: IO component (not used) + chipCopyInputs.add(Collections.emptyList()); // slot 5: IO component (not used) + chipCopyInputs.add(Collections.emptyList()); // slot 6: IO component (not used) + //chipCopyInputs.add(Collections.emptyList()); // slot 7: Output slot + chipCopyInputs.add(sourceChips); // slot 8: Source chip + chipCopyInputs.add(blankChips); // slot 9: Blank chip + //chipCopyInputs.add(Collections.emptyList()); // slot 10: Holding slot (not used) + chipCopyInputs.add(Collections.emptyList()); // slot 11: Chassis slot (not used) + + IRecipe chipCopyRecipe = new IRecipe() { + @Override public List getOutput() { + // Could return first as a fallback; the wrapper will override with setOutputLists + return java.util.Collections.singletonList(copiedOutputVariants.get(0)); + } + @Override + public List getFluidOutputs() { return Collections.emptyList(); } + @Override + public List> getIngredients() { return chipCopyInputs; } + @Override + public List getFluidIngredients() { return Collections.emptyList(); } + @Override + public int getTime() { return 200; } + @Override + public int getPower() { return 0; } + @Override + public String getOreDictString(int var1) { return ""; } + }; + + recipes.add(new SatelliteBuilderWrapper(chipCopyRecipe, true, copiedOutputVariants)); + + return recipes; + } +} From 9bef88dfcbff58ae7d1f4121235757350a052259 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 10:38:10 +0200 Subject: [PATCH 020/274] Add SatelliteBuilderWrapper for JEI integration --- .../SatelliteBuilderWrapper.java | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/integration/jei/satelliteBuilder/SatelliteBuilderWrapper.java diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/satelliteBuilder/SatelliteBuilderWrapper.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/satelliteBuilder/SatelliteBuilderWrapper.java new file mode 100644 index 000000000..4c6943055 --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/satelliteBuilder/SatelliteBuilderWrapper.java @@ -0,0 +1,147 @@ +package zmaster587.advancedRocketry.integration.jei.satelliteBuilder; + +import mezz.jei.api.gui.IGuiItemStackGroup; +import mezz.jei.api.gui.ITooltipCallback; +import mezz.jei.api.ingredients.IIngredients; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.resources.I18n; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.TextFormatting; +import zmaster587.advancedRocketry.api.AdvancedRocketryItems; +import zmaster587.advancedRocketry.integration.jei.MachineRecipe; +import zmaster587.libVulpes.LibVulpes; +import zmaster587.libVulpes.interfaces.IRecipe; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class SatelliteBuilderWrapper extends MachineRecipe { + public final boolean isCopyRecipe; + private final IRecipe baseRecipe; // keep a handle + private final List outputVariants; // for JEI cycling (copy recipe) + private static Set COPY_STRIP_STRINGS; + + public SatelliteBuilderWrapper(IRecipe rec, boolean isCopyRecipe) { + this(rec, isCopyRecipe, null); + } + + public SatelliteBuilderWrapper(IRecipe rec, boolean isCopyRecipe, List outputVariants) { + super(rec); + this.isCopyRecipe = isCopyRecipe; + this.baseRecipe = rec; + this.outputVariants = outputVariants; + } + + @Override + public void getIngredients(mezz.jei.api.ingredients.IIngredients ingredients) { + super.getIngredients(ingredients); // inputs already mapped + + if (isCopyRecipe) { + // ONE output slot cycling MANY variants + List variants = (outputVariants != null && !outputVariants.isEmpty()) + ? outputVariants + : baseRecipe.getOutput(); // fallback if you didn’t pass variants + + if (variants != null && !variants.isEmpty()) { + ingredients.setOutputLists(ItemStack.class, + java.util.Collections.singletonList(variants)); + } + } else { + // Assembly: single concrete output (first item) + List outs = baseRecipe.getOutput(); + if (outs != null && !outs.isEmpty()) { + ingredients.setOutput(ItemStack.class, outs.get(0)); + } + } + } + + + + public java.util.List getOutputVariants() { return outputVariants; } + + public void registerTooltipCallbacks(IGuiItemStackGroup stacks) { + final boolean isCopy = this.isCopyRecipe; + + stacks.addTooltipCallback(new ITooltipCallback() { + @Override + public void onTooltip(int slotIndex, boolean input, ItemStack stack, List tooltip) { + if (stack.isEmpty()) return; + + if (!isCopy) { + // === ASSEMBLY RECIPE === (only touch output slot) + if (slotIndex != 7) return; + + if (stack.getItem() == AdvancedRocketryItems.itemSatellite) { + // Remove "empty chassis" (whatever the localization) + String libEmpty = LibVulpes.proxy.getLocalizedString("msg.itemsatellite.empty"); + tooltip.removeIf(line -> { + String stripped = net.minecraft.util.text.TextFormatting.getTextWithoutFormattingCodes(line); + if (stripped == null) return false; + String s = stripped.trim(); + return s.equalsIgnoreCase(libEmpty) || s.equalsIgnoreCase("unprogrammed"); + }); + + // Add clean preview label if not already present + String label = I18n.format("jei.sb.satellitepreview"); + addIfMissing(tooltip, label); + } + return; + } + + // === CHIP-COPY RECIPE === + if (slotIndex == 7 || slotIndex == 8) { + ensureCopyStripStringsBuilt(); + + // Strip any "unprogrammed"/blank-style lines (locale + color safe) + tooltip.removeIf(line -> { + String stripped = net.minecraft.util.text.TextFormatting.getTextWithoutFormattingCodes(line); + return stripped != null && COPY_STRIP_STRINGS.contains(stripped.trim().toLowerCase()); + }); + + // Add concise labels + final String key = (slotIndex == 7) ? "jei.sb.copy.output" : "jei.sb.copy.source"; + String label = I18n.format(key); + addIfMissing(tooltip, label); + } + } + }); + } + + private static void addIfMissing(List tooltip, String label) { + for (String l : tooltip) { + String stripped = net.minecraft.util.text.TextFormatting.getTextWithoutFormattingCodes(l); + if (stripped != null && stripped.equalsIgnoreCase(label)) return; + } + tooltip.add(label); + } + + private static void ensureCopyStripStringsBuilt() { + if (COPY_STRIP_STRINGS != null) return; + COPY_STRIP_STRINGS = new HashSet<>(); + String[] keys = { + "msg.itemchip.unprogrammed", + "msg.satelliteidchip.unprogrammed", + "msg.planetidchip.unprogrammed", + "msg.stationchip.unprogrammed", + "msg.orescanner.unprogrammed", + "msg.itemsatellite.empty" + }; + for (String k : keys) { + String v1 = I18n.format(k); + if (v1 != null) COPY_STRIP_STRINGS.add(v1.trim().toLowerCase()); + String v2 = LibVulpes.proxy.getLocalizedString(k); + if (v2 != null) COPY_STRIP_STRINGS.add(v2.trim().toLowerCase()); + } + COPY_STRIP_STRINGS.add("unprogrammed"); + } + + @Override + public void drawInfo(Minecraft minecraft, int recipeWidth, int recipeHeight, int mouseX, int mouseY) { + FontRenderer fr = minecraft.fontRenderer; + String text = I18n.format(isCopyRecipe ? "jei.sb.copychiphint" : "jei.sb.assemblyhint"); + int tw = fr.getStringWidth(text); + fr.drawString(text, (recipeWidth - tw) / 2, recipeHeight - fr.FONT_HEIGHT - 4, 0x000000); + } +} From 16778040e74d4d0d3e843e434737de7e5f7de6e8 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 20:47:45 +0200 Subject: [PATCH 021/274] Add message for already assembled rocket --- src/main/resources/assets/advancedrocketry/lang/en_US.lang | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/assets/advancedrocketry/lang/en_US.lang b/src/main/resources/assets/advancedrocketry/lang/en_US.lang index 502730313..3141b0a38 100644 --- a/src/main/resources/assets/advancedrocketry/lang/en_US.lang +++ b/src/main/resources/assets/advancedrocketry/lang/en_US.lang @@ -412,6 +412,7 @@ msg.rocketbuilder.acc=Acc msg.rocketbuilder.build=Build msg.rocketbuilder.scan=Scan msg.rocketbuild.combinedthrust=Fuel types cannot be combined! +msg.rocketbuilder.alreadyassembled=Rocket already assembled msg.solar.collectingEnergy=Collecting Energy: msg.solar.cannotcollectEnergy=Unable to collect Energy msg.asteroidChip.asteroid=Asteroid From 5eceb8c6664faf6cecc036a40838aa575db0630a Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 20:50:28 +0200 Subject: [PATCH 022/274] Add translation for already assembled rocket message --- src/main/resources/assets/advancedrocketry/lang/de_DE.lang | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/assets/advancedrocketry/lang/de_DE.lang b/src/main/resources/assets/advancedrocketry/lang/de_DE.lang index d832ae4e5..4a6d75c7c 100644 --- a/src/main/resources/assets/advancedrocketry/lang/de_DE.lang +++ b/src/main/resources/assets/advancedrocketry/lang/de_DE.lang @@ -345,6 +345,7 @@ msg.rocketbuilder.fuel=Treibstoff msg.rocketbuilder.acc=Beschleunigung msg.rocketbuilder.build=Bauen msg.rocketbuilder.scan=Scannen +msg.rocketbuilder.alreadyassembled=Rakete bereits zusammengebaut msg.solar.collectingEnergy= Energie sammeln: msg.solar.cannotcollectEnergy=Kann keine Energie sammeln msg.asteroidChip.asteroid=Asteroid From 7c0816586d5e5f6f004f329a9f243fed4e27bf0b Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 20:51:16 +0200 Subject: [PATCH 023/274] Add Spanish translation for rocket builder message --- src/main/resources/assets/advancedrocketry/lang/es_ES.lang | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/resources/assets/advancedrocketry/lang/es_ES.lang b/src/main/resources/assets/advancedrocketry/lang/es_ES.lang index 76c126f26..dee6a00a0 100644 --- a/src/main/resources/assets/advancedrocketry/lang/es_ES.lang +++ b/src/main/resources/assets/advancedrocketry/lang/es_ES.lang @@ -108,6 +108,8 @@ item.jackhammer.name=Martillo neumático item.sealDetector.name=Detector de sellado tile.orientationControl.name=Controlador de orientación +msg.rocketbuilder.alreadyassembled=Cohete ya ensamblado + material.Dilithium.name=Dilitio From 74d784231c539d5d791a359bf36b2e8c3ac0c488 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 20:52:02 +0200 Subject: [PATCH 024/274] Add translation for already assembled rocket message --- src/main/resources/assets/advancedrocketry/lang/ru_RU.lang | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/assets/advancedrocketry/lang/ru_RU.lang b/src/main/resources/assets/advancedrocketry/lang/ru_RU.lang index 1f5c8ab0e..198fac170 100644 --- a/src/main/resources/assets/advancedrocketry/lang/ru_RU.lang +++ b/src/main/resources/assets/advancedrocketry/lang/ru_RU.lang @@ -376,6 +376,7 @@ msg.rocketbuilder.fuel=Топливо msg.rocketbuilder.acc=Точность msg.rocketbuilder.build=Стройка msg.rocketbuilder.scan=Сканирование +msg.rocketbuilder.alreadyassembled=Ракета вже зібрана msg.solar.collectingEnergy=Сбор энергии: msg.solar.cannotcollectEnergy=Невозможно собрать энергию msg.asteroidChip.asteroid=Астероид From 1a09c92dfe4c50258d2a7e111107a9a2ac3af02d Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 20:53:14 +0200 Subject: [PATCH 025/274] Fix translation for already assembled rocket message --- src/main/resources/assets/advancedrocketry/lang/ru_RU.lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/advancedrocketry/lang/ru_RU.lang b/src/main/resources/assets/advancedrocketry/lang/ru_RU.lang index 198fac170..5d41eca70 100644 --- a/src/main/resources/assets/advancedrocketry/lang/ru_RU.lang +++ b/src/main/resources/assets/advancedrocketry/lang/ru_RU.lang @@ -376,7 +376,7 @@ msg.rocketbuilder.fuel=Топливо msg.rocketbuilder.acc=Точность msg.rocketbuilder.build=Стройка msg.rocketbuilder.scan=Сканирование -msg.rocketbuilder.alreadyassembled=Ракета вже зібрана +msg.rocketbuilder.alreadyassembled=Ракета уже собрана msg.solar.collectingEnergy=Сбор энергии: msg.solar.cannotcollectEnergy=Невозможно собрать энергию msg.asteroidChip.asteroid=Астероид From cee2f150b1db30b4bec7667cd5e4a09ceb830421 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 20:53:43 +0200 Subject: [PATCH 026/274] Add translation for already assembled rocket message --- src/main/resources/assets/advancedrocketry/lang/zh_CN.lang | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/assets/advancedrocketry/lang/zh_CN.lang b/src/main/resources/assets/advancedrocketry/lang/zh_CN.lang index 84ccf28ac..6d5379489 100644 --- a/src/main/resources/assets/advancedrocketry/lang/zh_CN.lang +++ b/src/main/resources/assets/advancedrocketry/lang/zh_CN.lang @@ -412,6 +412,7 @@ msg.rocketbuilder.acc=飞行控制中心 msg.rocketbuilder.build=建造 msg.rocketbuilder.scan=扫描 msg.rocketbuild.combinedthrust=燃料类型不能组合! +msg.rocketbuilder.alreadyassembled=火箭已组装 msg.solar.collectingEnergy=收集能量: msg.solar.cannotcollectEnergy=无法收集能量 msg.asteroidChip.asteroid=小行星 From 0ca57a68f692225f594c5d138287a747e1c38fd6 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 21:13:34 +0200 Subject: [PATCH 027/274] Rocket assembler: fixed: errormessage and translationkey Automatically updates status to unscanned if no rocket is present when the GUI is opened. Localized error message for already assembled rockets. --- .../tile/TileRocketAssemblingMachine.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java b/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java index aa77c094d..089d35c8d 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java @@ -812,6 +812,17 @@ else if (ErrorCodes.INCOMPLETESTRCUTURE.equals(getStatus())) @Override public List getModules(int ID, EntityPlayer player) { + + // Automatically set status to unscanned if no rocket is present when opening GUI + if (!world.isRemote && status == ErrorCodes.ALREADY_ASSEMBLED) { + AxisAlignedBB box = (bbCache != null) ? bbCache : getRocketPadBounds(world, pos); + if (box == null || world.getEntitiesWithinAABB(EntityRocket.class, box).isEmpty()) { + status = ErrorCodes.UNSCANNED; + markDirty(); + } + } + + List modules = new LinkedList<>(); modules.add(new ModulePower(160, 90, this)); @@ -1155,7 +1166,7 @@ protected enum ErrorCodes { OUTPUTBLOCKED(LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.outputblocked")), INVALIDBLOCK(LibVulpes.proxy.getLocalizedString("msg.rocketbuild.invalidblock")), COMBINEDTHRUST(LibVulpes.proxy.getLocalizedString("msg.rocketbuild.combinedthrust")), - ALREADY_ASSEMBLED("rocket already assembled"); + ALREADY_ASSEMBLED(LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.alreadyassembled")); String code; From a052e20140eb2e7443e3a042b9009c264c933bcc Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 15 Oct 2025 23:52:06 +0200 Subject: [PATCH 028/274] Add unscanned station message to lang file Added new message for unscanned station status. --- src/main/resources/assets/advancedrocketry/lang/en_US.lang | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/resources/assets/advancedrocketry/lang/en_US.lang b/src/main/resources/assets/advancedrocketry/lang/en_US.lang index 3141b0a38..7a92d2177 100644 --- a/src/main/resources/assets/advancedrocketry/lang/en_US.lang +++ b/src/main/resources/assets/advancedrocketry/lang/en_US.lang @@ -397,7 +397,9 @@ msg.rocketbuilder.noseat=Missing seat or satellite bay! msg.rocketbuilder.noengines=You do not have enough thrust! msg.rocketbuilder.noguidance=Missing Guidance Computer msg.rocketbuilder.unscanned=Rocket unscanned +msg.rocketbuilder.unscanned_station=Standing by for scan msg.rocketbuilder.success_station=Ready! +msg.rocketbuilder.fail_cut=Build failed: area changed. msg.rocketbuilder.empty=Nothing here msg.rocketbuilder.finished=Build Complete! msg.rocketbuild.invalidblock=Invalid block! From 07b3319387dba044ad4fdcca65178750e4f662f3 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 16 Oct 2025 00:07:59 +0200 Subject: [PATCH 029/274] Fix failure message formatting in en_US.lang --- src/main/resources/assets/advancedrocketry/lang/en_US.lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/advancedrocketry/lang/en_US.lang b/src/main/resources/assets/advancedrocketry/lang/en_US.lang index 7a92d2177..b876edffe 100644 --- a/src/main/resources/assets/advancedrocketry/lang/en_US.lang +++ b/src/main/resources/assets/advancedrocketry/lang/en_US.lang @@ -399,7 +399,7 @@ msg.rocketbuilder.noguidance=Missing Guidance Computer msg.rocketbuilder.unscanned=Rocket unscanned msg.rocketbuilder.unscanned_station=Standing by for scan msg.rocketbuilder.success_station=Ready! -msg.rocketbuilder.fail_cut=Build failed: area changed. +msg.rocketbuilder.fail_cut=Build failed: area changed msg.rocketbuilder.empty=Nothing here msg.rocketbuilder.finished=Build Complete! msg.rocketbuild.invalidblock=Invalid block! From 45e0513554081c4b8de8be7396a7d3cc0fbb1fc4 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 16 Oct 2025 00:09:43 +0200 Subject: [PATCH 030/274] Add new error codes for rocket assembly (station assembler) --- .../advancedRocketry/tile/TileRocketAssemblingMachine.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java b/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java index 089d35c8d..6cb62ba97 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java @@ -1166,7 +1166,9 @@ protected enum ErrorCodes { OUTPUTBLOCKED(LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.outputblocked")), INVALIDBLOCK(LibVulpes.proxy.getLocalizedString("msg.rocketbuild.invalidblock")), COMBINEDTHRUST(LibVulpes.proxy.getLocalizedString("msg.rocketbuild.combinedthrust")), - ALREADY_ASSEMBLED(LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.alreadyassembled")); + ALREADY_ASSEMBLED(LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.alreadyassembled")), + UNSCANNED_STATION(LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.unscanned_station")), + FAIL_CUT(LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.fail_cut")); String code; From d0398b8cd7caec5ab0acc7e473712c5846967d28 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 16 Oct 2025 00:56:55 +0200 Subject: [PATCH 031/274] Station assembler properly communicates with player errormessages for all its operations --- .../tile/TileStationAssembler.java | 82 +++++++++++++------ 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/TileStationAssembler.java b/src/main/java/zmaster587/advancedRocketry/tile/TileStationAssembler.java index 74b2fdaaf..abc674c3c 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/TileStationAssembler.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/TileStationAssembler.java @@ -63,11 +63,13 @@ public boolean canScan() { public AxisAlignedBB scanRocket(World world, BlockPos pos2, AxisAlignedBB bb) { int actualMinX = (int) bb.maxX, - actualMinY = (int) bb.maxY, - actualMinZ = (int) bb.maxZ, - actualMaxX = (int) bb.minX, - actualMaxY = (int) bb.minY, - actualMaxZ = (int) bb.minZ; + actualMinY = (int) bb.maxY, + actualMinZ = (int) bb.maxZ, + actualMaxX = (int) bb.minX, + actualMaxY = (int) bb.minY, + actualMaxZ = (int) bb.minZ; + + boolean foundNonAir = false; for (int xCurr = (int) bb.minX; xCurr <= bb.maxX; xCurr++) { for (int zCurr = (int) bb.minZ; zCurr <= bb.maxZ; zCurr++) { @@ -76,29 +78,32 @@ public AxisAlignedBB scanRocket(World world, BlockPos pos2, AxisAlignedBB bb) { BlockPos posCurr = new BlockPos(xCurr, yCurr, zCurr); if (!world.isAirBlock(posCurr)) { - if (xCurr < actualMinX) - actualMinX = xCurr; - if (yCurr < actualMinY) - actualMinY = yCurr; - if (zCurr < actualMinZ) - actualMinZ = zCurr; - if (xCurr > actualMaxX) - actualMaxX = xCurr; - if (yCurr > actualMaxY) - actualMaxY = yCurr; - if (zCurr > actualMaxZ) - actualMaxZ = zCurr; + foundNonAir = true; + + if (xCurr < actualMinX) actualMinX = xCurr; + if (yCurr < actualMinY) actualMinY = yCurr; + if (zCurr < actualMinZ) actualMinZ = zCurr; + if (xCurr > actualMaxX) actualMaxX = xCurr; + if (yCurr > actualMaxY) actualMaxY = yCurr; + if (zCurr > actualMaxZ) actualMaxZ = zCurr; } } } } - status = ErrorCodes.SUCCESS_STATION; + // Tell the player whats up + if (!foundNonAir) { + status = ErrorCodes.EMPTY; // nothing to pack inside bb + return bb; // sanity check + } else { + status = ErrorCodes.SUCCESS_STATION; // ok to proceed with packing + } return new AxisAlignedBB(actualMinX, actualMinY, actualMinZ, actualMaxX, actualMaxY, actualMaxZ); } + @Override public void assembleRocket() { if (!world.isRemote) { @@ -113,6 +118,9 @@ public void assembleRocket() { try { storageChunk = StorageChunk.cutWorldBB(world, bbCache); } catch (NegativeArraySizeException e) { + status = ErrorCodes.FAIL_CUT; + markDirty(); + world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3); return; } @@ -152,20 +160,38 @@ public void assembleRocket() { @Override protected void updateText() { - if (!world.isRemote) { - if (getRocketPadBounds(world, pos) == null) + if (world != null && !world.isRemote) { + if (getRocketPadBounds(world, pos) == null) { setStatus(ErrorCodes.INCOMPLETESTRCUTURE.ordinal()); - else if (ErrorCodes.INCOMPLETESTRCUTURE.equals(getStatus())) - setStatus(ErrorCodes.UNSCANNED.ordinal()); + } else if (ErrorCodes.INCOMPLETESTRCUTURE.equals(getStatus())) { + setStatus(ErrorCodes.UNSCANNED_STATION.ordinal()); + } } - errorText.setText(status.getErrorCode()); + if (errorText != null) { + errorText.setText(status.getErrorCode()); + } } @Override public List getModules(int ID, EntityPlayer player) { List modules = new LinkedList<>(); + // GUI-open reset errorcode if pad is valid and we're idle + if (!world.isRemote) { + AxisAlignedBB bounds = getRocketPadBounds(world, pos); + if (bounds == null) { + setStatus(ErrorCodes.INCOMPLETESTRCUTURE.ordinal()); + } else if (!isScanning()) { + ErrorCodes s = getStatus(); + if (s == ErrorCodes.SUCCESS_STATION || s == ErrorCodes.SUCCESS || + s == ErrorCodes.FINISHED || s == ErrorCodes.EMPTY || + s == ErrorCodes.UNSCANNED) { + setStatus(ErrorCodes.UNSCANNED_STATION.ordinal()); + } + } + } + modules.add(new ModulePower(160, 30, this)); modules.add(new ModuleProgress(149, 30, 2, verticalProgressBar, this)); @@ -177,6 +203,7 @@ public List getModules(int ID, EntityPlayer player) { buttonBuild.setColor(0xFFFF2222); modules.add(errorText = new ModuleText(5, 22, "", 0xFFFFFF22)); modules.add(new ModuleSync(4, this)); + modules.add(new ModuleSync(2, this)); // sync error codes to client (on change) updateText(); @@ -190,19 +217,20 @@ public List getModules(int ID, EntityPlayer player) { @Override - public void useNetworkData(EntityPlayer player, Side side, byte id, - NBTTagCompound nbt) { + public void useNetworkData(EntityPlayer player, Side side, byte id, NBTTagCompound nbt) { + + super.useNetworkData(player, side, id, nbt); + // recompute AFTER super boolean isScanningFlag = !isScanning() && canScan(); - super.useNetworkData(player, side, id, nbt); if (id == 1 && isScanningFlag) { - storedId = (long) ItemStationChip.getUUID(inventory.getStackInSlot(1)); if (storedId == 0) storedId = null; } } + @Override public NBTTagCompound writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); From 6e997b4167ada636e10da040457c568b2bca80c5 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 17 Oct 2025 16:01:33 +0200 Subject: [PATCH 032/274] Perfomance fixes Enable/disable button actually means early exit. General Throttling to 20tick intervals, +phasing for multiple transcievers --- .../tile/cables/TileWirelessTransciever.java | 115 +++++++++++++----- 1 file changed, 85 insertions(+), 30 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java b/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java index 7687b9353..2ce4755c0 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java @@ -38,6 +38,10 @@ public class TileWirelessTransciever extends TileEntity implements INetworkMachine, IModularInventory, ILinkableTile, IDataHandler, ITickable, IToggleButton { + // How often to transfer data (in ticks) + private int transferIntervalTicks = 20; + // Fixed phase per tile to spread load + private int phase = -1; protected ModuleToggleSwitch toggleSwitch; boolean extractMode; @@ -53,6 +57,10 @@ public TileWirelessTransciever() { data.setMaxData(100); toggle = new ModuleToggleSwitch(50, 50, 0, LibVulpes.proxy.getLocalizedString("msg.wirelessTransciever.extract"), this, TextureResources.buttonGeneric, 64, 18, false); toggleSwitch = new ModuleToggleSwitch(160, 5, 1, "", this, zmaster587.libVulpes.inventory.TextureResources.buttonToggleImage, 11, 26, true); + + // Align internal booleans with UI defaults + extractMode = toggle.getState(); // false initially + enabled = toggleSwitch.getState(); // true initially } @@ -229,7 +237,7 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { nbt.setBoolean("mode", extractMode); nbt.setBoolean("enabled", enabled); nbt.setInteger("networkID", networkID); - data.writeToNBT(nbt); + data.writeToNBT(nbt); return super.writeToNBT(nbt); } @@ -248,51 +256,98 @@ public int addData(int maxAmount, DataType type, EnumFacing dir, @Override public void onLoad() { super.onLoad(); - if (!world.isRemote) { - if (!NetworkRegistry.dataNetwork.doesNetworkExist(networkID)) + // Server side only + if (world == null || world.isRemote) return; + + // Ensure sane interval before using it in modulo + if (transferIntervalTicks <= 0) transferIntervalTicks = 20; + + // Stable per-tile phase to spread work over time (no persistence needed) + phase = (int) Math.floorMod(this.pos.toLong(), transferIntervalTicks); + + // (Re)join the data network only if we’re actually linked to one + if (networkID != -1) { + if (!NetworkRegistry.dataNetwork.doesNetworkExist(networkID)) { + // Create (or re-create) this specific network id NetworkRegistry.dataNetwork.getNewNetworkID(networkID); + } + // Make sure we're not double-registered, then register with the right role NetworkRegistry.dataNetwork.getNetwork(networkID).removeFromAll(this); - if (extractMode) + if (extractMode) { NetworkRegistry.dataNetwork.getNetwork(networkID).addSource(this, EnumFacing.UP); - else + } else { NetworkRegistry.dataNetwork.getNetwork(networkID).addSink(this, EnumFacing.UP); - + } } } @Override public void update() { + // Server only + if (world.isRemote) return; - if (!world.isRemote) { - IBlockState state = world.getBlockState(getPos()); - if (state.getBlock() instanceof RotatableBlock) { - EnumFacing facing = RotatableBlock.getFront(state).getOpposite(); - - TileEntity tile = world.getTileEntity(getPos().add(facing.getFrontOffsetX(), facing.getFrontOffsetY(), facing.getFrontOffsetZ())); - - if (tile instanceof IDataHandler && !(tile instanceof TileWirelessTransciever)) { - for (DataType data : DataType.values()) { - - if (data == DataStorage.DataType.UNDEFINED) - continue; - - if (!extractMode) { - int amountCurrent = this.data.getDataAmount(data); - if (amountCurrent > 0) { - int amt = ((IDataHandler) tile).addData(amountCurrent, data, facing.getOpposite(), true); - this.data.extractData(amt, data, facing.getOpposite(), true); - } - } else { - int amt = ((IDataHandler) tile).extractData(this.data.getMaxData() - this.data.getDataAmount(data), data, facing.getOpposite(), true); - this.data.addData(amt, data, facing.getOpposite(), true); - } - } + // Respect front-panel enable switch + if (!enabled) return; + + // Guard against bad values (e.g., NBT edits) + if (transferIntervalTicks <= 0) transferIntervalTicks = 20; + + // Initialize a stable phase to spread load across ticks + if (phase < 0) { + phase = (int) Math.floorMod(this.pos.toLong(), transferIntervalTicks); + } + + // Throttle: only run on the tile's assigned tick + long now = world.getTotalWorldTime(); + if (((now + phase) % transferIntervalTicks) != 0) return; + + IBlockState state = world.getBlockState(getPos()); + if (!(state.getBlock() instanceof RotatableBlock)) return; + + // Face the block's "IO" side + EnumFacing facing = RotatableBlock.getFront(state).getOpposite(); + TileEntity neighbor = world.getTileEntity(getPos().offset(facing)); + + // Must be a data handler and not another wireless transceiver (avoid loops) + if (!(neighbor instanceof IDataHandler) || (neighbor instanceof TileWirelessTransciever)) return; + + boolean changed = false; + + for (DataStorage.DataType dataType : DataStorage.DataType.values()) { + if (dataType == DataStorage.DataType.UNDEFINED) continue; + + if (!extractMode) { + // PUSH: from this buffer -> neighbor + int have = this.data.getDataAmount(dataType); + if (have <= 0) continue; + + int moved = ((IDataHandler) neighbor).addData(have, dataType, facing.getOpposite(), true); + if (moved > 0) { + this.data.extractData(moved, dataType, facing.getOpposite(), true); + changed = true; + } + } else { + // PULL: from neighbor -> this buffer + int room = this.data.getMaxData() - this.data.getDataAmount(dataType); + if (room <= 0) continue; + + int moved = ((IDataHandler) neighbor).extractData(room, dataType, facing.getOpposite(), true); + if (moved > 0) { + this.data.addData(moved, dataType, facing.getOpposite(), true); + changed = true; } } } + + // Persist changes; a full block update isn't strictly required each tick + if (changed) { + this.markDirty(); + // If you want to sync the client meter instantly, you can uncomment: + // world.notifyBlockUpdate(pos, state, state, 3); + } } From 26b343c2c2c697bac9f1bc045c631d3ec51216ee Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 17 Oct 2025 16:08:43 +0200 Subject: [PATCH 033/274] fixed Satellite terminal no more broadcasting UI to every player in range, no more downloading data without power. --- .../tile/satellite/TileSatelliteTerminal.java | 170 +++++++++++++++--- 1 file changed, 142 insertions(+), 28 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java b/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java index 7dcfaef7f..0d42dcac5 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java @@ -17,7 +17,6 @@ import zmaster587.advancedRocketry.inventory.modules.ModuleSatellite; import zmaster587.advancedRocketry.item.ItemData; import zmaster587.advancedRocketry.item.ItemSatelliteIdentificationChip; -import zmaster587.advancedRocketry.network.PacketSatellite; import zmaster587.advancedRocketry.satellite.SatelliteData; import zmaster587.advancedRocketry.util.IDataInventory; import zmaster587.advancedRocketry.util.PlanetaryTravelHelper; @@ -36,6 +35,9 @@ public class TileSatelliteTerminal extends TileInventoriedRFConsumer implements INetworkMachine, IModularInventory, IButtonInventory, IDataInventory, IDataHandler { + // Subscribers: players who currently have this GUI open (server-side only) + private final java.util.Set subscribers = new java.util.HashSet<>(); + //private ModuleText satelliteText; private SatelliteBase satellite; @@ -121,12 +123,22 @@ public void readDataFromNetwork(ByteBuf in, byte packetId, @Override public void update() { super.update(); - - if (!world.isRemote) { - //update satellite for players nearby - if ((world.getTotalWorldTime() % 20) == 0) { - PacketHandler.sendToNearby(new PacketMachine(this, (byte) 22), world.provider.getDimension(), pos, 16); + if (world.isRemote) return; + + if ((world.getTotalWorldTime() % 20) == 0 && !subscribers.isEmpty()) { + PacketMachine pkt = new PacketMachine(this, (byte)22); + java.util.Set stale = new java.util.HashSet<>(); + + for (java.util.UUID id : subscribers) { + net.minecraft.entity.player.EntityPlayerMP mp = + (net.minecraft.entity.player.EntityPlayerMP) world.getPlayerEntityByUUID(id); + if (mp == null || !mp.isEntityAlive()) { + stale.add(id); + continue; + } + zmaster587.libVulpes.network.PacketHandler.sendToPlayer(pkt, mp); } + if (!stale.isEmpty()) subscribers.removeAll(stale); } } @@ -134,11 +146,35 @@ public void update() { public void useNetworkData(EntityPlayer player, Side side, byte id, NBTTagCompound nbt) { if (id == 0) { storeData(0); + } else if (id == 100) { + if (!world.isRemote) { + SatelliteBase sat = getSatelliteFromSlot(0); + + boolean inRange = false; + if (sat != null) { + int satDim = sat.getDimensionId(); + int hereDim = DimensionManager.getEffectiveDimId(world, pos).getId(); + inRange = PlanetaryTravelHelper.isTravelAnywhereInPlanetarySystem(satDim, hereDim); + } + boolean hasLink = (sat instanceof SatelliteData) && inRange; + boolean hasPower = getUniversalEnergyStored() >= getPowerPerOperation(); + + if (hasLink && hasPower) { + // perform action and pay the RF cost, just like extractData(commit=true) + sat.performAction(player, world, pos); + this.energy.extractEnergy(getPowerPerOperation(), false); + } - if (satellite != null && PlanetaryTravelHelper.isTravelAnywhereInPlanetarySystem(satellite.getDimensionId(), DimensionManager.getEffectiveDimId(world, pos).getId())) { - satellite.performAction(player, world, pos); + // Push a fresh status payload either way so the UI reflects current state + if (player instanceof net.minecraft.entity.player.EntityPlayerMP) { + zmaster587.libVulpes.network.PacketHandler.sendToPlayer( + new PacketMachine(this, (byte)22), + (net.minecraft.entity.player.EntityPlayerMP) player + ); + } } + } else if (id == 101) { onInventoryButtonPressed(id - 100); } @@ -147,25 +183,26 @@ public void useNetworkData(EntityPlayer player, Side side, byte id, NBTTagCompou if (world.isRemote) { // 22 should never arrive at the server int status = nbt.getInteger("status"); satellite = getSatelliteFromSlot(0); - if (moduleText != null){ - if (status != 0 && satellite != null) { - if (status == 1) - moduleText.setText(LibVulpes.proxy.getLocalizedString("msg.notenoughpower")); - - else if (status == 2) { - moduleText.setText(satellite.getName() + "\n\n" + LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.toofar")); - } else if (status == 3) { - moduleText.setText(satellite.getName() + "\n\n" + LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.info") + "\n" + - "Power gen.: "+nbt.getInteger("ppt")+"\n"+ - "Data: "+nbt.getInteger("data") +"/"+nbt.getInteger("maxdata")); + if (moduleText != null) { + if (status != 0 && satellite != null) { + if (status == 1) { + moduleText.setText(LibVulpes.proxy.getLocalizedString("msg.notenoughpower")); + } else if (status == 2) { + moduleText.setText(satellite.getName() + "\n\n" + LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.toofar")); + } else if (status == 3) { + moduleText.setText(satellite.getName() + "\n\n" + LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.info") + "\n" + + "Power gen.: " + nbt.getInteger("ppt") + "\n" + + "Data: " + nbt.getInteger("data") + "/" + nbt.getInteger("maxdata")); + } + } else { + moduleText.setText(LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.nolink")); } - } else - moduleText.setText(LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.nolink")); } } } } + @Override public void setInventorySlotContents(int slot, @Nonnull ItemStack stack) { super.setInventorySlotContents(slot, stack); @@ -191,6 +228,19 @@ public SatelliteBase getSatelliteFromSlot(int slot) { @Override public List getModules(int ID, EntityPlayer player) { + // Ensure the server registers the viewer and sends immediate state + if (!world.isRemote && player instanceof net.minecraft.entity.player.EntityPlayerMP) { + java.util.UUID uid = player.getUniqueID(); + if (!subscribers.contains(uid)) { + subscribers.add(uid); + } + // immediate payload so UI doesn’t show "no link" for up to 1s + zmaster587.libVulpes.network.PacketHandler.sendToPlayer( + new PacketMachine(this, (byte)22), + (net.minecraft.entity.player.EntityPlayerMP) player + ); + } + List modules = new LinkedList<>(); modules.add(new ModulePower(18, 20, this.energy)); modules.add(new ModuleButton(116, 70, 0, LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.connect"), this, zmaster587.libVulpes.inventory.TextureResources.buttonBuild)); @@ -274,18 +324,42 @@ public void storeData(int id) { @Override public int extractData(int maxAmount, DataType type, EnumFacing dir, boolean commit) { - //TODO + SatelliteBase sat = getSatelliteFromSlot(0); + + // Link + range + power gates (same as UI) + boolean inRange = false; + if (sat != null) { + int satDim = sat.getDimensionId(); + int hereDim = DimensionManager.getEffectiveDimId(world, pos).getId(); + inRange = PlanetaryTravelHelper.isTravelAnywhereInPlanetarySystem(satDim, hereDim); + } + boolean hasLink = (sat instanceof SatelliteData) && inRange; + boolean hasPower = getUniversalEnergyStored() >= getPowerPerOperation(); - SatelliteBase satellite = getSatelliteFromSlot(0); - if (satellite instanceof SatelliteData && PlanetaryTravelHelper.isTravelAnywhereInPlanetarySystem(satellite.getDimensionId(), DimensionManager.getEffectiveDimId(world, pos).getId())) { - satellite.performAction(null, world, pos); + if (!(hasLink && hasPower)) { + return 0; } - if (type == data.getDataType() || data.getDataType() == DataType.UNDEFINED) { - return data.removeData(maxAmount, commit); + if (!commit) { + // Simulate: do NOT pull from satellite; just report current availability + if (type != data.getDataType() && data.getDataType() != DataType.UNDEFINED) return 0; + int available = data.getData(); + return Math.min(maxAmount, available); } - return 0; + // COMMIT path: first pull fresh data from the satellite into our buffer + sat.performAction(null, world, pos); + + // Now validate type and figure out how much we can remove + if (type != data.getDataType() && data.getDataType() != DataType.UNDEFINED) return 0; + + int removable = Math.min(maxAmount, data.getData()); + if (removable <= 0) return 0; + + // Consume RF only if we're actually removing data + this.energy.extractEnergy(getPowerPerOperation(), false); + + return data.removeData(removable, true); } @Override @@ -298,4 +372,44 @@ public int addData(int maxAmount, DataType type, EnumFacing dir, boolean commit) public boolean canInteractWithContainer(EntityPlayer entity) { return true; } + + + // Subscribe/unsubscribe when GUI (container) opens/closes + @Override + public void openInventory(EntityPlayer player) { + super.openInventory(player); + if (!world.isRemote && player != null) { + subscribers.add(player.getUniqueID()); + // immediate first payload so UI populates without waiting a tick + if (player instanceof net.minecraft.entity.player.EntityPlayerMP) { + zmaster587.libVulpes.network.PacketHandler.sendToPlayer(new PacketMachine(this, (byte)22), + (net.minecraft.entity.player.EntityPlayerMP) player); + } + } + } + + @Override + public void closeInventory(EntityPlayer player) { + super.closeInventory(player); + if (!world.isRemote && player != null) { + subscribers.remove(player.getUniqueID()); + } + } + + @Override + public void onChunkUnload() { + super.onChunkUnload(); + if (!world.isRemote) { + subscribers.clear(); + } + } + + @Override + public void invalidate() { + super.invalidate(); + if (!world.isRemote) { + subscribers.clear(); + } + } + } From 11a4638d6e883f460b65a17210e9351512f53b27 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 17 Oct 2025 16:09:27 +0200 Subject: [PATCH 034/274] Change 'Connect!' to 'Download' and update thrust message to fit GUI --- src/main/resources/assets/advancedrocketry/lang/en_US.lang | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/assets/advancedrocketry/lang/en_US.lang b/src/main/resources/assets/advancedrocketry/lang/en_US.lang index b876edffe..ef50c3f68 100644 --- a/src/main/resources/assets/advancedrocketry/lang/en_US.lang +++ b/src/main/resources/assets/advancedrocketry/lang/en_US.lang @@ -359,7 +359,7 @@ msg.satctrlcenter.toofar=Too Far msg.satctrlcenter.nolink=No Link... msg.satctrlcenter.info=Info: msg.satctrlcenter.destroysat=Destroy Satellite -msg.satctrlcenter.connect=Connect! +msg.satctrlcenter.connect=Download msg.satbuilder.writesecondchip=Write to Secondary Chip msg.dockingport.target=Target Id msg.dockingport.me=My Id @@ -394,7 +394,7 @@ msg.warpmon.artifact=Artifacts msg.rocketbuilder.success=Clear for liftoff! msg.rocketbuilder.nofuel=Not enough fuel capacity! msg.rocketbuilder.noseat=Missing seat or satellite bay! -msg.rocketbuilder.noengines=You do not have enough thrust! +msg.rocketbuilder.noengines=Not enough thrust! msg.rocketbuilder.noguidance=Missing Guidance Computer msg.rocketbuilder.unscanned=Rocket unscanned msg.rocketbuilder.unscanned_station=Standing by for scan From 416a7a71a9ef20788d5a13ff6d9311c0c3c37c77 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 18 Oct 2025 19:47:52 +0200 Subject: [PATCH 035/274] Improve event bus registration in TileRocketAssemblingMachine Refactor event registration and handling for rocket assembly. Should fix GC going crazy when idle, aswell as lower overall GC for tile --- .../tile/TileRocketAssemblingMachine.java | 97 ++++++++++++------- 1 file changed, 63 insertions(+), 34 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java b/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java index 6cb62ba97..dc08ae779 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java @@ -28,6 +28,7 @@ import zmaster587.advancedRocketry.entity.EntityRocket; import zmaster587.advancedRocketry.item.ItemPackedStructure; import zmaster587.advancedRocketry.network.PacketInvalidLocationNotify; +import zmaster587.advancedRocketry.tile.TileRocketAssemblingMachine.ErrorCodes; import zmaster587.advancedRocketry.tile.hatch.TileSatelliteHatch; import zmaster587.advancedRocketry.util.StorageChunk; import zmaster587.advancedRocketry.util.WeightEngine; @@ -91,25 +92,44 @@ public TileRocketAssemblingMachine() { stats = new StatsRocket(); building = false; prevProgress = 0; - MinecraftForge.EVENT_BUS.register(this); } + private boolean registeredBus = false; + + @Override + public void onLoad() { + // Called after world is set and NBT is loaded; safe place to register (server only) + if (!world.isRemote && !registeredBus) { + MinecraftForge.EVENT_BUS.register(this); + registeredBus = true; + } + } + @Override public void invalidate() { super.invalidate(); - MinecraftForge.EVENT_BUS.unregister(this); - for (HashedBlockPosition pos : blockPos) { - TileEntity tile = world.getTileEntity(pos.getBlockPos()); + unregisterFromBus(); - if (tile instanceof IMultiblock) - ((IMultiblock) tile).setIncomplete(); + if (world != null) + for (HashedBlockPosition pos : blockPos) { + TileEntity tile = world.getTileEntity(pos.getBlockPos()); + if (tile instanceof IMultiblock) { + ((IMultiblock) tile).setIncomplete(); + } } } @Override public void onChunkUnload() { super.onChunkUnload(); - MinecraftForge.EVENT_BUS.unregister(this); + unregisterFromBus(); + } + + private void unregisterFromBus() { + if (registeredBus) { + MinecraftForge.EVENT_BUS.unregister(this); + registeredBus = false; + } } public ErrorCodes getStatus() { @@ -1117,39 +1137,48 @@ public List getConnectedInfrastructure() { } @SubscribeEvent - public void onRocketLand(RocketLandedEvent event) { - if (event.world.isRemote) - return; - EntityRocketBase rocket = (EntityRocketBase) event.getEntity(); - - - //This apparently happens sometimes - if (world == null) { - AdvancedRocketry.logger.debug("World null for rocket builder during rocket land event @ " + this.pos); - return; + public void onRocketLand(RocketLandedEvent e) { + // Server/world guard + if (e.world.isRemote || e.world != this.world) return; + + // Ensure we have pad bounds + if (bbCache == null) bbCache = getRocketPadBounds(world, pos); + if (bbCache == null) return; + + // Make sure the event entity is a rocket + final net.minecraft.entity.Entity ent = e.getEntity(); + if (!(ent instanceof EntityRocketBase)) return; + final EntityRocketBase landed = (EntityRocketBase) ent; + + // Quick membership test with tiny epsilon + final AxisAlignedBB box = bbCache.grow(1.0E-4, 1.0E-4, 1.0E-4); + if (!landed.getEntityBoundingBox().intersects(box)) return; + + // Track rocket id and (re)link infra + lastRocketID = landed.getEntityId(); + for (IInfrastructure infra : getConnectedInfrastructure()) { + landed.linkInfrastructure(infra); } - if (getBBCache() == null) { - bbCache = getRocketPadBounds(world, pos); + // Maintain original semantics: only fast-path when exactly one rocket in the pad + List rockets = world.getEntitiesWithinAABB(EntityRocket.class, box); + if (rockets.size() == 1) { + EntityRocket r = rockets.get(0); + r.recalculateStats(); + this.stats = r.stats.copy(); + this.status = ErrorCodes.ALREADY_ASSEMBLED; + markDirty(); + world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3); + } else { + // Fallback: rescan if something odd happens + scanRocket(world, pos, bbCache); } - if (getBBCache() != null) { - double buffer = 0.0001; - AxisAlignedBB bufferedBB = bbCache.grow(buffer, buffer, buffer); - List rockets = world.getEntitiesWithinAABB(EntityRocketBase.class, bufferedBB); - - if (rockets.contains(rocket)) { - lastRocketID = rocket.getEntityId(); - for (IInfrastructure infrastructure : getConnectedInfrastructure()) { - rocket.linkInfrastructure(infrastructure); - } - scanRocket(world,pos, bbCache); // rescan on landing - - PacketHandler.sendToPlayersTrackingEntity(new PacketMachine(this, (byte) 3), rocket); - } - } + // Preserve original networking + PacketHandler.sendToPlayersTrackingEntity(new PacketMachine(this, (byte)3), landed); } + protected enum ErrorCodes { SUCCESS(LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.success")), NOFUEL(LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.nofuel")), From 807c9a4f98b82a600541f046dc474229acd4fa38 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 19 Oct 2025 18:09:48 +0200 Subject: [PATCH 036/274] Add ModuleSatelliteTerminal for satelliteterminal really fixed DDosing everyone in 16block radius with updated UI-info. --- .../modules/ModuleSatelliteTerminal.java | 224 ++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleSatelliteTerminal.java diff --git a/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleSatelliteTerminal.java b/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleSatelliteTerminal.java new file mode 100644 index 000000000..1cc03ccdb --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleSatelliteTerminal.java @@ -0,0 +1,224 @@ +package zmaster587.advancedRocketry.inventory.modules; + +import java.util.Collections; +import java.util.List; + +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.IContainerListener; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +import zmaster587.advancedRocketry.tile.satellite.TileSatelliteTerminal; +import zmaster587.advancedRocketry.dimension.DimensionManager; +import zmaster587.advancedRocketry.util.PlanetaryTravelHelper; +import zmaster587.advancedRocketry.satellite.SatelliteData; +import zmaster587.advancedRocketry.api.satellite.SatelliteBase; +import zmaster587.advancedRocketry.item.ItemSatelliteIdentificationChip; + +import zmaster587.libVulpes.LibVulpes; +import zmaster587.libVulpes.inventory.modules.ModuleBase; +import zmaster587.libVulpes.inventory.modules.ModuleText; + +/** + * Per-viewer status module for the Satellite Control Center. + * Forces a sync every 0.5s (10 ticks) while the GUI is open. + * Sends 4 ints: 0=status, 1=ppt, 2=data, 3=maxdata. + */ +public class ModuleSatelliteTerminal extends ModuleBase { + + private final ModuleText text; + private final int color; + private final IInventory inv; // client: read chip name + private final TileSatelliteTerminal tile; // server: compute values + + // {status, ppt, data, max} + private final int[] vals = new int[4]; + + + // Force burst every 10 ticks + private long lastPushBucket = Long.MIN_VALUE; + private boolean burstPending = false; + + + // Add field to track current chip/satellite identity (server-side) + private long lastSatId = Long.MIN_VALUE; // or int; use -1 for "no sat" + + private static long getCurrentSatId(TileSatelliteTerminal t) { + zmaster587.advancedRocketry.api.satellite.SatelliteBase sat = t.getSatelliteFromSlot(0); + if (sat == null) return -1L; + return sat.getId(); // adjust if getId() is int; cast/convert as needed + } + + public ModuleSatelliteTerminal(int x, int y, int color) { + this(x, y, color, null, null); + } + + public ModuleSatelliteTerminal(int x, int y, int color, IInventory inv, TileSatelliteTerminal tile) { + super(x, y); + this.color = color; + this.inv = inv; + this.tile = tile; + this.text = new ModuleText(x, y, "", color); + this.text.setText(LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.nolink")); + } + + @Override + public void renderForeground(int x, int y, int mouseX, int mouseY, float zLevel, + GuiContainer gui, FontRenderer font) { + } + + @Override + public void renderBackground(GuiContainer gui, int x, int y, int mouseX, int mouseY, + FontRenderer font) { + + text.renderBackground(gui, x, y, mouseX, mouseY, font); + } + + @Override + public List getSlots(Container container) { return Collections.emptyList(); } + + @Override public int numberOfChangesToSend() { return 4; } + + // Some libVulpes builds use needsUpdate; keep it mapped to our logic. + @Override + public boolean needsUpdate(int localId) { return isUpdateRequired(localId); } + + @Override + public void sendInitialChanges(Container container, IContainerListener listener, int moduleIndex) { + if (tile != null && !tile.getWorld().isRemote) { + int[] now = computeStatusFromTile(tile); + for (int i = 0; i < 4; i++) vals[i] = now[i]; + lastSatId = getCurrentSatId(tile); + long t = tile.getWorld().getTotalWorldTime(); + lastPushBucket = t / 10L; + } + + for (int i = 0; i < 4; i++) { + listener.sendWindowProperty(container, moduleIndex + i, vals[i]); + } + burstPending = false; // reset + } + + @Override + public boolean isUpdateRequired(int relativeIdx) { + if (tile != null && !tile.getWorld().isRemote) { + final long t = tile.getWorld().getTotalWorldTime(); + final long bucket = t / 10L; + + // Detect satellite/chip change + final long curSatId = getCurrentSatId(tile); + final boolean satChanged = (curSatId != lastSatId); + if (satChanged) lastSatId = curSatId; + + // Arm a new burst on bucket edge OR sat change + if (bucket != lastPushBucket || satChanged) { + lastPushBucket = bucket; + + // Compute all four, assign immediately so all lanes read the same snapshot + final int[] now = computeStatusFromTile(tile); + System.arraycopy(now, 0, vals, 0, 4); + + // One atomic send of all lanes this tick + burstPending = true; + + } + } + + // During a burst, ALL lanes return true so container sends 0..3 in one pass. + return burstPending; + } + + @Override + public void sendChanges(Container container, IContainerListener listener, + int variableId, int relativeIdx) { + // 'variableId' IS the global property id. Do NOT add relativeIdx. + listener.sendWindowProperty(container, variableId, vals[relativeIdx]); + + // Clear the burst only after the last lane goes out + if (relativeIdx == 3) { + burstPending = false; + } + } + + + + @Override + public void onChangeRecieved(int relativeIdx, int value) { + vals[relativeIdx] = value; + rebuildClientText(); + } + + // ---- Helpers ---- + + private static int[] computeStatusFromTile(TileSatelliteTerminal t) { + int status = 0, ppt = 0, data = 0, max = 0; + + SatelliteBase sat = t.getSatelliteFromSlot(0); + + // --- Case 1: No chip or invalid satellite --- + if (!(sat instanceof SatelliteData)) { + return new int[] { 0, 0, 0, 0 }; + } + + // --- Case 2: Valid satellite --- + boolean hasPower = t.getUniversalEnergyStored() >= t.getPowerPerOperation(); + int hereDim = DimensionManager.getEffectiveDimId(t.getWorld(), t.getPos()).getId(); + boolean inRange = PlanetaryTravelHelper.isTravelAnywhereInPlanetarySystem(sat.getDimensionId(), hereDim); + + if (!hasPower) { + status = 1; // Not enough power + } else if (!inRange) { + status = 2; // Out of range + } else { + status = 3; // OK and connected + + SatelliteData s = (SatelliteData) sat; + ppt = s.getPowerPerTick(); // Power generation rate + data = s.data.getData(); // Current data amount + max = s.data.getMaxData(); // Maximum storage + } + + // --- Always return all four fields --- + return new int[] { status, ppt, data, max }; + } + + + // Client: rebuild visible text; sat name read locally from chip + private void rebuildClientText() { + final int status = vals[0]; + final int ppt = vals[1]; + final int data = vals[2]; + final int max = vals[3]; + + String satName = null; + if (inv != null && inv.getSizeInventory() > 0) { + ItemStack stack0 = inv.getStackInSlot(0); + if (!stack0.isEmpty() && stack0.getItem() instanceof ItemSatelliteIdentificationChip) { + SatelliteBase sat = ItemSatelliteIdentificationChip.getSatellite(stack0); + if (sat != null) satName = sat.getName(); + } + } + + String msg; + if (status == 0) { + msg = LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.nolink"); + } else if (status == 1) { + msg = LibVulpes.proxy.getLocalizedString("msg.notenoughpower"); + } else if (status == 2) { + msg = LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.toofar"); + } else { + msg = LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.info") + + "\nPower gen.: " + ppt + "\nData: " + data + "/" + max; + } + + if (satName != null && !satName.isEmpty()) { + msg = satName + "\n\n" + msg; + } + + text.setText(msg); + text.setColor(color); + } +} From dd697a61d3871701a683891594c92075c9078e16 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 19 Oct 2025 19:11:37 +0200 Subject: [PATCH 037/274] Refactor TileSatelliteTerminal for clarity and efficiency Refactor TileSatelliteTerminal class by removing unused code and simplifying methods. --- .../tile/satellite/TileSatelliteTerminal.java | 290 +++++------------- 1 file changed, 69 insertions(+), 221 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java b/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java index 0d42dcac5..114013040 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java @@ -20,6 +20,7 @@ import zmaster587.advancedRocketry.satellite.SatelliteData; import zmaster587.advancedRocketry.util.IDataInventory; import zmaster587.advancedRocketry.util.PlanetaryTravelHelper; + import zmaster587.libVulpes.LibVulpes; import zmaster587.libVulpes.inventory.modules.*; import zmaster587.libVulpes.network.PacketHandler; @@ -32,30 +33,20 @@ import java.util.LinkedList; import java.util.List; +public class TileSatelliteTerminal extends TileInventoriedRFConsumer + implements INetworkMachine, IModularInventory, IButtonInventory, IDataInventory, IDataHandler { -public class TileSatelliteTerminal extends TileInventoriedRFConsumer implements INetworkMachine, IModularInventory, IButtonInventory, IDataInventory, IDataHandler { - - // Subscribers: players who currently have this GUI open (server-side only) - private final java.util.Set subscribers = new java.util.HashSet<>(); - - - //private ModuleText satelliteText; - private SatelliteBase satellite; - private ModuleText moduleText; private DataStorage data; public TileSatelliteTerminal() { super(10000, 2); - data = new DataStorage(); data.setMaxData(1000); } @Override @Nonnull - public int[] getSlotsForFace(@Nullable EnumFacing side) { - return new int[0]; - } + public int[] getSlotsForFace(@Nullable EnumFacing side) { return new int[0]; } @Override public String getModularInventoryName() { @@ -63,9 +54,7 @@ public String getModularInventoryName() { } @Override - public boolean isItemValidForSlot(int slot, @Nonnull ItemStack stack) { - return true; - } + public boolean isItemValidForSlot(int slot, @Nonnull ItemStack stack) { return true; } @Override public boolean canPerformFunction() { @@ -73,81 +62,36 @@ public boolean canPerformFunction() { } @Override - public int getPowerPerOperation() { - return 1; - } + public int getPowerPerOperation() { return 1; } @Override public void performFunction() { - if (world.isRemote) - updateInventoryInfo(); + // No client push here anymore; module sync handles display updates. } + // Old custom packet not used anymore; keep empty to satisfy INetworkMachine @Override - public void writeDataToNetwork(ByteBuf out, byte packetId) { - if (packetId == (byte) 22) { - satellite = getSatelliteFromSlot(0); - if (satellite != null && satellite instanceof SatelliteData) { - if (getUniversalEnergyStored() < getPowerPerOperation()) { - out.writeInt(1); // no power - } else { - if (!PlanetaryTravelHelper.isTravelAnywhereInPlanetarySystem(satellite.getDimensionId(), DimensionManager.getEffectiveDimId(world, pos).getId())) { - out.writeInt(2);//out of range - } else { - out.writeInt(3); - out.writeInt(((SatelliteData) satellite).getPowerPerTick()); - out.writeInt(((SatelliteData) satellite).data.getData()); - out.writeInt(((SatelliteData) satellite).data.getMaxData()); - } - } - } else { - out.writeInt(0); // no link - } - } - } + public void writeDataToNetwork(ByteBuf out, byte packetId) { } + // Old custom packet not used anymore; keep empty to satisfy INetworkMachine @Override - public void readDataFromNetwork(ByteBuf in, byte packetId, - NBTTagCompound nbt) { - if (packetId == (byte) 22) { - int status = in.readInt(); - if (status == 3){ - nbt.setInteger("ppt", in.readInt()); - nbt.setInteger("data", in.readInt()); - nbt.setInteger("maxdata", in.readInt()); - } - nbt.setInteger("status", status); - } - } + public void readDataFromNetwork(ByteBuf in, byte packetId, NBTTagCompound nbt) { } - @Override - public void update() { - super.update(); - if (world.isRemote) return; - - if ((world.getTotalWorldTime() % 20) == 0 && !subscribers.isEmpty()) { - PacketMachine pkt = new PacketMachine(this, (byte)22); - java.util.Set stale = new java.util.HashSet<>(); - - for (java.util.UUID id : subscribers) { - net.minecraft.entity.player.EntityPlayerMP mp = - (net.minecraft.entity.player.EntityPlayerMP) world.getPlayerEntityByUUID(id); - if (mp == null || !mp.isEntityAlive()) { - stale.add(id); - continue; - } - zmaster587.libVulpes.network.PacketHandler.sendToPlayer(pkt, mp); - } - if (!stale.isEmpty()) subscribers.removeAll(stale); - } - } + // Tick: nothing needed; the module polls the tile every 9 tick while GUI is open + //@Override + //public void update() { + // super.update(); + // no status pushing needed + //} @Override public void useNetworkData(EntityPlayer player, Side side, byte id, NBTTagCompound nbt) { if (id == 0) { + // store data to item (server handles it inside storeData) storeData(0); } else if (id == 100) { + // "Connect" / perform action if (!world.isRemote) { SatelliteBase sat = getSatelliteFromSlot(0); @@ -161,153 +105,104 @@ public void useNetworkData(EntityPlayer player, Side side, byte id, NBTTagCompou boolean hasPower = getUniversalEnergyStored() >= getPowerPerOperation(); if (hasLink && hasPower) { - // perform action and pay the RF cost, just like extractData(commit=true) sat.performAction(player, world, pos); this.energy.extractEnergy(getPowerPerOperation(), false); } - - // Push a fresh status payload either way so the UI reflects current state - if (player instanceof net.minecraft.entity.player.EntityPlayerMP) { - zmaster587.libVulpes.network.PacketHandler.sendToPlayer( - new PacketMachine(this, (byte)22), - (net.minecraft.entity.player.EntityPlayerMP) player - ); - } } } else if (id == 101) { - onInventoryButtonPressed(id - 100); - } - - if (id == 22) { - if (world.isRemote) { // 22 should never arrive at the server - int status = nbt.getInteger("status"); - satellite = getSatelliteFromSlot(0); - if (moduleText != null) { - if (status != 0 && satellite != null) { - if (status == 1) { - moduleText.setText(LibVulpes.proxy.getLocalizedString("msg.notenoughpower")); - } else if (status == 2) { - moduleText.setText(satellite.getName() + "\n\n" + LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.toofar")); - } else if (status == 3) { - moduleText.setText(satellite.getName() + "\n\n" + LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.info") + "\n" + - "Power gen.: " + nbt.getInteger("ppt") + "\n" + - "Data: " + nbt.getInteger("data") + "/" + nbt.getInteger("maxdata")); - } - } else { - moduleText.setText(LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.nolink")); + if (!world.isRemote) { + ItemStack stack = getStackInSlot(0); + if (!stack.isEmpty() && stack.getItem() instanceof ItemSatelliteIdentificationChip) { + ItemSatelliteIdentificationChip idchip = (ItemSatelliteIdentificationChip) stack.getItem(); + + SatelliteBase sat = idchip.getSatellite(stack); + if (sat != null) { + DimensionManager.getInstance() + .getDimensionProperties(sat.getDimensionId()) + .removeSatellite(sat.getId()); } + + idchip.erase(stack); + // server mutates the inventory; client will get it via normal container sync + setInventorySlotContents(0, stack); } } } } - @Override public void setInventorySlotContents(int slot, @Nonnull ItemStack stack) { super.setInventorySlotContents(slot, stack); - satellite = getSatelliteFromSlot(0); - updateInventoryInfo(); } - public void updateInventoryInfo() { - - } - - public SatelliteBase getSatelliteFromSlot(int slot) { - ItemStack stack = getStackInSlot(slot); if (!stack.isEmpty() && stack.getItem() instanceof ItemSatelliteIdentificationChip) { return ItemSatelliteIdentificationChip.getSatellite(stack); } - return null; } @Override public List getModules(int ID, EntityPlayer player) { + List modules = new LinkedList<>(); - // Ensure the server registers the viewer and sends immediate state - if (!world.isRemote && player instanceof net.minecraft.entity.player.EntityPlayerMP) { - java.util.UUID uid = player.getUniqueID(); - if (!subscribers.contains(uid)) { - subscribers.add(uid); - } - // immediate payload so UI doesn’t show "no link" for up to 1s - zmaster587.libVulpes.network.PacketHandler.sendToPlayer( - new PacketMachine(this, (byte)22), - (net.minecraft.entity.player.EntityPlayerMP) player - ); - } + modules.add(new ModulePower(18, 20, this.energy) { + @Override public int numberOfChangesToSend() { return 2; } + }); - List modules = new LinkedList<>(); - modules.add(new ModulePower(18, 20, this.energy)); - modules.add(new ModuleButton(116, 70, 0, LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.connect"), this, zmaster587.libVulpes.inventory.TextureResources.buttonBuild)); - modules.add(new ModuleButton(173, 3, 1, "", this, TextureResources.buttonKill, LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.destroysat"), 24, 24)); - modules.add(new ModuleData(28, 20, 1, this, data)); - ModuleSatellite moduleSatellite = new ModuleSatellite(152, 10, this, 0); - moduleSatellite.setSatellite(satellite); - modules.add(moduleSatellite); + modules.add(new ModuleButton(116, 70, 0, + LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.connect"), + this, zmaster587.libVulpes.inventory.TextureResources.buttonBuild)); + + modules.add(new ModuleButton(173, 3, 1, "", + this, TextureResources.buttonKill, + LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.destroysat"), 24, 24)); - //Try to assign a satellite ASAP - //moduleSatellite.setSatellite(getSatelliteFromSlot(0)); + modules.add(new ModuleData(28, 20, 1, this, data) { + @Override public int numberOfChangesToSend() { return 2; } + }); - moduleText = new ModuleText(60, 20, LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.nolink"), 0x404040); - modules.add(moduleText); + modules.add(new ModuleSatellite(152, 10, this, 0) { + @Override public int numberOfChangesToSend() { return 0; } + }); + + // Add status module last; no need to keep a field reference + modules.add(new zmaster587.advancedRocketry.inventory.modules.ModuleSatelliteTerminal( + 60, 20, 0x404040, this, this)); - updateInventoryInfo(); return modules; } + @Override public void onInventoryButtonPressed(int buttonId) { - if (buttonId == 0) { - PacketHandler.sendToServer(new PacketMachine(this, (byte) (100 + buttonId))); - + PacketHandler.sendToServer(new PacketMachine(this, (byte) (100 + buttonId))); // id 100 } else if (buttonId == 1) { - ItemStack stack = getStackInSlot(0); - - if (!stack.isEmpty() && stack.getItem() instanceof ItemSatelliteIdentificationChip) { - ItemSatelliteIdentificationChip idchip = (ItemSatelliteIdentificationChip) stack.getItem(); - - SatelliteBase satellite = idchip.getSatellite(stack); - - //Somebody might want to erase the chip of an already existing satellite - if (satellite != null) - DimensionManager.getInstance().getDimensionProperties(satellite.getDimensionId()).removeSatellite(satellite.getId()); - - idchip.erase(stack); - setInventorySlotContents(0, stack); - PacketHandler.sendToServer(new PacketMachine(this, (byte) (100 + buttonId))); - } + PacketHandler.sendToServer(new PacketMachine(this, (byte) (100 + buttonId))); // id 101 } - } @Override public NBTTagCompound writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); - - NBTTagCompound data = new NBTTagCompound(); - - this.data.writeToNBT(data); - nbt.setTag("data", data); + NBTTagCompound dataTag = new NBTTagCompound(); + this.data.writeToNBT(dataTag); + nbt.setTag("data", dataTag); return nbt; } @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); - - NBTTagCompound data = nbt.getCompoundTag("data"); - this.data.readFromNBT(data); + NBTTagCompound dataTag = nbt.getCompoundTag("data"); + this.data.readFromNBT(dataTag); } @Override - public void loadData(int id) { - } + public void loadData(int id) { } @Override public void storeData(int id) { @@ -326,7 +221,6 @@ public void storeData(int id) { public int extractData(int maxAmount, DataType type, EnumFacing dir, boolean commit) { SatelliteBase sat = getSatelliteFromSlot(0); - // Link + range + power gates (same as UI) boolean inRange = false; if (sat != null) { int satDim = sat.getDimensionId(); @@ -336,80 +230,34 @@ public int extractData(int maxAmount, DataType type, EnumFacing dir, boolean com boolean hasLink = (sat instanceof SatelliteData) && inRange; boolean hasPower = getUniversalEnergyStored() >= getPowerPerOperation(); - if (!(hasLink && hasPower)) { - return 0; - } + if (!(hasLink && hasPower)) return 0; if (!commit) { - // Simulate: do NOT pull from satellite; just report current availability if (type != data.getDataType() && data.getDataType() != DataType.UNDEFINED) return 0; int available = data.getData(); return Math.min(maxAmount, available); } - // COMMIT path: first pull fresh data from the satellite into our buffer sat.performAction(null, world, pos); - // Now validate type and figure out how much we can remove if (type != data.getDataType() && data.getDataType() != DataType.UNDEFINED) return 0; int removable = Math.min(maxAmount, data.getData()); if (removable <= 0) return 0; - // Consume RF only if we're actually removing data this.energy.extractEnergy(getPowerPerOperation(), false); + int removed = data.removeData(removable, true); - return data.removeData(removable, true); + return removed; } @Override public int addData(int maxAmount, DataType type, EnumFacing dir, boolean commit) { + int added = data.addData(maxAmount, type, commit); - return data.addData(maxAmount, type, commit); + return added; } @Override - public boolean canInteractWithContainer(EntityPlayer entity) { - return true; - } - - - // Subscribe/unsubscribe when GUI (container) opens/closes - @Override - public void openInventory(EntityPlayer player) { - super.openInventory(player); - if (!world.isRemote && player != null) { - subscribers.add(player.getUniqueID()); - // immediate first payload so UI populates without waiting a tick - if (player instanceof net.minecraft.entity.player.EntityPlayerMP) { - zmaster587.libVulpes.network.PacketHandler.sendToPlayer(new PacketMachine(this, (byte)22), - (net.minecraft.entity.player.EntityPlayerMP) player); - } - } - } - - @Override - public void closeInventory(EntityPlayer player) { - super.closeInventory(player); - if (!world.isRemote && player != null) { - subscribers.remove(player.getUniqueID()); - } - } - - @Override - public void onChunkUnload() { - super.onChunkUnload(); - if (!world.isRemote) { - subscribers.clear(); - } - } - - @Override - public void invalidate() { - super.invalidate(); - if (!world.isRemote) { - subscribers.clear(); - } - } - + public boolean canInteractWithContainer(EntityPlayer entity) { return true; } } From 9d9dbbd1c674a29770c6908177ac8299b48dc975 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 19 Oct 2025 19:12:46 +0200 Subject: [PATCH 038/274] Change sync period from 10 ticks to 9 ticks added "private static final long PERIOD_TICKS = 9L;" 9 is just enough to never see data jump up by 2, --- .../inventory/modules/ModuleSatelliteTerminal.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleSatelliteTerminal.java b/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleSatelliteTerminal.java index 1cc03ccdb..c9ce27b44 100644 --- a/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleSatelliteTerminal.java +++ b/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleSatelliteTerminal.java @@ -24,7 +24,7 @@ /** * Per-viewer status module for the Satellite Control Center. - * Forces a sync every 0.5s (10 ticks) while the GUI is open. + * Forces a sync every 0.5s (9 ticks) while the GUI is open. * Sends 4 ints: 0=status, 1=ppt, 2=data, 3=maxdata. */ public class ModuleSatelliteTerminal extends ModuleBase { @@ -34,11 +34,12 @@ public class ModuleSatelliteTerminal extends ModuleBase { private final IInventory inv; // client: read chip name private final TileSatelliteTerminal tile; // server: compute values + private static final long PERIOD_TICKS = 9L; // {status, ppt, data, max} private final int[] vals = new int[4]; - // Force burst every 10 ticks + // Force burst every 9 ticks private long lastPushBucket = Long.MIN_VALUE; private boolean burstPending = false; @@ -93,7 +94,7 @@ public void sendInitialChanges(Container container, IContainerListener listener, for (int i = 0; i < 4; i++) vals[i] = now[i]; lastSatId = getCurrentSatId(tile); long t = tile.getWorld().getTotalWorldTime(); - lastPushBucket = t / 10L; + lastPushBucket = t / PERIOD_TICKS; } for (int i = 0; i < 4; i++) { @@ -106,7 +107,7 @@ public void sendInitialChanges(Container container, IContainerListener listener, public boolean isUpdateRequired(int relativeIdx) { if (tile != null && !tile.getWorld().isRemote) { final long t = tile.getWorld().getTotalWorldTime(); - final long bucket = t / 10L; + final long bucket = t / PERIOD_TICKS; // Detect satellite/chip change final long curSatId = getCurrentSatId(tile); From a0683cf1050b407217aef5af33d229798625c0f4 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 20 Oct 2025 08:18:47 +0200 Subject: [PATCH 039/274] Refactor extractData method in TileSatelliteTerminal fixes: wirelesstranciever can now pull from internal storage without a chip or link. moving data from satellite to terminal still gated behind "haspower" --- .../tile/satellite/TileSatelliteTerminal.java | 44 +++++++++++-------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java b/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java index 114013040..0c805adea 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java @@ -219,8 +219,27 @@ public void storeData(int id) { @Override public int extractData(int maxAmount, DataType type, EnumFacing dir, boolean commit) { - SatelliteBase sat = getSatelliteFromSlot(0); + // 1) Type guard (unchanged) + if (type != data.getDataType() && data.getDataType() != DataType.UNDEFINED) { + return 0; + } + + // 2) Simulation: report local only (don’t guess satellite yield) + if (!commit) { + int availableLocal = data.getData(); + return Math.min(maxAmount, availableLocal); + } + + // 3) Drain LOCAL first, chip or no chip + int availableLocal = data.getData(); + int toGive = Math.min(maxAmount, availableLocal); + int removed = 0; + if (toGive > 0) { + removed = data.removeData(toGive, true); + } + // 4) If we have link+power, auto-download to refill AFTER the pull + SatelliteBase sat = getSatelliteFromSlot(0); boolean inRange = false; if (sat != null) { int satDim = sat.getDimensionId(); @@ -230,27 +249,16 @@ public int extractData(int maxAmount, DataType type, EnumFacing dir, boolean com boolean hasLink = (sat instanceof SatelliteData) && inRange; boolean hasPower = getUniversalEnergyStored() >= getPowerPerOperation(); - if (!(hasLink && hasPower)) return 0; - - if (!commit) { - if (type != data.getDataType() && data.getDataType() != DataType.UNDEFINED) return 0; - int available = data.getData(); - return Math.min(maxAmount, available); + if (hasLink && hasPower) { + sat.performAction(null, world, pos); // same as GUI Download + this.energy.extractEnergy(getPowerPerOperation(), false); + // (No immediate extra removal here; we already served the request.) } - sat.performAction(null, world, pos); - - if (type != data.getDataType() && data.getDataType() != DataType.UNDEFINED) return 0; - - int removable = Math.min(maxAmount, data.getData()); - if (removable <= 0) return 0; - - this.energy.extractEnergy(getPowerPerOperation(), false); - int removed = data.removeData(removable, true); - - return removed; + return removed; // may be 0 if buffer empty and no link/power } + @Override public int addData(int maxAmount, DataType type, EnumFacing dir, boolean commit) { int added = data.addData(maxAmount, type, commit); From cb3d62e92626a6534571eb71c0e360c171aa4672 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 20 Oct 2025 17:04:42 +0200 Subject: [PATCH 040/274] Add insert message to wireless transceiver language file --- src/main/resources/assets/advancedrocketry/lang/en_US.lang | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/assets/advancedrocketry/lang/en_US.lang b/src/main/resources/assets/advancedrocketry/lang/en_US.lang index ef50c3f68..a1e234077 100644 --- a/src/main/resources/assets/advancedrocketry/lang/en_US.lang +++ b/src/main/resources/assets/advancedrocketry/lang/en_US.lang @@ -482,6 +482,7 @@ msg.entity.rocket.clear=Clear msg.entity.rocket.rcs=RCS Mode msg.entity.rocket.none=None Selected msg.wirelessTransciever.extract=extract +msg.wirelessTransciever.insert=insert msg.powerunit.rfpertick=FE/t msg.linker.error.firstMachine=This must be the first machine to link! From acaf48717d21d37c36c017d393573c904c49259b Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 20 Oct 2025 17:15:01 +0200 Subject: [PATCH 041/274] Add up and down facing states to wirelesstransciever --- .../blockstates/wirelesstransciever.json | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/main/resources/assets/advancedrocketry/blockstates/wirelesstransciever.json b/src/main/resources/assets/advancedrocketry/blockstates/wirelesstransciever.json index 72b127360..b2c7287f9 100644 --- a/src/main/resources/assets/advancedrocketry/blockstates/wirelesstransciever.json +++ b/src/main/resources/assets/advancedrocketry/blockstates/wirelesstransciever.json @@ -1,13 +1,19 @@ { - "variants": { - "facing=north,state=false": { "model": "advancedrocketry:wirelesstransciever" }, - "facing=south,state=false": { "model": "advancedrocketry:wirelesstransciever", "y": 180 }, - "facing=west,state=false": { "model": "advancedrocketry:wirelesstransciever", "y": 270 }, - "facing=east,state=false": { "model": "advancedrocketry:wirelesstransciever", "y": 90 }, - "facing=north,state=true": { "model": "advancedrocketry:wirelesstransciever" }, - "facing=south,state=true": { "model": "advancedrocketry:wirelesstransciever", "y": 180 }, - "facing=west,state=true": { "model": "advancedrocketry:wirelesstransciever", "y": 270 }, - "facing=east,state=true": { "model": "advancedrocketry:wirelesstransciever", "y": 90 }, - "inventory" : { "model": "advancedrocketry:wirelesstransciever" } - } + "variants": { + "facing=north,state=false": { "model": "advancedrocketry:wirelesstransciever" }, + "facing=south,state=false": { "model": "advancedrocketry:wirelesstransciever", "y": 180 }, + "facing=west,state=false": { "model": "advancedrocketry:wirelesstransciever", "y": 270 }, + "facing=east,state=false": { "model": "advancedrocketry:wirelesstransciever", "y": 90 }, + "facing=up,state=false": { "model": "advancedrocketry:wirelesstransciever", "x": 270 }, + "facing=down,state=false": { "model": "advancedrocketry:wirelesstransciever", "x": 90 }, + + "facing=north,state=true": { "model": "advancedrocketry:wirelesstransciever" }, + "facing=south,state=true": { "model": "advancedrocketry:wirelesstransciever", "y": 180 }, + "facing=west,state=true": { "model": "advancedrocketry:wirelesstransciever", "y": 270 }, + "facing=east,state=true": { "model": "advancedrocketry:wirelesstransciever", "y": 90 }, + "facing=up,state=true": { "model": "advancedrocketry:wirelesstransciever", "x": 270 }, + "facing=down,state=true": { "model": "advancedrocketry:wirelesstransciever", "x": 90 }, + + "inventory": { "model": "advancedrocketry:wirelesstransciever" } + } } From e2ee79b48098b849312c5c9b40d5038109134b0b Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 20 Oct 2025 17:19:11 +0200 Subject: [PATCH 042/274] Enhance TileWirelessTransciever Added network ID label and improved data handling. --- .../tile/cables/TileWirelessTransciever.java | 142 +++++++++++++----- 1 file changed, 108 insertions(+), 34 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java b/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java index 2ce4755c0..b3f5ce015 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java @@ -2,6 +2,7 @@ import io.netty.buffer.ByteBuf; import net.minecraft.block.state.IBlockState; +import net.minecraft.block.Block; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; @@ -21,11 +22,11 @@ import zmaster587.advancedRocketry.inventory.TextureResources; import zmaster587.advancedRocketry.world.util.MultiData; import zmaster587.libVulpes.LibVulpes; -import zmaster587.libVulpes.block.RotatableBlock; import zmaster587.libVulpes.interfaces.ILinkableTile; import zmaster587.libVulpes.inventory.modules.IModularInventory; import zmaster587.libVulpes.inventory.modules.IToggleButton; import zmaster587.libVulpes.inventory.modules.ModuleBase; +import zmaster587.libVulpes.inventory.modules.ModuleText; import zmaster587.libVulpes.inventory.modules.ModuleToggleSwitch; import zmaster587.libVulpes.items.ItemLinker; import zmaster587.libVulpes.network.PacketHandler; @@ -42,6 +43,15 @@ public class TileWirelessTransciever extends TileEntity implements INetworkMachi private int transferIntervalTicks = 20; // Fixed phase per tile to spread load private int phase = -1; + // Show network ID (label) + private ModuleText netIdLabel; + + // Avoid per-call allocations from DataType.values() + // needs update if DataType enum changes + private static final DataType[] TYPES = { + DataType.DISTANCE, DataType.HUMIDITY, DataType.TEMPERATURE, + DataType.COMPOSITION, DataType.ATMOSPHEREDENSITY, DataType.MASS + }; protected ModuleToggleSwitch toggleSwitch; boolean extractMode; @@ -57,12 +67,37 @@ public TileWirelessTransciever() { data.setMaxData(100); toggle = new ModuleToggleSwitch(50, 50, 0, LibVulpes.proxy.getLocalizedString("msg.wirelessTransciever.extract"), this, TextureResources.buttonGeneric, 64, 18, false); toggleSwitch = new ModuleToggleSwitch(160, 5, 1, "", this, zmaster587.libVulpes.inventory.TextureResources.buttonToggleImage, 11, 26, true); - + // Align internal booleans with UI defaults extractMode = toggle.getState(); // false initially enabled = toggleSwitch.getState(); // true initially + updateToggleLabel(); + + // Network ID label + netIdLabel = new ModuleText(40, 72, "Network: -", 0x000000); + netIdLabel.setAlwaysOnTop(true); // optional, so it renders over slots + } + + private void updateToggleLabel() { + if (toggle != null) { + String key = extractMode + ? "msg.wirelessTransciever.extract" // pulling from side → network + : "msg.wirelessTransciever.insert"; // pushing from network → side + toggle.setText(LibVulpes.proxy.getLocalizedString(key)); + } } + private EnumFacing resolveFront(IBlockState state) { + if (state == null) return EnumFacing.NORTH; + if (state.getBlock() instanceof zmaster587.advancedRocketry.block.BlockTransciever) { + return zmaster587.advancedRocketry.block.BlockTransciever.getFront(state); + } + // fallback for legacy blocks if any remain + if (state.getBlock() instanceof zmaster587.libVulpes.block.RotatableBlock) { + return zmaster587.libVulpes.block.RotatableBlock.getFront(state); + } + return EnumFacing.NORTH; + } @Override public boolean onLinkStart(@Nonnull ItemStack item, TileEntity entity, EntityPlayer player, World world) { @@ -78,6 +113,7 @@ public boolean onLinkStart(@Nonnull ItemStack item, TileEntity entity, EntityPla @Override public void onChunkUnload() { super.onChunkUnload(); + if (networkID == -1) return; if (NetworkRegistry.dataNetwork.doesNetworkExist(networkID)) NetworkRegistry.dataNetwork.getNetwork(networkID).removeFromAll(this); } @@ -85,8 +121,17 @@ public void onChunkUnload() { @Override public boolean onLinkComplete(@Nonnull ItemStack item, TileEntity entity, EntityPlayer player, World world) { BlockPos pos = ItemLinker.getMasterCoords(item); + if (pos == null) return false; // defensive + + if (pos.equals(this.pos)) { + if (world.isRemote) player.sendMessage(new TextComponentTranslation("msg.linker.sameblock")); + return false; + } + + if (!world.isBlockLoaded(pos)) return false; TileEntity tile = world.getTileEntity(pos); + if (!(tile instanceof TileWirelessTransciever)) return false; if (tile instanceof TileWirelessTransciever) { if (world.isRemote) { @@ -111,6 +156,16 @@ public boolean onLinkComplete(@Nonnull ItemStack item, TileEntity entity, Entity addToNetwork(); ((TileWirelessTransciever) tile).addToNetwork(); + + //SYNC CLIENT UI/STATE FOR BOTH TILES + this.markDirty(); + world.notifyBlockUpdate(this.pos, world.getBlockState(this.pos), world.getBlockState(this.pos), 3); + + tile.markDirty(); + world.notifyBlockUpdate(tile.getPos(), world.getBlockState(tile.getPos()), + world.getBlockState(tile.getPos()), 3); + + ItemLinker.resetPosition(item); return true; @@ -167,6 +222,7 @@ public List getModules(int id, EntityPlayer player) { list.add(toggle); list.add(toggleSwitch); + list.add(netIdLabel); return list; } @@ -197,22 +253,23 @@ public void readDataFromNetwork(ByteBuf in, byte packetId, } @Override - public void useNetworkData(EntityPlayer player, Side side, byte id, - NBTTagCompound nbt) { - - if (side.isServer()) { - if (id == 0) { - extractMode = nbt.getBoolean("state"); - if (NetworkRegistry.dataNetwork.doesNetworkExist(networkID)) { - NetworkRegistry.dataNetwork.getNetwork(networkID).removeFromAll(this); - - if (extractMode) - NetworkRegistry.dataNetwork.getNetwork(networkID).addSource(this, EnumFacing.UP); - else - NetworkRegistry.dataNetwork.getNetwork(networkID).addSink(this, EnumFacing.UP); - } - } else if (id == 1) { - enabled = nbt.getBoolean("state"); + public void useNetworkData(EntityPlayer player, Side side, byte id, NBTTagCompound nbt) { + if (!side.isServer()) return; + if (id == 1) { // enable/disable toggle doesn’t touch networks + enabled = nbt.getBoolean("state"); + return; + } + if (networkID == -1) return; // not linked yet; ignore network mutations + + if (id == 0) { + extractMode = nbt.getBoolean("state"); + updateToggleLabel(); + if (NetworkRegistry.dataNetwork.doesNetworkExist(networkID)) { + NetworkRegistry.dataNetwork.getNetwork(networkID).removeFromAll(this); + if (extractMode) + NetworkRegistry.dataNetwork.getNetwork(networkID).addSource(this, EnumFacing.UP); + else + NetworkRegistry.dataNetwork.getNetwork(networkID).addSink(this, EnumFacing.UP); } } } @@ -228,19 +285,26 @@ public void readFromNBT(NBTTagCompound nbt) { //addToNetwork(); toggle.setToggleState(extractMode); + updateToggleLabel(); toggleSwitch.setToggleState(enabled); + if (world != null && world.isRemote && netIdLabel != null) { + netIdLabel.setText("Network: " + networkID); + } + } @Override @Nonnull public NBTTagCompound writeToNBT(NBTTagCompound nbt) { + super.writeToNBT(nbt); // MOVE: call first nbt.setBoolean("mode", extractMode); nbt.setBoolean("enabled", enabled); nbt.setInteger("networkID", networkID); - data.writeToNBT(nbt); - return super.writeToNBT(nbt); + data.writeToNBT(nbt); + return nbt; } + @Override public int extractData(int maxAmount, DataType type, EnumFacing dir, boolean commit) { @@ -305,19 +369,17 @@ public void update() { if (((now + phase) % transferIntervalTicks) != 0) return; IBlockState state = world.getBlockState(getPos()); - if (!(state.getBlock() instanceof RotatableBlock)) return; - // Face the block's "IO" side - EnumFacing facing = RotatableBlock.getFront(state).getOpposite(); + // Resolve front for either 6-way or legacy block + EnumFacing front = resolveFront(state); + EnumFacing facing = front.getOpposite(); // keep existing IO semantics TileEntity neighbor = world.getTileEntity(getPos().offset(facing)); - - // Must be a data handler and not another wireless transceiver (avoid loops) - if (!(neighbor instanceof IDataHandler) || (neighbor instanceof TileWirelessTransciever)) return; + if (neighbor == null || neighbor instanceof TileWirelessTransciever) return; + if (!(neighbor instanceof IDataHandler)) return; boolean changed = false; - for (DataStorage.DataType dataType : DataStorage.DataType.values()) { - if (dataType == DataStorage.DataType.UNDEFINED) continue; + for (DataType dataType : TYPES) { if (!extractMode) { // PUSH: from this buffer -> neighbor @@ -342,6 +404,7 @@ public void update() { } } + // Persist changes; a full block update isn't strictly required each tick if (changed) { this.markDirty(); @@ -353,25 +416,36 @@ public void update() { @Override public void onInventoryButtonPressed(int buttonId) { - if (buttonId == 1) + if (buttonId == 1) { enabled = toggleSwitch.getState(); - else if (buttonId == 0) + } else if (buttonId == 0) { extractMode = toggle.getState(); + updateToggleLabel(); + } PacketHandler.sendToServer(new PacketMachine(this, (byte) buttonId)); } - @Override public void stateUpdated(ModuleBase module) { - if (module == toggleSwitch) + if (module == toggleSwitch) { enabled = toggleSwitch.getState(); - else if (module == toggle) + } else if (module == toggle) { extractMode = toggle.getState(); + updateToggleLabel(); + } if (!world.isRemote) { this.markDirty(); world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3); } } - + @Override + public void invalidate() { + // called when the TE is removed because the block changed/broke + if (!world.isRemote && NetworkRegistry.dataNetwork.doesNetworkExist(networkID)) { + NetworkRegistry.dataNetwork.getNetwork(networkID).removeFromAll(this); + } + super.invalidate(); + } + } From 07b5a209b8b7fd1186b5f7d66fb19839367dc7c7 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 20 Oct 2025 17:21:37 +0200 Subject: [PATCH 043/274] Refactor BlockTransciever for 6way placing Placing 6 ways! Also placement sticks to the face u are look at. ->Easier to place plugs without getting annoyed. --- .../block/BlockTransciever.java | 127 ++++++++++++++++-- 1 file changed, 117 insertions(+), 10 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java b/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java index 38b59d4b7..a3cedb36f 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java @@ -1,38 +1,145 @@ package zmaster587.advancedRocketry.block; +import javax.annotation.Nonnull; + +import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.BlockRenderLayer; // <-- correct package +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraft.block.properties.PropertyDirection; // <-- correct package +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.libVulpes.block.BlockTile; public class BlockTransciever extends BlockTile { - private static final AxisAlignedBB[] bb = {new AxisAlignedBB(.25, .25, .75, .75, .75, 1), - new AxisAlignedBB(.25, .25, 0, .75, .75, 0.25), - new AxisAlignedBB(.75, .25, .25, 1, .75, .75), - new AxisAlignedBB(0, .25, .25, 0.25, .75, .75)}; + public static final PropertyDirection FACING = PropertyDirection.create("facing"); + + private static final AxisAlignedBB AABB_N = new AxisAlignedBB(.25, .25, 0.00, .75, .75, .25); + private static final AxisAlignedBB AABB_S = new AxisAlignedBB(.25, .25, .75, .75, .75, 1.00); + private static final AxisAlignedBB AABB_W = new AxisAlignedBB(0.00, .25, .25, .25, .75, .75); + private static final AxisAlignedBB AABB_E = new AxisAlignedBB(.75, .25, .25, 1.00, .75, .75); + private static final AxisAlignedBB AABB_U = new AxisAlignedBB(.25, .75, .25, .75, 1.00, .75); + private static final AxisAlignedBB AABB_D = new AxisAlignedBB(.25, 0.00, .25, .75, .25, .75); public BlockTransciever(Class tileClass, int guiId) { super(tileClass, guiId); + this.setDefaultState( + this.blockState.getBaseState() + .withProperty(STATE, Boolean.FALSE) + .withProperty(FACING, EnumFacing.NORTH) + ); + this.setHardness(3f); + this.setResistance(10f); + this.setLightOpacity(0); } @Override - public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, - BlockPos pos) { + public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) { + EnumFacing f = state.getValue(FACING).getOpposite(); + switch (f) { + case NORTH: return AABB_N; + case SOUTH: return AABB_S; + case WEST: return AABB_W; + case EAST: return AABB_E; + case UP: return AABB_U; + case DOWN: return AABB_D; + default: return FULL_BLOCK_AABB; + } + } + @Override public boolean isFullCube(IBlockState state) { return false; } + @Override public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) { return false; } + @Override public boolean isOpaqueCube(IBlockState state) { return false; } - return bb[state.getValue(FACING).ordinal() - 2]; + @SideOnly(Side.CLIENT) + @Override + @Nonnull + public BlockRenderLayer getBlockLayer() { + return BlockRenderLayer.CUTOUT_MIPPED; } + // If this still errors in your mappings, rename the method to: + // public BlockRenderLayer getRenderLayer() { return BlockRenderLayer.CUTOUT_MIPPED; } @Override - public boolean isFullCube(IBlockState state) { - return false; + protected BlockStateContainer createBlockState() { + return new BlockStateContainer(this, FACING, STATE); + } + + @Override + public int getMetaFromState(IBlockState state) { + int face = state.getValue(FACING).getIndex(); // 0..5 + boolean on = state.getValue(STATE); + return face | (on ? 8 : 0); + } + + @Override + public IBlockState getStateFromMeta(int meta) { + EnumFacing f = EnumFacing.getFront(meta & 7); + boolean on = (meta & 8) != 0; + return this.getDefaultState().withProperty(FACING, f).withProperty(STATE, on); + } + + @Override + public IBlockState getActualState(IBlockState state, IBlockAccess world, BlockPos pos) { + return state; + } + + @Override + @Nonnull + public IBlockState getStateForPlacement( + World world, BlockPos pos, EnumFacing clickedFace, + float hitX, float hitY, float hitZ, int meta, + EntityLivingBase placer, EnumHand hand) { + return this.getDefaultState() + .withProperty(FACING, clickedFace) + .withProperty(STATE, Boolean.FALSE); + } + + @Override + public void onBlockPlacedBy(World world, BlockPos pos, IBlockState state, + EntityLivingBase placer, @Nonnull ItemStack stack) { + // keep orientation from getStateForPlacement } @Override - public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) { + public boolean rotateBlock(World world, BlockPos pos, EnumFacing axis) { + IBlockState s = world.getBlockState(pos); + EnumFacing cur = s.getValue(FACING); + EnumFacing next; + + switch (axis) { + case UP: + case DOWN: + next = (cur == EnumFacing.UP || cur == EnumFacing.DOWN) ? cur : cur.rotateY(); + break; + case NORTH: + case SOUTH: + case EAST: + case WEST: + next = (cur == EnumFacing.UP || cur == EnumFacing.DOWN) ? cur : cur.rotateY(); + break; + default: + next = cur; + } + + if (next != cur) { + world.setBlockState(pos, s.withProperty(FACING, next), 2); + return true; + } return false; } + + public static EnumFacing getFront(IBlockState state) { + if (state == null || !state.getPropertyKeys().contains(FACING)) return EnumFacing.NORTH; + return state.getValue(FACING); + } } From a11783907b980d0a22aa5d5eb562ba289f7a3610 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 20 Oct 2025 17:22:07 +0200 Subject: [PATCH 044/274] Fix import statements in BlockTransciever.java --- .../zmaster587/advancedRocketry/block/BlockTransciever.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java b/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java index a3cedb36f..a83b44248 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java @@ -7,14 +7,14 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.BlockRenderLayer; // <-- correct package +import net.minecraft.util.BlockRenderLayer; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; -import net.minecraft.block.properties.PropertyDirection; // <-- correct package +import net.minecraft.block.properties.PropertyDirection; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.libVulpes.block.BlockTile; From 009be847f6209dfdfa4a6778ac6a911c9966e871 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Tue, 21 Oct 2025 08:04:23 +0200 Subject: [PATCH 045/274] Implement scroll caching for GUI module hopefully fixed for modspaghetti-ppl --- ...oduleContainerPanYOnlyWithScrollCache.java | 124 ++++++++++++++---- 1 file changed, 101 insertions(+), 23 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleContainerPanYOnlyWithScrollCache.java b/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleContainerPanYOnlyWithScrollCache.java index 229933deb..f4368e04c 100644 --- a/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleContainerPanYOnlyWithScrollCache.java +++ b/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleContainerPanYOnlyWithScrollCache.java @@ -2,53 +2,131 @@ import zmaster587.libVulpes.inventory.modules.ModuleContainerPanYOnly; import zmaster587.libVulpes.inventory.modules.ModuleBase; + +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.util.ResourceLocation; -import java.util.concurrent.ConcurrentHashMap; -import java.util.Map; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + import java.util.List; +import java.util.concurrent.atomic.AtomicReference; public class ModuleContainerPanYOnlyWithScrollCache extends ModuleContainerPanYOnly { /** - * Scroll position cache for the observatory asteroid list. - * - One entry (per GUI layout) per client; cleared on new scan or scroll. - * - Minimal memory use (single Integer per layout). - * - Client-side only; no multiplayer or server impact. - * - Thread-safe for typical GUI use. - * - If reused, ensure cacheKey is unique per list type / GUI layout. + * Single global scroll position cache for the client. + * Stores one Integer (legal range [-containerSizeY, 0]) for the *most recently used* pane. + * Latest write always wins (old overwrites new; there is only one slot). */ + private static final AtomicReference GLOBAL_SCROLL = new AtomicReference<>(null); + + // Lazy, one-time restore (containerSizeY may not be final at ctor time) + private boolean didRestore = false; + private Integer pendingCachedPos = null; - // Cache: only stores latest scroll position per key - private static final Map scrollCache = new ConcurrentHashMap<>(); - private final String cacheKey; + // ===== Constructors ===== + public ModuleContainerPanYOnlyWithScrollCache( + int offsetX, int offsetY, + List moduleList, List staticModules, + ResourceLocation backdrop, + int screenSizeX, int screenSizeY, + int paddingX, int paddingY, + int containerSizeX, int containerSizeY + ) { + super(offsetX, offsetY, moduleList, staticModules, backdrop, screenSizeX, screenSizeY, + paddingX, paddingY, containerSizeX, containerSizeY); - public ModuleContainerPanYOnlyWithScrollCache(int offsetX, int offsetY, List moduleList, List staticModules, ResourceLocation backdrop, int screenSizeX, int screenSizeY, int paddingX, int paddingY, int containerSizeX, int containerSizeY) { - super(offsetX, offsetY, moduleList, staticModules, backdrop, screenSizeX, screenSizeY, paddingX, paddingY, containerSizeX, containerSizeY); + // Snapshot current global scroll to restore later (after layout stabilizes) + this.pendingCachedPos = GLOBAL_SCROLL.get(); + } + + // ===== Clamping & persistence ===== + private int clampScroll(int y) { + if (y > 0) return 0; + int min = -this.containerSizeY; + return (y < min) ? min : y; + } - // Create unique cache key - this.cacheKey = "observatory_asteroid_list:" + offsetX + ":" + offsetY + ":" + screenSizeX + ":" + screenSizeY; + private void saveScrollIfChanged() { + int y = clampScroll(super.getScrollY()); + Integer prev = GLOBAL_SCROLL.get(); + if (prev != null && prev.intValue() == y) return; // no write if unchanged + GLOBAL_SCROLL.set(y); // single slot: old key always overwritten by new write + } - // Restore scroll position if available - Integer cachedPos = scrollCache.get(cacheKey); - if (cachedPos != null) { - super.setOffset2(-cachedPos); + // One-time lazy restore when bounds should be final + @Override + @SideOnly(Side.CLIENT) + public void renderBackground(GuiContainer gui, int x, int y, int mouseX, int mouseY, FontRenderer font) { + if (!didRestore) { + if (pendingCachedPos != null) { + int clamped = clampScroll(pendingCachedPos); + // Base setOffset2 sets currentPosY = -y, so pass -clamped + super.setOffset2(-clamped); + } + didRestore = true; } + super.renderBackground(gui, x, y, mouseX, mouseY, font); } + // Capture all movement paths (wheel, drag, programmatic move, close) @Override protected void moveContainerInterior(int deltaY) { super.moveContainerInterior(deltaY); - scrollCache.put(cacheKey, super.getScrollY()); + saveScrollIfChanged(); } @Override public void onScroll(int dwheel) { super.onScroll(dwheel); - scrollCache.put(cacheKey, super.getScrollY()); + saveScrollIfChanged(); + } + + @Override + @SideOnly(Side.CLIENT) + public void onMouseClickedAndDragged(int x, int y, int button, long timeSinceLastClick) { + super.onMouseClickedAndDragged(x, y, button, timeSinceLastClick); + saveScrollIfChanged(); + } + + @Override + public void setEnabled(boolean state) { + if (!state && this.isEnabled()) { + // Persist on GUI disable/close + saveScrollIfChanged(); + } + super.setEnabled(state); + } + + // Persist programmatic jumps too + @Override + protected void setOffset2(int y) { + super.setOffset2(y); + saveScrollIfChanged(); + } + + // external centralized wheel dispatcher + @SideOnly(Side.CLIENT) + public void acceptExternalScroll(int dwheel, int mouseX, int mouseY) { + if (dwheel == 0 || !this.isEnabled()) return; + if (isMouseInBoundsForThis(mouseX, mouseY)) { + super.onScroll(dwheel); + saveScrollIfChanged(); + } + } + + // Corrected bounds check (local space; include edges) + private boolean isMouseInBoundsForThis(int mouseX, int mouseY) { + int localX = mouseX - this.offsetX; + int localY = mouseY - this.offsetY; + return localX >= 0 && localX < this.screenSizeX + && localY >= 0 && localY < this.screenSizeY; } - // Public method to clear cache (for new asteroid scans) + // ===== Cache management helpers ===== + /** Clear the single cached position (e.g., on new scan). */ public static void clearScrollCache() { - scrollCache.clear(); + GLOBAL_SCROLL.set(null); } } From a65205f30f6fd1bb405f5f56d53f50e57facfcad Mon Sep 17 00:00:00 2001 From: kaduvill Date: Tue, 21 Oct 2025 16:56:48 +0200 Subject: [PATCH 046/274] Mousewheel-scrolling asteroidlist part of fixing scrollreset. --- .../tile/multiblock/TileObservatory.java | 48 +++++++++++++------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java b/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java index 89f59d102..b20919e5e 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java @@ -383,36 +383,56 @@ public List getModules(int ID, EntityPlayer player) { int sizeX = 52; int sizeY = 46; if (world.isRemote) { - //Border + // Border for RIGHT composition pane (unchanged) modules.add(new ModuleScaledImage(baseX - 3, baseY - 3, 3, baseY + sizeY + 6, TextureResources.verticalBar)); modules.add(new ModuleScaledImage(baseX + sizeX, baseY - 3, -3, baseY + sizeY + 6, TextureResources.verticalBar)); modules.add(new ModuleScaledImage(baseX, baseY - 3, sizeX, 3, TextureResources.horizontalBar)); modules.add(new ModuleScaledImage(baseX, 2 * baseY + sizeY, sizeX, -3, TextureResources.horizontalBar)); } - ModuleContainerPanYOnly pan2 = new ModuleContainerPanYOnly(baseX, baseY, buttonList, new LinkedList<>(), null, 40, 48, 0, 0, 0, 72); - modules.add(pan2); - - //Add borders for asteroid - baseX = 5; - baseY = 32; - sizeX = 112; - sizeY = 46; + // Preserve RIGHT pane coords before reusing baseX/baseY for the LEFT pane + final int compX = baseX; + final int compY = baseY; + final int compScreenX = 40; // same as original + final int compScreenY = 48; // same as original + + // ---- LEFT pane (asteroid list) border + baseX = 5; + baseY = 32; + sizeX = 112; + sizeY = 46; if (world.isRemote) { - //Border + // Border for LEFT asteroid list modules.add(new ModuleScaledImage(baseX - 3, baseY - 3, 3, baseY + sizeY + 6, TextureResources.verticalBar)); modules.add(new ModuleScaledImage(baseX + sizeX, baseY - 3, -3, baseY + sizeY + 6, TextureResources.verticalBar)); modules.add(new ModuleScaledImage(baseX, baseY - 3, sizeX, 3, TextureResources.horizontalBar)); modules.add(new ModuleScaledImage(baseX, 2 * baseY + sizeY, sizeX, -3, TextureResources.horizontalBar)); } - //listing of asteroids with scrollcaching + // ---- LEFT asteroid list: wheel-enabled + cached if (lastSeed != -1) { - ModuleContainerPanYOnlyWithScrollCache pan = new ModuleContainerPanYOnlyWithScrollCache( - baseX, baseY, list2, new LinkedList<>(), null, sizeX - 2, sizeY, 0, -48, 0, 72); - modules.add(pan); + ModuleContainerPanYOnlyWithScrollCache panLeft = new ModuleContainerPanYOnlyWithScrollCache( + baseX, baseY, + list2, new LinkedList<>(), + null, + sizeX - 2, sizeY, // (screen width minus 2 like original) + 0, -48, // paddingX, paddingY + 0, 72 // containerSizeX, containerSizeY + ); + modules.add(panLeft); // LEFT FIRST to consume wheel } + // ---- RIGHT composition pane: parent class (drag-only; wheel will be 0 after left consumes it) + ModuleContainerPanYOnly panRight = new ModuleContainerPanYOnly( + compX, compY, + buttonList, new LinkedList<>(), + null, + compScreenX, compScreenY, + 0, 0, + 0, 72 + ); + modules.add(panRight); + } else if (tabModule.getTab() == 0) { modules.add(new ModulePower(18, 20, getBatteries())); From a69461ca442a4a83ce297142cf23b520e8595069 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Tue, 21 Oct 2025 16:58:07 +0200 Subject: [PATCH 047/274] Improve scroll caching and scroll asteroidlist with mousewheel. Refactor scroll position caching and event handling for better performance and memory management. --- ...oduleContainerPanYOnlyWithScrollCache.java | 255 ++++++++++++++---- 1 file changed, 202 insertions(+), 53 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleContainerPanYOnlyWithScrollCache.java b/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleContainerPanYOnlyWithScrollCache.java index f4368e04c..5e5265475 100644 --- a/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleContainerPanYOnlyWithScrollCache.java +++ b/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleContainerPanYOnlyWithScrollCache.java @@ -3,29 +3,52 @@ import zmaster587.libVulpes.inventory.modules.ModuleContainerPanYOnly; import zmaster587.libVulpes.inventory.modules.ModuleBase; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import java.io.IOException; +import java.lang.ref.WeakReference; import java.util.List; -import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicInteger; public class ModuleContainerPanYOnlyWithScrollCache extends ModuleContainerPanYOnly { - /** - * Single global scroll position cache for the client. - * Stores one Integer (legal range [-containerSizeY, 0]) for the *most recently used* pane. - * Latest write always wins (old overwrites new; there is only one slot). - */ - private static final AtomicReference GLOBAL_SCROLL = new AtomicReference<>(null); + // ===== Single-slot global cache (latest write wins; no memory growth) ===== + private static final int NO_SCROLL = Integer.MIN_VALUE; + private static final AtomicInteger GLOBAL_SCROLL = new AtomicInteger(NO_SCROLL); - // Lazy, one-time restore (containerSizeY may not be final at ctor time) + // ===== Track live instances so the event handler can find "this" without editing GuiModular ===== + @SideOnly(Side.CLIENT) + private static final CopyOnWriteArrayList> LIVE = + new CopyOnWriteArrayList<>(); + + @SideOnly(Side.CLIENT) + private WeakReference lastGui = new WeakReference<>(null); + + @SideOnly(Side.CLIENT) + private static volatile boolean EVENT_REGISTERED = false; + + // >>> Store GUI origin captured during render to avoid touching protected xSize/ySize + @SideOnly(Side.CLIENT) + private volatile int lastGuiLeft = 0, lastGuiTop = 0; + + // ===== Instance state ===== + private int lastSavedY = NO_SCROLL; private boolean didRestore = false; - private Integer pendingCachedPos = null; - // ===== Constructors ===== + // Debounce to avoid micro-stutter under heavy input + private long lastSaveNs = 0L; + private static final long SAVE_INTERVAL_NS = 30_000_000L; // 30 ms + public ModuleContainerPanYOnlyWithScrollCache( int offsetX, int offsetY, List moduleList, List staticModules, @@ -34,99 +57,225 @@ public ModuleContainerPanYOnlyWithScrollCache( int paddingX, int paddingY, int containerSizeX, int containerSizeY ) { - super(offsetX, offsetY, moduleList, staticModules, backdrop, screenSizeX, screenSizeY, - paddingX, paddingY, containerSizeX, containerSizeY); + super(offsetX, offsetY, moduleList, staticModules, backdrop, + screenSizeX, screenSizeY, paddingX, paddingY, + containerSizeX, containerSizeY); - // Snapshot current global scroll to restore later (after layout stabilizes) - this.pendingCachedPos = GLOBAL_SCROLL.get(); + // Register this instance for event routing (client-side only) + if (Minecraft.getMinecraft() != null) { + LIVE.add(new WeakReference<>(this)); + maybeRegisterEventHandler(); + } } - // ===== Clamping & persistence ===== + // Ensure we don’t leak refs if the module gets disabled/detached + @Override + public void setEnabled(boolean state) { + if (!state && this.isEnabled()) { + saveScrollIfChangedForce(); // persist last position + } + super.setEnabled(state); + // Optional: prune dead refs occasionally + pruneDeadRefs(); + } + + // Clamp to base’s legal range [-containerSizeY, 0] private int clampScroll(int y) { if (y > 0) return 0; int min = -this.containerSizeY; return (y < min) ? min : y; } + // Debounced save after movement, skipping no-op writes globally and per-instance private void saveScrollIfChanged() { - int y = clampScroll(super.getScrollY()); - Integer prev = GLOBAL_SCROLL.get(); - if (prev != null && prev.intValue() == y) return; // no write if unchanged - GLOBAL_SCROLL.set(y); // single slot: old key always overwritten by new write + final int y = clampScroll(super.getScrollY()); + + // Per-instance no-op: if we already observed y, don't do anything. + if (y == lastSavedY) return; + + // Global no-op: if the global cache already holds y, skip the write, but + // update our lastSavedY so we don't keep re-checking. + final int global = GLOBAL_SCROLL.get(); + if (global == y) { + lastSavedY = y; + return; + } + + // Keep debounce to avoid bursts during fine-grained drags. + final long now = System.nanoTime(); + if (now - lastSaveNs < SAVE_INTERVAL_NS) { + lastSavedY = y; // remember the new y even if we didn't write globally yet + return; + } + + lastSaveNs = now; + lastSavedY = y; + + // Use lazySet for cheap release write, perfectly fine for a UI cache + GLOBAL_SCROLL.lazySet(y); + + // DEBUG + //System.out.println("[SCROLLER] save y=" + y); } - // One-time lazy restore when bounds should be final + + // Force save (bypass debounce) on close or disable, still skipping no-op + private void saveScrollIfChangedForce() { + final int y = clampScroll(super.getScrollY()); + + // If both our last and the global already equal y, it's a no-op + if (y == lastSavedY && GLOBAL_SCROLL.get() == y) return; + + lastSavedY = y; + lastSaveNs = System.nanoTime(); + + GLOBAL_SCROLL.lazySet(y); + + // DEBUG + //System.out.println("[SCROLLER] force-save y=" + y); + } + + // Restore once when bounds are stable @Override @SideOnly(Side.CLIENT) public void renderBackground(GuiContainer gui, int x, int y, int mouseX, int mouseY, FontRenderer font) { + // Remember the GUI we’re rendering in so the event handler can filter by current screen + this.lastGui = new WeakReference<>(gui); + + // >>> Capture guiLeft/guiTop from the parameters + this.lastGuiLeft = x; + this.lastGuiTop = y; + if (!didRestore) { - if (pendingCachedPos != null) { - int clamped = clampScroll(pendingCachedPos); - // Base setOffset2 sets currentPosY = -y, so pass -clamped - super.setOffset2(-clamped); + int v = GLOBAL_SCROLL.get(); + if (v != NO_SCROLL) { + int clamped = clampScroll(v); + super.setOffset2(-clamped); // base uses -y + lastSavedY = clamped; + //System.out.println("[SCROLLER] restore y=" + clamped); // DEBUG } didRestore = true; } super.renderBackground(gui, x, y, mouseX, mouseY, font); } - // Capture all movement paths (wheel, drag, programmatic move, close) + + @Override + @SideOnly(Side.CLIENT) + public void renderForeground(int guiOffsetX, int guiOffsetY, int mouseX, int mouseY, float zLevel, + GuiContainer gui, FontRenderer font) { + super.renderForeground(guiOffsetX, guiOffsetY, mouseX, mouseY, zLevel, gui, font); + } + + // Single save point for any movement @Override protected void moveContainerInterior(int deltaY) { super.moveContainerInterior(deltaY); saveScrollIfChanged(); } + // Base onScroll calls moveContainerInterior; don’t double-save here @Override public void onScroll(int dwheel) { super.onScroll(dwheel); - saveScrollIfChanged(); } @Override @SideOnly(Side.CLIENT) public void onMouseClickedAndDragged(int x, int y, int button, long timeSinceLastClick) { super.onMouseClickedAndDragged(x, y, button, timeSinceLastClick); - saveScrollIfChanged(); } - @Override - public void setEnabled(boolean state) { - if (!state && this.isEnabled()) { - // Persist on GUI disable/close - saveScrollIfChanged(); - } - super.setEnabled(state); + // Public clear (e.g., on new scan) + public static void clearScrollCache() { + GLOBAL_SCROLL.set(NO_SCROLL); + //System.out.println("[SCROLLER] clear cache"); // DEBUG } - // Persist programmatic jumps too - @Override - protected void setOffset2(int y) { - super.setOffset2(y); - saveScrollIfChanged(); + // ===== Event routing (client-side only) ===== + + @SideOnly(Side.CLIENT) + private static void maybeRegisterEventHandler() { + if (!EVENT_REGISTERED) { + MinecraftForge.EVENT_BUS.register(new WheelRouter()); + EVENT_REGISTERED = true; + } } - // external centralized wheel dispatcher @SideOnly(Side.CLIENT) - public void acceptExternalScroll(int dwheel, int mouseX, int mouseY) { - if (dwheel == 0 || !this.isEnabled()) return; - if (isMouseInBoundsForThis(mouseX, mouseY)) { - super.onScroll(dwheel); - saveScrollIfChanged(); + private static void pruneDeadRefs() { + for (WeakReference ref : LIVE) { + if (ref.get() == null) LIVE.remove(ref); } } - // Corrected bounds check (local space; include edges) - private boolean isMouseInBoundsForThis(int mouseX, int mouseY) { - int localX = mouseX - this.offsetX; - int localY = mouseY - this.offsetY; + @SideOnly(Side.CLIENT) + private boolean isMouseOverThis(int relX, int relY) { + // relX/relY are GUI-relative to (guiLeft, guiTop) + int localX = relX - this.offsetX; + int localY = relY - this.offsetY; return localX >= 0 && localX < this.screenSizeX && localY >= 0 && localY < this.screenSizeY; } - // ===== Cache management helpers ===== - /** Clear the single cached position (e.g., on new scan). */ - public static void clearScrollCache() { - GLOBAL_SCROLL.set(null); + @SideOnly(Side.CLIENT) + private boolean isOnThisGui(GuiScreen current) { + GuiContainer g = lastGui.get(); + return g != null && g == current; + } + + @SideOnly(Side.CLIENT) + private static class WheelRouter { + private static int lastTickDispatched = -1; + private static int lastScreenId = 0; + private static int lastWheelSign = 0; // -1/+1 + + @SubscribeEvent + public void onMouseInputPre(GuiScreenEvent.MouseInputEvent.Pre evt) throws IOException { + GuiScreen screen = evt.getGui(); + if (!(screen instanceof GuiContainer)) return; + + int d = org.lwjgl.input.Mouse.getEventDWheel(); + if (d == 0) return; + + Minecraft mc = Minecraft.getMinecraft(); + int tick = (mc.ingameGUI != null) ? mc.ingameGUI.getUpdateCounter() : 0; + int screenId = System.identityHashCode(screen); + int sign = Integer.signum(d); + + // Coalesce: same screen + same tick + same direction => treat as duplicate + if (tick == lastTickDispatched && screenId == lastScreenId && sign == lastWheelSign) { + evt.setCanceled(true); + return; + } + + int scaledW = screen.width, scaledH = screen.height; + int mouseX = org.lwjgl.input.Mouse.getX() * scaledW / mc.displayWidth; + int mouseY = scaledH - org.lwjgl.input.Mouse.getY() * scaledH / mc.displayHeight - 1; + + boolean handled = false; + for (int i = LIVE.size() - 1; i >= 0; i--) { + WeakReference ref = LIVE.get(i); + ModuleContainerPanYOnlyWithScrollCache mod = ref.get(); + if (mod == null) { LIVE.remove(i); continue; } + if (!mod.getVisible() || !mod.isEnabled()) continue; + if (!mod.isOnThisGui(screen)) continue; + + int relX = mouseX - mod.lastGuiLeft; + int relY = mouseY - mod.lastGuiTop; + if (!mod.isMouseOverThis(relX, relY)) continue; + + mod.onScroll(d); // will call moveContainerInterior -> save + handled = true; + break; + } + + if (handled) { + lastTickDispatched = tick; + lastScreenId = screenId; + lastWheelSign = sign; + evt.setCanceled(true); + } + } } } From 937fbfbbc1635a34db3584de03552e9965556467 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Tue, 21 Oct 2025 22:29:07 +0200 Subject: [PATCH 048/274] Tooltip for ItemAsteroidChip Unique names, and Type showing in tooltip --- .../item/ItemAsteroidChip.java | 46 +++++++++++++++---- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java b/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java index 4ecc42e2f..bddbf843e 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java @@ -66,24 +66,50 @@ public void setType(@Nonnull ItemStack stack, String type) { nbt.setString(astType, type); stack.setTagCompound(nbt); } + // SplitMix64 mixer: great diffusion, tiny cost + // Make Unique ID from UUID and type (looks random, but is deterministic) + // Only for tooltip display purposes. Actual NBT untouched. + private static long mix64(long z) { + z += 0x9E3779B97F4A7C15L; + z = (z ^ (z >>> 30)) * 0xBF58476D1CE4E5B9L; + z = (z ^ (z >>> 27)) * 0x94D049BB133111EBL; + return z ^ (z >>> 31); + } - @Override - public void addInformation(@Nonnull ItemStack stack, World player, List list, ITooltipFlag bool) { + // Deterministic display id from UUID and type (no world dependence) + private static long makeDisplayId(Long uuid, String type) { + long base = (uuid == null) ? 0L : uuid; + long th = (type == null) ? 0L : Integer.toUnsignedLong(type.hashCode()); + return mix64(base ^ (th << 1)); // fold in type so same UUID/different types look different + } + @Override + public void addInformation(@Nonnull ItemStack stack, World world, List list, ITooltipFlag flag) { if (!stack.hasTagCompound()) { list.add(LibVulpes.proxy.getLocalizedString("msg.unprogrammed")); - } else { - if (stack.getItemDamage() == 0) { + return; + } + if (stack.getItemDamage() == 0) { + Long id = getUUID(stack); + String type = getType(stack); + + if (type != null && !type.isEmpty()) { + list.add(LibVulpes.proxy.getLocalizedString("msg.asteroidChip.type") + ": " + + ChatFormatting.AQUA + type); + } - list.add(LibVulpes.proxy.getLocalizedString("msg.asteroidChip.asteroid") + "-" + ChatFormatting.DARK_GREEN + getUUID(stack)); + // Tooltip-only, random-looking but deterministic + final long disp = makeDisplayId(id, type); + final String hex = Long.toUnsignedString(disp, 16).toUpperCase(); - super.addInformation(stack, player, list, bool); + // Fixed-length visual tag (avoid lookalikes by using N=6 chars) + final int N = 6; + final String shortHex = (hex.length() > N) ? hex.substring(hex.length() - N) : hex; - //list.add("Mass: " + unknown); - //list.add("Atmosphere Density: " + unknown); - //list.add("Distance From Star: " + unknown); + list.add(LibVulpes.proxy.getLocalizedString("msg.asteroidChip.asteroid") + ": " + + ChatFormatting.DARK_GREEN + shortHex); - } + super.addInformation(stack, world, list, flag); } } From 791e540ba119fa31b46c746f56662a24a98ae25c Mon Sep 17 00:00:00 2001 From: kaduvill Date: Tue, 21 Oct 2025 22:41:32 +0200 Subject: [PATCH 049/274] Add new observatory and asteroid chip messages --- src/main/resources/assets/advancedrocketry/lang/en_US.lang | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/resources/assets/advancedrocketry/lang/en_US.lang b/src/main/resources/assets/advancedrocketry/lang/en_US.lang index a1e234077..94ca254f1 100644 --- a/src/main/resources/assets/advancedrocketry/lang/en_US.lang +++ b/src/main/resources/assets/advancedrocketry/lang/en_US.lang @@ -287,6 +287,7 @@ msg.observetory.text.composition=Composition msg.observetory.text.processdiscovery=Process discovery msg.observetory.text.observabledistance=Observable distance: msg.observetory.text.missionTime=Mission Time: +msg.observetory.req.open=Observatory must be open (night, clear sky, sky access) or be in space! msg.tooltip.data=Data msg.tooltip.asteroidselection=Asteroid Selection msg.label.name=Name @@ -418,6 +419,7 @@ msg.rocketbuilder.alreadyassembled=Rocket already assembled msg.solar.collectingEnergy=Collecting Energy: msg.solar.cannotcollectEnergy=Unable to collect Energy msg.asteroidChip.asteroid=Asteroid +msg.asteroidChip.type=Type msg.atmanal.atmtype=Atmosphere Type: msg.atmanal.canbreathe=Breathable: msg.biomechanger.scan=Scan Biome From 4ca03d3bea0432aadd9cf00da431d4a115fd3a4c Mon Sep 17 00:00:00 2001 From: kaduvill Date: Tue, 21 Oct 2025 22:53:37 +0200 Subject: [PATCH 050/274] Dynamic Process button tooltip handling tell the player why button dont work if observatory is (!open) --- .../tile/multiblock/TileObservatory.java | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java b/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java index b20919e5e..0f3619525 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java @@ -303,8 +303,30 @@ public List getModules(int ID, EntityPlayer player) { modules.add(new ModuleTexturedSlotArray(5, 120, this, 1, 2, TextureResources.idChip)); modules.add(new ModuleOutputSlotArray(45, 120, this, 2, 3)); modules.add(new ModuleProgress(25, 120, 0, new ProgressBarImage(217, 0, 17, 17, 234, 0, EnumFacing.DOWN, TextureResources.progressBars), this)); - modules.add(new ModuleButton(25, 120, 1, "", this, zmaster587.libVulpes.inventory.TextureResources.buttonNull, LibVulpes.proxy.getLocalizedString("msg.observetory.text.processdiscovery"), 17, 17)); + + ModuleButton processBtn = new ModuleButton( + 25, 120, 1, "", + this, + zmaster587.libVulpes.inventory.TextureResources.buttonNull, + // default tooltip (will be replaced conditionally below) + LibVulpes.proxy.getLocalizedString("msg.observetory.text.processdiscovery"), + 17, 17 + ); + + // `isOpen` is synchronized to client via writeNetworkData/readNetworkData, so safe to read here. + if (!isOpen) { + // Show requirements when the dome isn't open (daytime, raining, no sky, etc.) + String tooltip = LibVulpes.proxy.getLocalizedString("msg.observetory.req.open"); + processBtn.setToolTipText(tooltip); + } else { + // Keep your normal tooltip when open + processBtn.setToolTipText(LibVulpes.proxy.getLocalizedString("msg.observetory.text.processdiscovery")); + } + + // Keep it enabled so the tooltip renders (ModuleButton.isMouseOver checks enabled) + processBtn.setEnabled(true); + modules.add(processBtn); ModuleButton scanButton = new ModuleButton(100, 120, 2, LibVulpes.proxy.getLocalizedString("msg.observetory.scan.button"), this, zmaster587.libVulpes.inventory.TextureResources.buttonBuild, LibVulpes.proxy.getLocalizedString("msg.observetory.scan.tooltip"), 64, 18); @@ -549,7 +571,7 @@ else if (id == PROCESS_CHIP && !world.isRemote) { if (inv.getStackInSlot(2).isEmpty() && isOpen && hasEnergy(500) && lastButton != -1) { ItemStack stack = inv.decrStackSize(1, 1); if (stack != ItemStack.EMPTY && stack.getItem() instanceof ItemAsteroidChip) { - ((ItemAsteroidChip) (stack.getItem())).setUUID(stack, lastSeed); + ((ItemAsteroidChip) (stack.getItem())).setUUID(stack, lastSeed + lastButton); ((ItemAsteroidChip) (stack.getItem())).setType(stack, lastType); ((ItemAsteroidChip) (stack.getItem())).setMaxData(stack, 1000); inv.setInventorySlotContents(2, stack); From 8dde7e417a14c3bf5981284c43203cade4023713 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 24 Oct 2025 15:27:47 +0200 Subject: [PATCH 051/274] Update RenderAsteroidSky.java Fixed: crossmod compat: Leaky GLstates broke entityculling e.g. Also made Asteroids glow if they are infront of a sun, and pushed them behind Disks. --- .../render/planet/RenderAsteroidSky.java | 551 ++++++++---------- 1 file changed, 244 insertions(+), 307 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/client/render/planet/RenderAsteroidSky.java b/src/main/java/zmaster587/advancedRocketry/client/render/planet/RenderAsteroidSky.java index 75bac2b36..ba7c44ef2 100644 --- a/src/main/java/zmaster587/advancedRocketry/client/render/planet/RenderAsteroidSky.java +++ b/src/main/java/zmaster587/advancedRocketry/client/render/planet/RenderAsteroidSky.java @@ -5,7 +5,6 @@ import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.GlStateManager.DestFactor; import net.minecraft.client.renderer.GlStateManager.SourceFactor; -import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; @@ -19,54 +18,70 @@ import zmaster587.advancedRocketry.api.dimension.solar.StellarBody; import zmaster587.advancedRocketry.dimension.DimensionManager; import zmaster587.advancedRocketry.dimension.DimensionProperties; -import zmaster587.advancedRocketry.event.RocketEventHandler; import zmaster587.advancedRocketry.inventory.TextureResources; import zmaster587.advancedRocketry.stations.SpaceObjectManager; import zmaster587.advancedRocketry.stations.SpaceStationObject; import zmaster587.advancedRocketry.util.AstronomicalBodyHelper; import zmaster587.libVulpes.util.Vector3F; -import java.util.LinkedList; +import java.util.ArrayList; import java.util.List; import java.util.Random; public class RenderAsteroidSky extends IRenderHandler { - + // === Textures === public static final ResourceLocation asteroid1 = new ResourceLocation("advancedRocketry:textures/planets/asteroid_a.png"); public static final ResourceLocation asteroid2 = new ResourceLocation("advancedRocketry:textures/planets/asteroid_b.png"); public static final ResourceLocation asteroid3 = new ResourceLocation("advancedRocketry:textures/planets/asteroid_c.png"); - ResourceLocation currentlyBoundTex = null; - float celestialAngle; - Vector3F axis; - Minecraft mc = Minecraft.getMinecraft(); - private int starGLCallList; - private int glSkyList; - private int glSkyList2; - private int glSkyList3; - - //Mostly vanilla code - //TODO: make usable on other planets + + // Per-frame texture bind cache (local to this renderer) + private ResourceLocation boundTex = null; + + // Runtime / state + private float celestialAngle; + private final Vector3F axis; + private final Minecraft mc = Minecraft.getMinecraft(); + + // Display lists + private final int starGLCallList; + private final int glSkyList; + private final int glSkyList2; + private final int glSkyList3; + + // Reused scratch buffers to reduce GC + private final List childrenBuf = new ArrayList<>(8); + private final float[] shadowColorTmp = new float[3]; + + // Helpers for ring/black-hole math + private static float xrotangle = 0; // for ring rotation (kept exactly as before) + private static final float[] skycolor = {0,0,0}; // for black hole rendering (same usage as before) + private static double currentplanetphi = 0; // ring/disk angle (same) + + // === ctor === public RenderAsteroidSky() { axis = new Vector3F<>(1f, 0f, 0f); + // Build display lists once (same seeds/geometry as original) this.starGLCallList = GLAllocation.generateDisplayLists(4); + GL11.glPushMatrix(); GL11.glNewList(this.starGLCallList, GL11.GL_COMPILE); - this.renderStars(); + this.renderStars(); // stars list GL11.glEndList(); GL11.glPopMatrix(); + BufferBuilder buffer = Tessellator.getInstance().getBuffer(); + + // Sky dome slice 1 this.glSkyList = this.starGLCallList + 1; GL11.glNewList(this.glSkyList, GL11.GL_COMPILE); byte b2 = 64; int i = 256 / b2 + 2; float f = 16.0F; - int j; - int k; - for (j = -b2 * i; j <= b2 * i; j += b2) { - for (k = -b2 * i; k <= b2 * i; k += b2) { + for (int j = -b2 * i; j <= b2 * i; j += b2) { + for (int k = -b2 * i; k <= b2 * i; k += b2) { buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION); buffer.pos(j, f, k).endVertex(); buffer.pos(j + b2, f, k).endVertex(); @@ -75,35 +90,43 @@ public RenderAsteroidSky() { Tessellator.getInstance().draw(); } } - GL11.glEndList(); + + // Sky dome slice 2 this.glSkyList2 = this.starGLCallList + 2; GL11.glNewList(this.glSkyList2, GL11.GL_COMPILE); f = -16.0F; buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION); - - for (j = -b2 * i; j <= b2 * i; j += b2) { - for (k = -b2 * i; k <= b2 * i; k += b2) { + for (int j = -b2 * i; j <= b2 * i; j += b2) { + for (int k = -b2 * i; k <= b2 * i; k += b2) { buffer.pos(j, f, k).endVertex(); buffer.pos(j + b2, f, k).endVertex(); buffer.pos(j + b2, f, k + b2).endVertex(); buffer.pos(j, f, k + b2).endVertex(); } } - Tessellator.getInstance().draw(); GL11.glEndList(); + // Asteroids list this.glSkyList3 = this.starGLCallList + 3; GL11.glPushMatrix(); GL11.glNewList(this.glSkyList3, GL11.GL_COMPILE); - renderAsteroids(); + renderAsteroids(); // geometry baked with fixed seed matching original GL11.glEndList(); GL11.glPopMatrix(); } + // Efficient texture binder (skip redundant binds per frame) + private void bind(ResourceLocation tex) { + if (tex != null && tex != boundTex) { + mc.renderEngine.bindTexture(tex); + boundTex = tex; + } + } + private void renderAsteroids() { - Random random = new Random(10843L); + Random random = new Random(10843L); // same seed => identical layout to original BufferBuilder buffer = Tessellator.getInstance().getBuffer(); buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR); @@ -132,10 +155,9 @@ private void renderAsteroids() { double d15 = Math.sin(d14); double d16 = Math.cos(d14); - float r, g, b; - r = random.nextFloat() * 0.05f + .95f; - g = random.nextFloat() * 0.1f + .9f; - b = random.nextFloat() * 0.1f + .9f; + float r = random.nextFloat() * 0.05f + .95f; + float g = random.nextFloat() * 0.1f + .9f; + float b = random.nextFloat() * 0.1f + .9f; for (int j = 0; j < 4; ++j) { double d17 = 0.0D; @@ -151,13 +173,11 @@ private void renderAsteroids() { } } } - Tessellator.getInstance().draw(); - //buffer.finishDrawing(); } private void renderStars() { - Random random = new Random(10842L); + Random random = new Random(10842L); // same seed => identical layout to original BufferBuilder buffer = Tessellator.getInstance().getBuffer(); buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION); @@ -200,50 +220,38 @@ private void renderStars() { } } } - Tessellator.getInstance().draw(); - //buffer.finishDrawing(); } - private static float xrotangle = 0; // used for ring rotation because I don't want to bother changing the definitions of methods. - private static float[] skycolor = {0,0,0}; // used for black hole rendering - same reason as above - private static double currentplanetphi = 0; // used for calculating ring/disk angle - @Override public void render(float partialTicks, WorldClient world, Minecraft mc) { + // per-frame texture bind cache reset + boundTex = null; - - //TODO: properly handle this + // === Gather properties (unchanged logic) === float atmosphere; int solarOrbitalDistance, planetOrbitalDistance = 0; double myPhi = 0, myTheta = 0, myPrevOrbitalTheta = 0, myRotationalPhi = 0; - boolean hasAtmosphere = false, isMoon; - float[] shadowColorMultiplier = {0f, 0f, 0f}; - float[] parentAtmColor = new float[]{1f, 1f, 1f}; + boolean isMoon; + // shadowColorTmp reused; values set below float[] parentRingColor = new float[]{1f, 1f, 1f}; float[] ringColor = new float[]{1f, 1f, 1f}; float sunSize = 1.0f; - float starSeparation = 0f; boolean isWarp = false; - boolean isGasGiant = false; boolean hasRings = false; - boolean parentPlanetHasDecorator = true; boolean parentHasRings = false; boolean parentHasATM = false; DimensionProperties parentProperties = null; DimensionProperties properties; EnumFacing travelDirection = null; - ResourceLocation parentPlanetIcon = null; List children; StellarBody primaryStar; celestialAngle = mc.world.getCelestialAngle(partialTicks); Vec3d sunColor; - if (mc.world.provider instanceof IPlanetaryProvider) { IPlanetaryProvider planetaryProvider = (IPlanetaryProvider) mc.world.provider; - properties = (DimensionProperties) planetaryProvider.getDimensionProperties(mc.player.getPosition()); atmosphere = planetaryProvider.getAtmosphereDensityFromHeight(mc.getRenderViewEntity().posY, mc.player.getPosition()); @@ -259,15 +267,16 @@ public void render(float partialTicks, WorldClient world, Minecraft mc) { hasRings = properties.hasRings(); ringColor = properties.ringColor; - children = new LinkedList<>(); + childrenBuf.clear(); for (Integer i : properties.getChildPlanets()) { - children.add(DimensionManager.getInstance().getDimensionProperties(i)); + childrenBuf.add(DimensionManager.getInstance().getDimensionProperties(i)); } + children = childrenBuf; solarOrbitalDistance = properties.getSolarOrbitalDistance(); - - if (isMoon = properties.isMoon()) { + isMoon = properties.isMoon(); + if (isMoon) { parentProperties = properties.getParentProperties(); planetOrbitalDistance = properties.getParentOrbitalDistance(); parentHasRings = parentProperties.hasRings; @@ -277,22 +286,22 @@ public void render(float partialTicks, WorldClient world, Minecraft mc) { sunColor = planetaryProvider.getSunColor(mc.player.getPosition()); primaryStar = properties.getStar(); if (primaryStar != null) { - sunSize = properties.getStar().getSize(); - } else + sunSize = primaryStar.getSize(); + } else { primaryStar = DimensionManager.getInstance().getStar(0); + } + if (world.provider.getDimension() == ARConfiguration.getCurrentConfig().spaceDimId) { isWarp = properties.getParentPlanet() == SpaceObjectManager.WARPDIMID; if (isWarp) { SpaceStationObject station = (SpaceStationObject) SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(mc.player.getPosition()); - travelDirection = station.getForwardDirection(); + if (station != null) travelDirection = station.getForwardDirection(); } } - } - else if (DimensionManager.getInstance().isDimensionCreated(mc.world.provider.getDimension())) { - + } else if (DimensionManager.getInstance().isDimensionCreated(mc.world.provider.getDimension())) { properties = DimensionManager.getInstance().getDimensionProperties(mc.world.provider.getDimension()); - atmosphere = properties.getAtmosphereDensityAtHeight(mc.getRenderViewEntity().posY);//planetaryProvider.getAtmosphereDensityFromHeight(mc.getRenderViewEntity().posY, mc.player.getPosition()); + atmosphere = properties.getAtmosphereDensityAtHeight(mc.getRenderViewEntity().posY); EnumFacing dir = getRotationAxis(properties, mc.player.getPosition()); axis.x = (float) dir.getFrontOffsetX(); axis.y = (float) dir.getFrontOffsetY(); @@ -305,15 +314,16 @@ else if (DimensionManager.getInstance().isDimensionCreated(mc.world.provider.get hasRings = properties.hasRings(); ringColor = properties.ringColor; - children = new LinkedList<>(); + childrenBuf.clear(); for (Integer i : properties.getChildPlanets()) { - children.add(DimensionManager.getInstance().getDimensionProperties(i)); + childrenBuf.add(DimensionManager.getInstance().getDimensionProperties(i)); } + children = childrenBuf; solarOrbitalDistance = properties.getSolarOrbitalDistance(); - - if (isMoon = properties.isMoon()) { + isMoon = properties.isMoon(); + if (isMoon) { parentProperties = properties.getParentProperties(); planetOrbitalDistance = properties.getParentOrbitalDistance(); parentHasRings = parentProperties.hasRings; @@ -322,22 +332,25 @@ else if (DimensionManager.getInstance().isDimensionCreated(mc.world.provider.get } float[] sunColorFloat = properties.getSunColor(); - sunColor = new Vec3d(sunColorFloat[0], sunColorFloat[1], sunColorFloat[2]);//planetaryProvider.getSunColor(mc.player.getPosition()); + sunColor = new Vec3d(sunColorFloat[0], sunColorFloat[1], sunColorFloat[2]); primaryStar = properties.getStar(); if (primaryStar != null) { - sunSize = properties.getStar().getSize(); - } else + sunSize = primaryStar.getSize(); + } else { primaryStar = DimensionManager.getInstance().getStar(0); + } + if (world.provider.getDimension() == ARConfiguration.getCurrentConfig().spaceDimId) { isWarp = properties.getParentPlanet() == SpaceObjectManager.WARPDIMID; if (isWarp) { SpaceStationObject station = (SpaceStationObject) SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(mc.player.getPosition()); - travelDirection = station.getForwardDirection(); + if (station != null) travelDirection = station.getForwardDirection(); } } - } - else { - children = new LinkedList<>(); + } else { + // No planet provider and dimension not registered: fall back to overworld props (exactly as before) + childrenBuf.clear(); + children = childrenBuf; isMoon = false; atmosphere = DimensionManager.overworldProperties.getAtmosphereDensityAtHeight(mc.getRenderViewEntity().posY); solarOrbitalDistance = DimensionManager.overworldProperties.orbitalDist; @@ -348,6 +361,7 @@ else if (DimensionManager.getInstance().isDimensionCreated(mc.world.provider.get currentplanetphi = myPhi; + // === Sky color & base dome === GlStateManager.disableTexture2D(); Vec3d vec3 = Minecraft.getMinecraft().world.getSkyColor(this.mc.getRenderViewEntity(), partialTicks); float f1 = (float) vec3.x; @@ -359,23 +373,17 @@ else if (DimensionManager.getInstance().isDimensionCreated(mc.world.provider.get float f4 = (f1 * 30.0F + f2 * 59.0F + f3 * 11.0F) / 100.0F; float f5 = (f1 * 30.0F + f2 * 70.0F) / 100.0F; f6 = (f1 * 30.0F + f3 * 70.0F) / 100.0F; - f1 = f4; - f2 = f5; - f3 = f6; + f1 = f4; f2 = f5; f3 = f6; } - //Simulate atmospheric thickness, vaugely - //This is done like this to prevent problems with superbright atmospheres on low-atmosphere planets - //Plus you couldn't see stars during the day anyway + // Atmospheric brightness shaping (unchanged) int atmosphereInt = properties.getAtmosphereDensity(); -// System.out.println("before:"+f1+":"+f2+":"+f3); f1 = atmosphereInt < 1 ? 0 : (float) Math.pow(f1, Math.sqrt(Math.max(atmosphere, 0.0001))); f2 = atmosphereInt < 1 ? 0 : (float) Math.pow(f2, Math.sqrt(Math.max(atmosphere, 0.0001))); f3 = atmosphereInt < 1 ? 0 : (float) Math.pow(f3, Math.sqrt(Math.max(atmosphere, 0.0001))); - - f1*=Math.min(1,atmosphere); - f2*=Math.min(1,atmosphere); - f3*=Math.min(1,atmosphere); + f1 *= Math.min(1, atmosphere); + f2 *= Math.min(1, atmosphere); + f3 *= Math.min(1, atmosphere); skycolor[0] = f1; skycolor[1] = f2; @@ -391,12 +399,10 @@ else if (DimensionManager.getInstance().isDimensionCreated(mc.world.provider.get GL11.glCallList(this.glSkyList); GlStateManager.disableFog(); GlStateManager.disableAlpha(); - RenderHelper.disableStandardItemLighting(); + net.minecraft.client.renderer.RenderHelper.disableStandardItemLighting(); + float[] afloat = mc.world.provider.calcSunriseSunsetColors(celestialAngle, partialTicks); - float f7; - float f8; - float f9; - float f10; + float f7, f8, f9, f10; if (afloat != null) { GlStateManager.disableTexture2D(); @@ -406,7 +412,6 @@ else if (DimensionManager.getInstance().isDimensionCreated(mc.world.provider.get GL11.glRotatef(MathHelper.sin(mc.world.getCelestialAngleRadians(partialTicks)) < 0.0F ? 180.0F : 0.0F, 0.0F, 0.0F, 1.0F); GL11.glRotated(90.0F - myRotationalPhi, 0.0F, 0.0F, 1.0F); - //Sim atmospheric thickness f6 = afloat[0]; f7 = afloat[1]; f8 = afloat[2]; @@ -416,9 +421,7 @@ else if (DimensionManager.getInstance().isDimensionCreated(mc.world.provider.get f9 = (f6 * 30.0F + f7 * 59.0F + f8 * 11.0F) / 100.0F; f10 = (f6 * 30.0F + f7 * 70.0F) / 100.0F; f11 = (f6 * 30.0F + f8 * 70.0F) / 100.0F; - f6 = f9; - f7 = f10; - f8 = f11; + f6 = f9; f7 = f10; f8 = f11; } buffer.begin(GL11.GL_TRIANGLE_FAN, DefaultVertexFormats.POSITION_COLOR); @@ -427,50 +430,49 @@ else if (DimensionManager.getInstance().isDimensionCreated(mc.world.provider.get for (int j = 0; j <= b0; ++j) { f11 = (float) j * (float) Math.PI * 2.0F / (float) b0; - float f12 = MathHelper.sin(f11); - float f13 = MathHelper.cos(f11); - buffer.pos(f12 * 120.0F, f13 * 120.0F, -f13 * 40.0F * afloat[3]).color(afloat[0], afloat[1], afloat[2], 0.0F).endVertex(); + float sx = MathHelper.sin(f11); + float cx = MathHelper.cos(f11); + buffer.pos(sx * 120.0F, cx * 120.0F, -cx * 40.0F * afloat[3]).color(afloat[0], afloat[1], afloat[2], 0.0F).endVertex(); } - Tessellator.getInstance().draw(); GL11.glPopMatrix(); GlStateManager.shadeModel(GL11.GL_FLAT); } - shadowColorMultiplier = new float[]{f1, f2, f3}; + + // shadow color multiplier (reused array) + shadowColorTmp[0] = f1; + shadowColorTmp[1] = f2; + shadowColorTmp[2] = f3; GlStateManager.enableTexture2D(); GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE); GL11.glPushMatrix(); + // rain alpha handling + if (atmosphere > 0) f6 = 1.0F - (mc.world.getRainStrength(partialTicks) * (atmosphere / 100f)); + else f6 = 1f; - if (atmosphere > 0) - f6 = 1.0F - (mc.world.getRainStrength(partialTicks) * (atmosphere / 100f)); - else - f6 = 1f; - - f7 = 0.0F; - f8 = 0.0F; - f9 = 0.0F; + f7 = 0.0F; f8 = 0.0F; f9 = 0.0F; GlStateManager.color(1.0F, 1.0F, 1.0F, f6); GL11.glTranslatef(f7, f8, f9); GL11.glRotatef(-90.0F, 0.0F, 1.0F, 0.0F); - float multiplier = (2 - atmosphere) / 2f;//atmosphere > 1 ? (2-atmosphere) : 1f; - if (mc.world.isRainingAt(mc.player.getPosition().add(0, 199, 0))) + float multiplier = (2 - atmosphere) / 2f; + if (mc.world.isRainingAt(mc.player.getPosition().add(0, 199, 0))) { multiplier *= 1 - mc.world.getRainStrength(partialTicks); + } GL11.glRotatef((float) myRotationalPhi, 0f, 1f, 0f); - //Draw Rings + // Rings (unchanged visuals) if (hasRings) { GL11.glPushMatrix(); GL11.glRotatef(90f, 0f, 1f, 0f); f10 = 100; double ringDist = 0; - //mc.renderEngine.bindTexture(DimensionProperties.planetRings); - mc.renderEngine.bindTexture(DimensionProperties.planetRingsNew); + bind(DimensionProperties.planetRingsNew); GL11.glRotated(70, 1, 0, 0); GL11.glTranslated(0, -10, 0); @@ -484,148 +486,120 @@ else if (DimensionManager.getInstance().isDimensionCreated(mc.world.provider.get Tessellator.getInstance().draw(); GL11.glPopMatrix(); - /* - GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); - GL11.glPushMatrix(); - - GL11.glRotatef(90f, 0f, 1f, 0f); - GL11.glRotated(70, 1, 0, 0); - GL11.glRotatef(isWarp ? 0 : celestialAngle * 360.0F, 0, 1, 0); - GL11.glTranslated(0, -10, 0); - - mc.renderEngine.bindTexture(DimensionProperties.planetRingShadow); - GlStateManager.color(0f, 0f, 0f, multiplier); - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); - buffer.pos(f10, ringDist, -f10).tex(1.0D, 0.0D).endVertex(); - buffer.pos(-f10, ringDist, -f10).tex(0.0D, 0.0D).endVertex(); - buffer.pos(-f10, ringDist, f10).tex(0.0D, 1.0D).endVertex(); - buffer.pos(f10, ringDist, f10).tex(1.0D, 1.0D).endVertex(); - Tessellator.getInstance().draw(); - GL11.glPopMatrix(); - */ - + // (Shadowed ring quad code left as in original) GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE); } GlStateManager.disableTexture2D(); - //This determines whether stars should come out regardless of thickness of atmosphere, as that is factored in later - // - it checks if the colors of the sky are so close to black that you'd see stars, or if the atmosphere is zero and so no one gives a damn - float f18 = mc.world.getStarBrightness(partialTicks) * f6;//((atmosphere == 0 || (f1 < 0.09 && f2 < 0.09 && f3 < 0.09)) ? 1 : 0);// - (atmosphere > 1 ? atmosphere - 1 : 0); + // Stars + float f18 = mc.world.getStarBrightness(partialTicks) * f6; + float starAlpha = 1 - ((1 - f18) * atmosphere); - float starAlpha = 1-((1-f18)*atmosphere); - //System.out.println(starAlpha+":"+f18+":"+atmosphere); + GlStateManager.disableDepth(); // stars always on top of sky Keep? makes asteroids glow :D - //if (f18 > 0.0F) { - if (true){ - GlStateManager.color(1, 1, 1, 1); - GL11.glPushMatrix(); - if (isWarp) { - for (int i = -3; i < 5; i++) { - GL11.glPushMatrix(); - double magnitude = i * -100 + (((System.currentTimeMillis()) + 50) % 2000) / 20f; - GL11.glTranslated(-travelDirection.getFrontOffsetZ() * magnitude, 0, travelDirection.getFrontOffsetX() * magnitude); - GL11.glCallList(this.starGLCallList); - GL11.glPopMatrix(); - } - //GL11.glTranslated(((System.currentTimeMillis()/10) + 50) % 100, 0, 0); - - } else { - GL11.glColor4f(1,1,1,starAlpha); + GlStateManager.color(1, 1, 1, 1); + GL11.glPushMatrix(); + if (isWarp && travelDirection != null) { + for (int n = -3; n < 5; n++) { + GL11.glPushMatrix(); + double magnitude = n * -100 + (((System.currentTimeMillis()) + 50) % 2000) / 20f; + GL11.glTranslated(-travelDirection.getFrontOffsetZ() * magnitude, 0, travelDirection.getFrontOffsetX() * magnitude); GL11.glCallList(this.starGLCallList); - //Extra stars for low ATM - if (atmosphere < 0.5) { - GL11.glColor4f(1,1,1,starAlpha/2); - GL11.glPushMatrix(); - GL11.glRotatef(-90, 0, 1, 0); - GL11.glCallList(this.starGLCallList); - GL11.glPopMatrix(); - } - if (atmosphere < 0.25) { - GL11.glColor4f(1,1,1,starAlpha/4); - GL11.glPushMatrix(); - GL11.glRotatef(90, 0, 1, 0); - GL11.glCallList(this.starGLCallList); - GL11.glPopMatrix(); - } - GlStateManager.color(1, 1, 1, 1); + GL11.glPopMatrix(); + } + } else { + GL11.glColor4f(1, 1, 1, starAlpha); + GL11.glCallList(this.starGLCallList); + if (atmosphere < 0.5f) { + GL11.glColor4f(1, 1, 1, starAlpha / 2f); + GL11.glPushMatrix(); + GL11.glRotatef(-90, 0, 1, 0); + GL11.glCallList(this.starGLCallList); + GL11.glPopMatrix(); } - GL11.glPopMatrix(); + if (atmosphere < 0.25f) { + GL11.glColor4f(1, 1, 1, starAlpha / 4f); + GL11.glPushMatrix(); + GL11.glRotatef(90, 0, 1, 0); + GL11.glCallList(this.starGLCallList); + GL11.glPopMatrix(); + } + GlStateManager.color(1, 1, 1, 1); } + GL11.glPopMatrix(); + GlStateManager.enableTexture2D(); + GlStateManager.enableDepth(); // keep? - mc.renderEngine.bindTexture(TextureResources.locationSunPng); + // Sun & sub-stars + bind(TextureResources.locationSunPng); - //--------------------------- Draw the suns -------------------- if (!isWarp) { if (parentProperties == null || !parentProperties.isStar()) { - xrotangle = ((float) (properties.getSolarTheta() * 180f / Math.PI) % 360f); // for black hole disk - //System.out.println(xrotangle+":"+properties.getSolarTheta()); + xrotangle = ((float) (properties.getSolarTheta() * 180f / Math.PI) % 360f); // used in black hole path drawStarAndSubStars(buffer, primaryStar, properties, solarOrbitalDistance, sunSize, sunColor, multiplier); xrotangle = 0; } } + // Moons/parent planets (unchanged logic) + if (DimensionProperties.AtmosphereTypes.SUPERHIGHPRESSURE.denserThan( + DimensionProperties.AtmosphereTypes.getAtmosphereTypeFromValue((int) (100 * atmosphere)))) { - //For these parts only render if the atmosphere is below a certain threshold (SHP atmosphere) - if (DimensionProperties.AtmosphereTypes.SUPERHIGHPRESSURE.denserThan(DimensionProperties.AtmosphereTypes.getAtmosphereTypeFromValue((int) (100 * atmosphere)))) { - //Render the parent planet - if (isMoon) { + if (isMoon && parentProperties != null) { GL11.glPushMatrix(); - //Do a whole lotta math to figure out where the parent planet is supposed to be - //That 0.3054325f is there because we need to do adjustments for some ^$%^$% reason and it's consistently off by 17.5 degrees - float planetPositionTheta = AstronomicalBodyHelper.getParentPlanetThetaFromMoon(properties.rotationalPeriod, properties.orbitalDist, parentProperties.gravitationalMultiplier, myTheta, properties.baseOrbitTheta); + float planetPositionTheta = AstronomicalBodyHelper.getParentPlanetThetaFromMoon( + properties.rotationalPeriod, properties.orbitalDist, parentProperties.gravitationalMultiplier, + myTheta, properties.baseOrbitTheta); GL11.glRotatef((float) myPhi, 0f, 0f, 1f); GL11.glRotatef(planetPositionTheta, 1f, 0f, 0f); - float phiAngle = (float) ((myPhi) * Math.PI / 180f); - - //Close enough approximation, I missed something but seems to off by no more than 30* - //Nobody will look + float phiAngle = (float) (myPhi * Math.PI / 180f); double x = MathHelper.sin(phiAngle) * MathHelper.cos((float) myTheta); double y = -MathHelper.sin((float) myTheta); double rotation = -Math.PI / 2f + Math.atan2(x, y) - (myTheta - Math.PI) * MathHelper.sin(phiAngle); if (parentHasRings) { - //Semihacky rotation stuff to keep rings synced to a different rotation than planet in the sky xrotangle = -planetPositionTheta + ((float) (myTheta * 180f / Math.PI) % 360f); - //System.out.println("r:"+xrotangle); } - shadowColorMultiplier = new float[]{f1, f2, f3}; + shadowColorTmp[0] = f1; + shadowColorTmp[1] = f2; + shadowColorTmp[2] = f3; - //System.out.println("draw moon (renderplanet"); - renderPlanet(buffer, parentProperties, planetOrbitalDistance, multiplier, rotation, false, parentHasRings, (float) Math.pow(parentProperties.getGravitationalMultiplier(), 0.4), shadowColorMultiplier, 1); + renderPlanet(buffer, parentProperties, planetOrbitalDistance, multiplier, rotation, false, parentHasRings, + (float) Math.pow(parentProperties.getGravitationalMultiplier(), 0.4), shadowColorTmp, 1); xrotangle = 0; GL11.glPopMatrix(); } - //This needs to exist specifically for init purposes - //The overworld literally breaks without it - shadowColorMultiplier[0] = 1.000001f * shadowColorMultiplier[0]; + // init quirk kept as-is + shadowColorTmp[0] = 1.000001f * shadowColorTmp[0]; for (DimensionProperties moons : children) { GL11.glPushMatrix(); float planetPositionTheta = (float) ((partialTicks * moons.orbitTheta + ((1 - partialTicks) * moons.prevOrbitalTheta)) * 180F / Math.PI); - float flippedPlanetPositionTheta = 360 - planetPositionTheta; GL11.glRotatef((float) moons.orbitalPhi, 0f, 0f, 1f); GL11.glRotated(planetPositionTheta, 1f, 0f, 0f); - //Close enough approximation, I missed something but seems to off by no more than 30* - //Nobody will look - float phiAngle = (float) ((moons.orbitalPhi) * Math.PI / 180f); + float phiAngle = (float) (moons.orbitalPhi * Math.PI / 180f); double x = -MathHelper.sin(phiAngle) * MathHelper.cos((float) moons.orbitTheta); double y = MathHelper.sin((float) moons.orbitTheta); double rotation = (-Math.PI / 2f + Math.atan2(x, y) - (moons.orbitTheta - Math.PI) * MathHelper.sin(phiAngle)) + Math.PI; - shadowColorMultiplier = new float[]{f1, f2, f3}; - renderPlanet(buffer, moons, moons.getParentOrbitalDistance(), multiplier, rotation, moons.hasAtmosphere(), moons.hasRings, (float) Math.pow(moons.gravitationalMultiplier, 0.4), shadowColorMultiplier, 1); + shadowColorTmp[0] = f1; + shadowColorTmp[1] = f2; + shadowColorTmp[2] = f3; + + renderPlanet(buffer, moons, moons.getParentOrbitalDistance(), multiplier, rotation, moons.hasAtmosphere(), + moons.hasRings, (float) Math.pow(moons.gravitationalMultiplier, 0.4), shadowColorTmp, 1); GL11.glPopMatrix(); } } @@ -635,35 +609,48 @@ else if (DimensionManager.getInstance().isDimensionCreated(mc.world.provider.get GlStateManager.disableBlend(); GlStateManager.enableAlpha(); - GL11.glPopMatrix(); + GL11.glPopMatrix(); // matching the big push before rings/stars/sun + // === Asteroid billboards === GlStateManager.enableTexture2D(); - - mc.renderEngine.bindTexture(asteroid1); GlStateManager.color(1, 1, 1); + GlStateManager.depthMask(false); + GlStateManager.enableBlend(); // additive star style keeps them in "sky" + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE); + + GlStateManager.disableDepth(); // keep? + + bind(asteroid1); GL11.glCallList(this.glSkyList3); GL11.glPushMatrix(); GL11.glRotatef(90, 0.2f, 0.8f, 0); - mc.renderEngine.bindTexture(asteroid2); + bind(asteroid2); GL11.glCallList(this.glSkyList3); GL11.glRotatef(90, 0.2f, 0.8f, 0); - mc.renderEngine.bindTexture(asteroid3); + bind(asteroid3); GL11.glCallList(this.glSkyList3); GL11.glPopMatrix(); - GL11.glDepthMask(true); + GlStateManager.enableDepth(); // keep? - - //RocketEventHandler.onPostWorldRender(partialTicks); - //Fix player/items going transparent + // === PROPER GL STATE RESET === + // Keep depth mask on, but DO NOT clear depth here + GlStateManager.depthMask(true); + GlStateManager.disableBlend(); OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 0, 0); + GlStateManager.shadeModel(GL11.GL_FLAT); + GlStateManager.enableTexture2D(); + GlStateManager.enableAlpha(); + GlStateManager.alphaFunc(GL11.GL_GREATER, 0.1f); + GlStateManager.color(1f, 1f, 1f, 1f); + GlStateManager.enableCull(); } + protected void drawStarAndSubStars(BufferBuilder buffer, StellarBody sun, DimensionProperties properties, int solarOrbitalDistance, float sunSize, Vec3d sunColor, float multiplier) { drawStar(buffer, sun, properties, solarOrbitalDistance, sunSize, sunColor, multiplier); List subStars = sun.getSubStars(); - if (subStars != null && !subStars.isEmpty()) { GL11.glPushMatrix(); float phaseInc = 360f / subStars.size(); @@ -674,12 +661,14 @@ protected void drawStarAndSubStars(BufferBuilder buffer, StellarBody sun, Dimens GL11.glRotatef(subStar.getStarSeparation() * AstronomicalBodyHelper.getBodySizeMultiplier(solarOrbitalDistance), 1, 0, 0); float[] color = subStar.getColor(); - drawStar(buffer, subStar, properties, solarOrbitalDistance, subStar.getSize(), new Vec3d(color[0], color[1], color[2]), multiplier); + drawStar(buffer, subStar, properties, solarOrbitalDistance, subStar.getSize(), + new Vec3d(color[0], color[1], color[2]), multiplier); GL11.glPopMatrix(); } GL11.glPopMatrix(); } } + protected ResourceLocation getTextureForPlanet(DimensionProperties properties) { return properties.getPlanetIcon(); } @@ -692,7 +681,6 @@ protected EnumFacing getRotationAxis(DimensionProperties properties, BlockPos po return EnumFacing.EAST; } - protected void renderPlanet(BufferBuilder buffer, DimensionProperties properties, float planetOrbitalDistance, float alphaMultiplier, double shadowAngle, boolean hasAtmosphere, boolean hasRing, float gravitationalMultiplier, float[] shadowColorMultiplier, float alphaMultiplier2) { renderPlanet2(buffer, properties, 20f * AstronomicalBodyHelper.getBodySizeMultiplier(planetOrbitalDistance) * gravitationalMultiplier, alphaMultiplier, shadowAngle, hasRing, shadowColorMultiplier, alphaMultiplier2); } @@ -704,9 +692,15 @@ protected void renderPlanet2(BufferBuilder buffer, DimensionProperties propertie boolean gasGiant = properties.isGasGiant(); float[] skyColor = properties.skyColor; float[] ringColor = properties.ringColor; - RenderPlanetarySky. renderPlanetPubHelper(buffer, icon, 0, 0, -20, size * 0.2f, alphaMultiplier, shadowAngle, hasAtmosphere, skyColor, ringColor, gasGiant, hasRing, properties.ringAngle, hasDecorators, shadowColorMultiplier, alphaMultiplier2); - } + // Keep external call identical + RenderPlanetarySky.renderPlanetPubHelper( + buffer, icon, 0, 0, -20, + size * 0.2f, alphaMultiplier, shadowAngle, + hasAtmosphere, skyColor, ringColor, gasGiant, hasRing, properties.ringAngle, + hasDecorators, shadowColorMultiplier, alphaMultiplier2 + ); + } protected Vector3F getRotateAxis() { return axis; @@ -718,12 +712,12 @@ public void renderSphere(double x, double y, double z, float radius, int slices, bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); - for(int i = 0; i < slices; i++) { - for(int j = 0; j < stacks; j++) { - double firstLong = 2 * Math.PI * (i / (double)slices); - double secondLong = 2 * Math.PI * ((i + 1) / (double)slices); - double firstLat = Math.PI * (j / (double)stacks) - Math.PI / 2; - double secondLat = Math.PI * ((j + 1) / (double)stacks) - Math.PI / 2; + for (int i = 0; i < slices; i++) { + for (int j = 0; j < stacks; j++) { + double firstLong = 2 * Math.PI * (i / (double) slices); + double secondLong = 2 * Math.PI * ((i + 1) / (double) slices); + double firstLat = Math.PI * (j / (double) stacks) - Math.PI / 2; + double secondLat = Math.PI * ((j + 1) / (double) stacks) - Math.PI / 2; bufferBuilder.pos(x + radius * Math.cos(firstLat) * Math.cos(firstLong), y + radius * Math.sin(firstLat), z + radius * Math.cos(firstLat) * Math.sin(firstLong)).tex(0.0D, 0.0D).endVertex(); bufferBuilder.pos(x + radius * Math.cos(secondLat) * Math.cos(firstLong), y + radius * Math.sin(secondLat), z + radius * Math.cos(secondLat) * Math.sin(firstLong)).tex(1.0D, 0.0D).endVertex(); @@ -731,9 +725,9 @@ public void renderSphere(double x, double y, double z, float radius, int slices, bufferBuilder.pos(x + radius * Math.cos(firstLat) * Math.cos(secondLong), y + radius * Math.sin(firstLat), z + radius * Math.cos(firstLat) * Math.sin(secondLong)).tex(0.0D, 1.0D).endVertex(); } } - tessellator.draw(); } + protected void drawStar(BufferBuilder buffer, StellarBody sun, DimensionProperties properties, int solarOrbitalDistance, float sunSize, Vec3d sunColor, float multiplier) { if (sun != null && sun.isBlackHole()) { GlStateManager.enableAlpha(); @@ -742,86 +736,38 @@ protected void drawStar(BufferBuilder buffer, StellarBody sun, DimensionProperti GL11.glPushMatrix(); GL11.glTranslatef(0, 30, 0); - GL11.glDisable(GL11.GL_BLEND); GlStateManager.depthMask(true); + // Black hole sphere GL11.glPushMatrix(); GL11.glTranslatef(0, 100, 0); f10 = sunSize * 2f * AstronomicalBodyHelper.getBodySizeMultiplier(solarOrbitalDistance); - - mc.renderEngine.bindTexture(TextureResources.locationWhitePng); + bind(TextureResources.locationWhitePng); GlStateManager.disableCull(); - GlStateManager.color(skycolor[0], skycolor[1], skycolor[2]); // Set the color - renderSphere(0, 0, 0, f10, 16, 16); // Draw the sphere + GlStateManager.color(skycolor[0], skycolor[1], skycolor[2]); + renderSphere(0, 0, 0, f10, 16, 16); GlStateManager.enableCull(); GL11.glEnable(GL11.GL_BLEND); GL11.glDepthMask(false); GL11.glPopMatrix(); -/* - GL11.glPushMatrix(); - mc.renderEngine.bindTexture(TextureResources.locationBlackHole); - GL11.glTranslatef(0, 100, 0); - f10 = sunSize * 2f * AstronomicalBodyHelper.getBodySizeMultiplier(solarOrbitalDistance); - //float scale = 1 ; - //GL11.glRotatef(phase, 0, 1, 0); - //GL11.glScaled(scale, scale, scale); - GlStateManager.color((float) 1, (float) .5, (float) .4, 1f); - - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); - //multiplier = 2; - buffer.pos(-f10, 0.0D, -f10).tex(0.0D, 0.0D).endVertex(); - buffer.pos(f10, 0.0D, -f10).tex(1.0D, 0.0D).endVertex(); - buffer.pos(f10, 0.0D, f10).tex(1.0D, 1.0D).endVertex(); - buffer.pos(-f10, 0.0D, f10).tex(0.0D, 1.0D).endVertex(); - Tessellator.getInstance().draw(); - GL11.glPopMatrix(); - - - GL11.glEnable(GL11.GL_BLEND); - GL11.glDepthMask(false); - - GL11.glPushMatrix(); - mc.renderEngine.bindTexture(TextureResources.locationBlackHoleBorder); - GL11.glTranslatef( 0, 99.8F, 0); - //GL11.glRotatef(phase, 0, 1, 0); - float scale = 1.1F; - GL11.glScaled(scale, scale, scale); - GlStateManager.color((float) 1, (float) .5, (float) .4, 1f); - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); - //multiplier = 2; - buffer.pos(-f10, 0.0D, -f10).tex(0.0D, 0.0D).endVertex(); - buffer.pos(f10, 0.0D, -f10).tex(1.0D, 0.0D).endVertex(); - buffer.pos(f10, 0.0D, f10).tex(1.0D, 1.0D).endVertex(); - buffer.pos(-f10, 0.0D, f10).tex(0.0D, 1.0D).endVertex(); - Tessellator.getInstance().draw(); - GL11.glPopMatrix(); -*/ float diskangle = sun.diskAngle; - float m = -xrotangle; - while (m > 360) - m-=360; - while (m < 0) - m+=360; - //Render accretion disk - mc.renderEngine.bindTexture(TextureResources.locationAccretionDiskDense); - GlStateManager.depthMask(false); + while (m > 360) m -= 360; + while (m < 0) m += 360; - float speedMult = 5; + // Dense inner disk - ORIGINAL ROTATIONS + bind(TextureResources.locationAccretionDiskDense); + GlStateManager.depthMask(false); GlStateManager.disableCull(); - GL11.glPushMatrix(); GL11.glTranslatef(0, 100, 0); GL11.glRotatef(90, 0f, 1f, 0f); - //GL11.glRotatef(m, 1f, 0f, 0f); - //GL11.glRotatef(diskangle, 0, 0, 1); - //GL11.glRotatef(90, 1, 0, 0); - GL11.glRotatef((System.currentTimeMillis() % (int) (360 * 360 * speedMult)) / (360f * speedMult), 0, 1, 0); - - GlStateManager.color((float) 1, (float) .7, (float) .55, 1f); + // Original rotation with speedMult = 5 + GL11.glRotatef((System.currentTimeMillis() % (int) (360 * 360 * 5)) / (360f * 5), 0, 1, 0); + GlStateManager.color(1f, .7f, .55f, 1f); buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); f10 = sunSize * 6.5f * AstronomicalBodyHelper.getBodySizeMultiplier(solarOrbitalDistance); buffer.pos(-f10, 0.0D, -f10).tex(0.0D, 0.0D).endVertex(); @@ -831,23 +777,23 @@ protected void drawStar(BufferBuilder buffer, StellarBody sun, DimensionProperti Tessellator.getInstance().draw(); GL11.glPopMatrix(); - - mc.renderEngine.bindTexture(TextureResources.locationAccretionDisk); - + // Outer translucent disks - COMPLEX ORIGINAL LOGIC + bind(TextureResources.locationAccretionDisk); for (int i = 0; i < 3; i++) { - speedMult = ((0) * 1.01f + 1)/0.1F; + float speedMult = 10.0f; // ORIGINAL CALCULATION: ((0) * 1.01f + 1)/0.1F + + // First layer - 100.01f GL11.glPushMatrix(); GL11.glTranslatef(0, 100.01f, 0); + // RESTORE ALL ORIGINAL ROTATIONS: GL11.glRotatef((float) currentplanetphi, 0f, 1f, 0f); GL11.glRotatef(m, 1f, 0f, 0f); GL11.glRotatef(diskangle, 0, 0, 1); GL11.glRotatef((System.currentTimeMillis() % (int) (speedMult * 36000)) / (100f * speedMult), 0, 1, 0); - - // make every disks angle slightly different - GL11.glRotatef(120*i, 0, 1, 0); + GL11.glRotatef(120 * i, 0, 1, 0); GL11.glRotatef(0.5f, 1, 0, 0); - GlStateManager.color((float) 1, (float) .5, (float) .4, 0.3f); + GlStateManager.color(1f, .5f, .4f, 0.3f); buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); f10 = sunSize * 40f * AstronomicalBodyHelper.getBodySizeMultiplier(solarOrbitalDistance); buffer.pos(-f10, 0.0D, -f10).tex(0.0D, 0.0D).endVertex(); @@ -857,22 +803,19 @@ protected void drawStar(BufferBuilder buffer, StellarBody sun, DimensionProperti Tessellator.getInstance().draw(); GL11.glPopMatrix(); - + // Second layer - 100f GL11.glPushMatrix(); - GL11.glTranslatef(0, 100f, 0); GL11.glRotatef((float) currentplanetphi, 0f, 1f, 0f); GL11.glRotatef(m, 1f, 0f, 0f); GL11.glRotatef(diskangle, 0, 0, 1); GL11.glRotatef((System.currentTimeMillis() % (int) (speedMult * 360 * 50)) / (50f * speedMult), 0, 1, 0); - // make every disks angle slightly different - GL11.glRotatef(120*i, 0, 1, 0); + GL11.glRotatef(120 * i, 0, 1, 0); GL11.glRotatef(0.5f, 1, 0, 0); - GlStateManager.color((float) 0.8, (float) .7, (float) .4, 0.3f); + GlStateManager.color(0.8f, .7f, .4f, 0.3f); buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); f10 = sunSize * 30f * AstronomicalBodyHelper.getBodySizeMultiplier(solarOrbitalDistance); - //multiplier = 2; buffer.pos(-f10, 0.0D, -f10).tex(0.0D, 0.0D).endVertex(); buffer.pos(f10, 0.0D, -f10).tex(1.0D, 0.0D).endVertex(); buffer.pos(f10, 0.0D, f10).tex(1.0D, 1.0D).endVertex(); @@ -880,47 +823,41 @@ protected void drawStar(BufferBuilder buffer, StellarBody sun, DimensionProperti Tessellator.getInstance().draw(); GL11.glPopMatrix(); + // Third layer - 99.99f GL11.glPushMatrix(); - GL11.glTranslatef(0, 99.99f, 0); GL11.glRotatef((float) currentplanetphi, 0f, 1f, 0f); GL11.glRotatef(m, 1f, 0f, 0f); GL11.glRotatef(diskangle, 0, 0, 1); GL11.glRotatef((System.currentTimeMillis() % (int) (speedMult * 360 * 25)) / (25f * speedMult), 0, 1, 0); - // make every disks angle slightly different - GL11.glRotatef(120*i, 0, 1, 0); + GL11.glRotatef(120 * i, 0, 1, 0); GL11.glRotatef(0.5f, 1, 0, 0); - GlStateManager.color((float) 0.2, (float) .4, (float) 1, 0.3f); + GlStateManager.color(0.2f, .4f, 1f, 0.3f); buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); f10 = sunSize * 15f * AstronomicalBodyHelper.getBodySizeMultiplier(solarOrbitalDistance); - //multiplier = 2; buffer.pos(-f10, 0.0D, -f10).tex(0.0D, 0.0D).endVertex(); buffer.pos(f10, 0.0D, -f10).tex(1.0D, 0.0D).endVertex(); buffer.pos(f10, 0.0D, f10).tex(1.0D, 1.0D).endVertex(); buffer.pos(-f10, 0.0D, f10).tex(0.0D, 1.0D).endVertex(); Tessellator.getInstance().draw(); GL11.glPopMatrix(); - - - - } + // ORIGINAL DEPTH MANAGEMENT GlStateManager.depthMask(true); GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT); GlStateManager.depthMask(false); + GL11.glPopMatrix(); GlStateManager.enableCull(); - - + //GlStateManager.depthMask(true); // keep ? } else { - mc.renderEngine.bindTexture(TextureResources.locationSunPng); - //Set sun color and distance + // Regular star (quad) path + bind(TextureResources.locationSunPng); GlStateManager.color((float) sunColor.x, (float) sunColor.y, (float) sunColor.z, Math.min((multiplier) * 2f, 1f)); buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); float f10 = sunSize * 15f * AstronomicalBodyHelper.getBodySizeMultiplier(solarOrbitalDistance); - //multiplier = 2; buffer.pos(-f10, 120.0D, -f10).tex(0.0D, 0.0D).endVertex(); buffer.pos(f10, 120.0D, -f10).tex(1.0D, 0.0D).endVertex(); buffer.pos(f10, 120.0D, f10).tex(1.0D, 1.0D).endVertex(); From 3c1cf60e56b6e58805be3d4eb66fd99419d13d17 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 24 Oct 2025 16:02:42 +0200 Subject: [PATCH 052/274] Fixing rocketmonitor tickspam Implement neighbor change handling for redstone power updates. Add neighborChanged method for block updates. --- .../block/BlockTileNeighborUpdate.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockTileNeighborUpdate.java b/src/main/java/zmaster587/advancedRocketry/block/BlockTileNeighborUpdate.java index a39b6b5c3..4ee00b0d3 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockTileNeighborUpdate.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockTileNeighborUpdate.java @@ -15,6 +15,21 @@ public BlockTileNeighborUpdate(Class tileClass, int guiId) super(tileClass, guiId); } + // redstone power uses neighbor change to update redstone power + @Override + public void neighborChanged(net.minecraft.block.state.IBlockState state, + net.minecraft.world.World world, + net.minecraft.util.math.BlockPos pos, + net.minecraft.block.Block blockIn, + net.minecraft.util.math.BlockPos fromPos) { + super.neighborChanged(state, world, pos, blockIn, fromPos); + TileEntity te = world.getTileEntity(pos); + if (te instanceof zmaster587.libVulpes.util.IAdjBlockUpdate) { + ((zmaster587.libVulpes.util.IAdjBlockUpdate) te).onAdjacentBlockUpdated(); + } + } + + @Override public void onNeighborChange(IBlockAccess world, BlockPos pos, BlockPos neighbor) { super.onNeighborChange(world, pos, neighbor); From 788a9f820e6a22023a1be94f7eabd8c10f3962fd Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 24 Oct 2025 16:08:21 +0200 Subject: [PATCH 053/274] Enhance TileRocketMonitoringStation functionality Added redstone power caching on neigbourchange, no more polling for redstonechanges 20 times per second. Improved event handling for rocket launch preparation. Updated fuel and height snapshots with tick throttles for performance. UX: subscribe to rocketevents to make GUI feel alive. Launchbutton will listen for Rocketevents like "prelaunch, launch, reached orbit, landed" --- .../TileRocketMonitoringStation.java | 389 +++++++++++++----- 1 file changed, 285 insertions(+), 104 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java index 9ab6b6334..07bd0793b 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java @@ -5,21 +5,29 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.play.server.SPacketUpdateTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.ITickable; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.eventhandler.EventPriority; + import zmaster587.advancedRocketry.api.ARConfiguration; import zmaster587.advancedRocketry.api.EntityRocketBase; import zmaster587.advancedRocketry.api.IInfrastructure; import zmaster587.advancedRocketry.api.IMission; +import zmaster587.advancedRocketry.api.RocketEvent; import zmaster587.advancedRocketry.api.fuel.FuelRegistry; import zmaster587.advancedRocketry.api.satellite.SatelliteBase; import zmaster587.advancedRocketry.dimension.DimensionManager; import zmaster587.advancedRocketry.entity.EntityRocket; import zmaster587.advancedRocketry.inventory.TextureResources; + import zmaster587.libVulpes.LibVulpes; import zmaster587.libVulpes.client.util.IndicatorBarImage; import zmaster587.libVulpes.client.util.ProgressBarImage; @@ -31,7 +39,6 @@ import zmaster587.libVulpes.tile.IComparatorOverride; import zmaster587.libVulpes.util.IAdjBlockUpdate; import zmaster587.libVulpes.util.INetworkMachine; -import zmaster587.libVulpes.util.ZUtils.RedstoneState; import javax.annotation.Nonnull; import java.util.LinkedList; @@ -39,28 +46,80 @@ public class TileRocketMonitoringStation extends TileEntity implements IModularInventory, ITickable, IAdjBlockUpdate, IInfrastructure, ILinkableTile, INetworkMachine, IButtonInventory, IProgressBar, IComparatorOverride { + // ==== TUNABLE TICK THROTTLES ==== + // 2–3 ticks for height/vel feels live; 5–10 ticks is fine for fuel. + private static final int T_HEIGHTVEL_TICKS = 3; // ~6.7 Hz + private static final int T_FUEL_TICKS = 10; // ~2 Hz + private static final int T_COMPARATOR_TICKS = 3; // match height cadence + // ================================= + EntityRocketBase linkedRocket; IMission mission; ModuleText missionText; - //RedstoneState state; - //ModuleRedstoneOutputButton redstoneControl; + + // Cached redstone state from neighbor callbacks (don’t poll every tick) + private boolean isPoweredCached = false, initPower = false; + + // Throttles + private int heightVelTick = 0, fuelTick = 0, comparatorTick = 0; + + // Comparator cache (change-only) + private int lastComparator = -1; + + // Server snapshots (served via ModuleProgress polling) + private int snapHeight = 0, snapVel = 0; + private int snapFuel = 0, snapFuelCap = 0; // active fuel (id=2 semantics) + private int snapOx = 0, snapOxCap = 0; // oxidizer (id=6 semantics) + + // GUI cached fields (client) boolean was_powered = false; int rocketHeight; int velocity; int fuelLevel, maxFuelLevel; int oxidizerFuelLevel; + // === GUI event status (server -> client via TE update) === + // 0=idle, 1=prelaunch, 2=launching, 3=orbit, 4=landed, 5=aborted + private int uiStatus = 0; + private transient ModuleText launchStatus; // client-only widget + private transient int lastUiStatusShown = -1; // client change-detect + + // Event bus registration flag + private boolean registeredBus = false; + public TileRocketMonitoringStation() { mission = null; missionText = new ModuleText(20, 90, LibVulpes.proxy.getLocalizedString("msg.monitoringStation.missionProgressNA"), 0x2b2b2b); - //redstoneControl = new ModuleRedstoneOutputButton(174, 4, -1, "", this); - //state = RedstoneState.ON; } + // --- Lifecycle / bus registration --- + + @Override + public void onLoad() { + if (!world.isRemote && !registeredBus) { + MinecraftForge.EVENT_BUS.register(this); + registeredBus = true; + } + if (!world.isRemote && !initPower) { + boolean now = world.isBlockIndirectlyGettingPowered(pos) > 0; + isPoweredCached = now; + was_powered = now; // <- important: no phantom rising edge later + initPower = true; + } + } + + @Override public void invalidate() { super.invalidate(); + // Unregister bus + if (!world.isRemote && registeredBus) { + MinecraftForge.EVENT_BUS.unregister(this); + registeredBus = false; + } + + // Preserve original unlink-on-destroy semantics if (linkedRocket != null) { linkedRocket.unlinkInfrastructure(this); unlinkRocket(); @@ -71,49 +130,178 @@ public void invalidate() { } } - public boolean getEquivalentPower() { - //if (state == RedstoneState.OFF) - // return false; + @Override + public void onChunkUnload() { + super.onChunkUnload(); + // IMPORTANT: do NOT unlink here — preserve original behavior: + // this tile remains linked across unload/reload and during flight/space. + if (!world.isRemote && registeredBus) { + MinecraftForge.EVENT_BUS.unregister(this); + registeredBus = false; + } + } - boolean state2 = world.isBlockIndirectlyGettingPowered(pos) > 0; + // --- Redstone power caching via block neighbor callbacks --- - //if (state == RedstoneState.INVERTED) - // state2 = !state2; - return state2; + @Deprecated + public boolean getEquivalentPower() { + return world.isBlockIndirectlyGettingPowered(pos) > 0; } @Override public void onAdjacentBlockUpdated() { + if (world == null || world.isRemote) return; + + boolean now = world.isBlockIndirectlyGettingPowered(pos) > 0; + boolean rising = now && !isPoweredCached; + + // Update cache first so it stays correct even with no rocket linked + isPoweredCached = now; + was_powered = now; // optional if you surface this elsewhere + if (rising && linkedRocket != null) { + linkedRocket.prepareLaunch(); // only on true 0->1 edge + markDirty(); + } } + + + // --- IInfrastructure --- + @Override public int getMaxLinkDistance() { return 300000; } + @Override + public boolean disconnectOnLiftOff() { + return false; + } + + @Override + public boolean linkRocket(EntityRocketBase rocket) { + this.linkedRocket = rocket; + this.lastComparator = -1; // ensure first comparator notify fires if needed + return true; + } + + @Override + public void unlinkRocket() { + linkedRocket = null; + + // Reset snapshots so viewers don't see stale values + snapHeight = 0; snapVel = 0; + snapFuel = 0; snapFuelCap = 0; + snapOx = 0; snapOxCap = 0; + + // Server-only: force comparator to 0 and notify once + if (world != null && !world.isRemote) { + lastComparator = 0; + world.updateComparatorOutputLevel(pos, world.getBlockState(pos).getBlock()); + } + } + + // --- Ticking --- + @Override public void update() { - if (!world.isRemote) { - if (linkedRocket instanceof EntityRocket) { - if ((int) (15 * ((EntityRocket) linkedRocket).getRelativeHeightFraction()) != (int) (15 * ((EntityRocket) linkedRocket).getPreviousRelativeHeightFraction())) { - markDirty(); - } - if (getEquivalentPower() && linkedRocket != null) { - if (!was_powered) { - System.out.println("prepare launch (redstone powered)"); - linkedRocket.prepareLaunch(); - //System.out.println("launching..."); - was_powered = true; + if (world.isRemote) return; + + // One-time prime (in case no neighbor event has fired yet) + if (!initPower) { + isPoweredCached = world.isBlockIndirectlyGettingPowered(pos) > 0; + initPower = true; + } + + // Runs infrequently to recover from any missed neighbor events. + if ( (world.getTotalWorldTime() & 100) == 0 ) { // every 100 ticks + boolean polled = world.isBlockIndirectlyGettingPowered(pos) > 0; + isPoweredCached = polled; // DO NOT trigger launch here; just reconcile the cache + } + // Idle fast-exit + if (linkedRocket == null) { return; } + + // ---- height + velocity snapshots, every T_HEIGHTVEL_TICKS ---- + if (++heightVelTick >= Math.max(1, T_HEIGHTVEL_TICKS)) { + heightVelTick = 0; + + snapHeight = (int) linkedRocket.posY; + snapVel = (int) (linkedRocket.motionY * 100); + + // comparator (0–15) change-only, every T_COMPARATOR_TICKS + if (++comparatorTick >= Math.max(1, T_COMPARATOR_TICKS)) { + comparatorTick = 0; + if (linkedRocket instanceof EntityRocket) { + int comp = (int)(15 * ((EntityRocket) linkedRocket).getRelativeHeightFraction()); + if (comp != lastComparator) { + lastComparator = comp; + world.updateComparatorOutputLevel(pos, world.getBlockState(pos).getBlock()); } } } - if(!getEquivalentPower()){ - was_powered = false; // - } + } + + // ---- fuel snapshots, every T_FUEL_TICKS ---- + if (++fuelTick >= Math.max(1, T_FUEL_TICKS)) { + fuelTick = 0; + + // Original semantics: + // - id=2 shows the *active* rocket fuel + // - id=6 shows oxidizer independently + final FuelRegistry.FuelType active = linkedRocket.getRocketFuelType(); + snapFuel = linkedRocket.getFuelAmount(active); + snapFuelCap = linkedRocket.getFuelCapacity(active); + + snapOx = linkedRocket.getFuelAmount(FuelRegistry.FuelType.LIQUID_OXIDIZER); + snapOxCap = linkedRocket.getFuelCapacity(FuelRegistry.FuelType.LIQUID_OXIDIZER); + } + } + + // --- Forge Rocket Events -> authorititative UI status (server -> client via TE update) --- + + @SubscribeEvent(priority = EventPriority.LOWEST) // see final canceled state + public void onPreLaunch(RocketEvent.RocketPreLaunchEvent e) { + if (world == null || world.isRemote) return; + if (linkedRocket != null && e.getEntity() == linkedRocket) { + // At LOWEST, if someone canceled it, isCanceled() will be true now. + uiStatus = e.isCanceled() ? 5 : 1; // aborted or prelaunch + markDirty(); + world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3); } } + @SubscribeEvent + public void onLaunch(RocketEvent.RocketLaunchEvent e) { + if (world == null || world.isRemote) return; + if (linkedRocket != null && e.getEntity() == linkedRocket) { + uiStatus = 2; // launching! + markDirty(); + world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3); + } + } + + @SubscribeEvent + public void onOrbit(RocketEvent.RocketReachesOrbitEvent e) { + if (world == null || world.isRemote) return; + if (linkedRocket != null && e.getEntity() == linkedRocket) { + uiStatus = 3; // reached orbit + markDirty(); + world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3); + } + } + + @SubscribeEvent + public void onLanded(RocketEvent.RocketLandedEvent e) { + if (world == null || world.isRemote) return; + if (linkedRocket != null && e.getEntity() == linkedRocket) { + uiStatus = 4; // landed + markDirty(); + world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3); + } + } + + // --- Linker flow --- @Override public boolean onLinkStart(@Nonnull ItemStack item, TileEntity entity, EntityPlayer player, World world) { @@ -128,7 +316,10 @@ public boolean onLinkStart(@Nonnull ItemStack item, TileEntity entity, EntityPla } if (player.world.isRemote) - Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentTranslation("%s %s", new TextComponentTranslation("msg.monitoringStation.link"), ": " + getPos().getX() + " " + getPos().getY() + " " + getPos().getZ())); + Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage( + new TextComponentTranslation("%s %s", + new TextComponentTranslation("msg.monitoringStation.link"), + ": " + getPos().getX() + " " + getPos().getY() + " " + getPos().getZ())); return true; } @@ -139,69 +330,62 @@ public boolean onLinkComplete(@Nonnull ItemStack item, TileEntity entity, Entity return false; } - @Override - public void unlinkRocket() { - linkedRocket = null; - } + // --- NBT / TE sync --- @Override - public boolean disconnectOnLiftOff() { - return false; + public NBTTagCompound getUpdateTag() { + return writeToNBT(new NBTTagCompound()); } @Override - public boolean linkRocket(EntityRocketBase rocket) { - this.linkedRocket = rocket; - return true; + public SPacketUpdateTileEntity getUpdatePacket() { + NBTTagCompound tag = new NBTTagCompound(); + writeToNBT(tag); + return new SPacketUpdateTileEntity(pos, 0, tag); } @Override - public NBTTagCompound getUpdateTag() { - return writeToNBT(new NBTTagCompound()); + public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) { + readFromNBT(pkt.getNbtCompound()); } @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); - - //state = RedstoneState.values()[nbt.getByte("redstoneState")]; - //redstoneControl.setRedstoneState(state); was_powered = nbt.getBoolean("was_powered"); if (nbt.hasKey("missionID")) { long id = nbt.getLong("missionID"); - int dimid = nbt.getInteger("missionDimId"); - SatelliteBase sat = DimensionManager.getInstance().getSatellite(id); - - if (sat instanceof IMission) + if (sat instanceof IMission) { mission = (IMission) sat; + } } + uiStatus = nbt.getInteger("uiStatus"); } @Override public NBTTagCompound writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); - //nbt.setByte("redstoneState", (byte) state.ordinal()); nbt.setBoolean("was_powered", was_powered); if (mission != null) { nbt.setLong("missionID", mission.getMissionId()); nbt.setInteger("missionDimId", mission.getOriginatingDimension()); } + nbt.setInteger("uiStatus", uiStatus); return nbt; } + // --- LibVulpes network bridge --- + @Override public void writeDataToNetwork(ByteBuf out, byte id) { if (id == 1) out.writeLong(mission == null ? -1 : mission.getMissionId()); - //else if (id == 2) - //out.writeByte(state.ordinal()); } @Override - public void readDataFromNetwork(ByteBuf in, byte packetId, - NBTTagCompound nbt) { + public void readDataFromNetwork(ByteBuf in, byte packetId, NBTTagCompound nbt) { if (packetId == 1) { nbt.setLong("id", in.readLong()); } else if (packetId == 2) { @@ -210,8 +394,7 @@ public void readDataFromNetwork(ByteBuf in, byte packetId, } @Override - public void useNetworkData(EntityPlayer player, Side side, byte id, - NBTTagCompound nbt) { + public void useNetworkData(EntityPlayer player, Side side, byte id, NBTTagCompound nbt) { if (id == 1) { long idNum = nbt.getLong("id"); if (idNum == -1) { @@ -219,15 +402,13 @@ public void useNetworkData(EntityPlayer player, Side side, byte id, setMissionText(); } else { SatelliteBase base = DimensionManager.getInstance().getSatellite(idNum); - if (base instanceof IMission) { mission = (IMission) base; setMissionText(); } } } else if (id == 2) { - //state = RedstoneState.values()[nbt.getByte("state")]; - //redstoneControl.setRedstoneState(state); + // redstone control path was commented in original; preserved } if (id == 100) { if (linkedRocket != null) @@ -235,20 +416,26 @@ public void useNetworkData(EntityPlayer player, Side side, byte id, } } + // --- GUI / Modules --- + @Override public List getModules(int ID, EntityPlayer player) { - LinkedList modules = new LinkedList<>(); modules.add(new ModuleButton(20, 40, 0, "Launch!", this, zmaster587.libVulpes.inventory.TextureResources.buttonBuild)); + + // Status line for rocket events (client only) + if (world.isRemote) { + launchStatus = new ModuleText(10, 30, "", 0xFFFFFF22); + modules.add(launchStatus); + } + modules.add(new ModuleProgress(98, 4, 0, new IndicatorBarImage(2, 7, 12, 81, 17, 0, 6, 6, 1, 0, EnumFacing.UP, TextureResources.rocketHud), this)); modules.add(new ModuleProgress(120, 14, 1, new IndicatorBarImage(2, 95, 12, 71, 17, 0, 6, 6, 1, 0, EnumFacing.UP, TextureResources.rocketHud), this)); modules.add(new ModuleProgress(142, 14, 2, new ProgressBarImage(2, 173, 12, 71, 17, 6, 3, 69, 1, 1, EnumFacing.UP, TextureResources.rocketHud), this)); modules.add(new ModuleProgress(148, 14, 6, new ProgressBarImage(2, 173, 12, 71, 17, 75, 3, 69, 1, 1, EnumFacing.UP, TextureResources.rocketHud), this)); - //modules.add(redstoneControl); setMissionText(); - modules.add(missionText); modules.add(new ModuleProgress(30, 110, 3, TextureResources.progressToMission, this)); modules.add(new ModuleProgress(30, 120, 4, TextureResources.workMission, this)); @@ -268,19 +455,23 @@ private void setMissionText() { int minutes = (time / 60) % 60; int hours = time / 3600; - missionText.setText(((SatelliteBase) mission).getName() + LibVulpes.proxy.getLocalizedString("msg.monitoringStation.progress") + String.format("\n%02dhr:%02dm:%02ds", hours, minutes, seconds)); - } else + String name = (mission instanceof SatelliteBase) + ? ((SatelliteBase) mission).getName() + : LibVulpes.proxy.getLocalizedString("msg.monitoringStation.mission"); + + missionText.setText(name + LibVulpes.proxy.getLocalizedString("msg.monitoringStation.progress") + + String.format("\n%02dhr:%02dm:%02ds", hours, minutes, seconds)); + } else { missionText.setText(LibVulpes.proxy.getLocalizedString("msg.monitoringStation.missionProgressNA")); + } } @Override public void onInventoryButtonPressed(int buttonId) { if (buttonId != -1) PacketHandler.sendToServer(new PacketMachine(this, (byte) (buttonId + 100))); - else { - //state = redstoneControl.getState(); + else PacketHandler.sendToServer(new PacketMachine(this, (byte) 2)); - } } @Override @@ -306,7 +497,22 @@ public float getNormallizedProgress(int id) { return (float) Math.min(Math.max(3f * (mission.getProgress(this.world) - 0.666f), 0f), 1f); } - //keep text updated + // Client: reflect server-driven rocket event status in the GUI text + if (world.isRemote && launchStatus != null && uiStatus != lastUiStatusShown) { + lastUiStatusShown = uiStatus; + String msg; + switch (uiStatus) { + case 1: msg = LibVulpes.proxy.getLocalizedString("msg.monitoringStation.prelaunch"); break; // "Pre-launch checks…" + case 2: msg = LibVulpes.proxy.getLocalizedString("msg.monitoringStation.launching"); break; // "Launching!" + case 3: msg = LibVulpes.proxy.getLocalizedString("msg.monitoringStation.orbit"); break; // "Reached orbit" + case 4: msg = LibVulpes.proxy.getLocalizedString("msg.monitoringStation.landed"); break; // "Landed" + case 5: msg = LibVulpes.proxy.getLocalizedString("msg.monitoringStation.aborted"); break; // "Launch aborted" + default: msg = ""; break; + } + launchStatus.setText(msg); + } + + // Keep mission text updated on client if (world.isRemote && mission != null) setMissionText(); @@ -327,31 +533,20 @@ else if (id == 6) @Override public int getProgress(int id) { - //Try to keep client synced with server, this also allows us to put the monitor on a different world altogether - if (world.isRemote) - if (mission != null && id == 0) - return getTotalProgress(id); - else if (id == 0) - return rocketHeight; - else if (id == 1) - return velocity; - else if (id == 2) - return fuelLevel; - else if (id == 6) - return oxidizerFuelLevel; - - if (linkedRocket == null) + // Client: use client-side cached fields (preserve original mission/height quirk) + if (world.isRemote) { + if (mission != null && id == 0) return getTotalProgress(id); // original oddity preserved + if (id == 0) return rocketHeight; + if (id == 1) return velocity; + if (id == 2) return fuelLevel; + if (id == 6) return oxidizerFuelLevel; return 0; - - if (id == 0) - return (int) linkedRocket.posY; - else if (id == 1) - return (int) (linkedRocket.motionY * 100); - else if (id == 2) - return linkedRocket.getFuelAmount(linkedRocket.getRocketFuelType()); - else if (id == 6) - return linkedRocket.getFuelAmount(FuelRegistry.FuelType.LIQUID_OXIDIZER); - + } + // Server: return snapshots only (cheap) + if (id == 0) return snapHeight; + if (id == 1) return snapVel; + if (id == 2) return snapFuel; // active fuel amount + if (id == 6) return snapOx; // oxidizer amount return 0; } @@ -362,23 +557,9 @@ public int getTotalProgress(int id) { else if (id == 1) return 1000; else if (id == 2) - if (world.isRemote) - return maxFuelLevel; - else if (linkedRocket == null) - return 0; - else - return linkedRocket.getFuelCapacity(linkedRocket.getRocketFuelType()); - + return world.isRemote ? maxFuelLevel : snapFuelCap; else if (id == 6) - if (world.isRemote) - return maxFuelLevel; - else if (linkedRocket == null) - return 0; - else - return linkedRocket.getFuelCapacity(FuelRegistry.FuelType.LIQUID_OXIDIZER); - - - + return world.isRemote ? maxFuelLevel : snapOxCap; return 1; } From 1203b91ca67c50adb7ff501d0933a0d720c890c4 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 24 Oct 2025 16:10:22 +0200 Subject: [PATCH 054/274] Add monitoring station status messages Added monitoring station messages for prelaunch, launching, orbit, landed, and aborted states. --- src/main/resources/assets/advancedrocketry/lang/en_US.lang | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/resources/assets/advancedrocketry/lang/en_US.lang b/src/main/resources/assets/advancedrocketry/lang/en_US.lang index 94ca254f1..865ad4a84 100644 --- a/src/main/resources/assets/advancedrocketry/lang/en_US.lang +++ b/src/main/resources/assets/advancedrocketry/lang/en_US.lang @@ -314,6 +314,11 @@ msg.fuelingStation.link=You program the linker with the fueling station at msg.monitoringStation.missionProgressNA=Mission Progress: N/A msg.monitoringStation.link=You program the linker with the monitoring station at msg.monitoringStation.progress= Progress: +msg.monitoringStation.prelaunch=Initiating... +msg.monitoringStation.launching=Launching! +msg.monitoringStation.orbit=Reached orbit +msg.monitoringStation.landed=Landed +msg.monitoringStation.aborted=Aborted msg.guidanceComputerHatch.loadingState=Loading State: msg.guidanceComputerHatch.ejectonlanding=Auto Eject Upon Landing msg.guidanceComputerHatch.ejectonsatlanding=Allow Ejection of Satellite Chips From e149f8bdaa3e14ad6616e6dd01be8c8137a89a59 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 27 Oct 2025 15:59:59 +0100 Subject: [PATCH 055/274] Implement fuel rate recomputation in EntityRocket Added a method to recompute fuel consumption rates based on fuel types and their capacities. HardFix 0 burnrate --- .../advancedRocketry/entity/EntityRocket.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java b/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java index 96a725916..e5566c6d7 100644 --- a/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java +++ b/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java @@ -177,6 +177,32 @@ public EntityRocket(World world, StorageChunk storage, StatsRocket stats, double landingPadDisplayText.setColor(0x00ff00); } + private void recomputeFuelRates() { + for (FuelRegistry.FuelType t : new FuelRegistry.FuelType[]{ + FuelRegistry.FuelType.LIQUID_MONOPROPELLANT, + FuelRegistry.FuelType.LIQUID_BIPROPELLANT, + FuelRegistry.FuelType.LIQUID_OXIDIZER, + FuelRegistry.FuelType.NUCLEAR_WORKING_FLUID}) { + + if (getFuelCapacity(t) <= 0) continue; + + String name = (t == FuelRegistry.FuelType.LIQUID_OXIDIZER) ? stats.getOxidizerFluid() + : (t == FuelRegistry.FuelType.NUCLEAR_WORKING_FLUID) ? stats.getWorkingFluid() + : stats.getFuelFluid(); + if ("null".equals(name)) continue; + + Fluid f = FluidRegistry.getFluid(name); + if (f == null) continue; + + int base = stats.getBaseFuelRate(t); + if (base <= 0) continue; + + int rate = (int)(FuelRegistry.instance.getMultiplier(t, f) * base); + if (rate > 0) setFuelConsumptionRate(t, rate); + } + } + + /** * @param blockState the blockstate to damage * @return the blockstate that the input blockstate turns into @@ -1747,6 +1773,7 @@ public void explode() { public void recalculateStats(){ this.storage.recalculateStats(this.stats); + recomputeFuelRates(); } /** @@ -1764,6 +1791,7 @@ public void launch() { boolean allowLaunch = false; this.storage.recalculateStats(this.stats); + recalculateStats(); NBTTagCompound nbtdata = new NBTTagCompound(); writeToNBT(nbtdata); @@ -2039,6 +2067,7 @@ protected void readEntityFromNBT(NBTTagCompound nbt) { } spacePosition.readFromNBT(nbt); + recomputeFuelRates(); } protected void writeNetworkableNBT(NBTTagCompound nbt) { From 6177518c34d9aca8687297fd529e37f35d23eed2 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 27 Oct 2025 16:06:47 +0100 Subject: [PATCH 056/274] Refactor BlockTileRedstoneEmitter methods Refactor methods for clarity and efficiency, ensuring server-only updates to block state. Reducing redstone spam --- .../block/BlockTileRedstoneEmitter.java | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockTileRedstoneEmitter.java b/src/main/java/zmaster587/advancedRocketry/block/BlockTileRedstoneEmitter.java index fefcbe482..b59042f81 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockTileRedstoneEmitter.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockTileRedstoneEmitter.java @@ -8,17 +8,21 @@ import net.minecraft.world.World; import zmaster587.libVulpes.block.BlockTile; +// Fueling Station block public class BlockTileRedstoneEmitter extends BlockTile { - public BlockTileRedstoneEmitter(Class tileClass, - int guiId) { + public BlockTileRedstoneEmitter(Class tileClass, int guiId) { super(tileClass, guiId); } @Override - public int getWeakPower(IBlockState blockState, IBlockAccess blockAccess, - BlockPos pos, EnumFacing side) { - return blockState.getValue(STATE) ? 15 : 0; + public int getWeakPower(IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing side) { + return state.getValue(STATE) ? 15 : 0; + } + + @Override + public int getStrongPower(IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing side) { + return getWeakPower(state, world, pos, side); } @Override @@ -26,11 +30,23 @@ public boolean canProvidePower(IBlockState state) { return true; } - public void setRedstoneState(World world, IBlockState state, BlockPos pos, boolean newState) { - if (world.getBlockState(pos).getBlock() != this) - return; + public void setRedstoneState(World world, IBlockState _ignored, BlockPos pos, boolean newState) { + // Server-only to avoid client mutations + if (world.isRemote) return; + + // skip if chunk isn't loaded + if (!world.isBlockLoaded(pos)) return; + + // Read the current state from the world to avoid acting on a stale IBlockState + IBlockState curState = world.getBlockState(pos); + if (curState.getBlock() != this) return; + + boolean current = curState.getValue(STATE); + if (current == newState) return; // no-op if unchanged + + IBlockState updated = curState.withProperty(STATE, newState); - world.setBlockState(pos, state.withProperty(STATE, newState)); - world.notifyBlockUpdate(pos, state, state, 3); + // 3 = neighbors notified (1) + clients updated (2) + world.setBlockState(pos, updated, 3); } } From 2c4e13642554be69d391978fc1c03e7a4b7a9f12 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 27 Oct 2025 19:05:02 +0100 Subject: [PATCH 057/274] Enhance fluid management and redstone control in TileFuelingStation Improve fluid handling and redstone state management. Removed most of per-tick-behavior, lookups and redstonespam. Fixed BUG that allowed u to fill hydrogen/oxygen into monoproptanks, and getting 0 burnrate forever on ur rocket Huge Permormance update. --- .../infrastructure/TileFuelingStation.java | 503 ++++++++++++++---- 1 file changed, 394 insertions(+), 109 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java index 70a77e210..0f17f956c 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java @@ -17,6 +17,8 @@ import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidTankProperties; import net.minecraftforge.fml.relauncher.Side; import zmaster587.advancedRocketry.api.*; import zmaster587.advancedRocketry.api.fuel.FuelRegistry; @@ -41,13 +43,28 @@ import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.List; +import java.util.Objects; public class TileFuelingStation extends TileInventoriedRFConsumerTank implements IModularInventory, IMultiblock, IInfrastructure, ILinkableTile, INetworkMachine, IButtonInventory { + private EntityRocketBase linkedRocket; private HashedBlockPosition masterBlock; private ModuleRedstoneOutputButton redstoneControl; private RedstoneState state; + // Tune cadence: Ticks between operations + private static final int OP_THROTTLE_TICKS = 5; + + // Stop polling after full for current link/fluid + private boolean fuelingActive = false; + + // Cache last emitted redstone to avoid duplicate updates + private Boolean lastRs = null; + + // Small perf win: cache resolved fluids from rocket stats + private String lastFuelStr = null, lastOxStr = null, lastWorkStr = null; + private Fluid cachedFuelFluid = null, cachedOxFluid = null, cachedWorkFluid = null; + public TileFuelingStation() { super(1000, 3, 5000); masterBlock = new HashedBlockPosition(0, -1, 0); @@ -55,68 +72,254 @@ public TileFuelingStation() { state = RedstoneState.ON; } - @Override - public int getMaxLinkDistance() { - return 10; + private void syncTE() { + markDirty(); + net.minecraft.block.state.IBlockState s = world.getBlockState(pos); + world.notifyBlockUpdate(pos, s, s, 3); } + @Override + public int getMaxLinkDistance() { return 10; } + + // ---- redstone emission with duplicate suppression ---- private void setRedstoneState(boolean condition) { - if (state == RedstoneState.INVERTED) - condition = !condition; - else if (state == RedstoneState.OFF) - condition = false; - ((BlockTileRedstoneEmitter) AdvancedRocketryBlocks.blockFuelingStation).setRedstoneState(world, world.getBlockState(pos), pos, condition); + if (world == null || world.isRemote) return; + + if (state == RedstoneState.INVERTED) condition = !condition; + else if (state == RedstoneState.OFF) condition = false; + if (lastRs != null && lastRs == condition) return; + lastRs = condition; + + net.minecraft.block.state.IBlockState s = world.getBlockState(pos); + if (AdvancedRocketryBlocks.blockFuelingStation instanceof BlockTileRedstoneEmitter) { + ((BlockTileRedstoneEmitter) AdvancedRocketryBlocks.blockFuelingStation) + .setRedstoneState(world, s, pos, condition); + } + markDirty(); + } + + + // ---- small cache to avoid repeated FluidRegistry lookups per tick ---- + private void refreshFluidCachesIfNeeded() { + if (linkedRocket == null || linkedRocket.stats == null) return; + String f = linkedRocket.stats.getFuelFluid(); + String o = linkedRocket.stats.getOxidizerFluid(); + String w = linkedRocket.stats.getWorkingFluid(); + + if (!Objects.equals(f, lastFuelStr)) { + lastFuelStr = f; + cachedFuelFluid = (f == null || "null".equals(f)) ? null : FluidRegistry.getFluid(f); + } + if (!Objects.equals(o, lastOxStr)) { + lastOxStr = o; + cachedOxFluid = (o == null || "null".equals(o)) ? null : FluidRegistry.getFluid(o); + } + if (!Objects.equals(w, lastWorkStr)) { + lastWorkStr = w; + cachedWorkFluid = (w == null || "null".equals(w)) ? null : FluidRegistry.getFluid(w); + } } + private boolean isStationFluidForThisRocket(Fluid current) { + refreshFluidCachesIfNeeded(); + if (current == null || linkedRocket == null) return false; + + // If a specific fluid was already chosen, match directly. + if (current == cachedFuelFluid || current == cachedOxFluid || current == cachedWorkFluid) { + return true; + } + + // Allow first-time lock-in when rocket hasn't chosen a fluid yet, + // but DOES have capacity for the corresponding tank and "current" is valid for that type. + if ("null".equals(linkedRocket.stats.getFuelFluid())) { + if ((linkedRocket.getFuelCapacity(FuelType.LIQUID_MONOPROPELLANT) > 0 && + FuelRegistry.instance.isFuel(FuelType.LIQUID_MONOPROPELLANT, current)) || + (linkedRocket.getFuelCapacity(FuelType.LIQUID_BIPROPELLANT) > 0 && + FuelRegistry.instance.isFuel(FuelType.LIQUID_BIPROPELLANT, current))) { + return true; + } + } + + if ("null".equals(linkedRocket.stats.getOxidizerFluid())) { + if (linkedRocket.getFuelCapacity(FuelType.LIQUID_OXIDIZER) > 0 && + FuelRegistry.instance.isFuel(FuelType.LIQUID_OXIDIZER, current)) { + return true; + } + } + + if ("null".equals(linkedRocket.stats.getWorkingFluid())) { + if (linkedRocket.getFuelCapacity(FuelType.NUCLEAR_WORKING_FLUID) > 0 && + FuelRegistry.instance.isFuel(FuelType.NUCLEAR_WORKING_FLUID, current)) { + return true; + } + } + + return false; + } + + + @Override + public void update() { + if (world.isRemote) return; + + // Lightweight bucket poll every 10 ticks (automation/hoppers) + if ((world.getTotalWorldTime() % 10L) == 0L) { + ItemStack in = inventory.getStackInSlot(0); + if (!in.isEmpty() && useBucket(0, in)) { + syncTE(); // only when something actually changed + } + } + + super.update(); // IMPORTANT: preserve parent RF/ticking pipeline + } + + @Override public void performFunction() { - if (!world.isRemote) { - //Lock rocket to a specific fluid so that it has only one oxidizer/bipropellant/monopropellant/etc - FluidStack currentFluidStack = tank.getFluid(); - if (currentFluidStack != null) { - Fluid currentFluid = currentFluidStack.getFluid(); - - //Check to see if we should set the rocket fuel - if (linkedRocket.stats.getFuelFluid().equals("null")) { - if ((FuelRegistry.instance.isFuel(FuelType.LIQUID_MONOPROPELLANT, currentFluid) && linkedRocket.getFuelCapacity(FuelType.LIQUID_MONOPROPELLANT) > 0) || (FuelRegistry.instance.isFuel(FuelType.LIQUID_BIPROPELLANT, currentFluid) && linkedRocket.getFuelCapacity(FuelType.LIQUID_BIPROPELLANT) > 0)) - linkedRocket.stats.setFuelFluid(currentFluid.getName()); - } - if (linkedRocket.stats.getOxidizerFluid().equals("null")) { - if (FuelRegistry.instance.isFuel(FuelType.LIQUID_OXIDIZER, currentFluid)) - linkedRocket.stats.setOxidizerFluid(currentFluid.getName()); - } - if (linkedRocket.stats.getWorkingFluid().equals("null")) { - if (FuelRegistry.instance.isFuel(FuelType.NUCLEAR_WORKING_FLUID, currentFluid)) - linkedRocket.stats.setWorkingFluid(currentFluid.getName()); - } + if (world.isRemote) return; // server-only + + if (!fuelingActive) { + FluidStack fs = tank.getFluid(); + boolean relevant = false, room = false; + + if (linkedRocket != null && fs != null) { + Fluid f = fs.getFluid(); + // relevant if this fluid matches what this rocket can actually use + relevant = isStationFluidForThisRocket(f); + // room if the matching logical tank has capacity + room = relevant && canRocketFitFluid(f); + } - //Actually fill the fuel if that is the case - if (currentFluid == FluidRegistry.getFluid(linkedRocket.stats.getFuelFluid()) || currentFluid == FluidRegistry.getFluid(linkedRocket.stats.getOxidizerFluid()) || currentFluid == FluidRegistry.getFluid(linkedRocket.stats.getWorkingFluid())) { - if (linkedRocket.getRocketFuelType() == FuelType.LIQUID_BIPROPELLANT && FuelRegistry.instance.isFuel(FuelType.LIQUID_OXIDIZER, currentFluid)) { - int fuelRate = (int) (FuelRegistry.instance.getMultiplier(FuelType.LIQUID_OXIDIZER, currentFluid) * linkedRocket.stats.getBaseFuelRate(FuelType.LIQUID_OXIDIZER)); - tank.drain(linkedRocket.addFuelAmount(FuelType.LIQUID_OXIDIZER, ARConfiguration.getCurrentConfig().fuelPointsPer10Mb), true); - linkedRocket.setFuelConsumptionRate(FuelType.LIQUID_OXIDIZER, fuelRate); - } else { - int fuelRate = (int) (FuelRegistry.instance.getMultiplier(linkedRocket.getRocketFuelType(), currentFluid) * linkedRocket.stats.getBaseFuelRate(linkedRocket.getRocketFuelType())); - tank.drain(linkedRocket.addFuelAmount(linkedRocket.getRocketFuelType(), ARConfiguration.getCurrentConfig().fuelPointsPer10Mb), true); - linkedRocket.setFuelConsumptionRate(linkedRocket.getRocketFuelType(), fuelRate); - } + setRedstoneState(relevant && !room); // emit when relevant but full + fuelingActive = room; // arm when relevant and there’s room + if (!fuelingActive) return; + } - } + // from here: only do rocket-facing work when it's worth it... + if (linkedRocket == null) { + fuelingActive = false; + setRedstoneState(false); + return; + } + + // Stop all work once full (until unlink/relink) + if (!fuelingActive) { + FluidStack fs = tank.getFluid(); + if (fs != null && canRocketFitFluid(fs.getFluid())) { + fuelingActive = true; // resume fueling after reload + // don’t run expensive work this tick; we’ll catch it on the next throttled pass + } else { + // already full or no relevant fluid — keep RS accurate + setRedstoneState(fs != null && isStationFluidForThisRocket(fs.getFluid()) && !canRocketFitFluid(fs.getFluid())); + } + return; + } + + // Throttle only the expensive fueling/redstone path + if ((world.getTotalWorldTime() % OP_THROTTLE_TICKS) != 0L) return; + + FluidStack currentFluidStack = tank.getFluid(); + if (currentFluidStack == null) { + // No fluid to offer; keep fuelingActive so we’ll retry when fluid arrives + setRedstoneState(false); + return; + } + + final Fluid currentFluid = currentFluidStack.getFluid(); + + // Lock rocket to specific fluids if unset + if ("null".equals(linkedRocket.stats.getFuelFluid())) { + if ((FuelRegistry.instance.isFuel(FuelType.LIQUID_MONOPROPELLANT, currentFluid) && linkedRocket.getFuelCapacity(FuelType.LIQUID_MONOPROPELLANT) > 0) + || (FuelRegistry.instance.isFuel(FuelType.LIQUID_BIPROPELLANT, currentFluid) && linkedRocket.getFuelCapacity(FuelType.LIQUID_BIPROPELLANT) > 0)) { + linkedRocket.stats.setFuelFluid(currentFluid.getName()); + } + } + if ("null".equals(linkedRocket.stats.getOxidizerFluid())) { + if (FuelRegistry.instance.isFuel(FuelType.LIQUID_OXIDIZER, currentFluid)) { + linkedRocket.stats.setOxidizerFluid(currentFluid.getName()); + } + } + if ("null".equals(linkedRocket.stats.getWorkingFluid())) { + if (FuelRegistry.instance.isFuel(FuelType.NUCLEAR_WORKING_FLUID, currentFluid)) { + linkedRocket.stats.setWorkingFluid(currentFluid.getName()); + } + } + + // Update caches after potential stat change + refreshFluidCachesIfNeeded(); + + // If station fluid isn't relevant for this rocket, we can't help + if (!isStationFluidForThisRocket(currentFluid)) { + setRedstoneState(false); + fuelingActive = false; // go fully idle if station fluid not relevant + return; + } + + if (!canRocketFitFluid(currentFluid)) { + setRedstoneState(true); + fuelingActive = false; // early-return above- next pass + markDirty(); + return; + } - //If the rocket is full then emit redstone - setRedstoneState(!canRocketFitFluid(currentFluid)); + // Determine which tank to fill + final FuelType typeToFill; + if (FuelRegistry.instance.isFuel(FuelType.LIQUID_OXIDIZER, currentFluid) + && linkedRocket.getFuelCapacity(FuelType.LIQUID_OXIDIZER) > linkedRocket.getFuelAmount(FuelType.LIQUID_OXIDIZER)) { + typeToFill = FuelType.LIQUID_OXIDIZER; + + } else if (FuelRegistry.instance.isFuel(FuelType.LIQUID_BIPROPELLANT, currentFluid) + && linkedRocket.getFuelCapacity(FuelType.LIQUID_BIPROPELLANT) > linkedRocket.getFuelAmount(FuelType.LIQUID_BIPROPELLANT)) { + typeToFill = FuelType.LIQUID_BIPROPELLANT; + + } else if (FuelRegistry.instance.isFuel(FuelType.LIQUID_MONOPROPELLANT, currentFluid) + && linkedRocket.getFuelCapacity(FuelType.LIQUID_MONOPROPELLANT) > linkedRocket.getFuelAmount(FuelType.LIQUID_MONOPROPELLANT)) { + typeToFill = FuelType.LIQUID_MONOPROPELLANT; + + } else if (FuelRegistry.instance.isFuel(FuelType.NUCLEAR_WORKING_FLUID, currentFluid) + && linkedRocket.getFuelCapacity(FuelType.NUCLEAR_WORKING_FLUID) > linkedRocket.getFuelAmount(FuelType.NUCLEAR_WORKING_FLUID)) { + typeToFill = FuelType.NUCLEAR_WORKING_FLUID; + + } else { + // not relevant or no room + setRedstoneState(false); + fuelingActive = false; + return; + } + // Bounded transfer scaled by throttle; drain exactly what was accepted + int step = ARConfiguration.getCurrentConfig().fuelPointsPer10Mb; + int toOffer = Math.min(step * OP_THROTTLE_TICKS, tank.getFluidAmount()); + if (toOffer > 0) { + int accepted = linkedRocket.addFuelAmount(typeToFill, toOffer); // assumes returns actual mB accepted + if (accepted > 0) { + tank.drain(accepted, true); + int baseRate = linkedRocket.stats.getBaseFuelRate(typeToFill); + if (baseRate > 0) { + int multRate = (int)(FuelRegistry.instance.getMultiplier(typeToFill, currentFluid) * baseRate); + if (multRate > 0) { + linkedRocket.setFuelConsumptionRate(typeToFill, multRate); + } + } } } - useBucket(0, inventory.getStackInSlot(0)); + + // Re-evaluate full; if full now, stop within this link + boolean fullNow = !canRocketFitFluid(currentFluid); + setRedstoneState(fullNow); + if (fullNow) { + fuelingActive = false; + markDirty(); + } } @Override public int getPowerPerOperation() { - return 30; + // same average RF/mb as before, just throttled + return 30 * OP_THROTTLE_TICKS; } + @Override public SPacketUpdateTileEntity getUpdatePacket() { return new SPacketUpdateTileEntity(pos, getBlockMetadata(), getUpdateTag()); @@ -132,45 +335,74 @@ public NBTTagCompound getUpdateTag() { return writeToNBT(new NBTTagCompound()); } - @Override public boolean canPerformFunction() { - boolean v = linkedRocket != null && (tank.getFluid() != null && tank.getFluidAmount() > 9 && canRocketFitFluid(tank.getFluid().getFluid())); - //System.out.println(v); - return v; + if (world.isRemote) return false; + if (linkedRocket == null) return false; + + FluidStack fs = tank.getFluid(); + if (fs == null || fs.amount <= 9) return false; + + // only if the rocket can fit this fluid + if (!canRocketFitFluid(fs.getFluid())) return false; + + // Consume RF only on the throttled ticks + return (world.getTotalWorldTime() % OP_THROTTLE_TICKS) == 0L; } @Override public boolean canFill(Fluid fluid) { - return FuelRegistry.instance.isFuel(FuelType.LIQUID_MONOPROPELLANT, fluid) || FuelRegistry.instance.isFuel(FuelType.NUCLEAR_WORKING_FLUID, fluid) || FuelRegistry.instance.isFuel(FuelType.LIQUID_BIPROPELLANT, fluid) || FuelRegistry.instance.isFuel(FuelType.LIQUID_OXIDIZER, fluid); + if (fluid == null) return false; + return FuelRegistry.instance.isFuel(FuelType.LIQUID_MONOPROPELLANT, fluid) + || FuelRegistry.instance.isFuel(FuelType.NUCLEAR_WORKING_FLUID, fluid) + || FuelRegistry.instance.isFuel(FuelType.LIQUID_BIPROPELLANT, fluid) + || FuelRegistry.instance.isFuel(FuelType.LIQUID_OXIDIZER, fluid); } - /** * @param fluid the fluid to check whether the rocket has space for it * @return boolean on whether the rocket can accept the fluid */ - public boolean canRocketFitFluid(Fluid fluid) { - return canFill(fluid) && ((linkedRocket.getRocketFuelType() == FuelType.LIQUID_BIPROPELLANT && FuelRegistry.instance.isFuel(FuelType.LIQUID_OXIDIZER, fluid)) ? linkedRocket.getFuelCapacity(FuelType.LIQUID_OXIDIZER) > linkedRocket.getFuelAmount(FuelType.LIQUID_OXIDIZER) : linkedRocket.getFuelCapacity(linkedRocket.getRocketFuelType()) > linkedRocket.getFuelAmount(linkedRocket.getRocketFuelType())); - } + private boolean canRocketFitFluid(Fluid f) { + if (f == null || linkedRocket == null) return false; + if (FuelRegistry.instance.isFuel(FuelType.LIQUID_OXIDIZER, f)) { + return linkedRocket.getFuelAmount(FuelType.LIQUID_OXIDIZER) < linkedRocket.getFuelCapacity(FuelType.LIQUID_OXIDIZER); + } + if (FuelRegistry.instance.isFuel(FuelType.LIQUID_BIPROPELLANT, f)) { + return linkedRocket.getFuelAmount(FuelType.LIQUID_BIPROPELLANT) < linkedRocket.getFuelCapacity(FuelType.LIQUID_BIPROPELLANT); + } + if (FuelRegistry.instance.isFuel(FuelType.LIQUID_MONOPROPELLANT, f)) { + return linkedRocket.getFuelAmount(FuelType.LIQUID_MONOPROPELLANT) < linkedRocket.getFuelCapacity(FuelType.LIQUID_MONOPROPELLANT); + } + if (FuelRegistry.instance.isFuel(FuelType.NUCLEAR_WORKING_FLUID, f)) { + return linkedRocket.getFuelAmount(FuelType.NUCLEAR_WORKING_FLUID) < linkedRocket.getFuelCapacity(FuelType.NUCLEAR_WORKING_FLUID); + } + return false; + } @Override public String getModularInventoryName() { return AdvancedRocketryBlocks.blockFuelingStation.getLocalizedName(); } + // keep original claim of custom name, but return non-null to avoid GUI NPEs @Override - public boolean hasCustomName() { - return true; + public boolean hasCustomName() { return true; } + + @Override + public String getName() { + return AdvancedRocketryBlocks.blockFuelingStation.getLocalizedName(); } @Override public void setInventorySlotContents(int slot, @Nonnull ItemStack stack) { - super.setInventorySlotContents(slot, stack); - while (useBucket(0, getStackInSlot(0))) ; - + if (!world.isRemote) { + boolean changed = false; + while (useBucket(0, getStackInSlot(0))) changed = true; // drain all at once + if (changed) syncTE(); // one sync if anything changed + } } /** @@ -184,32 +416,52 @@ private boolean useBucket(int slot, @Nonnull ItemStack stack) { return FluidUtils.attemptDrainContainerIInv(inventory, tank, stack, 0, 1); } + @Override public boolean isItemValidForSlot(int slot, @Nonnull ItemStack stack) { - if (stack.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, EnumFacing.UP)) { - FluidStack fstack = stack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, EnumFacing.UP).getTankProperties()[0].getContents(); - return fstack != null && canFill(fstack.getFluid()); - } - return false; + if (!stack.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, EnumFacing.UP)) return false; + IFluidHandler cap = stack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, EnumFacing.UP); + if (cap == null) return false; + IFluidTankProperties[] props = cap.getTankProperties(); + if (props == null || props.length == 0) return false; + FluidStack fstack = props[0].getContents(); + return fstack != null && canFill(fstack.getFluid()); } @Override public void unlinkRocket() { this.linkedRocket = null; - ((BlockTileRedstoneEmitter) AdvancedRocketryBlocks.blockFuelingStation).setRedstoneState(world, world.getBlockState(pos), pos, false); - + this.fuelingActive = false; + this.lastRs = null; + ((BlockTileRedstoneEmitter) AdvancedRocketryBlocks.blockFuelingStation) + .setRedstoneState(world, world.getBlockState(pos), pos, false); + markDirty(); } @Override - public boolean disconnectOnLiftOff() { - return true; - } + public boolean disconnectOnLiftOff() { return true; } @Override public boolean linkRocket(EntityRocketBase rocket) { this.linkedRocket = rocket; - if (tank.getFluid() != null) - setRedstoneState(!canRocketFitFluid(tank.getFluid().getFluid())); + this.lastRs = null; + refreshFluidCachesIfNeeded(); + + boolean room = false; + + if (tank.getFluid() != null) { + Fluid f = tank.getFluid().getFluid(); + boolean relevant = isStationFluidForThisRocket(f); + room = relevant && canRocketFitFluid(f); + setRedstoneState(relevant && !room); + } else { + setRedstoneState(false); + } + + // Arm fueling only if there’s actually room for the current fluid + this.fuelingActive = room; + + syncTE(); return true; } @@ -225,7 +477,9 @@ public boolean onLinkStart(@Nonnull ItemStack item, TileEntity entity, } if (player.world.isRemote) - Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage((new TextComponentString(LibVulpes.proxy.getLocalizedString("msg.fuelingStation.link") + ": " + this.pos.getX() + " " + this.pos.getY() + " " + this.pos.getZ()))); + Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage( + new TextComponentString(LibVulpes.proxy.getLocalizedString("msg.fuelingStation.link") + + ": " + this.pos.getX() + " " + this.pos.getY() + " " + this.pos.getZ())); return true; } @@ -233,18 +487,29 @@ public boolean onLinkStart(@Nonnull ItemStack item, TileEntity entity, public void invalidate() { super.invalidate(); if (getMasterBlock() instanceof TileRocketAssemblingMachine) - ((TileRocketAssemblingMachine) getMasterBlock()).removeConnectedInfrastructure(this); + ((TileRocketAssemblingMachine)getMasterBlock()).removeConnectedInfrastructure(this); - //Mostly for client rendering stuff if (linkedRocket != null) linkedRocket.unlinkInfrastructure(this); + + // Hard-off to avoid stale output when chunk unload order is weird + lastRs = null; + fuelingActive = false; + + if (world != null && AdvancedRocketryBlocks.blockFuelingStation instanceof BlockTileRedstoneEmitter) { + ((BlockTileRedstoneEmitter) AdvancedRocketryBlocks.blockFuelingStation) + .setRedstoneState(world, world.getBlockState(pos), pos, false); + } + + markDirty(); } @Override public boolean onLinkComplete(@Nonnull ItemStack item, TileEntity entity, EntityPlayer player, World world) { if (player.world.isRemote) - Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentTranslation("msg.linker.error.firstMachine")); + Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage( + new TextComponentTranslation("msg.linker.error.firstMachine")); return false; } @@ -273,23 +538,13 @@ public List getModules(int ID, EntityPlayer player) { } @Override - public String getName() { - return null; - } + public boolean canInteractWithContainer(EntityPlayer entity) { return true; } @Override - public boolean canInteractWithContainer(EntityPlayer entity) { - return true; - } - - @Override - public boolean linkMission(IMission mission) { - return false; - } + public boolean linkMission(IMission mission) { return false; } @Override - public void unlinkMission() { - } + public void unlinkMission() { } @Override public NBTTagCompound writeToNBT(NBTTagCompound nbt) { @@ -298,6 +553,7 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { if (hasMaster()) { nbt.setIntArray("masterPos", new int[]{masterBlock.x, masterBlock.y, masterBlock.z}); } + // fuelingActive not persisted on purpose to match original continuous behavior after reload return nbt; } @@ -311,12 +567,11 @@ public void readFromNBT(NBTTagCompound nbt) { int[] pos = nbt.getIntArray("masterPos"); setMasterBlock(new BlockPos(pos[0], pos[1], pos[2])); } + // lastRs/fuelingActive intentionally not restored; link events will reset as needed } @Override - public boolean hasMaster() { - return masterBlock.y > -1; - } + public boolean hasMaster() { return masterBlock.y > -1; } @Override public TileEntity getMasterBlock() { @@ -324,23 +579,15 @@ public TileEntity getMasterBlock() { } @Override - public void setMasterBlock(BlockPos pos) { - masterBlock = new HashedBlockPosition(pos); - } + public void setMasterBlock(BlockPos pos) { masterBlock = new HashedBlockPosition(pos); } @Override - public void setComplete(BlockPos pos) { - - } + public void setComplete(BlockPos pos) { } @Override - public void setIncomplete() { - masterBlock.y = -1; - } + public void setIncomplete() { masterBlock.y = -1; } - public boolean canRenderConnection() { - return true; - } + public boolean canRenderConnection() { return true; } @Override public void onInventoryButtonPressed(int buttonId) { @@ -354,22 +601,60 @@ public void writeDataToNetwork(ByteBuf out, byte id) { } @Override - public void readDataFromNetwork(ByteBuf in, byte packetId, - NBTTagCompound nbt) { + public void readDataFromNetwork(ByteBuf in, byte packetId, NBTTagCompound nbt) { nbt.setByte("state", in.readByte()); } @Override - public void useNetworkData(EntityPlayer player, Side side, byte id, - NBTTagCompound nbt) { + public void useNetworkData(EntityPlayer player, Side side, byte id, NBTTagCompound nbt) { state = RedstoneState.values()[nbt.getByte("state")]; + markDirty(); + if (side == Side.SERVER && linkedRocket != null) { + FluidStack fs = tank.getFluid(); + if (fs == null) { setRedstoneState(false); return; } + Fluid f = fs.getFluid(); + boolean relevant = isStationFluidForThisRocket(f); + boolean room = relevant && canRocketFitFluid(f); + setRedstoneState(relevant && !room); + } + } - if (linkedRocket != null && tank.getFluid() != null) - setRedstoneState(!canRocketFitFluid(tank.getFluid().getFluid())); + + @Override + public void onLoad() { + if (world.isRemote) return; + lastRs = null; // allow first emit + refreshFluidCachesIfNeeded(); + + boolean emit = false; + if (linkedRocket != null) { + FluidStack fs = tank.getFluid(); + if (fs != null) { + Fluid f = fs.getFluid(); + emit = isStationFluidForThisRocket(f) && !canRocketFitFluid(f); + // also re-arm fueling if we actually can fit + if (!emit && isStationFluidForThisRocket(f) && canRocketFitFluid(f)) { + fuelingActive = true; + } + } + } + setRedstoneState(emit); } @Override - public boolean isEmpty() { - return inventory.isEmpty(); + public void onChunkUnload() { + super.onChunkUnload(); + if (world == null || world.isRemote) return; + + lastRs = null; + fuelingActive = false; + if (AdvancedRocketryBlocks.blockFuelingStation instanceof BlockTileRedstoneEmitter) { + ((BlockTileRedstoneEmitter) AdvancedRocketryBlocks.blockFuelingStation) + .setRedstoneState(world, world.getBlockState(pos), pos, false); + } + markDirty(); } + + @Override + public boolean isEmpty() { return inventory.isEmpty(); } } From ca6aa6b5bdb779e3198842ca0ca0d18ede016424 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 27 Oct 2025 23:15:24 +0100 Subject: [PATCH 058/274] fixed status updates fixed stale statuses, and properly show status on guiReload --- .../TileRocketMonitoringStation.java | 93 ++++++++++++++----- 1 file changed, 69 insertions(+), 24 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java index 07bd0793b..4f07181fc 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java @@ -83,9 +83,25 @@ public class TileRocketMonitoringStation extends TileEntity implements IModularI private int uiStatus = 0; private transient ModuleText launchStatus; // client-only widget private transient int lastUiStatusShown = -1; // client change-detect + // How long a status is considered fresh after the last event (in ticks) + private static final long STATUS_STALE_TICKS = 400L; // over 20 seconds is outdated + private long lastStatusTick = 0L; // server-only; persisted // Event bus registration flag private boolean registeredBus = false; + + private void pushState() { + if (world != null && !world.isRemote) { + markDirty(); + world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3); + } + } + + private void clearUiStatus() { + uiStatus = 0; + lastUiStatusShown = -1; // force client label to refresh to empty + pushState(); + } public TileRocketMonitoringStation() { mission = null; @@ -103,9 +119,23 @@ public void onLoad() { if (!world.isRemote && !initPower) { boolean now = world.isBlockIndirectlyGettingPowered(pos) > 0; isPoweredCached = now; - was_powered = now; // <- important: no phantom rising edge later + was_powered = now; initPower = true; } + + if (!world.isRemote) { + boolean stale = lastStatusTick == 0L || + (world.getTotalWorldTime() - lastStatusTick) > STATUS_STALE_TICKS; + + if (stale || linkedRocket == null) { + clearUiStatus(); + lastStatusTick = 0L; // reset tick + } else { + pushState(); // keep fresh status visible + } + } + + } @@ -182,26 +212,34 @@ public boolean disconnectOnLiftOff() { @Override public boolean linkRocket(EntityRocketBase rocket) { this.linkedRocket = rocket; - this.lastComparator = -1; // ensure first comparator notify fires if needed + this.lastComparator = -1; + + if (!world.isRemote) { + clearUiStatus(); + lastStatusTick = 0L; // reset tick + } return true; } + @Override public void unlinkRocket() { linkedRocket = null; - // Reset snapshots so viewers don't see stale values - snapHeight = 0; snapVel = 0; - snapFuel = 0; snapFuelCap = 0; - snapOx = 0; snapOxCap = 0; + // reset snapshots + snapHeight = snapVel = 0; + snapFuel = snapFuelCap = 0; + snapOx = snapOxCap = 0; - // Server-only: force comparator to 0 and notify once - if (world != null && !world.isRemote) { + if (!world.isRemote) { lastComparator = 0; world.updateComparatorOutputLevel(pos, world.getBlockState(pos).getBlock()); + clearUiStatus(); + lastStatusTick = 0L; // reset tick } } + // --- Ticking --- @Override @@ -215,7 +253,7 @@ public void update() { } // Runs infrequently to recover from any missed neighbor events. - if ( (world.getTotalWorldTime() & 100) == 0 ) { // every 100 ticks + if (world.getTotalWorldTime() % 100 == 0) { // every 100 ticks boolean polled = world.isBlockIndirectlyGettingPowered(pos) > 0; isPoweredCached = polled; // DO NOT trigger launch here; just reconcile the cache } @@ -260,14 +298,13 @@ public void update() { // --- Forge Rocket Events -> authorititative UI status (server -> client via TE update) --- - @SubscribeEvent(priority = EventPriority.LOWEST) // see final canceled state + @SubscribeEvent(priority = EventPriority.LOWEST) public void onPreLaunch(RocketEvent.RocketPreLaunchEvent e) { if (world == null || world.isRemote) return; if (linkedRocket != null && e.getEntity() == linkedRocket) { - // At LOWEST, if someone canceled it, isCanceled() will be true now. - uiStatus = e.isCanceled() ? 5 : 1; // aborted or prelaunch - markDirty(); - world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3); + uiStatus = e.isCanceled() ? 5 : 1; // aborted or prelaunch + lastStatusTick = world.getTotalWorldTime(); + pushState(); // single place to mark+notify } } @@ -275,9 +312,9 @@ public void onPreLaunch(RocketEvent.RocketPreLaunchEvent e) { public void onLaunch(RocketEvent.RocketLaunchEvent e) { if (world == null || world.isRemote) return; if (linkedRocket != null && e.getEntity() == linkedRocket) { - uiStatus = 2; // launching! - markDirty(); - world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3); + uiStatus = 2; + lastStatusTick = world.getTotalWorldTime(); + pushState(); } } @@ -285,9 +322,9 @@ public void onLaunch(RocketEvent.RocketLaunchEvent e) { public void onOrbit(RocketEvent.RocketReachesOrbitEvent e) { if (world == null || world.isRemote) return; if (linkedRocket != null && e.getEntity() == linkedRocket) { - uiStatus = 3; // reached orbit - markDirty(); - world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3); + uiStatus = 3; + lastStatusTick = world.getTotalWorldTime(); + pushState(); } } @@ -295,12 +332,13 @@ public void onOrbit(RocketEvent.RocketReachesOrbitEvent e) { public void onLanded(RocketEvent.RocketLandedEvent e) { if (world == null || world.isRemote) return; if (linkedRocket != null && e.getEntity() == linkedRocket) { - uiStatus = 4; // landed - markDirty(); - world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3); + uiStatus = 4; + lastStatusTick = world.getTotalWorldTime(); + pushState(); } } + // --- Linker flow --- @Override @@ -362,6 +400,7 @@ public void readFromNBT(NBTTagCompound nbt) { } } uiStatus = nbt.getInteger("uiStatus"); + lastStatusTick = nbt.getLong("lastStatusTick"); } @Override @@ -373,6 +412,7 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { nbt.setInteger("missionDimId", mission.getOriginatingDimension()); } nbt.setInteger("uiStatus", uiStatus); + nbt.setLong("lastStatusTick", lastStatusTick); return nbt; } @@ -428,8 +468,12 @@ public List getModules(int ID, EntityPlayer player) { if (world.isRemote) { launchStatus = new ModuleText(10, 30, "", 0xFFFFFF22); modules.add(launchStatus); + + // Force the label to refresh on this GUI open + lastUiStatusShown = -1; } + modules.add(new ModuleProgress(98, 4, 0, new IndicatorBarImage(2, 7, 12, 81, 17, 0, 6, 6, 1, 0, EnumFacing.UP, TextureResources.rocketHud), this)); modules.add(new ModuleProgress(120, 14, 1, new IndicatorBarImage(2, 95, 12, 71, 17, 0, 6, 6, 1, 0, EnumFacing.UP, TextureResources.rocketHud), this)); modules.add(new ModuleProgress(142, 14, 2, new ProgressBarImage(2, 173, 12, 71, 17, 6, 3, 69, 1, 1, EnumFacing.UP, TextureResources.rocketHud), this)); @@ -442,7 +486,8 @@ public List getModules(int ID, EntityPlayer player) { modules.add(new ModuleProgress(30, 130, 5, TextureResources.progressFromMission, this)); if (!world.isRemote) { - PacketHandler.sendToPlayer(new PacketMachine(this, (byte) 1), player); + PacketHandler.sendToPlayer(new PacketMachine(this, (byte) 1), player); // mission sync + pushState(); // TE sync (includes cleared/derived uiStatus) } return modules; From b95ff89cd005097d6623e3595003e4d26fb962b4 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Tue, 28 Oct 2025 01:01:02 +0100 Subject: [PATCH 059/274] Refactor fuel rates and implement chunk preloading Fuel rate computation on launch, hardFixing cheating Add chunk preloading for rocket launch if we are changing dims, holding force chunload 3x3 for 60 from launch event --- .../advancedRocketry/entity/EntityRocket.java | 163 ++++++++++++++---- 1 file changed, 130 insertions(+), 33 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java b/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java index e5566c6d7..8310fcf3f 100644 --- a/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java +++ b/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java @@ -25,6 +25,7 @@ import net.minecraft.util.SoundCategory; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentString; @@ -33,6 +34,9 @@ import net.minecraft.world.WorldServer; import net.minecraft.world.chunk.Chunk; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.ForgeChunkManager; +import net.minecraftforge.common.ForgeChunkManager.Ticket; +import net.minecraftforge.common.ForgeChunkManager.Type; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTank; @@ -90,6 +94,8 @@ import javax.annotation.Nullable; import java.util.*; + + public class EntityRocket extends EntityRocketBase implements INetworkEntity, IModularInventory, IProgressBar, IButtonInventory, ISelectionNotify, IPlanetDefiner { // set to 2 seconds because keyboard event is not sent to server @@ -140,6 +146,18 @@ public class EntityRocket extends EntityRocketBase implements INetworkEntity, IM private int rcs_mode_counter = 0; //Used to most of the logic, determining if in RCS mode or not private boolean rcs_mode = false; + + // Preload ticket for destination chunks on launch event should be enough time to get a warm dimension + private Ticket destPreloadTicket = null; + private int destPreloadDim = Integer.MIN_VALUE; + private long destPreloadExpire = Long.MIN_VALUE; // world time when we auto-release + + // Only show an oxidizer bar when the rocket actually provides oxidizer capacity. + public boolean shouldShowOxBar() { + return getFuelCapacity(FuelRegistry.FuelType.LIQUID_OXIDIZER) > 0; + } + + public EntityRocket(World p_i1582_1_) { super(p_i1582_1_); @@ -177,32 +195,6 @@ public EntityRocket(World world, StorageChunk storage, StatsRocket stats, double landingPadDisplayText.setColor(0x00ff00); } - private void recomputeFuelRates() { - for (FuelRegistry.FuelType t : new FuelRegistry.FuelType[]{ - FuelRegistry.FuelType.LIQUID_MONOPROPELLANT, - FuelRegistry.FuelType.LIQUID_BIPROPELLANT, - FuelRegistry.FuelType.LIQUID_OXIDIZER, - FuelRegistry.FuelType.NUCLEAR_WORKING_FLUID}) { - - if (getFuelCapacity(t) <= 0) continue; - - String name = (t == FuelRegistry.FuelType.LIQUID_OXIDIZER) ? stats.getOxidizerFluid() - : (t == FuelRegistry.FuelType.NUCLEAR_WORKING_FLUID) ? stats.getWorkingFluid() - : stats.getFuelFluid(); - if ("null".equals(name)) continue; - - Fluid f = FluidRegistry.getFluid(name); - if (f == null) continue; - - int base = stats.getBaseFuelRate(t); - if (base <= 0) continue; - - int rate = (int)(FuelRegistry.instance.getMultiplier(t, f) * base); - if (rate > 0) setFuelConsumptionRate(t, rate); - } - } - - /** * @param blockState the blockstate to damage * @return the blockstate that the input blockstate turns into @@ -235,6 +227,50 @@ private static IBlockState getDamagedBlock(IBlockState blockState) { return null; } + private void preloadDestinationChunks(int dimId, double x, double z, int radiusChunks, int holdSeconds) { + if (world.isRemote) return; + + // Clean any previous + releaseDestinationPreload(); + + MinecraftServer server = this.getServer(); + if (server == null) return; + + WorldServer target = server.getWorld(dimId); + if (target == null) return; // dimension not available + + // Request a NORMAL ticket in the DESTINATION world (not bound to this entity) + destPreloadTicket = ForgeChunkManager.requestTicket(AdvancedRocketry.instance, target, Type.NORMAL); + if (destPreloadTicket == null) { + AdvancedRocketry.logger.warn("[EntityRocket] Could not acquire destination preload ticket for dim {}", dimId); + return; + } + + int cx = ((int)Math.floor(x)) >> 4; + int cz = ((int)Math.floor(z)) >> 4; + for (int dx = -radiusChunks; dx <= radiusChunks; dx++) { + for (int dz = -radiusChunks; dz <= radiusChunks; dz++) { + ForgeChunkManager.forceChunk(destPreloadTicket, new ChunkPos(cx + dx, cz + dz)); + } + } + + destPreloadDim = dimId; + // use *server* time base; holdSeconds should be enough to cover ascent (~6s) + destPreloadExpire = world.getTotalWorldTime() + holdSeconds * 20L; + AdvancedRocketry.logger.debug("[EntityRocket] Preloaded 3x3 chunks at dim {} around {},{} for ~{}s", + dimId, (cx<<4), (cz<<4), holdSeconds); + } + + private void releaseDestinationPreload() { + if (destPreloadTicket != null) { + ForgeChunkManager.releaseTicket(destPreloadTicket); + destPreloadTicket = null; + destPreloadDim = Integer.MIN_VALUE; + destPreloadExpire = Long.MIN_VALUE; + } + } + + public void toggleRCS() { if (DimensionManager.getInstance().getDimensionProperties(this.world.provider.getDimension()).isAsteroid()) { rcs_mode = !rcs_mode; @@ -1110,6 +1146,11 @@ else if (!getRCS() && rcs_mode_counter > 0) { entity.fallDistance = 0; } this.fallDistance = 0; + + // Auto-release destination preload after timeout + if (destPreloadTicket != null && world.getTotalWorldTime() >= destPreloadExpire) { + releaseDestinationPreload(); + } } // When flying around in space @@ -1314,6 +1355,7 @@ else if (distanceSq > this.spacePosition.world.getRenderSizePlanetView() * this. this.motionY = 0; this.setInFlight(false); this.setInOrbit(false); + releaseDestinationPreload(); } @@ -1773,7 +1815,6 @@ public void explode() { public void recalculateStats(){ this.storage.recalculateStats(this.stats); - recomputeFuelRates(); } /** @@ -1791,7 +1832,6 @@ public void launch() { boolean allowLaunch = false; this.storage.recalculateStats(this.stats); - recalculateStats(); NBTTagCompound nbtdata = new NBTTagCompound(); writeToNBT(nbtdata); @@ -1874,12 +1914,37 @@ public void launch() { //TODO: Clean this logic a bit? - if (allowLaunch || !stats.hasSeat() || ((DimensionManager.getInstance().isDimensionCreated(destinationDimId)) || destinationDimId == ARConfiguration.getCurrentConfig().spaceDimId || destinationDimId == 0)) { //Abort if destination is invalid + if (allowLaunch || !stats.hasSeat() || ((DimensionManager.getInstance().isDimensionCreated(destinationDimId)) || destinationDimId == ARConfiguration.getCurrentConfig().spaceDimId || destinationDimId == 0)) { setInFlight(true); Iterator connectedTiles = connectedInfrastructure.iterator(); MinecraftForge.EVENT_BUS.post(new RocketLaunchEvent(this)); + // ---- PRELOAD DESTINATION 3x3 (server only) ---- + if (!world.isRemote) { + boolean willTeleportAtAscent = + !(ARConfiguration.getCurrentConfig().experimentalSpaceFlight && storage.getGuidanceComputer().isEmpty()); + + // Only preload when we know we’ll teleport off this world soon + if (willTeleportAtAscent) { + int dimId = destinationDimId; + + boolean canLoad = + DimensionManager.getInstance().isDimensionCreated(dimId) || + dimId == ARConfiguration.getCurrentConfig().spaceDimId; + + if (canLoad) { + Vector3F destVec = (storage != null) ? storage.getDestinationCoordinates(dimId, true) : null; + double dx = (destVec != null) ? destVec.x : this.posX; + double dz = (destVec != null) ? destVec.z : this.posZ; + + preloadDestinationChunks(dimId, dx, dz, /*radiusChunks*/ 1, /*holdSeconds*/ 60); + } + } + } + // ----------------------------------------------- + + //Disconnect things linked to the rocket on liftoff while (connectedTiles.hasNext()) { @@ -1939,6 +2004,7 @@ public void deconstructRocket() { @Override public void setDead() { super.setDead(); + releaseDestinationPreload(); if (storage != null && storage.world.displayListIndex != -1) GLAllocation.deleteDisplayLists(storage.world.displayListIndex); @@ -2067,7 +2133,6 @@ protected void readEntityFromNBT(NBTTagCompound nbt) { } spacePosition.readFromNBT(nbt); - recomputeFuelRates(); } protected void writeNetworkableNBT(NBTTagCompound nbt) { @@ -2285,6 +2350,7 @@ else if (id == PacketType.RECIEVENBT.ordinal()) { this.turningDownforWhat = nbt.getBoolean("down"); } else if (id == PacketType.ABORTLAUNCH.ordinal()) { this.dataManager.set(LAUNCH_COUNTER, -1); + releaseDestinationPreload(); } else if (id == PacketType.SENDSPACEPOS.ordinal()) { this.spacePosition.readFromNBT(nbt); } else if (id >= STATION_LOC_OFFSET + BUTTON_ID_OFFSET) { @@ -2415,6 +2481,15 @@ public List getModules(int ID, EntityPlayer player) { //Fuel modules.add(new ModuleProgress(192, 7, 0, new ProgressBarImage(2, 173, 12, 71, 17, 6, 3, 69, 1, 1, EnumFacing.UP, TextureResources.rocketHud), this)); + // Conditional oxidizer bar + if (shouldShowOxBar()) { + // Add a second, distinct bar for oxidizer (reuse the monitoring station’s UVs) + modules.add(new ModuleProgress( + 198, 7, 6, // position offset to avoid overlap; ID=6 matches monitoring station semantics + new ProgressBarImage(2, 173, 12, 71, 17, 75, 3, 69, 1, 1, EnumFacing.UP, TextureResources.rocketHud), + this + )); + } //Add buttons @@ -2489,14 +2564,23 @@ public float getNormallizedProgress(int id) { case LIQUID_BIPROPELLANT: case LIQUID_MONOPROPELLANT: case NUCLEAR_WORKING_FLUID: - return getFuelAmount(fuelType) / (float) getFuelCapacity(fuelType); + int amt = getFuelAmount(fuelType); + int cap = getFuelCapacity(fuelType); + return (cap > 0) ? (amt / (float) cap) : 0f; } } + // oxidizer bar matches monitoring station’s ID=6 semantics + if (id == 6) { + int oxAmt = getFuelAmount(FuelType.LIQUID_OXIDIZER); + int oxCap = getFuelCapacity(FuelType.LIQUID_OXIDIZER); + return (oxCap > 0) ? (oxAmt / (float) oxCap) : 0f; + } - return 0; + return 0f; } + public double getRelativeHeightFraction() { return (posY - getTopBlock(getPosition()).getY()) / (getEntryHeight(dimension) - getTopBlock(getPosition()).getY()); } @@ -2512,12 +2596,25 @@ public void setProgress(int id, int progress) { @Override public int getProgress(int id) { + if (id == 0) { + FuelType ft = getRocketFuelType(); + return (ft != null) ? getFuelAmount(ft) : 0; + } else if (id == 6) { + return getFuelAmount(FuelType.LIQUID_OXIDIZER); + } return 0; } @Override public int getTotalProgress(int id) { - return 0; + if (id == 0) { + FuelType ft = getRocketFuelType(); + return (ft != null) ? getFuelCapacity(ft) : 1; // never 0 + } else if (id == 6) { + int cap = getFuelCapacity(FuelType.LIQUID_OXIDIZER); + return (cap > 0) ? cap : 1; // never 0 + } + return 1; } @Override From 2448947599f026dbd164df547ec1a57ece7327d0 Mon Sep 17 00:00:00 2001 From: Marvin Eckhardt Date: Tue, 28 Oct 2025 12:02:15 +0100 Subject: [PATCH 060/274] Update gradle.properties --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index f80f2cd54..474210579 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ org.gradle.daemon=false # Project mcVersion=1.12.2 forgeVersion=14.23.5.2860 -modVersion=2.1.10 +modVersion=2.2.0 archiveBase=AdvancedRocketry startGitRev=8e676bd From ae446a9f077edf633907f7bef294d8fff69bd8e4 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 29 Oct 2025 11:37:14 +0100 Subject: [PATCH 061/274] Improved tooltip information display Will show preview of current build instead of "Error in weight calculation" --- .../advancedRocketry/item/ItemSatellite.java | 138 ++++++++++++++---- 1 file changed, 106 insertions(+), 32 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java b/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java index c26b9d0c5..9ca3d49c2 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java @@ -8,6 +8,7 @@ import zmaster587.advancedRocketry.api.SatelliteRegistry; import zmaster587.advancedRocketry.api.satellite.SatelliteBase; import zmaster587.advancedRocketry.api.satellite.SatelliteProperties; +import zmaster587.advancedRocketry.item.ItemSatellite.SatelliteModuleInventory; import zmaster587.libVulpes.LibVulpes; import zmaster587.libVulpes.util.EmbeddedInventory; import zmaster587.libVulpes.util.ZUtils; @@ -17,6 +18,10 @@ public class ItemSatellite extends ItemIdWithName { + private static final int CORE_SLOT = 0; + private static final int FIRST_MOD_SLOT = 1; + private static final int LAST_MOD_SLOT = 6; + //Guarding inventory to ensure only valid items are placed in slots. public static class SatelliteModuleInventory extends EmbeddedInventory { public SatelliteModuleInventory() { super(7); } // slots 0-6 embedded from chassis @@ -25,26 +30,23 @@ public static class SatelliteModuleInventory extends EmbeddedInventory { public boolean isItemValidForSlot(int slot, @Nonnull ItemStack stack) { if (stack.isEmpty()) return false; - // Registry-driven: only accept items that have SatelliteProperties SatelliteProperties p = SatelliteRegistry.getSatelliteProperty(stack); if (p == null) return false; int f = p.getPropertyFlag(); - - // Slot 0: ONLY primary function meta 0-6 - if (slot == 0) { + // only allow appropriate items in appropriate slots + if (slot == CORE_SLOT) { return SatelliteProperties.Property.MAIN.isOfType(f); } - // Slots 1–6: power gen, battery, or data modules - if (slot >= 1 && slot <= 6) { + if (slot >= FIRST_MOD_SLOT && slot <= LAST_MOD_SLOT) { return SatelliteProperties.Property.POWER_GEN.isOfType(f) || SatelliteProperties.Property.BATTERY.isOfType(f) || SatelliteProperties.Property.DATA.isOfType(f); } - return false; } + @Override public void setInventorySlotContents(int index, ItemStack stack) { if (!stack.isEmpty() && !isItemValidForSlot(index, stack)) return; @@ -95,47 +97,119 @@ public void setSatellite(@Nonnull ItemStack stack, SatelliteProperties propertie } - @Override - public void addInformation(@Nonnull ItemStack stack, World player, List list, ITooltipFlag bool) { - if (stack.getItem() instanceof ItemSatellite && SatelliteRegistry.getSatelliteProperties(stack) != null) { - SatelliteProperties properties = SatelliteRegistry.getSatelliteProperties(stack); + public void addInformation(@Nonnull ItemStack stack, World world, List list, ITooltipFlag flag) { + // Assembled = has properties AND a real ID (>0) + SatelliteProperties props = SatelliteRegistry.getSatelliteProperties(stack); + final boolean isAssembled = (props != null && props.getId() > 0); + if (isAssembled) { int dataStorage, powerGeneration, powerStorage; float weight; list.add(getName(stack)); - list.add("ID: " + properties.getId()); + list.add("ID: " + props.getId()); - if (SatelliteProperties.Property.BATTERY.isOfType(properties.getPropertyFlag())) { - if ((powerStorage = properties.getPowerStorage()) > 0) - list.add(LibVulpes.proxy.getLocalizedString("msg.itemsatellite.pwr") + powerStorage); - else - list.add(ChatFormatting.RED + LibVulpes.proxy.getLocalizedString("msg.itemsatellite.nopwr")); + if (SatelliteProperties.Property.BATTERY.isOfType(props.getPropertyFlag())) { + powerStorage = props.getPowerStorage(); + list.add((powerStorage > 0) + ? LibVulpes.proxy.getLocalizedString("msg.itemsatellite.pwr") + powerStorage + : ChatFormatting.RED + LibVulpes.proxy.getLocalizedString("msg.itemsatellite.nopwr")); } - if (SatelliteProperties.Property.POWER_GEN.isOfType(properties.getPropertyFlag())) { - if ((powerGeneration = properties.getPowerGeneration()) > 0) - list.add(LibVulpes.proxy.getLocalizedString("msg.itemsatellite.pwrgen") + powerGeneration); - else - list.add(ChatFormatting.RED + LibVulpes.proxy.getLocalizedString("msg.itemsatellite.nopwrgen")); + if (SatelliteProperties.Property.POWER_GEN.isOfType(props.getPropertyFlag())) { + powerGeneration = props.getPowerGeneration(); + list.add((powerGeneration > 0) + ? LibVulpes.proxy.getLocalizedString("msg.itemsatellite.pwrgen") + powerGeneration + : ChatFormatting.RED + LibVulpes.proxy.getLocalizedString("msg.itemsatellite.nopwrgen")); } - if (SatelliteProperties.Property.DATA.isOfType(properties.getPropertyFlag())) { - if ((dataStorage = properties.getMaxDataStorage()) > 0) - list.add(LibVulpes.proxy.getLocalizedString("msg.itemsatellite.data") + ZUtils.formatNumber(dataStorage)); - else - list.add(ChatFormatting.YELLOW + LibVulpes.proxy.getLocalizedString("msg.itemsatellite.nodata")); + if (SatelliteProperties.Property.DATA.isOfType(props.getPropertyFlag())) { + dataStorage = props.getMaxDataStorage(); + list.add((dataStorage > 0) + ? LibVulpes.proxy.getLocalizedString("msg.itemsatellite.data") + ZUtils.formatNumber(dataStorage) + : ChatFormatting.YELLOW + LibVulpes.proxy.getLocalizedString("msg.itemsatellite.nodata")); } - if ((weight = properties.getWeight()) > 0) - list.add(LibVulpes.proxy.getLocalizedString("msg.itemsatellite.weight") + weight); - else - list.add(ChatFormatting.YELLOW + LibVulpes.proxy.getLocalizedString("msg.itemsatellite.noweight")); + weight = props.getWeight(); + list.add((weight > 0f) + ? LibVulpes.proxy.getLocalizedString("msg.itemsatellite.weight") + weight + : ChatFormatting.YELLOW + LibVulpes.proxy.getLocalizedString("msg.itemsatellite.noweight")); + return; + } + + // --- Preview for unassembled chassis --- + EmbeddedInventory inv = readInvFromNBT(stack); - } else { + boolean hasParts = false; + for (int i = CORE_SLOT; i <= LAST_MOD_SLOT; i++) { + if (!inv.getStackInSlot(i).isEmpty()) { hasParts = true; break; } + } + if (!hasParts) { list.add(ChatFormatting.RED + LibVulpes.proxy.getLocalizedString("msg.itemsatellite.empty")); + return; } + int flags = 0; + int powerGen = 0, powerStor = 0, dataMax = 0; + float weight = 0f; + + // Core first: flags + preview type name (no weight from core) + ItemStack core = inv.getStackInSlot(CORE_SLOT); + if (!core.isEmpty()) { + SatelliteProperties cp = SatelliteRegistry.getSatelliteProperty(core); + if (cp != null) { + flags |= cp.getPropertyFlag(); + String satType = cp.getSatelliteType(); + SatelliteBase satBase = SatelliteRegistry.getNewSatellite(satType); + if (satBase != null) { + // Show same display name users will see after assembly + list.add(satBase.getName()); + } + } + } + + // Modules: stats + weight + for (int i = FIRST_MOD_SLOT; i <= LAST_MOD_SLOT; i++) { + ItemStack s = inv.getStackInSlot(i); + if (s.isEmpty()) continue; + + SatelliteProperties p = SatelliteRegistry.getSatelliteProperty(s); + if (p != null) { + flags |= p.getPropertyFlag(); + int f = p.getPropertyFlag(); + if (f == SatelliteProperties.Property.POWER_GEN.getFlag()) + powerGen += p.getPowerGeneration(); + else if (f == SatelliteProperties.Property.BATTERY.getFlag()) + powerStor += p.getPowerStorage(); + else if (f == SatelliteProperties.Property.DATA.getFlag()) + dataMax += p.getMaxDataStorage(); + } + weight += zmaster587.advancedRocketry.util.WeightEngine.INSTANCE.getWeight(s); + } + + // Match assembly semantics: base buffer is always present + powerStor += 720; + + // Always show power storage in preview (even if no battery modules are installed) + list.add(LibVulpes.proxy.getLocalizedString("msg.itemsatellite.pwr") + powerStor); + + if (SatelliteProperties.Property.POWER_GEN.isOfType(flags)) { + list.add((powerGen > 0) + ? LibVulpes.proxy.getLocalizedString("msg.itemsatellite.pwrgen") + powerGen + : ChatFormatting.RED + LibVulpes.proxy.getLocalizedString("msg.itemsatellite.nopwrgen")); + } + if (SatelliteProperties.Property.DATA.isOfType(flags)) { + list.add((dataMax > 0) + ? LibVulpes.proxy.getLocalizedString("msg.itemsatellite.data") + ZUtils.formatNumber(dataMax) + : ChatFormatting.YELLOW + LibVulpes.proxy.getLocalizedString("msg.itemsatellite.nodata")); + } + if (weight > 0f) { + list.add(LibVulpes.proxy.getLocalizedString("msg.itemsatellite.weight") + weight); + } + + // Footer LAST + list.add(ChatFormatting.RED + LibVulpes.proxy.getLocalizedString("msg.itemsatellite.unassembled")); } + } From fa2f5e98a0225de2999a82548636118557d5b76a Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 29 Oct 2025 11:39:06 +0100 Subject: [PATCH 062/274] Update weight message for satellite tooltip --- src/main/resources/assets/advancedrocketry/lang/en_US.lang | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/resources/assets/advancedrocketry/lang/en_US.lang b/src/main/resources/assets/advancedrocketry/lang/en_US.lang index 865ad4a84..f899e02d0 100644 --- a/src/main/resources/assets/advancedrocketry/lang/en_US.lang +++ b/src/main/resources/assets/advancedrocketry/lang/en_US.lang @@ -458,8 +458,10 @@ msg.itemsatellite.microwavestatus=Collecting Power msg.itemsatellite.data=Data Storage: msg.itemsatellite.nodata=No Data Storage! msg.itemsatellite.empty=Empty Chassis -msg.itemsatellite.weight=Chassis weight: +msg.itemsatellite.weight=Chassis weight: msg.itemsatellite.noweight=Error in weight calculation +msg.itemsatellite.unassembled=Not assembled (preview) + msg.brokenstage.text=Destruction stage @@ -524,4 +526,3 @@ jei.sb.copy.source=Source jei.sb.copy.output=New Copy jei.sb.assemblyhint=Atleast one solar panel jei.sb.copychiphint=Make backups! - From c9a24ea33b0c67ce5adc22e3d5dba1805de989d8 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 29 Oct 2025 14:12:28 +0100 Subject: [PATCH 063/274] Remove unused import for SatelliteModuleInventory --- .../java/zmaster587/advancedRocketry/item/ItemSatellite.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java b/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java index 9ca3d49c2..ba705ca14 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java @@ -8,7 +8,6 @@ import zmaster587.advancedRocketry.api.SatelliteRegistry; import zmaster587.advancedRocketry.api.satellite.SatelliteBase; import zmaster587.advancedRocketry.api.satellite.SatelliteProperties; -import zmaster587.advancedRocketry.item.ItemSatellite.SatelliteModuleInventory; import zmaster587.libVulpes.LibVulpes; import zmaster587.libVulpes.util.EmbeddedInventory; import zmaster587.libVulpes.util.ZUtils; From 00be1dd55930ab3c66f771828414668cba5646e5 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 29 Oct 2025 14:13:14 +0100 Subject: [PATCH 064/274] Fixed --- .../java/zmaster587/advancedRocketry/item/ItemSatellite.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java b/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java index ba705ca14..78fb03ce7 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemSatellite.java @@ -192,7 +192,7 @@ else if (f == SatelliteProperties.Property.DATA.getFlag()) // Always show power storage in preview (even if no battery modules are installed) list.add(LibVulpes.proxy.getLocalizedString("msg.itemsatellite.pwr") + powerStor); - + if (SatelliteProperties.Property.POWER_GEN.isOfType(flags)) { list.add((powerGen > 0) ? LibVulpes.proxy.getLocalizedString("msg.itemsatellite.pwrgen") + powerGen From b18977049e8dcc03c74abc8694dc27ffc4e74e47 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 30 Oct 2025 00:04:10 +0100 Subject: [PATCH 065/274] Remove super.init() to optimize world initialization // Removed super.init(): it recreates per-world managers (loot/adv/scoreboard/functions) will be reloaded per dimension, slow and breaks custom data. --- .../advancedRocketry/world/WorldServerNotMulti.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/world/WorldServerNotMulti.java b/src/main/java/zmaster587/advancedRocketry/world/WorldServerNotMulti.java index cf3f46408..3614f1737 100644 --- a/src/main/java/zmaster587/advancedRocketry/world/WorldServerNotMulti.java +++ b/src/main/java/zmaster587/advancedRocketry/world/WorldServerNotMulti.java @@ -56,7 +56,9 @@ protected void saveLevel() throws MinecraftException { } public World init() { - super.init(); + // Removed super.init(): it recreates per-world managers (loot/adv/scoreboard/functions) + // will be reloaded per dimension, slow and breaks custom data. + // load weather data from NBT WorldInfoSavedData wi = (WorldInfoSavedData) perWorldStorage.getOrLoadData(WorldInfoSavedData.class, "WorldInfoSavedData"); if (wi == null) { From f593ad400d2e85e00f1330869f6ebe79f14e5845 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 30 Oct 2025 11:59:53 +0100 Subject: [PATCH 066/274] Enhance data type handling in DataStorage Refactor data handling in DataStorage class to improve type management and data addition logic. --- .../advancedRocketry/api/DataStorage.java | 63 +++++++++++++++---- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/api/DataStorage.java b/src/main/java/zmaster587/advancedRocketry/api/DataStorage.java index 5cb5dc963..ac53852fc 100644 --- a/src/main/java/zmaster587/advancedRocketry/api/DataStorage.java +++ b/src/main/java/zmaster587/advancedRocketry/api/DataStorage.java @@ -20,16 +20,25 @@ public DataStorage(DataType data) { } public boolean setData(int data, DataType dataType) { - if (this.dataType == DataStorage.DataType.UNDEFINED) + // If empty/typeless, allow adopting the provided type (unless locked) + if (this.dataType == DataStorage.DataType.UNDEFINED && !this.locked) { this.dataType = dataType; + } if (dataType == DataStorage.DataType.UNDEFINED || dataType == this.dataType) { this.data = Math.min(data, maxData); + + // If we just became empty and are not locked, clear type + if (!this.locked && this.data == 0) { + this.dataType = DataType.UNDEFINED; + } return true; } return false; } + + public int getData() { return data; } @@ -78,20 +87,46 @@ public boolean isLocked() { * @param dataType type to add * @return data amount added */ - public int addData(int data, DataType dataType, boolean commit) { - if ((!this.locked && (dataType == DataStorage.DataType.UNDEFINED)) || dataType == this.dataType || this.dataType == DataStorage.DataType.UNDEFINED) { + public int addData(int data, DataType incomingType, boolean commit) { + // Snapshot + final boolean empty = (this.data == 0); + DataType current = this.dataType; + + // Compute effective type without mutating state on simulation + DataType effective = current; + if (!this.locked && empty) { + effective = (incomingType != DataType.UNDEFINED) ? incomingType : DataType.UNDEFINED; + } + + // Accept if: unlocked+UNDEFINED (wildcard), same type, or typeless + boolean accepts = + (!this.locked && incomingType == DataType.UNDEFINED) || + (incomingType == effective) || + (!this.locked && effective == DataType.UNDEFINED); + + + if (!accepts) return 0; - if (this.dataType == DataStorage.DataType.UNDEFINED) - this.dataType = dataType; + int amountToAdd = Math.min(data, this.maxData - this.data); + if (amountToAdd <= 0) return 0; - int amountToAdd = Math.min(data, this.maxData - this.data); - if (commit) - this.data += amountToAdd; - return amountToAdd; + if (commit) { + // Finalize adoption only on real add + if (!this.locked && this.data == 0) { + this.dataType = (incomingType != DataType.UNDEFINED) ? incomingType : DataType.UNDEFINED; + } + this.data += amountToAdd; + + // If still UNDEFINED but we added concrete data (edge case), solidify + if (this.dataType == DataType.UNDEFINED && incomingType != DataType.UNDEFINED) { + this.dataType = incomingType; + } } - return 0; + return amountToAdd; } + + /** * @param data max amount of data to remove * @return amount of data removed @@ -122,14 +157,18 @@ public void readFromNBT(NBTTagCompound nbt) { dataType = DataType.UNDEFINED; } - - ///TODO: dev compat if (nbt.hasKey("locked")) locked = nbt.getBoolean("locked"); else locked = false; + + // >>> ADD: heal stale type on empty <<< + if (!locked && data == 0) { + dataType = DataType.UNDEFINED; + } } + public enum DataType { UNDEFINED, DISTANCE, From 50c2c2274121de48c3352da0835cd3691436f84a Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 30 Oct 2025 12:01:51 +0100 Subject: [PATCH 067/274] Add ModuleWirelessBufferBar for wireless Tranciever This class provides a minimal, read-only data bar for the wireless transceiver's internal buffer, displaying current data, max data, and data type with appropriate rendering. Avoids confusion about voided data --- .../modules/ModuleWirelessBufferBar.java | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleWirelessBufferBar.java diff --git a/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleWirelessBufferBar.java b/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleWirelessBufferBar.java new file mode 100644 index 000000000..3ec7c6e66 --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/inventory/modules/ModuleWirelessBufferBar.java @@ -0,0 +1,138 @@ +package zmaster587.advancedRocketry.inventory.modules; + +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.resources.I18n; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import zmaster587.advancedRocketry.api.DataStorage; +import zmaster587.advancedRocketry.api.DataStorage.DataType; +import zmaster587.libVulpes.gui.CommonResources; +import zmaster587.libVulpes.inventory.modules.ModuleBase; + +import java.util.LinkedList; +import java.util.List; + +/** + * Minimal, read-only data bar for the wireless transceiver's internal buffer. + * - No buttons + * - No slots + * - Server-authoritative: syncs amount, max, and type via tiny window properties. + */ +public class ModuleWirelessBufferBar extends ModuleBase { + + // Reuse same visuals as ModuleData so it looks consistent + static final int BAR_Y_SIZE = 38; + static final int BAR_X_SIZE = 6; + static final int TEX_OFFSET_X = 0; + static final int TEX_OFFSET_Y = 215; + + private final DataStorage data; // points to your uiBuffer + private int prevAmount = -1; + private int prevMax = -1; + private int prevTypeOrdinal = -1; + + public ModuleWirelessBufferBar(int offsetX, int offsetY, DataStorage data) { + super(offsetX, offsetY); + this.data = data; + this.sizeX = 10; // hitbox-ish; not used for layout + this.sizeY = BAR_Y_SIZE + 12; + } + + @Override + public int numberOfChangesToSend() { + // amount, max, type + return 3; + } + + @Override + public boolean needsUpdate(int localId) { + switch (localId) { + case 0: return data.getData() != prevAmount; + case 1: return data.getMaxData() != prevMax; + case 2: return data.getDataType().ordinal() != prevTypeOrdinal; + default: return false; + } + } + + @Override + protected void updatePreviousState(int localId) { + if (localId == 0) prevAmount = data.getData(); + else if (localId == 1) prevMax = data.getMaxData(); + else if (localId == 2) prevTypeOrdinal = data.getDataType().ordinal(); + } + + @Override + public void sendChanges(net.minecraft.inventory.Container container, + net.minecraft.inventory.IContainerListener crafter, + int variableId, int localId) { + int v; + if (localId == 0) v = data.getData(); + else if (localId == 1) v = data.getMaxData(); + else /* localId == 2 */ v = data.getDataType().ordinal(); + crafter.sendWindowProperty(container, variableId, v); + } + + @Override + public void onChangeRecieved(int slot, int value) { + if (slot == 0) { + // amount (type set below or left unchanged) + data.setData(value, DataType.UNDEFINED); + } else if (slot == 1) { + data.setMaxData(value); + } else if (slot == 2) { + DataType t = DataType.values()[Math.max(0, Math.min(DataType.values().length - 1, value))]; + data.setDataType(t); + } + } + + @SideOnly(Side.CLIENT) + @Override + public void renderForeground(int guiOffsetX, int guiOffsetY, int mouseX, int mouseY, float zLevel, + GuiContainer gui, FontRenderer font) { + int relX = mouseX - offsetX; + int relY = mouseY - offsetY; + if (relX >= 0 && relX < BAR_X_SIZE && relY >= 0 && relY < BAR_Y_SIZE) { + List tt = new LinkedList<>(); + // "Data" + tt.add(net.minecraft.client.resources.I18n.format( + "msg.tooltip.data") + " " + data.getData() + " / " + data.getMaxData()); + + // "Type: %s" with translated type + String typeName = net.minecraft.client.resources.I18n.format(data.getDataType().toString()); + tt.add(net.minecraft.client.resources.I18n.format("msg.wirelessTransciever.type", typeName)); + + + this.drawTooltip(gui, tt, mouseX, mouseY, zLevel, font); + } + } + + + @SideOnly(Side.CLIENT) + @Override + public void renderBackground(GuiContainer gui, int x, int y, int mouseX, int mouseY, FontRenderer font) { + // Bind the correct texture (same sheet as ModuleData) + gui.mc.getTextureManager().bindTexture(CommonResources.genericBackground); + + // Draw only the bar frame (8x40 at UV 176,18) + gui.drawTexturedModalRect(offsetX + x, offsetY + y, 176, 18, 8, 40); + + // Compute fill amount + int max = Math.max(1, data.getMaxData()); + float percent = Math.min(1f, Math.max(0f, data.getData() / (float) max)); + int filled = (int) (percent * BAR_Y_SIZE); + + // Draw the green fill (6 x filled) from UV (0, 215 + (BAR_Y_SIZE - filled)) + // Fill grows upward inside the frame + if (filled > 0) { + gui.drawTexturedModalRect( + offsetX + x + 1, + offsetY + y + 1 + (BAR_Y_SIZE - filled), + 0, + 215 + (BAR_Y_SIZE - filled), + BAR_X_SIZE, + filled + ); + } + } +} From 9aebe12fcb7f879332766ac640712b072be5b746 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 30 Oct 2025 12:36:52 +0100 Subject: [PATCH 068/274] Implement auto-download with exponential backoff Added auto-download functionality with exponential backoff and improved satellite handling. Wireless Transciever opens up for autodownload --- .../tile/satellite/TileSatelliteTerminal.java | 206 ++++++++++++++---- 1 file changed, 166 insertions(+), 40 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java b/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java index 0c805adea..9346726cc 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java @@ -4,6 +4,8 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.EnumFacing; import net.minecraftforge.fml.relauncher.Side; import zmaster587.advancedRocketry.api.AdvancedRocketryBlocks; @@ -30,7 +32,8 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.LinkedList; + +import java.util.ArrayList; import java.util.List; public class TileSatelliteTerminal extends TileInventoriedRFConsumer @@ -38,15 +41,121 @@ public class TileSatelliteTerminal extends TileInventoriedRFConsumer private DataStorage data; + // Auto-download polling with exponential backoff + private static final int AUTO_DL_BASE_INTERVAL_TICKS = 64; // min interval + private static final int AUTO_DL_MAX_INTERVAL_TICKS = 512; // cap + private int autoDlInterval = AUTO_DL_BASE_INTERVAL_TICKS; // current interval + private long nextAutoDlTick = 0L; // worldTime gate + + public TileSatelliteTerminal() { super(10000, 2); data = new DataStorage(); data.setMaxData(1000); } + private final BlockPos.MutableBlockPos mpos = new BlockPos.MutableBlockPos(); + + private boolean hasExtractPlugAdjacent() { + if (world == null) return false; + for (EnumFacing f : EnumFacing.values()) { + mpos.setPos(pos.getX() + f.getFrontOffsetX(), + pos.getY() + f.getFrontOffsetY(), + pos.getZ() + f.getFrontOffsetZ()); + if (!world.isBlockLoaded(mpos)) continue; + + TileEntity te = world.getTileEntity(mpos); + if (te instanceof zmaster587.advancedRocketry.tile.cables.TileWirelessTransciever) { + zmaster587.advancedRocketry.tile.cables.TileWirelessTransciever w = + (zmaster587.advancedRocketry.tile.cables.TileWirelessTransciever) te; + if (w.isEnabledWireless() && w.isExtractModeWireless()) return true; + } + } + return false; + } + + + + // Link+power check using an already-looked-up satellite + private boolean hasLinkAndPower(@Nonnull SatelliteBase sat) { + // must be a data satellite + if (!(sat instanceof zmaster587.advancedRocketry.satellite.SatelliteData)) return false; + + // check range + final int hereDim = zmaster587.advancedRocketry.dimension.DimensionManager + .getEffectiveDimId(world, pos).getId(); + final int satDim = sat.getDimensionId(); + + final boolean inRange = zmaster587.advancedRocketry.util.PlanetaryTravelHelper + .isTravelAnywhereInPlanetarySystem(satDim, hereDim); + if (!inRange) return false; + + // check power + return getUniversalEnergyStored() >= getPowerPerOperation(); + } + + // Keep convenience overload + private void maybeAutoDownloadFromSatellite() { + maybeAutoDownloadFromSatellite(false); + } + + private void maybeAutoDownloadFromSatellite(boolean force) { + if (world == null || world.isRemote) return; + + final long now = world.getTotalWorldTime(); + + if (force) { + autoDlInterval = AUTO_DL_BASE_INTERVAL_TICKS; + nextAutoDlTick = now + autoDlInterval; // avoid same-tick multi-pulls + } else if (now < nextAutoDlTick) { + return; + } + + // Buffer full → just schedule next check + if (data.getData() >= data.getMaxData()) { + nextAutoDlTick = now + autoDlInterval; + return; + } + + // No eligible plug → back off (unless forced) + if (!hasExtractPlugAdjacent()) { + if (!force) autoDlInterval = Math.min(autoDlInterval << 1, AUTO_DL_MAX_INTERVAL_TICKS); + nextAutoDlTick = now + autoDlInterval; + return; + } + + // Hoist satellite once + final SatelliteBase sat = getCachedSatellite(); + if (sat == null) { + if (!force) autoDlInterval = Math.min(autoDlInterval << 1, AUTO_DL_MAX_INTERVAL_TICKS); + nextAutoDlTick = now + autoDlInterval; + return; + } + + + + // No link or power → back off (unless forced) + if (!hasLinkAndPower(sat)) { + if (!force) autoDlInterval = Math.min(autoDlInterval << 1, AUTO_DL_MAX_INTERVAL_TICKS); + nextAutoDlTick = now + autoDlInterval; + return; + } + + // Do the pull + sat.performAction(null, world, pos); + this.energy.extractEnergy(getPowerPerOperation(), false); + + // Success → reset interval + autoDlInterval = AUTO_DL_BASE_INTERVAL_TICKS; + nextAutoDlTick = now + autoDlInterval; + } + + + private static final int[] NO_SLOTS = new int[0]; + @Override @Nonnull - public int[] getSlotsForFace(@Nullable EnumFacing side) { return new int[0]; } + public int[] getSlotsForFace(@Nullable EnumFacing side) { return NO_SLOTS; } @Override public String getModularInventoryName() { @@ -58,7 +167,9 @@ public String getModularInventoryName() { @Override public boolean canPerformFunction() { - return world.getTotalWorldTime() % 16 == 0 && getSatelliteFromSlot(0) != null; + if (world == null) return false; + final long now = world.getTotalWorldTime(); + return (now % 16 == 0) && (now >= nextAutoDlTick); } @Override @@ -66,9 +177,12 @@ public boolean canPerformFunction() { @Override public void performFunction() { - // No client push here anymore; module sync handles display updates. + if (world == null || world.isRemote) return; + maybeAutoDownloadFromSatellite(false); } + + // Old custom packet not used anymore; keep empty to satisfy INetworkMachine @Override public void writeDataToNetwork(ByteBuf out, byte packetId) { } @@ -131,11 +245,21 @@ public void useNetworkData(EntityPlayer player, Side side, byte id, NBTTagCompou } } + @Nullable private SatelliteBase cachedSat = null; + @Override public void setInventorySlotContents(int slot, @Nonnull ItemStack stack) { super.setInventorySlotContents(slot, stack); + if (!world.isRemote && slot == 0) { + cachedSat = (!stack.isEmpty() && stack.getItem() instanceof ItemSatelliteIdentificationChip) + ? ItemSatelliteIdentificationChip.getSatellite(stack) + : null; + maybeAutoDownloadFromSatellite(true); // force reset to base + } } + private @Nullable SatelliteBase getCachedSatellite() { return cachedSat; } + public SatelliteBase getSatelliteFromSlot(int slot) { ItemStack stack = getStackInSlot(slot); if (!stack.isEmpty() && stack.getItem() instanceof ItemSatelliteIdentificationChip) { @@ -146,15 +270,20 @@ public SatelliteBase getSatelliteFromSlot(int slot) { @Override public List getModules(int ID, EntityPlayer player) { - List modules = new LinkedList<>(); + List modules = new ArrayList<>(6); modules.add(new ModulePower(18, 20, this.energy) { @Override public int numberOfChangesToSend() { return 2; } }); - modules.add(new ModuleButton(116, 70, 0, + modules.add(new ModuleButton( + 116, 70, 0, LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.connect"), - this, zmaster587.libVulpes.inventory.TextureResources.buttonBuild)); + this, + zmaster587.libVulpes.inventory.TextureResources.buttonBuild, + LibVulpes.proxy.getLocalizedString("msg.satctrlcenter.autodl_hint") // tooltip + )); + modules.add(new ModuleButton(173, 3, 1, "", this, TextureResources.buttonKill, @@ -219,43 +348,21 @@ public void storeData(int id) { @Override public int extractData(int maxAmount, DataType type, EnumFacing dir, boolean commit) { - // 1) Type guard (unchanged) - if (type != data.getDataType() && data.getDataType() != DataType.UNDEFINED) { - return 0; - } + // 1) Type guard + if (type != data.getDataType() && data.getDataType() != DataType.UNDEFINED) return 0; - // 2) Simulation: report local only (don’t guess satellite yield) - if (!commit) { - int availableLocal = data.getData(); - return Math.min(maxAmount, availableLocal); - } - - // 3) Drain LOCAL first, chip or no chip - int availableLocal = data.getData(); - int toGive = Math.min(maxAmount, availableLocal); - int removed = 0; - if (toGive > 0) { - removed = data.removeData(toGive, true); - } + // 2) Simulation + if (!commit) return Math.min(maxAmount, data.getData()); - // 4) If we have link+power, auto-download to refill AFTER the pull - SatelliteBase sat = getSatelliteFromSlot(0); - boolean inRange = false; - if (sat != null) { - int satDim = sat.getDimensionId(); - int hereDim = DimensionManager.getEffectiveDimId(world, pos).getId(); - inRange = PlanetaryTravelHelper.isTravelAnywhereInPlanetarySystem(satDim, hereDim); - } - boolean hasLink = (sat instanceof SatelliteData) && inRange; - boolean hasPower = getUniversalEnergyStored() >= getPowerPerOperation(); + // 3) Drain LOCAL once + int toGive = Math.min(maxAmount, data.getData()); + int removed = (toGive > 0) ? data.removeData(toGive, true) : 0; - if (hasLink && hasPower) { - sat.performAction(null, world, pos); // same as GUI Download - this.energy.extractEnergy(getPowerPerOperation(), false); - // (No immediate extra removal here; we already served the request.) + // 4) Opportunistic refill (cheap guard inside function) + if (removed > 0) { + maybeAutoDownloadFromSatellite(true); } - - return removed; // may be 0 if buffer empty and no link/power + return removed; } @@ -266,6 +373,25 @@ public int addData(int maxAmount, DataType type, EnumFacing dir, boolean commit) return added; } + @Override + public void onLoad() { + super.onLoad(); + if (!world.isRemote) { + // Rebuild cache from current slot-0 + ItemStack s0 = getStackInSlot(0); + cachedSat = (!s0.isEmpty() && s0.getItem() instanceof ItemSatelliteIdentificationChip) + ? ItemSatelliteIdentificationChip.getSatellite(s0) + : null; + + autoDlInterval = AUTO_DL_BASE_INTERVAL_TICKS; + nextAutoDlTick = Math.min(nextAutoDlTick, world.getTotalWorldTime() + AUTO_DL_MAX_INTERVAL_TICKS); + maybeAutoDownloadFromSatellite(false); + } + } + + + + @Override public boolean canInteractWithContainer(EntityPlayer entity) { return true; } } From 0c363b1ce5b95812cd4e436f3c36dce0c8b2a8c6 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 30 Oct 2025 12:38:38 +0100 Subject: [PATCH 069/274] Refactor TileWirelessTransciever code structure added databar and langkeys to GUI --- .../tile/cables/TileWirelessTransciever.java | 128 ++++++++++++++---- 1 file changed, 99 insertions(+), 29 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java b/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java index b3f5ce015..1f8c9187a 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java @@ -2,7 +2,6 @@ import io.netty.buffer.ByteBuf; import net.minecraft.block.state.IBlockState; -import net.minecraft.block.Block; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; @@ -28,24 +27,28 @@ import zmaster587.libVulpes.inventory.modules.ModuleBase; import zmaster587.libVulpes.inventory.modules.ModuleText; import zmaster587.libVulpes.inventory.modules.ModuleToggleSwitch; +import zmaster587.advancedRocketry.inventory.modules.ModuleWirelessBufferBar; import zmaster587.libVulpes.items.ItemLinker; import zmaster587.libVulpes.network.PacketHandler; import zmaster587.libVulpes.network.PacketMachine; import zmaster587.libVulpes.util.INetworkMachine; + + import javax.annotation.Nonnull; import java.util.LinkedList; import java.util.List; public class TileWirelessTransciever extends TileEntity implements INetworkMachine, IModularInventory, ILinkableTile, IDataHandler, ITickable, IToggleButton { - // How often to transfer data (in ticks) - private int transferIntervalTicks = 20; - // Fixed phase per tile to spread load - private int phase = -1; - // Show network ID (label) - private ModuleText netIdLabel; - + + private int transferIntervalTicks = 20; // How often to transfer data (in ticks) + private int phase = -1; // Fixed phase per tile to spread load + private ModuleText netIdLabel; // Show network ID (label) + private final DataStorage uiBuffer = new DataStorage(); // UI-only, never used for logic + + + // Avoid per-call allocations from DataType.values() // needs update if DataType enum changes private static final DataType[] TYPES = { @@ -65,6 +68,9 @@ public TileWirelessTransciever() { networkID = -1; data = new MultiData(); data.setMaxData(100); + uiBuffer.setMaxData(data.getMaxData()); // UI mirror max should match MultiData max + uiBuffer.setData(0, DataType.UNDEFINED); + syncUiBufferFromMultiData(); toggle = new ModuleToggleSwitch(50, 50, 0, LibVulpes.proxy.getLocalizedString("msg.wirelessTransciever.extract"), this, TextureResources.buttonGeneric, 64, 18, false); toggleSwitch = new ModuleToggleSwitch(160, 5, 1, "", this, zmaster587.libVulpes.inventory.TextureResources.buttonToggleImage, 11, 26, true); @@ -74,8 +80,45 @@ public TileWirelessTransciever() { updateToggleLabel(); // Network ID label - netIdLabel = new ModuleText(40, 72, "Network: -", 0x000000); - netIdLabel.setAlwaysOnTop(true); // optional, so it renders over slots + String initial = LibVulpes.proxy.getLocalizedString("msg.wirelessTransciever.network") + " -"; + netIdLabel = new ModuleText(40, 72, initial, 0x000000); + netIdLabel.setAlwaysOnTop(true); + + } + + // Helpers for other terminals to query state + public boolean isEnabledWireless() { + return this.enabled; + } + public boolean isExtractModeWireless() { + return this.extractMode; + } + + // helper for syncing UI buffer from multiData + private void syncUiBufferFromMultiData() { + int total = 0; + int max = data.getMaxData(); + + int nonZero = 0; + DataType lastTypeWithData = DataType.UNDEFINED; + + for (DataType t : TYPES) { + int amt = data.getDataAmount(t); + if (amt > 0) { + nonZero++; + lastTypeWithData = t; + total += amt; + } + } + + if (total < 0) total = 0; + if (total > max) total = max; + + final DataType displayType = (nonZero == 1) ? lastTypeWithData : DataType.UNDEFINED; + + // Mirror into UI-only storage (server-authoritative; GUI module will poll this) + uiBuffer.setMaxData(max); + uiBuffer.setData(total, displayType); } private void updateToggleLabel() { @@ -222,11 +265,15 @@ public List getModules(int id, EntityPlayer player) { list.add(toggle); list.add(toggleSwitch); - list.add(netIdLabel); + list.add(netIdLabel); + + // Bar-only UI (no buttons/slots). Place it where you want it. + list.add(new ModuleWirelessBufferBar(14, 22, uiBuffer)); return list; } + @Override public String getModularInventoryName() { return "tile.wirelessTransciever.name"; @@ -255,25 +302,31 @@ public void readDataFromNetwork(ByteBuf in, byte packetId, @Override public void useNetworkData(EntityPlayer player, Side side, byte id, NBTTagCompound nbt) { if (!side.isServer()) return; - if (id == 1) { // enable/disable toggle doesn’t touch networks + + if (id == 1) { // enable/disable toggle — always allowed enabled = nbt.getBoolean("state"); return; } - if (networkID == -1) return; // not linked yet; ignore network mutations - if (id == 0) { + if (id == 0) { // extract/insert toggle + // Always update local state so neighbors (like the terminal) can see it extractMode = nbt.getBoolean("state"); updateToggleLabel(); - if (NetworkRegistry.dataNetwork.doesNetworkExist(networkID)) { + + // Only touch the network if we are actually linked + if (networkID != -1 && NetworkRegistry.dataNetwork.doesNetworkExist(networkID)) { NetworkRegistry.dataNetwork.getNetwork(networkID).removeFromAll(this); - if (extractMode) + if (extractMode) { NetworkRegistry.dataNetwork.getNetwork(networkID).addSource(this, EnumFacing.UP); - else + } else { NetworkRegistry.dataNetwork.getNetwork(networkID).addSink(this, EnumFacing.UP); + } } + return; } } + @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); @@ -282,21 +335,25 @@ public void readFromNBT(NBTTagCompound nbt) { enabled = nbt.getBoolean("enabled"); networkID = nbt.getInteger("networkID"); data.readFromNBT(nbt); + syncUiBufferFromMultiData(); //addToNetwork(); toggle.setToggleState(extractMode); updateToggleLabel(); toggleSwitch.setToggleState(enabled); if (world != null && world.isRemote && netIdLabel != null) { - netIdLabel.setText("Network: " + networkID); + String idStr = (networkID == -1) + ? net.minecraft.client.resources.I18n.format("msg.wirelessTransciever.network.unlinked") + : Integer.toString(networkID); + String label = LibVulpes.proxy.getLocalizedString("msg.wirelessTransciever.network"); + netIdLabel.setText(label + idStr); } - } - + @Override @Nonnull public NBTTagCompound writeToNBT(NBTTagCompound nbt) { - super.writeToNBT(nbt); // MOVE: call first + super.writeToNBT(nbt); nbt.setBoolean("mode", extractMode); nbt.setBoolean("enabled", enabled); nbt.setInteger("networkID", networkID); @@ -306,21 +363,35 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { @Override - public int extractData(int maxAmount, DataType type, EnumFacing dir, - boolean commit) { - return enabled ? data.extractData(maxAmount, type, dir, commit) : 0; + public int extractData(int maxAmount, DataType type, EnumFacing dir, boolean commit) { + int out = enabled ? data.extractData(maxAmount, type, dir, commit) : 0; + if (commit && out > 0) { + syncUiBufferFromMultiData(); + } + return out; } @Override - public int addData(int maxAmount, DataType type, EnumFacing dir, - boolean commit) { - return enabled ? data.addData(maxAmount, type, dir, commit) : 0; + public int addData(int maxAmount, DataType type, EnumFacing dir, boolean commit) { + int in = enabled ? data.addData(maxAmount, type, dir, commit) : 0; + if (commit && in > 0) { + syncUiBufferFromMultiData(); + } + return in; } + @Override public void onLoad() { super.onLoad(); + if (!world.isRemote) { + syncUiBufferFromMultiData(); // ensures server-side mirror matches after load + // Ensure booleans reflect current UI widgets on server after load/place + extractMode = toggle.getState(); + enabled = toggleSwitch.getState(); + } + // Server side only if (world == null || world.isRemote) return; @@ -408,8 +479,7 @@ public void update() { // Persist changes; a full block update isn't strictly required each tick if (changed) { this.markDirty(); - // If you want to sync the client meter instantly, you can uncomment: - // world.notifyBlockUpdate(pos, state, state, 3); + syncUiBufferFromMultiData(); } } From 609ecdef7e24d11d779856ac0480072c530b2db5 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 30 Oct 2025 13:00:59 +0100 Subject: [PATCH 070/274] Prevent duplicate chipwrites for same seed and button Added functionality to prevent duplicate chipwrites for the same seed and button in TileObservatory. --- .../tile/multiblock/TileObservatory.java | 84 ++++++++++++++++--- 1 file changed, 74 insertions(+), 10 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java b/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java index 0f3619525..9fa3a02db 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java @@ -49,6 +49,10 @@ public class TileObservatory extends TileMultiPowerConsumer implements IModularInventory, IDataInventory, IGuiCallback { + // Dont allow duplicate chipwrites for the same seed + button + private java.util.HashSet printedButtonsThisSeed = new java.util.HashSet<>(); + private long printedSetSeed = -1; // track which seed the set belongs to + final static int openTime = 100; final static int observationTime = 1000; private static final Block[] lens = {AdvancedRocketryBlocks.blockLens, Blocks.GLASS}; @@ -234,35 +238,56 @@ protected void writeNetworkData(NBTTagCompound nbt) { nbt.setInteger("lastButton", lastButton); if (lastType != null && !lastType.isEmpty()) nbt.setString("lastType", lastType); + + nbt.setLong("printedSetSeed", printedSetSeed); + if (!printedButtonsThisSeed.isEmpty()) { + int[] arr = printedButtonsThisSeed.stream().mapToInt(Integer::intValue).toArray(); + nbt.setIntArray("printedButtons", arr); + } } @Override protected void readNetworkData(NBTTagCompound nbt) { super.readNetworkData(nbt); openProgress = nbt.getInteger("openProgress"); - isOpen = nbt.getBoolean("isOpen"); - viewDistance = nbt.getInteger("viewableDist"); lastSeed = nbt.getLong("lastSeed"); lastButton = nbt.getInteger("lastButton"); lastType = nbt.getString("lastType"); + + printedSetSeed = nbt.getLong("printedSetSeed"); + printedButtonsThisSeed.clear(); + int[] arr = nbt.getIntArray("printedButtons"); + if (arr != null) for (int v : arr) printedButtonsThisSeed.add(v); } + @Override public NBTTagCompound writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); inv.writeToNBT(nbt); + + nbt.setLong("printedSetSeed", printedSetSeed); + if (!printedButtonsThisSeed.isEmpty()) { + int[] arr = printedButtonsThisSeed.stream().mapToInt(Integer::intValue).toArray(); + nbt.setIntArray("printedButtons", arr); + } return nbt; } @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); - inv.readFromNBT(nbt); + + printedSetSeed = nbt.getLong("printedSetSeed"); + printedButtonsThisSeed.clear(); + int[] arr = nbt.getIntArray("printedButtons"); + if (arr != null) for (int v : arr) printedButtonsThisSeed.add(v); } + public LinkedList getDataBus() { return dataCables; } @@ -314,15 +339,20 @@ public List getModules(int ID, EntityPlayer player) { ); // `isOpen` is synchronized to client via writeNetworkData/readNetworkData, so safe to read here. + boolean alreadyPrinted = (lastButton != -1) && printedButtonsThisSeed.contains(lastButton); + if (!isOpen) { - // Show requirements when the dome isn't open (daytime, raining, no sky, etc.) - String tooltip = LibVulpes.proxy.getLocalizedString("msg.observetory.req.open"); - processBtn.setToolTipText(tooltip); + processBtn.setToolTipText(LibVulpes.proxy.getLocalizedString("msg.observetory.req.open")); + processBtn.setEnabled(true); + } else if (alreadyPrinted) { + processBtn.setToolTipText(LibVulpes.proxy.getLocalizedString("msg.observetory.print.already")); + processBtn.setEnabled(false); // <-- } else { - // Keep your normal tooltip when open processBtn.setToolTipText(LibVulpes.proxy.getLocalizedString("msg.observetory.text.processdiscovery")); + processBtn.setEnabled(true); } + // Keep it enabled so the tooltip renders (ModuleButton.isMouseOver checks enabled) processBtn.setEnabled(true); @@ -557,6 +587,9 @@ else if (id == SEED_CHANGE) { lastButton = -1; lastType = ""; + printedButtonsThisSeed.clear(); + printedSetSeed = lastSeed; + // Clear scroll cache when scanning new data ModuleContainerPanYOnlyWithScrollCache.clearScrollCache(); @@ -568,20 +601,51 @@ else if (id == SEED_CHANGE) { } else if (id == PROCESS_CHIP && !world.isRemote) { + // Keep printed set aligned with current seed (covers edge cases like load) + if (printedSetSeed != lastSeed) { + printedButtonsThisSeed.clear(); + printedSetSeed = lastSeed; + } + + // Hard block duplicates for this scan/selection + if (lastButton != -1 && printedButtonsThisSeed.contains(lastButton)) { + // No status message; just refresh UI so tooltip updates + world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 2); + markDirty(); + if (player != null) { + player.openGui(LibVulpes.instance, GuiHandler.guiId.MODULARNOINV.ordinal(), + getWorld(), pos.getX(), pos.getY(), pos.getZ()); + } + return; + } + if (inv.getStackInSlot(2).isEmpty() && isOpen && hasEnergy(500) && lastButton != -1) { ItemStack stack = inv.decrStackSize(1, 1); if (stack != ItemStack.EMPTY && stack.getItem() instanceof ItemAsteroidChip) { - ((ItemAsteroidChip) (stack.getItem())).setUUID(stack, lastSeed + lastButton); - ((ItemAsteroidChip) (stack.getItem())).setType(stack, lastType); - ((ItemAsteroidChip) (stack.getItem())).setMaxData(stack, 1000); + ((ItemAsteroidChip)(stack.getItem())).setUUID(stack, lastSeed + lastButton); + ((ItemAsteroidChip)(stack.getItem())).setType(stack, lastType); + ((ItemAsteroidChip)(stack.getItem())).setMaxData(stack, 1000); inv.setInventorySlotContents(2, stack); extractData(1000, DataType.COMPOSITION, EnumFacing.UP, true); extractData(1000, DataType.MASS, EnumFacing.UP, true); useEnergy(500); + + // Mark this selection as consumed for this seed + printedButtonsThisSeed.add(lastButton); + + // Sync + rebuild GUI so tooltip and button state update immediately + markDirty(); + world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 2); + if (player != null) { + player.openGui(LibVulpes.instance, GuiHandler.guiId.MODULARNOINV.ordinal(), + getWorld(), pos.getX(), pos.getY(), pos.getZ()); + } } } } + + } @Override From 28a9feae12b5d42d9a8f6df41d04aadbe7263650 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 30 Oct 2025 13:46:13 +0100 Subject: [PATCH 071/274] Update modVersion to 2.2.1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 474210579..b16343f8a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ org.gradle.daemon=false # Project mcVersion=1.12.2 forgeVersion=14.23.5.2860 -modVersion=2.2.0 +modVersion=2.2.1 archiveBase=AdvancedRocketry startGitRev=8e676bd From 815567120b13cfa84595ee4307dae1decb535af5 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 1 Nov 2025 14:08:45 +0100 Subject: [PATCH 072/274] Optimize data extraction in TileObservatory Removed redundant data extraction calls for composition and mass. --- .../advancedRocketry/tile/multiblock/TileObservatory.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java b/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java index 9fa3a02db..3f1e3dcc4 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java @@ -627,8 +627,6 @@ else if (id == PROCESS_CHIP && !world.isRemote) { ((ItemAsteroidChip)(stack.getItem())).setMaxData(stack, 1000); inv.setInventorySlotContents(2, stack); - extractData(1000, DataType.COMPOSITION, EnumFacing.UP, true); - extractData(1000, DataType.MASS, EnumFacing.UP, true); useEnergy(500); // Mark this selection as consumed for this seed From a0a6b44d974cbcfea8c142b44db546c38fcab996 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 1 Nov 2025 14:09:47 +0100 Subject: [PATCH 073/274] Fix missing newline at end of ItemSatellite.java Added missing newline at the end of the file. From 9f53a714e17f62c91969843b473f044b06d5bc7e Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 2 Nov 2025 10:36:07 +0100 Subject: [PATCH 074/274] removed useless GUI calculation when player arent even looking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit originally recomputed and updated the GUI text every tick so the ModuleTexts were always “fresh,” even when no GUI was open. --- .../station/TileStationGravityController.java | 153 +++++++++++++----- 1 file changed, 114 insertions(+), 39 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/station/TileStationGravityController.java b/src/main/java/zmaster587/advancedRocketry/tile/station/TileStationGravityController.java index 51446c235..e1f863c37 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/station/TileStationGravityController.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/station/TileStationGravityController.java @@ -1,6 +1,8 @@ package zmaster587.advancedRocketry.tile.station; import io.netty.buffer.ByteBuf; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.NetworkManager; @@ -54,14 +56,95 @@ public static int getMinGravity() { public List getModules(int id, EntityPlayer player) { List modules = new LinkedList<>(); modules.add(moduleGrav); - //modules.add(numThrusters); modules.add(maxGravBuildSpeed); modules.add(redstoneControl); modules.add(targetGrav); modules.add(new ModuleSlider(6, 60, 0, TextureResources.doubleWarningSideBarIndicator, this)); - updateText(); + // inline updater that runs only while GUI is open + modules.add(new ModuleBase(0, 0) { + // --- Caches (live only for GUI lifetime) --- + private SpaceStationObject cached; // strong ref during GUI life + private int cachedId = Integer.MIN_VALUE; // station id for validation + + // last *displayed* keys (so we only update text when the user can see a change) + private int lastGravKey = Integer.MIN_VALUE; // 2dp: round(grav*100) + private int lastRateKey = Integer.MIN_VALUE; // 1dp: round(rate*10) + private int lastTgtKey = Integer.MIN_VALUE; // int + + // localized prefixes + private final String prefixGrav = LibVulpes.proxy.getLocalizedString("msg.stationgravctrl.alt"); + private final String prefixMax = LibVulpes.proxy.getLocalizedString("msg.stationgravctrl.maxaltrate"); + private final String prefixTgt = LibVulpes.proxy.getLocalizedString("msg.stationgravctrl.tgtalt"); + + // tiny formatters (no String.format churn) --- + private String twoDpFromKey(int key) { // key = round(value * 100) + int abs = Math.abs(key), whole = abs / 100, frac = abs % 100; + String s = whole + "." + (frac < 10 ? "0" : "") + frac; + return key < 0 ? "-" + s : s; + } + private String oneDpFromKey(int key) { // key = round(value * 10) + int abs = Math.abs(key), whole = abs / 10, frac = abs % 10; + String s = whole + "." + frac; + return key < 0 ? "-" + s : s; + } + + // Resolve or revalidate the cached station safely. + private boolean ensureStation() { + // Resolve if no cache yet + if (cached == null) { + ISpaceObject so = SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(pos); + if (!(so instanceof SpaceStationObject)) return false; + cached = (SpaceStationObject) so; + cachedId = so.getId(); + return true; + } + // Revalidate in case manager swapped instances + ISpaceObject current = SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(pos); + if (!(current instanceof SpaceStationObject)) { cached = null; cachedId = Integer.MIN_VALUE; return false; } + if (current.getId() != cachedId) { // instance swapped or different station under pos + cached = (SpaceStationObject) current; + cachedId = current.getId(); + } + return true; + } + + @Override + public void renderBackground(GuiContainer gui, int x, int y, int mouseX, int mouseY, FontRenderer font) { + // Only runs while GUI is visible → zero idle cost when closed. + if (!ensureStation()) return; + + // Pull current (client-synced) values + float grav = cached.getProperties().getGravitationalMultiplier(); // e.g. 0.57 + double maxRate = 7200D * cached.getMaxRotationalAcceleration(); // e.g. 144.0 + int tgt = cached.targetGravity; // 10..100 + + // Compute compare keys at display precision + int gravKey = Math.round(grav * 100f); // 2dp + int rateKey = (int)Math.round(maxRate * 10d); // 1dp + int tgtKey = tgt; // int + + // Only touch ModuleText when the visible value actually changes + if (gravKey != lastGravKey) { + moduleGrav.setText(prefixGrav + twoDpFromKey(gravKey)); + lastGravKey = gravKey; + } + if (rateKey != lastRateKey) { + maxGravBuildSpeed.setText(prefixMax + oneDpFromKey(rateKey)); + lastRateKey = rateKey; + } + if (tgtKey != lastTgtKey) { + targetGrav.setText(prefixTgt + tgtKey); + lastTgtKey = tgtKey; + } + } + + @Override public int getSizeX() { return 0; } // no visual footprint + @Override public int getSizeY() { return 0; } + }); + + return modules; } @@ -103,49 +186,41 @@ private void updateText() { @Override public void update() { + if (!(this.world.provider instanceof WorldProviderSpace)) return; - if (this.world.provider instanceof WorldProviderSpace) { + if (!world.isRemote) { + ISpaceObject spaceObject = SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(pos); + if (spaceObject == null) return; - if (!world.isRemote) { - ISpaceObject spaceObject = SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(pos); + if (redstoneControl.getState() == RedstoneState.ON) { + ((SpaceStationObject) spaceObject).targetGravity = (world.getStrongPower(pos) * 6) + 10; + } else if (redstoneControl.getState() == RedstoneState.INVERTED) { + ((SpaceStationObject) spaceObject).targetGravity = Math.abs(15 - world.getStrongPower(pos)) * 6 + 10; + } - if (spaceObject != null) { - if (redstoneControl.getState() == RedstoneState.ON) - ((SpaceStationObject) spaceObject).targetGravity = (world.getStrongPower(pos) * 6) + 10; - else if (redstoneControl.getState() == RedstoneState.INVERTED) - ((SpaceStationObject) spaceObject).targetGravity = Math.abs(15 - world.getStrongPower(pos)) * 6 + 10; - - progress = ((SpaceStationObject) spaceObject).targetGravity - minGravity; - - int targetMultiplier = (ARConfiguration.getCurrentConfig().allowZeroGSpacestations) ? ((SpaceStationObject) spaceObject).targetGravity : Math.max(10, ((SpaceStationObject) spaceObject).targetGravity); - double targetGravity = targetMultiplier / 100D; - double angVel = spaceObject.getProperties().getGravitationalMultiplier(); - double acc = 0.001; - - double difference = targetGravity - angVel; - - if (Math.abs(difference) >= 0.001) { - double finalVel = angVel; - if (difference < 0) { - finalVel = angVel + Math.max(difference, -acc); - } else if (difference > 0) { - finalVel = angVel + Math.min(difference, acc); - } - - spaceObject.getProperties().setGravitationalMultiplier((float) finalVel); - if (!world.isRemote) { - //PacketHandler.sendToNearby(new PacketStationUpdate(spaceObject, PacketStationUpdate.Type.ROTANGLE_UPDATE), this.worldObj.provider.dimensionId, this.xCoord, this.yCoord, this.zCoord, 1024); - PacketHandler.sendToAll(new PacketStationUpdate(spaceObject, PacketStationUpdate.Type.DIM_PROPERTY_UPDATE)); - markDirty(); - } else - updateText(); - } - } - } else - updateText(); + progress = ((SpaceStationObject) spaceObject).targetGravity - minGravity; + + int targetMultiplier = ARConfiguration.getCurrentConfig().allowZeroGSpacestations + ? ((SpaceStationObject) spaceObject).targetGravity + : Math.max(10, ((SpaceStationObject) spaceObject).targetGravity); + + double targetGravity = targetMultiplier / 100D; + double angVel = spaceObject.getProperties().getGravitationalMultiplier(); + double acc = 0.001; + + double difference = targetGravity - angVel; + if (Math.abs(difference) >= 0.001) { + double finalVel = angVel + (difference < 0 ? Math.max(difference, -acc) : Math.min(difference, acc)); + spaceObject.getProperties().setGravitationalMultiplier((float) finalVel); + + // networking unchanged + PacketHandler.sendToAll(new PacketStationUpdate(spaceObject, PacketStationUpdate.Type.DIM_PROPERTY_UPDATE)); + markDirty(); + } } } + @Override public String getModularInventoryName() { return AdvancedRocketryBlocks.blockGravityController.getLocalizedName(); From cf0c0b6548ef6232ca15f43f4263458cdcec9bb8 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 2 Nov 2025 11:43:23 +0100 Subject: [PATCH 075/274] shaving the spam even more. (sendtoall) changed from 20times/s to 4times/sec. reducing packets, and making this really lightweight. old worstcase: 1000packets to all players over 45sec. new: 200packets over 45sec, no noticable change for players --- .../tile/station/TileStationGravityController.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/station/TileStationGravityController.java b/src/main/java/zmaster587/advancedRocketry/tile/station/TileStationGravityController.java index e1f863c37..34d5e4bcb 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/station/TileStationGravityController.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/station/TileStationGravityController.java @@ -36,6 +36,7 @@ public class TileStationGravityController extends TileEntity implements IModular private RedstoneState state = RedstoneState.OFF; private ModuleText moduleGrav, maxGravBuildSpeed, targetGrav; private ModuleRedstoneOutputButton redstoneControl; + private long lastDimPropSyncTick = -5; public TileStationGravityController() { moduleGrav = new ModuleText(6, 15, LibVulpes.proxy.getLocalizedString("msg.stationgravctrl.alt"), 0xaa2020); @@ -213,8 +214,13 @@ public void update() { double finalVel = angVel + (difference < 0 ? Math.max(difference, -acc) : Math.min(difference, acc)); spaceObject.getProperties().setGravitationalMultiplier((float) finalVel); - // networking unchanged - PacketHandler.sendToAll(new PacketStationUpdate(spaceObject, PacketStationUpdate.Type.DIM_PROPERTY_UPDATE)); + long wt = world.getTotalWorldTime(); + + if ((wt - lastDimPropSyncTick) >= 5) { // every 5 ticks ≈ 4 Hz + PacketHandler.sendToAll(new PacketStationUpdate(spaceObject, PacketStationUpdate.Type.DIM_PROPERTY_UPDATE)); + lastDimPropSyncTick = wt; + } + markDirty(); } } From b0340c74390d5ddccfec957c0088c41596d4db74 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Tue, 4 Nov 2025 00:57:42 +0100 Subject: [PATCH 076/274] Enhance TileFluidTank with fluid handling features Added fluid handling capabilities and improved fluid transfer logic. Tower configuration + dropping correct fillevel --- .../advancedRocketry/tile/TileFluidTank.java | 233 ++++++++++++++++-- 1 file changed, 208 insertions(+), 25 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/TileFluidTank.java b/src/main/java/zmaster587/advancedRocketry/tile/TileFluidTank.java index faddcb90f..8cde1f94f 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/TileFluidTank.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/TileFluidTank.java @@ -8,11 +8,13 @@ import net.minecraft.util.EnumFacing; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidTankProperties; import zmaster587.advancedRocketry.api.AdvancedRocketryBlocks; import zmaster587.advancedRocketry.world.util.WorldDummy; import zmaster587.libVulpes.tile.multiblock.hatch.TileFluidHatch; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class TileFluidTank extends TileFluidHatch { @@ -20,6 +22,11 @@ public class TileFluidTank extends TileFluidHatch { private long lastUpdateTime; private boolean fluidChanged; + private boolean removing = false; + private boolean inColumnOp = false; + + public void setRemoving(boolean removing) { this.removing = removing; } + public TileFluidTank() { super(); fluidChanged = false; @@ -30,15 +37,56 @@ public TileFluidTank(int i) { fluidChanged = false; } + // Single, reusable delegating handler (column-aware) + private final net.minecraftforge.fluids.capability.IFluidHandler selfHandler = + new net.minecraftforge.fluids.capability.IFluidHandler() { + @Override public int fill(FluidStack r, boolean doFill) { return TileFluidTank.this.fill(r, doFill); } + @Override public FluidStack drain(FluidStack r, boolean doDrain) { return TileFluidTank.this.drain(r, doDrain); } + @Override public FluidStack drain(int max, boolean doDrain) { return TileFluidTank.this.drain(max, doDrain); } + @Override public IFluidTankProperties[] getTankProperties() { return TileFluidTank.this.getTankProperties(); } + }; + + @Override + public boolean hasCapability(net.minecraftforge.common.capabilities.Capability cap, + @Nullable EnumFacing side) { + if (cap == net.minecraftforge.fluids.capability.CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { + return true; // expose our own handler for fluids, all sides + } + return super.hasCapability(cap, side); // items and anything else come from the parent + } + + + @Override + @SuppressWarnings("unchecked") + public T getCapability(net.minecraftforge.common.capabilities.Capability cap, + @Nullable EnumFacing side) { + if (cap == net.minecraftforge.fluids.capability.CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { + return (T) selfHandler; // never fall back to parent for fluids + } + return super.getCapability(cap, side); // items etc. still via TileFluidHatch (EmbeddedInventory) + } + + + + private void checkForUpdate() { - if (fluidChanged && world instanceof WorldDummy || world.getTotalWorldTime() - lastUpdateTime > MAX_UPDATE) { - this.markDirty(); + if (world == null) return; + if (fluidChanged && (world instanceof WorldDummy || world.getTotalWorldTime() - lastUpdateTime > MAX_UPDATE)) { + markDirty(); world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 2); lastUpdateTime = world.getTotalWorldTime(); fluidChanged = false; } } + private boolean enterColumnOp() { + if (inColumnOp) return false; + inColumnOp = true; + return true; + } + private void exitColumnOp() { inColumnOp = false; } + + @Override public SPacketUpdateTileEntity getUpdatePacket() { return new SPacketUpdateTileEntity(getPos(), getBlockMetadata(), getUpdateTag()); @@ -49,12 +97,24 @@ public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) { readFromNBT(pkt.getNbtCompound()); } + @Override + public NBTTagCompound getUpdateTag() { + return writeToNBT(new NBTTagCompound()); + } + + @Override + public void handleUpdateTag(NBTTagCompound tag) { + readFromNBT(tag); + } + @Override public int fill(FluidStack resource, boolean doFill) { if (resource == null) return 0; + if (world == null || world.isRemote || removing) return 0; + TileFluidTank handler2 = this.getFluidTankInDirection(EnumFacing.UP); //Move up, check if we can fill there, do top down @@ -79,9 +139,10 @@ private int fillInternal2(FluidStack resource, boolean doFill) { if (resource2.amount > 0) amt += super.fill(resource2, doFill); - if (amt > 0 && doFill) + if (amt > 0 && doFill) { fluidChanged = true; - + markDirty(); + } checkForUpdate(); return amt; @@ -92,16 +153,28 @@ public String getModularInventoryName() { return AdvancedRocketryBlocks.blockPressureTank.getLocalizedName(); } + @Nullable + public FluidStack getOwnContentsCopy() { + FluidStack f = fluidTank.getFluid(); + return f == null ? null : f.copy(); + } + + @Override public FluidStack drain(int maxDrain, boolean doDrain) { + if (world == null || world.isRemote || removing) return null; + IFluidHandler handler = this.getFluidTankInDirection(EnumFacing.UP); FluidStack fStack = null; - if (handler != null && handler.getTankProperties()[0].getContents() != null && - fluidTank.getFluid() != null && fluidTank.getFluid().getFluid() == - handler.getTankProperties()[0].getContents().getFluid()) { - - fStack = handler.drain(maxDrain, doDrain); + if (handler != null) { + IFluidTankProperties[] props = handler.getTankProperties(); + FluidStack contents = (props != null && props.length > 0) ? props[0].getContents() : null; + if (contents != null && + fluidTank.getFluid() != null && + fluidTank.getFluid().getFluid() == contents.getFluid()) { + fStack = handler.drain(maxDrain, doDrain); + } } if (fStack != null) return fStack; @@ -110,6 +183,7 @@ public FluidStack drain(int maxDrain, boolean doDrain) { if (fStack2 != null && doDrain) { fluidChanged = true; + markDirty(); } checkForUpdate(); @@ -118,8 +192,8 @@ public FluidStack drain(int maxDrain, boolean doDrain) { } @Override - public FluidStack drain(FluidStack resource, - boolean doDrain) { + public FluidStack drain(FluidStack resource, boolean doDrain) { + if (world == null || world.isRemote || removing || resource == null) return null; if (this.fluidTank.getFluid() == null || resource.getFluid() != this.fluidTank.getFluid().getFluid()) return null; @@ -127,6 +201,7 @@ public FluidStack drain(FluidStack resource, } public TileFluidTank getFluidTankInDirection(EnumFacing direction) { + if (world == null) return null; TileEntity tile = world.getTileEntity(pos.offset(direction)); if (tile instanceof TileFluidTank) { @@ -161,30 +236,138 @@ protected boolean useBucket(int slot, @Nonnull ItemStack stack) { if (bucketUsed) { IFluidHandler handler = getFluidTankInDirection(EnumFacing.DOWN); if (handler != null) { - FluidStack othertank = handler.getTankProperties()[0].getContents(); - if (othertank == null || (othertank.amount < handler.getTankProperties()[0].getCapacity())) - fluidTank.drain(handler.fill(fluidTank.getFluid(), true), true); + IFluidTankProperties[] props = handler.getTankProperties(); + FluidStack contents = (props != null && props.length > 0) ? props[0].getContents() : null; + int capacity = (props != null && props.length > 0) ? props[0].getCapacity() : 0; + + // If the tank below is empty or has room, push fluid down + if (contents == null || (capacity > 0 && contents.amount < capacity)) { + FluidStack ours = fluidTank.getFluid(); + if (ours != null && ours.amount > 0) { + int canMove = handler.fill(new FluidStack(ours.getFluid(), ours.amount), false); + if (canMove > 0) { + FluidStack drained = fluidTank.drain(canMove, true); + int filled = handler.fill(drained, true); + if (filled < drained.amount) { + fluidTank.fill(new FluidStack(drained.getFluid(), drained.amount - filled), true); + } + fluidChanged = true; + markDirty(); + checkForUpdate(); + } + } + } } } return bucketUsed; } - public void onAdjacentBlockUpdated(EnumFacing dir) { - if (dir != EnumFacing.DOWN) - return; + @Override + public void invalidate() { + removing = true; + super.invalidate(); + } - TileFluidTank tank = getFluidTankInDirection(EnumFacing.UP); + @Override + public void onChunkUnload() { + removing = true; + super.onChunkUnload(); + } - if (tank != null && tank.getTankProperties()[0].getContents() != null) { - if (fluidTank.getFluid() == null) { - fluidTank.fill(tank.fluidTank.drain(fluidTank.getCapacity(), true), true); - } else if (tank.getTankProperties()[0].getContents().getFluid() == fluidTank.getFluid().getFluid()) { - fluidTank.fill(tank.drain(fluidTank.getCapacity() - fluidTank.getFluidAmount(), true), true); - tank.fluidTank.drain(fluidTank.getCapacity() - fluidTank.getFluidAmount(), true); + public void onAdjacentBlockUpdated(EnumFacing dir) { + if (world == null || world.isRemote || removing) return; + if (!enterColumnOp()) return; + try { + // If the block BELOW changed, push our fluid down into it and cascade. + if (dir == EnumFacing.DOWN) { + TileFluidTank down = getFluidTankInDirection(EnumFacing.DOWN); + if (down != null) { + FluidStack ours = fluidTank.getFluid(); + if (ours != null && ours.amount > 0) { + IFluidTankProperties[] props = down.getTankProperties(); + FluidStack below = (props != null && props.length > 0) ? props[0].getContents() : null; + boolean compatible = (below == null) || (below.getFluid() == ours.getFluid()); + + if (compatible) { + int room = down.fluidTank.getCapacity() - down.fluidTank.getFluidAmount(); + if (room > 0) { + int toMove = Math.min(room, ours.amount); + + // Use capability: simulate then commit + IFluidHandler downH = down.getCapability( + net.minecraftforge.fluids.capability.CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, + EnumFacing.UP + ); + if (downH != null) { + int canFill = downH.fill(new FluidStack(ours.getFluid(), toMove), false); + if (canFill > 0) { + FluidStack drained = fluidTank.drain(canFill, true); + int filled = downH.fill(drained, true); + if (filled < drained.amount) { + // Put any remainder back to avoid loss + fluidTank.fill(new FluidStack(drained.getFluid(), drained.amount - filled), true); + } + fluidChanged = true; + markDirty(); + checkForUpdate(); + down.markDirty(); + down.checkForUpdate(); + + // Cascade to the next tank down + down.onAdjacentBlockUpdated(EnumFacing.DOWN); + } + } + } + } + } + } + } + // If the block ABOVE changed, pull fluid from the tank above into THIS tank (column-aware). + else if (dir == EnumFacing.UP) { + TileFluidTank up = getFluidTankInDirection(EnumFacing.UP); + if (up != null) { + IFluidTankProperties[] props = up.getTankProperties(); + FluidStack above = (props != null && props.length > 0) ? props[0].getContents() : null; + + if (above != null) { + if (fluidTank.getFluid() == null) { + // We're empty: pull directly from the upper tank's internal store + FluidStack moved = up.drain(fluidTank.getCapacity(), true); + if (moved != null && moved.amount > 0) { + fluidTank.fill(moved, true); + fluidChanged = true; + markDirty(); + checkForUpdate(); + } + } else if (above.getFluid() == fluidTank.getFluid().getFluid()) { + // Same fluid: do a column-aware pull from the upper tank + int room = fluidTank.getCapacity() - fluidTank.getFluidAmount(); + if (room > 0) { + FluidStack moved = up.drain(room, true); + if (moved != null && moved.amount > 0) { + fluidTank.fill(moved, true); + fluidChanged = true; + markDirty(); + checkForUpdate(); + } + } + } + } + } } - this.markDirty(); + // Final safety: ensure any state change is persisted/sent + if (fluidChanged) { + this.markDirty(); + checkForUpdate(); + } + } finally { + exitColumnOp(); } } + + + + } From 8384bdf6ef8a5b6076341be989adeab95011aff0 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Tue, 4 Nov 2025 00:58:13 +0100 Subject: [PATCH 077/274] Refactor ItemBlockFluidTank to improve fluid handling --- .../item/ItemBlockFluidTank.java | 74 ++++++++++++------- 1 file changed, 48 insertions(+), 26 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java b/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java index 614a958ae..f034a86ad 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java @@ -2,6 +2,7 @@ import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemBlock; @@ -10,6 +11,7 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TextFormatting; import net.minecraft.world.World; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTank; @@ -18,6 +20,9 @@ import zmaster587.advancedRocketry.api.ARConfiguration; import zmaster587.advancedRocketry.tile.TileFluidTank; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; @@ -29,48 +34,65 @@ public ItemBlockFluidTank(Block block) { super(block); } + /** Capacity of the item tank in mB, using the same base as the block (64_000 mB), + * preserving fractional multipliers and clamping to int range. */ + private static int getCapMb() { + // Math.round(double) -> long; keep it in long, then clamp to int range + long computed = Math.round(64000d * ARConfiguration.getCurrentConfig().blockTankCapacity); + return (int) Math.min(Integer.MAX_VALUE, Math.max(0L, computed)); + } + @Override + @SideOnly(Side.CLIENT) @ParametersAreNonnullByDefault - public void addInformation(@Nonnull ItemStack stack, @Nullable World world, List list, ITooltipFlag bool) { - super.addInformation(stack, world, list, bool); + public void addInformation(@Nonnull ItemStack stack, @Nullable World world, List list, ITooltipFlag flag) { + super.addInformation(stack, world, list, flag); - FluidStack fluidStack = getFluid(stack); + final int capMb = getCapMb(); + final FluidStack fs = getFluid(stack); - if (fluidStack == null) { - list.add("Empty"); - } else { - list.add(fluidStack.getLocalizedName() + ": " + fluidStack.amount/1000 + "/"+64* ARConfiguration.getCurrentConfig().blockTankCapacity+"b"); - } + final String fluidName = (fs != null && fs.getFluid() != null) ? fs.getLocalizedName() : "Empty"; + final int amount = (fs != null) ? fs.amount : 0; + + list.add("Fluid: " + fluidName); + list.add("Level: " + amount + "/" + capMb + " mB"); } @Override @ParametersAreNonnullByDefault - public boolean placeBlockAt(@Nonnull ItemStack stack, EntityPlayer player, World world, BlockPos pos, EnumFacing side, float hitX, float hitY, float hitZ, IBlockState newState) { - super.placeBlockAt(stack, player, world, pos, side, hitX, hitY, hitZ, newState); - + public boolean placeBlockAt(@Nonnull ItemStack stack, EntityPlayer player, World world, BlockPos pos, + EnumFacing side, float hitX, float hitY, float hitZ, IBlockState newState) { + if (!super.placeBlockAt(stack, player, world, pos, side, hitX, hitY, hitZ, newState)) { + return false; + } TileEntity tile = world.getTileEntity(pos); - if (tile instanceof TileFluidTank) { IFluidHandler handler = tile.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, EnumFacing.DOWN); - ItemStack stack2 = stack.copy(); - stack2.setCount(1); - handler.fill(drain(stack2, Integer.MAX_VALUE), true); + if (handler != null) { + ItemStack one = stack.copy(); + one.setCount(1); + FluidStack drained = drain(one, Integer.MAX_VALUE); + if (drained != null && drained.amount > 0) { // <- guard + handler.fill(drained, true); + } + } } - return true; } - public void fill(@Nonnull ItemStack stack, FluidStack fluid) { + public void fill(@Nonnull ItemStack stack, FluidStack fluid) { NBTTagCompound nbt; - FluidTank tank = new FluidTank((int) (640000* ARConfiguration.getCurrentConfig().blockTankCapacity)); + FluidTank tank = new FluidTank(getCapMb()); if (stack.hasTagCompound()) { nbt = stack.getTagCompound(); tank.readFromNBT(nbt); - } else + } else { nbt = new NBTTagCompound(); + } - tank.fill(fluid, true); + if (fluid != null) {tank.fill(fluid, true); + } tank.writeToNBT(nbt); stack.setTagCompound(nbt); @@ -78,29 +100,29 @@ public void fill(@Nonnull ItemStack stack, FluidStack fluid) { public FluidStack drain(@Nonnull ItemStack stack, int amt) { NBTTagCompound nbt; - FluidTank tank = new FluidTank((int) (640000* ARConfiguration.getCurrentConfig().blockTankCapacity)); + FluidTank tank = new FluidTank(getCapMb()); if (stack.hasTagCompound()) { nbt = stack.getTagCompound(); tank.readFromNBT(nbt); - } else + } else { nbt = new NBTTagCompound(); + } - FluidStack stack2 = tank.drain(amt, true); + FluidStack drained = tank.drain(amt, true); tank.writeToNBT(nbt); stack.setTagCompound(nbt); - return stack2; + return drained; } public FluidStack getFluid(@Nonnull ItemStack stack) { NBTTagCompound nbt; - FluidTank tank = new FluidTank((int) (640000* ARConfiguration.getCurrentConfig().blockTankCapacity)); + FluidTank tank = new FluidTank(getCapMb()); if (stack.hasTagCompound()) { nbt = stack.getTagCompound(); tank.readFromNBT(nbt); } - return tank.getFluid(); } } From 333b45768c9b737c31ae60610eb6d6279e18fc13 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Tue, 4 Nov 2025 00:58:42 +0100 Subject: [PATCH 078/274] Refactor BlockPressurizedFluidTank interactions and methods --- .../block/BlockPressurizedFluidTank.java | 179 ++++++++++++++---- 1 file changed, 139 insertions(+), 40 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockPressurizedFluidTank.java b/src/main/java/zmaster587/advancedRocketry/block/BlockPressurizedFluidTank.java index cd6dffcfa..ed15835d6 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockPressurizedFluidTank.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockPressurizedFluidTank.java @@ -15,7 +15,6 @@ import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.fluids.FluidUtil; -import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler; import zmaster587.advancedRocketry.api.ARConfiguration; import zmaster587.advancedRocketry.api.AdvancedRocketryBlocks; @@ -48,66 +47,139 @@ public boolean hasTileEntity(IBlockState state) { } @Override - public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ) { - TileEntity tile = world.getTileEntity(pos); - - //Do some fancy fluid stuff - if (FluidUtils.containsFluid(player.getHeldItem(hand))) { - FluidUtil.interactWithFluidHandler(player, hand, ((TileFluidHatch) tile).getFluidTank()); - } else if (!world.isRemote) - player.openGui(LibVulpes.instance, guiId.MODULAR.ordinal(), world, pos.getX(), pos.getY(), pos.getZ()); + public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, + EnumFacing side, float hitX, float hitY, float hitZ) { + TileEntity te = world.getTileEntity(pos); + if (!(te instanceof TileFluidTank)) return false; + + // Client: consume the click (let server do the actual transfer) + if (world.isRemote) return true; + + // Try to interact via the tile's FLUID CAPABILITY (column-aware path), + // NOT the raw internal tank. + IFluidHandler handler = te.getCapability( + net.minecraftforge.fluids.capability.CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, + side + ); + if (handler == null) { + handler = te.getCapability( + net.minecraftforge.fluids.capability.CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, + null + ); + } + + boolean acted = false; + if (handler != null) { + // Server-side inventory mutation + acted = net.minecraftforge.fluids.FluidUtil.interactWithFluidHandler(player, hand, handler); + if (acted) { + TileFluidTank tank = (TileFluidTank) te; + // Persist + sync + tank.markDirty(); + tank.onAdjacentBlockUpdated(EnumFacing.DOWN); + tank.onAdjacentBlockUpdated(EnumFacing.UP); + } + } + + // If we didn't perform a fluid interaction, open the GUI + if (!acted) { + player.openGui(zmaster587.libVulpes.LibVulpes.instance, + zmaster587.libVulpes.inventory.GuiHandler.guiId.MODULAR.ordinal(), + world, pos.getX(), pos.getY(), pos.getZ()); + } return true; } + + + @Override + public void onBlockAdded(World world, BlockPos pos, IBlockState state) { + super.onBlockAdded(world, pos, state); + if (world.isRemote) return; // <- add this + TileEntity teAbove = world.getTileEntity(pos.up()); + if (teAbove instanceof TileFluidTank) { + ((TileFluidTank) teAbove).onAdjacentBlockUpdated(EnumFacing.DOWN); + } + } + + @Override @ParametersAreNullableByDefault public TileEntity createTileEntity(World world, IBlockState state) { - return new TileFluidTank((int) (64000 * ARConfiguration.getCurrentConfig().blockTankCapacity)); + long computed = Math.round(64000d * ARConfiguration.getCurrentConfig().blockTankCapacity); + int capMb = (int) Math.min(Integer.MAX_VALUE, Math.max(0L, computed)); + return new TileFluidTank(capMb); } @Override @Nonnull @ParametersAreNullableByDefault - public List getDrops(IBlockAccess world, BlockPos pos, - IBlockState state, int fortune) { - return new LinkedList<>(); - } + public List getDrops(IBlockAccess world, BlockPos pos, IBlockState state, int fortune) { + List drops = new LinkedList<>(); + TileEntity te = world.getTileEntity(pos); - @Override - @ParametersAreNonnullByDefault - public void harvestBlock(World world, EntityPlayer player, BlockPos pos, IBlockState state, @Nullable TileEntity te, @Nonnull ItemStack stack) { + ItemStack out = new ItemStack(AdvancedRocketryBlocks.blockPressureTank); if (te instanceof TileFluidTank) { - IFluidHandler fluid = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, EnumFacing.DOWN); + net.minecraftforge.fluids.FluidStack own = ((TileFluidTank) te).getOwnContentsCopy(); + // 1.12: FluidStack has no isEmpty(); guard on null and amount > 0 + if (own != null && own.amount > 0) { + ((ItemBlockFluidTank) out.getItem()).fill(out, own); + } + } + drops.add(out); + return drops; + } - ItemStack itemstack = new ItemStack(AdvancedRocketryBlocks.blockPressureTank); - ((ItemBlockFluidTank) itemstack.getItem()).fill(itemstack, fluid.drain(Integer.MAX_VALUE, false)); + @Override + public boolean removedByPlayer(IBlockState state, World world, BlockPos pos, EntityPlayer player, boolean willHarvest) { + if (!world.isRemote) { + TileEntity te = world.getTileEntity(pos); + if (te instanceof TileFluidTank) { + ((TileFluidTank) te).setRemoving(true); // <- you’ll add this setter in the tile + } + } + // Let vanilla handle removal; we’ll control drops in harvestBlock + return super.removedByPlayer(state, world, pos, player, willHarvest); + } - EntityItem entityitem; + @Override + public void harvestBlock(World world, EntityPlayer player, BlockPos pos, IBlockState state, + @Nullable TileEntity te, @Nonnull ItemStack tool) { + if (world.isRemote) return; - int j1 = world.rand.nextInt(21) + 10; - float f = world.rand.nextFloat() * 0.8F + 0.1F; - float f1 = world.rand.nextFloat() * 0.8F + 0.1F; - float f2 = world.rand.nextFloat() * 0.8F + 0.1F; + // Creative: no drop, just remove + if (player.capabilities.isCreativeMode) { + world.setBlockToAir(pos); + return; + } - itemstack.setCount(1); - entityitem = new EntityItem(world, (float) pos.getX() + f, (float) pos.getY() + f1, (float) pos.getZ() + f2, new ItemStack(itemstack.getItem(), 1, 0)); - float f3 = 0.05F; - entityitem.motionX = (float) world.rand.nextGaussian() * f3; - entityitem.motionY = (float) world.rand.nextGaussian() * f3 + 0.2F; - entityitem.motionZ = (float) world.rand.nextGaussian() * f3; + // Build ONE drop item from the authoritative server tile we received + ItemStack drop = new ItemStack(AdvancedRocketryBlocks.blockPressureTank); + if (te instanceof TileFluidTank) { + // Make sure the tile knows it's in teardown; block cross-tile moves + ((TileFluidTank) te).setRemoving(true); - if (itemstack.hasTagCompound()) { - entityitem.getItem().setTagCompound(itemstack.getTagCompound().copy()); + net.minecraftforge.fluids.FluidStack own = ((TileFluidTank) te).getOwnContentsCopy(); + if (own != null && own.amount > 0) { + ((ItemBlockFluidTank) drop.getItem()).fill(drop, own); } - world.spawnEntity(entityitem); } - super.harvestBlock(world, player, pos, state, te, stack); + // Spawn our single, correct drop + EntityItem ei = new EntityItem(world, + pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, drop); + world.spawnEntity(ei); + + // Finally remove the block (this will call breakBlock and clear TE) + world.setBlockToAir(pos); } + + + @Override @ParametersAreNonnullByDefault public boolean shouldSideBeRendered(IBlockState blockState, @@ -133,12 +205,39 @@ public boolean isFullCube(IBlockState state) { return false; } + private void notifyTankOfNeighborChange(World world, BlockPos pos, BlockPos fromPos) { + // Only act for strictly adjacent vertical neighbors (no diagonals, no sides) + int dx = fromPos.getX() - pos.getX(); + int dy = fromPos.getY() - pos.getY(); + int dz = fromPos.getZ() - pos.getZ(); + + // Must be exactly one block away on Y, and same X/Z + if (dx != 0 || dz != 0) return; + if (dy != 1 && dy != -1) return; + + TileEntity te = world.getTileEntity(pos); + if (!(te instanceof zmaster587.advancedRocketry.tile.TileFluidTank)) return; + + EnumFacing dir = (dy == 1) ? EnumFacing.UP : EnumFacing.DOWN; + ((zmaster587.advancedRocketry.tile.TileFluidTank) te).onAdjacentBlockUpdated(dir); + } + + + + // Reliable for block state changes (place/break) + @Override + public void neighborChanged(IBlockState state, World world, BlockPos pos, Block blockIn, BlockPos fromPos) { + super.neighborChanged(state, world, pos, blockIn, fromPos); + if (!world.isRemote) notifyTankOfNeighborChange(world, pos, fromPos); + } + + // TE-only neighbor updates (no block state change) @Override - public void onNeighborChange(IBlockAccess world, BlockPos pos, - BlockPos neighbor) { - TileEntity tile = world.getTileEntity(pos); - if (tile instanceof TileFluidTank) - ((TileFluidTank) tile).onAdjacentBlockUpdated(EnumFacing.getFacingFromVector(neighbor.getX() - pos.getX(), neighbor.getY() - pos.getY(), neighbor.getZ() - pos.getZ())); + public void onNeighborChange(IBlockAccess world, BlockPos pos, BlockPos neighbor) { + if (world instanceof World) { + World w = (World) world; + if (!w.isRemote) notifyTankOfNeighborChange(w, pos, neighbor); + } } @Override From 31b926ac5f9fe8813301d11490379c0f925cd4c9 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Tue, 4 Nov 2025 01:27:14 +0100 Subject: [PATCH 079/274] Update language file with new and corrected entries --- .../assets/advancedrocketry/lang/en_US.lang | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/resources/assets/advancedrocketry/lang/en_US.lang b/src/main/resources/assets/advancedrocketry/lang/en_US.lang index f899e02d0..45a2887da 100644 --- a/src/main/resources/assets/advancedrocketry/lang/en_US.lang +++ b/src/main/resources/assets/advancedrocketry/lang/en_US.lang @@ -11,6 +11,7 @@ death.attack.Heat=%1$s died due to overheating death.attack.Heat.player=%1$s died due to overheating entity.advancedRocketry.rocket.name=Rocket entity.rocket.name=Rocket +entity.deployedRocket.name=Rocket entity.hovercraft.name=Hovercraft tile.landingPad.name=Landing Pad @@ -288,6 +289,7 @@ msg.observetory.text.processdiscovery=Process discovery msg.observetory.text.observabledistance=Observable distance: msg.observetory.text.missionTime=Mission Time: msg.observetory.req.open=Observatory must be open (night, clear sky, sky access) or be in space! +msg.observetory.print.already=You already have a chip for this asteroid! msg.tooltip.data=Data msg.tooltip.asteroidselection=Asteroid Selection msg.label.name=Name @@ -366,6 +368,7 @@ msg.satctrlcenter.nolink=No Link... msg.satctrlcenter.info=Info: msg.satctrlcenter.destroysat=Destroy Satellite msg.satctrlcenter.connect=Download +msg.satctrlcenter.autodl_hint=Automatic with Wireless Tranciever (Extract) msg.satbuilder.writesecondchip=Write to Secondary Chip msg.dockingport.target=Target Id msg.dockingport.me=My Id @@ -375,7 +378,7 @@ msg.stationaltctrl.tgtalt=Target Altitude: msg.stationaltctrl.alt=Altitude: msg.stationgravctrl.maxaltrate=Max Gravity Change Rate: msg.stationgravctrl.tgtalt=Target Gravity: -msg.stationgravctrl.alt=Artifical Gravity: +msg.stationgravctrl.alt=Artificial Gravity: msg.stationorientctrl.alt=Angular Velocity: msg.stationorientctrl.tgtalt=Target Ang Vel: msg.warpmon.tab.warp=Warp Selection @@ -421,10 +424,12 @@ msg.rocketbuilder.build=Build msg.rocketbuilder.scan=Scan msg.rocketbuild.combinedthrust=Fuel types cannot be combined! msg.rocketbuilder.alreadyassembled=Rocket already assembled +msg.rocketbuilder.nointake=Missing Gas Intake! +msg.rocketbuilder.notank=Missing Fluidtank! msg.solar.collectingEnergy=Collecting Energy: msg.solar.cannotcollectEnergy=Unable to collect Energy msg.asteroidChip.asteroid=Asteroid -msg.asteroidChip.type=Type +msg.asteroidChip.type=Type: msg.atmanal.atmtype=Atmosphere Type: msg.atmanal.canbreathe=Breathable: msg.biomechanger.scan=Scan Biome @@ -485,13 +490,16 @@ msg.entity.rocket.launch=Launch in T- msg.entity.rocket.launch2=Press [Space] to abort msg.entity.rocket.station=Station msg.entity.rocket.pad=Pad: -msg.entity.rocket.disass=Dissassemble +msg.entity.rocket.disass=Disassemble msg.entity.rocket.seldst=Select Dst msg.entity.rocket.clear=Clear msg.entity.rocket.rcs=RCS Mode msg.entity.rocket.none=None Selected msg.wirelessTransciever.extract=extract msg.wirelessTransciever.insert=insert +msg.wirelessTransciever.type=Type: %s +msg.wirelessTransciever.network=Network: +msg.wirelessTransciever.network.unlinked=Unlinked msg.powerunit.rfpertick=FE/t msg.linker.error.firstMachine=This must be the first machine to link! From 165ea2d95df296d873d9f502ca502b23cb4f2991 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 5 Nov 2025 13:58:19 +0100 Subject: [PATCH 080/274] Using same calculation, safety and performance as parent (rocketassembler) Using same calculation, safety and performance as parent (rocketassembler) allows for all enginetypes/tanks. --- .../tile/TileUnmannedVehicleAssembler.java | 364 ++++++++++++------ 1 file changed, 243 insertions(+), 121 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/TileUnmannedVehicleAssembler.java b/src/main/java/zmaster587/advancedRocketry/tile/TileUnmannedVehicleAssembler.java index 6869bb1ee..2091c4a2c 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/TileUnmannedVehicleAssembler.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/TileUnmannedVehicleAssembler.java @@ -18,6 +18,7 @@ import zmaster587.advancedRocketry.entity.EntityStationDeployedRocket; import zmaster587.advancedRocketry.network.PacketInvalidLocationNotify; import zmaster587.advancedRocketry.util.StorageChunk; +import zmaster587.advancedRocketry.util.WeightEngine; import zmaster587.libVulpes.block.BlockFullyRotatable; import zmaster587.libVulpes.block.RotatableBlock; import zmaster587.libVulpes.network.PacketEntity; @@ -99,64 +100,102 @@ public AxisAlignedBB getRocketPadBounds(World world, BlockPos pos2) { return new AxisAlignedBB(xMin, yCurrent, zMin, xMax, yCurrent + yMax - 1, zMax); } + @Override public void assembleRocket() { - if (bbCache == null || world.isRemote) - return; - //Need to scan again b/c something may have changed - scanRocket(world, getPos(), bbCache); + if (bbCache == null || world.isRemote) return; - if (status != ErrorCodes.SUCCESS) - return; - StorageChunk storageChunk; + // 1) Rescan like the parent (may update stats/status and tighten AABB) + AxisAlignedBB rocketBB = scanRocket(world, getPos(), bbCache); + if (status != ErrorCodes.SUCCESS || rocketBB == null) return; - //Breaks if nothing is there + // 2) Remove replaceable/blacklisted blocks before cutting (uses parent’s helper) + removeReplaceableBlocks(bbCache); + + // 3) Cut the world into a storage chunk + final StorageChunk storageChunk; try { storageChunk = StorageChunk.cutWorldBB(world, bbCache); } catch (NegativeArraySizeException e) { return; } + // 4) Spawn the SD rocket, centered from the *rescanned* bbox + final double cx = rocketBB.minX + (rocketBB.maxX - rocketBB.minX) / 2f + 0.5f; + final double cz = rocketBB.minZ + (rocketBB.maxZ - rocketBB.minZ) / 2f + 0.5f; + final double cy = this.getPos().getY(); - EntityStationDeployedRocket rocket = new EntityStationDeployedRocket(world, storageChunk, stats.copy(), bbCache.minX + (bbCache.maxX - bbCache.minX) / 2f + .5f, getPos().getY(), bbCache.minZ + (bbCache.maxZ - bbCache.minZ) / 2f + .5f); + EntityStationDeployedRocket rocket = + new EntityStationDeployedRocket(world, storageChunk, stats.copy(), cx, cy, cz); - //TODO: setRocketDirection + // Orientations for SD rockets rocket.forwardDirection = RotatableBlock.getFront(world.getBlockState(getPos())).getOpposite(); rocket.launchDirection = EnumFacing.DOWN; - //Change engine direction + // 5) Rotate *all* engine types to match forwardDirection (defensive: only if block supports FACING) for (int x = 0; x < storageChunk.getSizeX(); x++) { for (int y = 0; y < storageChunk.getSizeY(); y++) { for (int z = 0; z < storageChunk.getSizeZ(); z++) { + BlockPos bp = new BlockPos(x, y, z); + IBlockState st = storageChunk.getBlockState(bp); + Block b = st.getBlock(); + + boolean isEngine = (b instanceof BlockRocketMotor) + || (b instanceof BlockBipropellantRocketMotor) + || (b instanceof BlockNuclearRocketMotor); - BlockPos pos3 = new BlockPos(x, y, z); - if (storageChunk.getBlockState(pos3).getBlock() instanceof BlockRocketMotor) { - storageChunk.setBlockState(pos3, storageChunk.getBlockState(pos3).withProperty(BlockFullyRotatable.FACING, rocket.forwardDirection)); + if (isEngine && st.getPropertyKeys().contains(BlockFullyRotatable.FACING)) { + storageChunk.setBlockState(bp, st.withProperty(BlockFullyRotatable.FACING, rocket.forwardDirection)); } } } } + // 6) Spawn + sync world.spawnEntity(rocket); - NBTTagCompound nbtdata = new NBTTagCompound(); - - rocket.writeToNBT(nbtdata); - PacketHandler.sendToNearby(new PacketEntity(rocket, (byte) 0, nbtdata), rocket.world.provider.getDimension(), this.pos, 64); - - stats.reset(); - this.status = ErrorCodes.UNSCANNED; - this.markDirty(); + NBTTagCompound nbt = new NBTTagCompound(); + rocket.writeToNBT(nbt); + PacketHandler.sendToNearby(new PacketEntity(rocket, (byte) 0, nbt), + rocket.world.provider.getDimension(), this.pos, 64); + // Link existing infrastructure (same order as parent) for (IInfrastructure infrastructure : getConnectedInfrastructure()) { rocket.linkInfrastructure(infrastructure); } + + // 7) Directly stamp tile stats from the entity we just created + rocket.recalculateStats(); + this.stats = rocket.stats.copy(); + + // Now finish up — and DO NOT reset after this + this.status = ErrorCodes.FINISHED; + this.markDirty(); + world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3); + + // Rescan to immediately show fresh stats after build + scanRocket(world, getPos(), bbCache); } - //TODO get direction of rocket + @Override public AxisAlignedBB scanRocket(World world, BlockPos pos2, AxisAlignedBB bb) { - // TODO Refactor! Duplicated with TileRocketAssemblingMachine + + // fast-path: rocket entity already present? + if (getBBCache() == null) bbCache = getRocketPadBounds(world, getPos()); + if (bbCache != null) { + final AxisAlignedBB buffered = bbCache.grow(1.0e-4, 1.0e-4, 1.0e-4); + + java.util.List sdr = + world.getEntitiesWithinAABB(EntityStationDeployedRocket.class, buffered); + if (sdr.size() == 1) { + EntityStationDeployedRocket r = sdr.get(0); + r.recalculateStats(); + this.stats = r.stats.copy(); + this.status = ErrorCodes.ALREADY_ASSEMBLED; + return null; + } + } int thrustMonopropellant = 0; int thrustBipropellant = 0; int thrustNuclearNozzleLimit = 0; @@ -169,45 +208,36 @@ public AxisAlignedBB scanRocket(World world, BlockPos pos2, AxisAlignedBB bb) { int fuelCapacityBipropellant = 0; int fuelCapacityOxidizer = 0; int fuelCapacityNuclearWorkingFluid = 0; - int numBlocks = 0; - float drillPower = 0f; + float weight = 0f; + stats.reset(); int actualMinX = (int) bb.maxX, - actualMinY = (int) bb.maxY, - actualMinZ = (int) bb.maxZ, - actualMaxX = (int) bb.minX, - actualMaxY = (int) bb.minY, - actualMaxZ = (int) bb.minZ; - + actualMinY = (int) bb.maxY, + actualMinZ = (int) bb.maxZ, + actualMaxX = (int) bb.minX, + actualMaxY = (int) bb.minY, + actualMaxZ = (int) bb.minZ; + // tighten AABB to non-air for (int xCurr = (int) bb.minX; xCurr <= bb.maxX; xCurr++) { for (int zCurr = (int) bb.minZ; zCurr <= bb.maxZ; zCurr++) { for (int yCurr = (int) bb.minY; yCurr <= bb.maxY; yCurr++) { - - BlockPos currPos = new BlockPos(xCurr, yCurr, zCurr); - - if (!world.isAirBlock(currPos)) { - if (xCurr < actualMinX) - actualMinX = xCurr; - if (yCurr < actualMinY) - actualMinY = yCurr; - if (zCurr < actualMinZ) - actualMinZ = zCurr; - if (xCurr > actualMaxX) - actualMaxX = xCurr; - if (yCurr > actualMaxY) - actualMaxY = yCurr; - if (zCurr > actualMaxZ) - actualMaxZ = zCurr; + BlockPos p = new BlockPos(xCurr, yCurr, zCurr); + if (!world.isAirBlock(p)) { + if (xCurr < actualMinX) actualMinX = xCurr; + if (yCurr < actualMinY) actualMinY = yCurr; + if (zCurr < actualMinZ) actualMinZ = zCurr; + if (xCurr > actualMaxX) actualMaxX = xCurr; + if (yCurr > actualMaxY) actualMaxY = yCurr; + if (zCurr > actualMaxZ) actualMaxZ = zCurr; } } } } - boolean hasSatellite = false; - boolean hasGuidance = false; boolean invalidBlock = false; + boolean foundFluidTank = false; int fluidCapacity = 0; if (verifyScan(bb, world)) { @@ -216,124 +246,216 @@ public AxisAlignedBB scanRocket(World world, BlockPos pos2, AxisAlignedBB bb) { for (int zCurr = (int) bb.minZ; zCurr <= bb.maxZ; zCurr++) { BlockPos currPos = new BlockPos(xCurr, yCurr, zCurr); - if (!world.isAirBlock(currPos)) { - IBlockState state = world.getBlockState(currPos); - Block block = state.getBlock(); - - if (ARConfiguration.getCurrentConfig().blackListRocketBlocks.contains(block)) { - if (!block.isReplaceable(world, currPos)) { - invalidBlock = true; - if (!world.isRemote) - PacketHandler.sendToNearby(new PacketInvalidLocationNotify(new HashedBlockPosition(xCurr, yCurr, zCurr)), world.provider.getDimension(), getPos(), 64); + if (world.isAirBlock(currPos)) continue; + + IBlockState state = world.getBlockState(currPos); + Block block = state.getBlock(); + + // blacklist guard + if (ARConfiguration.getCurrentConfig().blackListRocketBlocks.contains(block)) { + if (!block.isReplaceable(world, currPos)) { + invalidBlock = true; + if (!world.isRemote) { + PacketHandler.sendToNearby( + new PacketInvalidLocationNotify(new HashedBlockPosition(xCurr, yCurr, zCurr)), + world.provider.getDimension(), getPos(), 64 + ); } - continue; } + continue; + } - numBlocks++; - - //If rocketEngine increaseThrust - if (block instanceof IRocketEngine) { - if (block instanceof BlockNuclearRocketMotor) { - nuclearWorkingFluidUseMax += ((IRocketEngine) block).getFuelConsumptionRate(world, xCurr, yCurr, zCurr); - thrustNuclearNozzleLimit += ((IRocketEngine) block).getThrust(world, currPos); - } else if (block instanceof BlockBipropellantRocketMotor) { - bipropellantfuelUse += ((IRocketEngine) block).getFuelConsumptionRate(world, xCurr, yCurr, zCurr); - thrustBipropellant += ((IRocketEngine) block).getThrust(world, currPos); - } else if (block instanceof BlockRocketMotor) { - monopropellantfuelUse += ((IRocketEngine) block).getFuelConsumptionRate(world, xCurr, yCurr, zCurr); - thrustMonopropellant += ((IRocketEngine) block).getThrust(world, currPos); - } + if (ARConfiguration.getCurrentConfig().advancedWeightSystem) { + weight += WeightEngine.INSTANCE.getWeight(world, currPos); + } else { + weight += 1f; // fallback: count blocks + } - stats.addEngineLocation(xCurr - actualMinX - ((float) (actualMaxX - actualMinX) / 2f), yCurr - actualMinY, zCurr - actualMinZ - ((float) (actualMaxZ - actualMinZ) / 2f)); - //stats.addEngineLocation(xCurr - actualMinX, yCurr - actualMinY, zCurr - actualMinZ); + // Engines + thrust/fuel use + if (block instanceof IRocketEngine) { + if (block instanceof BlockNuclearRocketMotor) { + nuclearWorkingFluidUseMax += ((IRocketEngine) block).getFuelConsumptionRate(world, xCurr, yCurr, zCurr); + thrustNuclearNozzleLimit += ((IRocketEngine) block).getThrust(world, currPos); + } else if (block instanceof BlockBipropellantRocketMotor) { + bipropellantfuelUse += ((IRocketEngine) block).getFuelConsumptionRate(world, xCurr, yCurr, zCurr); + thrustBipropellant += ((IRocketEngine) block).getThrust(world, currPos); + } else if (block instanceof BlockRocketMotor) { + monopropellantfuelUse += ((IRocketEngine) block).getFuelConsumptionRate(world, xCurr, yCurr, zCurr); + thrustMonopropellant += ((IRocketEngine) block).getThrust(world, currPos); } - if (block instanceof IFuelTank) { - if (block instanceof BlockFuelTank) { - fuelCapacityMonopropellant += (((IFuelTank) block).getMaxFill(world, currPos, state) * ARConfiguration.getCurrentConfig().fuelCapacityMultiplier); - } else if (block instanceof BlockBipropellantFuelTank) { - fuelCapacityBipropellant += (((IFuelTank) block).getMaxFill(world, currPos, state) * ARConfiguration.getCurrentConfig().fuelCapacityMultiplier); - } else if (block instanceof BlockOxidizerFuelTank) { - fuelCapacityOxidizer += (((IFuelTank) block).getMaxFill(world, currPos, state) * ARConfiguration.getCurrentConfig().fuelCapacityMultiplier); - } else if (block instanceof BlockNuclearFuelTank) { - fuelCapacityNuclearWorkingFluid += (((IFuelTank) block).getMaxFill(world, currPos, state) * ARConfiguration.getCurrentConfig().fuelCapacityMultiplier); - } - } + // center engine location for UI/particles + final float halfX = (actualMaxX - actualMinX + 1) / 2f; + final float halfZ = (actualMaxZ - actualMinZ + 1) / 2f; - if (block instanceof IRocketNuclearCore) { - thrustNuclearReactorLimit += ((IRocketNuclearCore) block).getMaxThrust(world, currPos); - } + final float ex = (xCurr - actualMinX + 0.5f) - halfX; + final float ez = (zCurr - actualMinZ + 0.5f) - halfZ; + final float ey = (yCurr - actualMinY); // <- no +0.5 here + + stats.addEngineLocation(ex, ey, ez); + } - if (block instanceof IIntake) { - stats.setStatTag("intakePower", (int) stats.getStatTag("intakePower") + ((IIntake) block).getIntakeAmt(state)); + // Fuel tanks (family-specific capacities) + if (block instanceof IFuelTank) { + if (block instanceof BlockBipropellantFuelTank) { + fuelCapacityBipropellant += ((IFuelTank) block).getMaxFill(world, currPos, state) * ARConfiguration.getCurrentConfig().fuelCapacityMultiplier; + } else if (block instanceof BlockOxidizerFuelTank) { + fuelCapacityOxidizer += ((IFuelTank) block).getMaxFill(world, currPos, state) * ARConfiguration.getCurrentConfig().fuelCapacityMultiplier; + } else if (block instanceof BlockNuclearFuelTank) { + fuelCapacityNuclearWorkingFluid += ((IFuelTank) block).getMaxFill(world, currPos, state) * ARConfiguration.getCurrentConfig().fuelCapacityMultiplier; + } else if (block instanceof BlockFuelTank) { + fuelCapacityMonopropellant += ((IFuelTank) block).getMaxFill(world, currPos, state) * ARConfiguration.getCurrentConfig().fuelCapacityMultiplier; } + } - TileEntity tile = world.getTileEntity(currPos); - IFluidHandler handler; + // Nuclear core limits + if (block instanceof IRocketNuclearCore) { + thrustNuclearReactorLimit += ((IRocketNuclearCore) block).getMaxThrust(world, currPos); + } - if (tile != null && (handler = tile.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, null)) != null) { - for (IFluidTankProperties info : handler.getTankProperties()) + // Intakes + if (block instanceof IIntake) { + stats.setStatTag("intakePower", + (int) stats.getStatTag("intakePower") + ((IIntake) block).getIntakeAmt(state)); + } + + // Generic fluid capability presence + capacity + TileEntity tile = world.getTileEntity(currPos); + if (tile != null) { + IFluidHandler handler = tile.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, null); + if (handler != null) { + for (IFluidTankProperties info : handler.getTankProperties()) { + if (info == null) continue; + if (!foundFluidTank && info.getCapacity() > 0) foundFluidTank = true; fluidCapacity += info.getCapacity(); + } } } } } } + // --- Nuclear working fluid scaling (guarded) --- int nuclearWorkingFluidUse = 0; if (thrustNuclearNozzleLimit > 0) { - //Only run the number of engines our cores can support - we can't throttle these effectively because they're small, so they shut off if they don't get full power thrustNuclearTotalLimit = Math.min(thrustNuclearNozzleLimit, thrustNuclearReactorLimit); - nuclearWorkingFluidUse = (int) (nuclearWorkingFluidUseMax * (thrustNuclearTotalLimit / (float) thrustNuclearNozzleLimit)); - thrustNuclearTotalLimit = (nuclearWorkingFluidUse * thrustNuclearNozzleLimit) / nuclearWorkingFluidUseMax; + if (nuclearWorkingFluidUseMax > 0) { + nuclearWorkingFluidUse = (int) (nuclearWorkingFluidUseMax * (thrustNuclearTotalLimit / (float) thrustNuclearNozzleLimit)); + thrustNuclearTotalLimit = (nuclearWorkingFluidUse * thrustNuclearNozzleLimit) / nuclearWorkingFluidUseMax; + } else { + nuclearWorkingFluidUse = 0; + thrustNuclearTotalLimit = 0; + } } - //Set fuel stats - //Thrust depending on rocket type + // Write stats stats.setBaseFuelRate(FuelType.LIQUID_MONOPROPELLANT, monopropellantfuelUse); - stats.setBaseFuelRate(FuelType.LIQUID_BIPROPELLANT, bipropellantfuelUse); - stats.setBaseFuelRate(FuelType.LIQUID_OXIDIZER, bipropellantfuelUse); + stats.setBaseFuelRate(FuelType.LIQUID_BIPROPELLANT, bipropellantfuelUse); + stats.setBaseFuelRate(FuelType.LIQUID_OXIDIZER, bipropellantfuelUse); stats.setBaseFuelRate(FuelType.NUCLEAR_WORKING_FLUID, nuclearWorkingFluidUse); - //Fuel storage depending on rocket type + + stats.setFuelRate(FuelType.LIQUID_MONOPROPELLANT, monopropellantfuelUse); + stats.setFuelRate(FuelType.LIQUID_BIPROPELLANT, bipropellantfuelUse); + stats.setFuelRate(FuelType.LIQUID_OXIDIZER, bipropellantfuelUse); + stats.setFuelRate(FuelType.NUCLEAR_WORKING_FLUID, nuclearWorkingFluidUse); + stats.setFuelCapacity(FuelType.LIQUID_MONOPROPELLANT, fuelCapacityMonopropellant); - stats.setFuelCapacity(FuelType.LIQUID_BIPROPELLANT, fuelCapacityBipropellant); - stats.setFuelCapacity(FuelType.LIQUID_OXIDIZER, fuelCapacityOxidizer); - stats.setFuelCapacity(FuelType.NUCLEAR_WORKING_FLUID, thrustNuclearTotalLimit); + stats.setFuelCapacity(FuelType.LIQUID_BIPROPELLANT, fuelCapacityBipropellant); + stats.setFuelCapacity(FuelType.LIQUID_OXIDIZER, fuelCapacityOxidizer); + stats.setFuelCapacity(FuelType.NUCLEAR_WORKING_FLUID, fuelCapacityNuclearWorkingFluid); - //Non-fuel stats - stats.setThrust(Math.max(thrustMonopropellant, thrustBipropellant)); - stats.setWeight(numBlocks); + stats.setThrust(Math.max(Math.max(thrustMonopropellant, thrustBipropellant), thrustNuclearTotalLimit)); + stats.setWeight(weight); stats.setStatTag("liquidCapacity", fluidCapacity); - //Total stats, used to check if the user has tried to apply two or more types of thrust/fuel - int totalFuel = fuelCapacityBipropellant + fuelCapacityNuclearWorkingFluid + fuelCapacityMonopropellant; + // Cross-family checks + int totalFuel = fuelCapacityBipropellant + fuelCapacityNuclearWorkingFluid + fuelCapacityMonopropellant; int totalFuelUse = bipropellantfuelUse + nuclearWorkingFluidUse + monopropellantfuelUse; - //Set status - if (invalidBlock) + if (invalidBlock) { status = ErrorCodes.INVALIDBLOCK; - else if (((fuelCapacityBipropellant > 0 && totalFuel > fuelCapacityBipropellant) || (fuelCapacityMonopropellant > 0 && totalFuel > fuelCapacityMonopropellant) || (fuelCapacityNuclearWorkingFluid > 0 && totalFuel > fuelCapacityNuclearWorkingFluid)) || ((thrustBipropellant > 0 && totalFuelUse > bipropellantfuelUse) || (thrustMonopropellant > 0 && totalFuelUse > monopropellantfuelUse) || (thrustNuclearTotalLimit > 0 && totalFuelUse > nuclearWorkingFluidUse))) + } else if (((fuelCapacityBipropellant > 0 && totalFuel > fuelCapacityBipropellant) + || (fuelCapacityMonopropellant > 0 && totalFuel > fuelCapacityMonopropellant) + || (fuelCapacityNuclearWorkingFluid > 0 && totalFuel > fuelCapacityNuclearWorkingFluid)) + || + ((thrustBipropellant > 0 && totalFuelUse > bipropellantfuelUse) + || (thrustMonopropellant > 0 && totalFuelUse > monopropellantfuelUse) + || (thrustNuclearTotalLimit > 0 && totalFuelUse > nuclearWorkingFluidUse))) { status = ErrorCodes.COMBINEDTHRUST; - else if (getThrust() < getNeededThrust()) + } else if (getThrust() <= getNeededThrust()) { status = ErrorCodes.NOENGINES; - else if (((thrustBipropellant > 0) && getFuel(FuelType.LIQUID_BIPROPELLANT) < getNeededFuel(FuelType.LIQUID_BIPROPELLANT)) || ((thrustMonopropellant > 0) && getFuel(FuelType.LIQUID_MONOPROPELLANT) < getNeededFuel(FuelType.LIQUID_MONOPROPELLANT)) || ((thrustNuclearTotalLimit > 0) && getFuel(FuelType.NUCLEAR_WORKING_FLUID) < getNeededFuel(FuelType.NUCLEAR_WORKING_FLUID))) + } else if (((int) stats.getStatTag("intakePower")) <= 0) { + status = ErrorCodes.NOINTAKE; + } else if (!foundFluidTank) { + status = ErrorCodes.NOTANK; + } else if (thrustBipropellant > 0 && (fuelCapacityBipropellant <= 0 || fuelCapacityOxidizer <= 0)) { + status = ErrorCodes.NOFUEL; // missing one of the required tanks + } else if (((thrustBipropellant > 0) && !hasEnoughFuelUnmanned(FuelType.LIQUID_BIPROPELLANT)) + || ((thrustMonopropellant > 0) && !hasEnoughFuelUnmanned(FuelType.LIQUID_MONOPROPELLANT)) + || ((thrustNuclearTotalLimit > 0) && !hasEnoughFuelUnmanned(FuelType.NUCLEAR_WORKING_FLUID))) { status = ErrorCodes.NOFUEL; - else + } else { status = ErrorCodes.SUCCESS; + } } return new AxisAlignedBB(actualMinX, actualMinY, actualMinZ, actualMaxX, actualMaxY, actualMaxZ); } - public float getNeededFuel(@Nonnull FuelType fuelType) { - return 1; + private boolean hasEnoughFuelUnmanned(@Nonnull FuelType family) { + // SD flight: acceleration in entity code is ≈ 0.005 blocks/tick^2 + final float a_station = 0.005f; + final float targetS = 128f; // SD rocket switches to orbit after ~128 blocks + + float t; // seconds (ticks) we can sustain full burn + + switch (family) { + case LIQUID_MONOPROPELLANT: { + final int cap = stats.getFuelCapacity(FuelType.LIQUID_MONOPROPELLANT); + final int rate = stats.getBaseFuelRate(FuelType.LIQUID_MONOPROPELLANT); + if (cap <= 0 || rate <= 0) return false; + t = cap / (float) rate; + break; + } + + case LIQUID_BIPROPELLANT: { + // Both streams must exist; consume in lockstep at their own rates. + final int capFuel = stats.getFuelCapacity(FuelType.LIQUID_BIPROPELLANT); + final int capOx = stats.getFuelCapacity(FuelType.LIQUID_OXIDIZER); + final int rateFuel= stats.getBaseFuelRate(FuelType.LIQUID_BIPROPELLANT); + final int rateOx = stats.getBaseFuelRate(FuelType.LIQUID_OXIDIZER); + if (capFuel <= 0 || capOx <= 0 || rateFuel <= 0 || rateOx <= 0) return false; + + final float tFuel = capFuel / (float) rateFuel; + final float tOx = capOx / (float) rateOx; + t = Math.min(tFuel, tOx); // limiting stream dictates burn time + break; + } + + case NUCLEAR_WORKING_FLUID: { + final int cap = stats.getFuelCapacity(FuelType.NUCLEAR_WORKING_FLUID); + final int rate = stats.getBaseFuelRate(FuelType.NUCLEAR_WORKING_FLUID); + if (cap <= 0 || rate <= 0) return false; + t = cap / (float) rate; + break; + } + + default: + return false; + } + + // distance under constant accel: s = 0.5 * a * t^2 + final float sCan = 0.5f * a_station * t * t; + return sCan >= targetS; } + + //No additional scanning is needed @Override protected boolean verifyScan(AxisAlignedBB bb, World world) { return true; } -} \ No newline at end of file +} From a5db4c9b8b832887138225caf359afd30bca8ac9 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 5 Nov 2025 13:58:58 +0100 Subject: [PATCH 081/274] Change intake amount from 10 to 1 part of a larger rewrite to gasmission timings --- .../java/zmaster587/advancedRocketry/block/BlockIntake.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockIntake.java b/src/main/java/zmaster587/advancedRocketry/block/BlockIntake.java index 706f2f883..33a7260fe 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockIntake.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockIntake.java @@ -13,7 +13,7 @@ public BlockIntake(Material material) { @Override public int getIntakeAmt(IBlockState state) { - return 10; + return 1; } } From 45c0bacd57af84dc4356504289291400c71ac30d Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 5 Nov 2025 14:00:22 +0100 Subject: [PATCH 082/274] Add gas harvest amount multiplier and infinite option Added configuration options for gas harvesting. --- .../advancedRocketry/api/ARConfiguration.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/api/ARConfiguration.java b/src/main/java/zmaster587/advancedRocketry/api/ARConfiguration.java index 617d27f1f..9051d7528 100644 --- a/src/main/java/zmaster587/advancedRocketry/api/ARConfiguration.java +++ b/src/main/java/zmaster587/advancedRocketry/api/ARConfiguration.java @@ -165,6 +165,10 @@ public class ARConfiguration { @ConfigProperty(needsSync = true) public double gasCollectionMult; @ConfigProperty(needsSync = true) + public double gasHarvestAmountMultiplier; + @ConfigProperty(needsSync = true) + public boolean gasHarvestInfinite; + @ConfigProperty(needsSync = true) public double terraformSpeed; @ConfigProperty public boolean terraformRequiresFluid; @@ -412,6 +416,16 @@ public static void loadPreInit() { arConfig.gasCollectionMult = config.get(MISSION, "gasMissionMultiplier", 1.0, "Multiplier for the amount of time gas collection missions take").getDouble(); harvestableGasses = config.getStringList("harvestableGasses", MISSION, new String[]{}, "list of fluid names that can be harvested as Gas from any gas giant"); spawnableGasses = config.getStringList("spawnableGasses", MISSION, new String[]{"hydrogen;125;1600;1.0", "helium;125;1600;0.9", "helium3;175;1600;0.2", "oxygen;0;124;1.0", "nitrogen;0;124;1.0", "ammonia;0;124;0.75", "methane;0;124;0.25"}, "list of fluid names that can be spawned as a gas giant. Format is fluid;minGravity;maxGravity;chance"); + arConfig.gasHarvestAmountMultiplier = config.get( + MISSION, "gasHarvestAmountMultiplier", 1.0, + "Per-mission harvest cap = 64,000 mB × multiplier. Actual yield = min(cap, total free tank space at launch). Ignored if gasHarvestInfinite=true." + ).getDouble(); + + arConfig.gasHarvestInfinite = config.get( + MISSION, "gasHarvestInfinite", false, + "Fill all attached tanks up to their total free space at launch, capped at 2,147,483,647 mB per mission." + ).getBoolean(); + //Energy Production arConfig.solarGeneratorMult = config.get(ENERGY, "solarGeneratorMultiplier", 1, "Amount of power per tick the solar generator should produce").getInt(); From 3b003f763a2e1690cffddf6c081aaf67381a664e Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 5 Nov 2025 14:01:49 +0100 Subject: [PATCH 083/274] part of update for child (concerning gas missions) --- .../tile/TileRocketAssemblingMachine.java | 71 +++++++++++++------ 1 file changed, 51 insertions(+), 20 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java b/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java index dc08ae779..1b05536af 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java @@ -282,7 +282,7 @@ public AxisAlignedBB scanRocket(World world, BlockPos pos2, AxisAlignedBB bb) { double buffer = 0.0001; AxisAlignedBB bufferedBB = bbCache.grow(buffer, buffer, buffer); List rockets = world.getEntitiesWithinAABB(EntityRocket.class, bufferedBB); - if (rockets.size() == 1){ // only if axactly one rocket is here + if (rockets.size() == 1){ // only if exactly one rocket is here rockets.get(0).recalculateStats(); this.stats = rockets.get(0).stats; status = ErrorCodes.ALREADY_ASSEMBLED; // to prevent assembly @@ -443,17 +443,23 @@ public AxisAlignedBB scanRocket(World world, BlockPos pos2, AxisAlignedBB bb) { thrustNuclearTotalLimit = (nuclearWorkingFluidUse * thrustNuclearNozzleLimit) / nuclearWorkingFluidUseMax; } - //Set fuel stats - //Thrust depending on rocket type + // Set fuel stats + // Thrust depending on rocket type stats.setBaseFuelRate(FuelType.LIQUID_MONOPROPELLANT, monopropellantfuelUse); - stats.setBaseFuelRate(FuelType.LIQUID_BIPROPELLANT, bipropellantfuelUse); - stats.setBaseFuelRate(FuelType.LIQUID_OXIDIZER, bipropellantfuelUse); + stats.setBaseFuelRate(FuelType.LIQUID_BIPROPELLANT, bipropellantfuelUse); + stats.setBaseFuelRate(FuelType.LIQUID_OXIDIZER, bipropellantfuelUse); stats.setBaseFuelRate(FuelType.NUCLEAR_WORKING_FLUID, nuclearWorkingFluidUse); - //Fuel storage depending on rocket type - stats.setFuelCapacity(FuelType.LIQUID_MONOPROPELLANT, fuelCapacityMonopropellant); - stats.setFuelCapacity(FuelType.LIQUID_BIPROPELLANT, fuelCapacityBipropellant); - stats.setFuelCapacity(FuelType.LIQUID_OXIDIZER, fuelCapacityOxidizer); - stats.setFuelCapacity(FuelType.NUCLEAR_WORKING_FLUID, fuelCapacityNuclearWorkingFluid); + + stats.setFuelRate(FuelType.LIQUID_MONOPROPELLANT, monopropellantfuelUse); + stats.setFuelRate(FuelType.LIQUID_BIPROPELLANT, bipropellantfuelUse); + stats.setFuelRate(FuelType.LIQUID_OXIDIZER, bipropellantfuelUse); + stats.setFuelRate(FuelType.NUCLEAR_WORKING_FLUID, nuclearWorkingFluidUse); + + // Fuel storage depending on rocket type + stats.setFuelCapacity(FuelType.LIQUID_MONOPROPELLANT, fuelCapacityMonopropellant); + stats.setFuelCapacity(FuelType.LIQUID_BIPROPELLANT, fuelCapacityBipropellant); + stats.setFuelCapacity(FuelType.LIQUID_OXIDIZER, fuelCapacityOxidizer); + stats.setFuelCapacity(FuelType.NUCLEAR_WORKING_FLUID, fuelCapacityNuclearWorkingFluid); //Non-fuel stats stats.setWeight(weight); @@ -465,27 +471,50 @@ public AxisAlignedBB scanRocket(World world, BlockPos pos2, AxisAlignedBB bb) { int totalFuelUse = bipropellantfuelUse + nuclearWorkingFluidUse + monopropellantfuelUse; //System.out.println("rocket fuel use:"+totalFuelUse); + // --- Biprop requirement: if any bipropellant thrust exists, require both tanks --- + if (thrustBipropellant > 0) { + if (fuelCapacityBipropellant <= 0 || fuelCapacityOxidizer <= 0) { + status = ErrorCodes.NOFUEL; // or a dedicated error if you add one + return new AxisAlignedBB(actualMinX, actualMinY, actualMinZ, actualMaxX, actualMaxY, actualMaxZ); + } + } + //Set status - if (invalidBlock) + if (invalidBlock) { status = ErrorCodes.INVALIDBLOCK; - else if (((fuelCapacityBipropellant > 0 && totalFuel > fuelCapacityBipropellant) || (fuelCapacityMonopropellant > 0 && totalFuel > fuelCapacityMonopropellant) || (fuelCapacityNuclearWorkingFluid > 0 && totalFuel > fuelCapacityNuclearWorkingFluid)) + + } else if (((fuelCapacityBipropellant > 0 && totalFuel > fuelCapacityBipropellant) + || (fuelCapacityMonopropellant > 0 && totalFuel > fuelCapacityMonopropellant) + || (fuelCapacityNuclearWorkingFluid > 0 && totalFuel > fuelCapacityNuclearWorkingFluid)) || - ((thrustBipropellant > 0 && totalFuelUse > bipropellantfuelUse) || (thrustMonopropellant > 0 && totalFuelUse > monopropellantfuelUse) || (thrustNuclearTotalLimit > 0 && totalFuelUse > nuclearWorkingFluidUse))) + ((thrustBipropellant > 0 && totalFuelUse > bipropellantfuelUse) + || (thrustMonopropellant > 0 && totalFuelUse > monopropellantfuelUse) + || (thrustNuclearTotalLimit > 0 && totalFuelUse > nuclearWorkingFluidUse))) { status = ErrorCodes.COMBINEDTHRUST; - else if (!hasGuidance && !hasSatellite) + + } else if (!hasGuidance && !hasSatellite) { status = ErrorCodes.NOGUIDANCE; - else if (getThrust() <= getNeededThrust()) + + } else if (getThrust() <= getNeededThrust()) { status = ErrorCodes.NOENGINES; - else if (((thrustBipropellant > 0) && !hasEnoughFuel(FuelType.LIQUID_BIPROPELLANT)) || ((thrustMonopropellant > 0) && !hasEnoughFuel(FuelType.LIQUID_MONOPROPELLANT)) || ((thrustNuclearTotalLimit > 0) && !hasEnoughFuel(FuelType.NUCLEAR_WORKING_FLUID))) + + } else if (thrustBipropellant > 0 && (fuelCapacityBipropellant <= 0 || fuelCapacityOxidizer <= 0)) { + // Biprop engines require BOTH bipropellant AND oxidizer capacity + status = ErrorCodes.NOFUEL; + + } else if (((thrustBipropellant > 0) && !hasEnoughFuel(FuelType.LIQUID_BIPROPELLANT)) + || ((thrustMonopropellant > 0) && !hasEnoughFuel(FuelType.LIQUID_MONOPROPELLANT)) + || ((thrustNuclearTotalLimit > 0) && !hasEnoughFuel(FuelType.NUCLEAR_WORKING_FLUID))) { status = ErrorCodes.NOFUEL; - else + + } else { status = ErrorCodes.SUCCESS; + } } - return new AxisAlignedBB(actualMinX, actualMinY, actualMinZ, actualMaxX, actualMaxY, actualMaxZ); } - private void removeReplaceableBlocks(AxisAlignedBB bb) { + protected void removeReplaceableBlocks(AxisAlignedBB bb) { for (int yCurr = (int) bb.minY; yCurr <= bb.maxY; yCurr++) { for (int xCurr = (int) bb.minX; xCurr <= bb.maxX; xCurr++) { for (int zCurr = (int) bb.minZ; zCurr <= bb.maxZ; zCurr++) { @@ -1197,7 +1226,9 @@ protected enum ErrorCodes { COMBINEDTHRUST(LibVulpes.proxy.getLocalizedString("msg.rocketbuild.combinedthrust")), ALREADY_ASSEMBLED(LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.alreadyassembled")), UNSCANNED_STATION(LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.unscanned_station")), - FAIL_CUT(LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.fail_cut")); + FAIL_CUT(LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.fail_cut")), + NOINTAKE(LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.nointake")), + NOTANK(LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.notank")); String code; From 691eb289fa55b7a04fd9b23747d0a9b460b308e9 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 5 Nov 2025 14:02:48 +0100 Subject: [PATCH 084/274] Enhance gas collection and fuel consumption logic Added plannedHarvestMb to track gas collection capacity and updated fuel consumption logic for ascent. Allows all enginetypes and tanks like normal rocket. reused logic from parent --- .../entity/EntityStationDeployedRocket.java | 175 +++++++++++++++++- 1 file changed, 167 insertions(+), 8 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/entity/EntityStationDeployedRocket.java b/src/main/java/zmaster587/advancedRocketry/entity/EntityStationDeployedRocket.java index 228d593d5..0f6f48d83 100644 --- a/src/main/java/zmaster587/advancedRocketry/entity/EntityStationDeployedRocket.java +++ b/src/main/java/zmaster587/advancedRocketry/entity/EntityStationDeployedRocket.java @@ -26,14 +26,13 @@ import zmaster587.advancedRocketry.api.RocketEvent.RocketLaunchEvent; import zmaster587.advancedRocketry.api.RocketEvent.RocketPreLaunchEvent; import zmaster587.advancedRocketry.api.StatsRocket; -import zmaster587.advancedRocketry.api.atmosphere.AtmosphereRegister; +import zmaster587.advancedRocketry.api.fuel.FuelRegistry; import zmaster587.advancedRocketry.api.stations.ISpaceObject; import zmaster587.advancedRocketry.client.SoundRocketEngine; import zmaster587.advancedRocketry.dimension.DimensionManager; import zmaster587.advancedRocketry.dimension.DimensionProperties; import zmaster587.advancedRocketry.mission.MissionGasCollection; import zmaster587.advancedRocketry.network.PacketSatellite; -import zmaster587.advancedRocketry.network.PacketSatellitesUpdate; import zmaster587.advancedRocketry.stations.SpaceObjectManager; import zmaster587.advancedRocketry.util.AudioRegistry; import zmaster587.advancedRocketry.util.StorageChunk; @@ -62,6 +61,7 @@ public class EntityStationDeployedRocket extends EntityRocket { private ModuleText atmText; private short gasId; private Ticket ticket; + private long plannedHarvestMb = 0L; // planned total mB to attempt this mission public EntityStationDeployedRocket(World world) { super(world); @@ -121,8 +121,21 @@ public void launch() { setInFlight(true); return; } - if (getFuelAmount(getRocketFuelType()) < getFuelCapacity(getRocketFuelType())) - return; + + if (storage != null) { + storage.recalculateStats(this.stats); // keeps everything else in sync + } + + + FuelRegistry.FuelType rt = getRocketFuelType(); + if (rt != null && ARConfiguration.getCurrentConfig().rocketRequireFuel) { + if (getFuelAmount(rt) < getFuelCapacity(rt)) return; + + if (rt == FuelRegistry.FuelType.LIQUID_BIPROPELLANT) { + if (getFuelAmount(FuelRegistry.FuelType.LIQUID_OXIDIZER) + < getFuelCapacity(FuelRegistry.FuelType.LIQUID_OXIDIZER)) return; + } + } ISpaceObject spaceObj; if (world.provider.getDimension() == ARConfiguration.getCurrentConfig().spaceDimId && @@ -281,7 +294,12 @@ public void onUpdate() { motionX += acc * forwardDirection.getFrontOffsetX(); motionY += acc * forwardDirection.getFrontOffsetY(); motionZ += acc * forwardDirection.getFrontOffsetZ(); - setFuelAmount(getRocketFuelType(), getFuelAmount(getRocketFuelType()) - 1); + + // server-side fuel consumption for thrust ticks + if (!world.isRemote && burningFuel) { + // only consume if we actually need to (respect config + biprop pairing) + tryConsumeAscentFuel(); + } } if (!world.isRemote && this.getDistance(actualLaunchLocation.x, actualLaunchLocation.y, actualLaunchLocation.z) > 128) { @@ -402,14 +420,64 @@ public void onOrbitReached() { return; } - //one intake with a 1 bucket tank should take 100 seconds - float intakePower = (Integer) stats.getStatTag("intakePower"); + // --- Plan harvest & cap duration by what we can actually get --- + final net.minecraftforge.fluids.Fluid targetFluid = + properties.getHarvestableGasses().get(gasId); + + // (1) config harvest cap (mB) + final boolean infinite = ARConfiguration.getCurrentConfig().gasHarvestInfinite; + final double mult = Math.max(0.0, ARConfiguration.getCurrentConfig().gasHarvestAmountMultiplier); + final long base64k = 64_000L; + final int harvestCapMb = infinite + ? Integer.MAX_VALUE + : (int) Math.min(Integer.MAX_VALUE, Math.round(base64k * mult)); + + // (2) free capacity for this gas across all rocket tanks (simulate) + int freeMb = 0; + for (TileEntity tile : this.storage.getFluidTiles()) { + net.minecraftforge.fluids.capability.IFluidHandler h = + tile.getCapability(net.minecraftforge.fluids.capability.CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, null); + if (h == null) continue; + int couldTake = h.fill(new net.minecraftforge.fluids.FluidStack(targetFluid, Integer.MAX_VALUE), false); + if (couldTake > 0) { + freeMb = (int) Math.min((long) Integer.MAX_VALUE, (long) freeMb + (long) couldTake); + } + } + + // (3) final planned harvest for this mission + this.plannedHarvestMb = Math.max(0, Math.min(harvestCapMb, freeMb)); + + // (4) duration = min( baseCurveTime(capForTiming), ceil(plannedHarvest / rate) ) + // Keep your curve and denominator 25 + final int liquidCapacity = safeTagInt(stats, "liquidCapacity"); + final int intake = safeTagInt(stats, "intakePower"); + final long rate = DENOM_PER_INTAKE * (long) Math.max(1, intake); // mB/s + + final long durationSeconds; + if (intake <= 0 || this.plannedHarvestMb <= 0) { + durationSeconds = 360L; // safety default + } else { + // IMPORTANT: cap the capacity used by the curve to the harvest cap, + // so durations match the table when harvest is smaller than tank size. + final int capForTiming = infinite ? liquidCapacity : Math.min(liquidCapacity, harvestCapMb); + + double effCapMb = computeEffectiveCapacityMb(capForTiming); + long baseSeconds = (long) Math.floor(effCapMb / (double) rate); + long capSeconds = (long) Math.ceil((double) this.plannedHarvestMb / (double) rate); + + durationSeconds = Math.max(1L, Math.min(baseSeconds, capSeconds)); + } + final long durationTicks = Math.max(1L, durationSeconds * 20L); + + + MissionGasCollection miningMission = + new MissionGasCollection(durationTicks, this, connectedInfrastructure, targetFluid); - MissionGasCollection miningMission = new MissionGasCollection(intakePower == 0 ? 360 : (long) (2 * ((int) stats.getStatTag("liquidCapacity") / intakePower)), this, connectedInfrastructure, properties.getHarvestableGasses().get(gasId)); miningMission.setDimensionId(properties.getId()); properties.addSatellite(miningMission); + // broadcast if (!world.isRemote) { PacketHandler.sendToAll(new PacketSatellite(miningMission)); } @@ -495,8 +563,99 @@ public void writeMissionPersistentNBT(NBTTagCompound nbt) { nbt.setShort("gas", gasId); + nbt.setLong("plannedHarvestMb", Math.max(0L, this.plannedHarvestMb)); + } + + // handle possible bad data gracefully + private static int safeTagInt(StatsRocket s, String key) { + Object v = s.getStatTag(key); + return (v instanceof Number) ? Math.max(0, ((Number) v).intValue()) : 0; + } + + // --- Nonlinear gas mission timing (alpha = 0.2) --- + // effectiveCapacity = BASE_CAP * (liquidCapacity / BASE_CAP)^ALPHA + // baseSeconds = floor( effectiveCapacity / (DENOM_PER_INTAKE * intakePower) ) + // finalSeconds = min(baseSeconds, ceil(plannedHarvestMb / (DENOM_PER_INTAKE * intakePower))) + private static final long BASE_CAP = 64_000L; // 64,000 mB (64 buckets) + private static final double ALPHA = 0.2d; // gentle sublinear scaling + private static final long DENOM_PER_INTAKE = 25L; // you picked "25 * intakePower" + + // Returns the effective capacity (mB) from your nonlinear curve. + private static double computeEffectiveCapacityMb(int liquidCapacity) { + double ratio = Math.max(1.0d, ((double) liquidCapacity) / (double) BASE_CAP); + return (double) BASE_CAP * Math.pow(ratio, ALPHA); } + private static long computeMissionDurationSeconds(int liquidCapacity, int intakePower) { + // default fallback if bad data + if (intakePower <= 0) return 360L; // 6 minutes safety default + + // scale in double to avoid precision loss, clamp ratio >= 1 to avoid shrinking below base + double ratio = Math.max(1.0d, ((double) liquidCapacity) / (double) BASE_CAP); + double effectiveCapacity = (double) BASE_CAP * Math.pow(ratio, ALPHA); + + long denom = DENOM_PER_INTAKE * (long) Math.max(1, intakePower); + long secs = (long) Math.floor(effectiveCapacity / (double) denom); + + return Math.max(1L, secs); // never zero + } + + // Consume ascent fuel exactly like the parent rocket does. + // Returns true if fuel was consumed this tick (or fuel is not required by config). + private boolean tryConsumeAscentFuel() { + if (!ARConfiguration.getCurrentConfig().rocketRequireFuel) + return true; + + final FuelRegistry.FuelType rt = getRocketFuelType(); + if (rt == null) + return false; + + // current amounts + int main = getFuelAmount(rt); + final int mainRate = Math.max(1, getFuelConsumptionRate(rt)); // defensive + + if (rt == FuelRegistry.FuelType.LIQUID_BIPROPELLANT) { + int ox = getFuelAmount(FuelRegistry.FuelType.LIQUID_OXIDIZER); + final int oxRate = Math.max(1, getFuelConsumptionRate(FuelRegistry.FuelType.LIQUID_OXIDIZER)); + + // both-or-nothing + if (main >= mainRate && ox >= oxRate) { + setFuelAmount(rt, main - mainRate); + setFuelAmount(FuelRegistry.FuelType.LIQUID_OXIDIZER, ox - oxRate); + } else { + return false; // not enough of one stream + } + + // normalize + clear fluid names when empty + setFuelAmount(rt, Math.max(0, getFuelAmount(rt))); + setFuelAmount(FuelRegistry.FuelType.LIQUID_OXIDIZER, Math.max(0, getFuelAmount(FuelRegistry.FuelType.LIQUID_OXIDIZER))); + + if (getFuelAmount(rt) == 0) { + stats.setFuelFluid("null"); + stats.setWorkingFluid("null"); + } + if (getFuelAmount(FuelRegistry.FuelType.LIQUID_OXIDIZER) == 0) { + stats.setOxidizerFluid("null"); + } + return true; + } else { + if (main >= mainRate) { + setFuelAmount(rt, main - mainRate); + } else { + return false; + } + + // normalize + clear when empty + setFuelAmount(rt, Math.max(0, getFuelAmount(rt))); + if (getFuelAmount(rt) == 0) { + stats.setFuelFluid("null"); + stats.setWorkingFluid("null"); + } + return true; + } + } + + @Override public void readMissionPersistentNBT(NBTTagCompound nbt) { super.readMissionPersistentNBT(nbt); From 9228b33aceba0b4728837b609547ab290f1d09b1 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 5 Nov 2025 14:03:31 +0100 Subject: [PATCH 085/274] Add intake power calculation and refine liquid capacity Refactor StorageChunk to include intake power calculation and improve liquid capacity handling. --- .../advancedRocketry/util/StorageChunk.java | 54 +++++++++++++------ 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/util/StorageChunk.java b/src/main/java/zmaster587/advancedRocketry/util/StorageChunk.java index 48dd09f56..b61cbc90e 100644 --- a/src/main/java/zmaster587/advancedRocketry/util/StorageChunk.java +++ b/src/main/java/zmaster587/advancedRocketry/util/StorageChunk.java @@ -168,7 +168,7 @@ public void recalculateStats(StatsRocket stats) { int fuelCapacityBipropellant = 0; int fuelCapacityOxidizer = 0; int fuelCapacityNuclearWorkingFluid = 0; - + int intakePower = 0; float drillPower = 0f; //stats.reset_no_fuel(); stats.reset_no_fuel();// Oh Quarter... you can not keep adding engine and seat locations every launch @@ -230,24 +230,14 @@ public void recalculateStats(StatsRocket stats) { if (block instanceof IMiningDrill) { drillPower += ((IMiningDrill) block).getMiningSpeed(world, currBlockPos); } + if (block instanceof IIntake) { + intakePower += ((IIntake) block).getIntakeAmt(state); + } if (block.getUnlocalizedName().contains("servicemonitor")) { hasServiceMonitor = true; } - - TileEntity tile = world.getTileEntity(currBlockPos); - if (tile instanceof TileSatelliteHatch) { - if (ARConfiguration.getCurrentConfig().advancedWeightSystem) { - TileSatelliteHatch hatch = (TileSatelliteHatch) tile; - if (hatch.getSatellite() != null) { - weight += hatch.getSatellite().getProperties().getWeight(); - } else if (hatch.getStackInSlot(0).getItem() instanceof ItemPackedStructure) { - ItemPackedStructure struct = (ItemPackedStructure) hatch.getStackInSlot(0).getItem(); - weight += struct.getStructure(hatch.getStackInSlot(0)).getWeight(); - } - } - } - } + } } } } @@ -272,10 +262,42 @@ public void recalculateStats(StatsRocket stats) { stats.setFuelCapacity(FuelRegistry.FuelType.LIQUID_OXIDIZER, fuelCapacityOxidizer); stats.setFuelCapacity(FuelRegistry.FuelType.NUCLEAR_WORKING_FLUID, fuelCapacityNuclearWorkingFluid); - //Non-fuel stats + // SAFE liquid capacity sum (saturating at Integer.MAX_VALUE) + long liquidCapacitySum = 0L; + + outer: + for (TileEntity te : this.getFluidTiles()) { + net.minecraftforge.fluids.capability.IFluidHandler fh = + te.getCapability(net.minecraftforge.fluids.capability.CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, null); + if (fh == null) continue; + + net.minecraftforge.fluids.capability.IFluidTankProperties[] props = fh.getTankProperties(); + if (props == null) continue; + + for (net.minecraftforge.fluids.capability.IFluidTankProperties p : props) { + if (p == null) continue; + long cap = Math.max(0L, (long) p.getCapacity()); // guard negatives + if (cap == 0L) continue; + + long next = liquidCapacitySum + cap; // saturating add + if (next >= (long) Integer.MAX_VALUE) { + liquidCapacitySum = (long) Integer.MAX_VALUE; + break outer; // early exit once saturated + } + liquidCapacitySum = next; + } + } + + int liquidCapacitySafe = (int) Math.max(0L, Math.min(liquidCapacitySum, (long) Integer.MAX_VALUE)); + stats.setStatTag("liquidCapacity", liquidCapacitySafe); + + + //Non-fuel stats (keep these after the capacity/tag work) stats.setWeight(weight); stats.setThrust(Math.max(Math.max(thrustMonopropellant, thrustBipropellant), thrustNuclearTotalLimit)); stats.setDrillingPower(drillPower); + stats.setStatTag("intakePower", intakePower); + // (liquidCapacity already set above) } public void addTileEntity(TileEntity te) { From 26403d47d9ee56f725f05db82d8f522aa75d2889 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 5 Nov 2025 14:06:09 +0100 Subject: [PATCH 086/274] Simplify power per operation smoother powerdraw (broken in last update) --- .../tile/infrastructure/TileFuelingStation.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java index 0f17f956c..06aa2a755 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java @@ -315,8 +315,7 @@ public void performFunction() { @Override public int getPowerPerOperation() { - // same average RF/mb as before, just throttled - return 30 * OP_THROTTLE_TICKS; + return 30; } @@ -343,11 +342,8 @@ public boolean canPerformFunction() { FluidStack fs = tank.getFluid(); if (fs == null || fs.amount <= 9) return false; - // only if the rocket can fit this fluid - if (!canRocketFitFluid(fs.getFluid())) return false; - - // Consume RF only on the throttled ticks - return (world.getTotalWorldTime() % OP_THROTTLE_TICKS) == 0L; + // Only draw power when the rocket can actually take this fluid + return canRocketFitFluid(fs.getFluid()); } @Override From 93a4cd434d245f67575cac95b1759e3663a16aa9 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 5 Nov 2025 14:07:39 +0100 Subject: [PATCH 087/274] Refactor gas collection logic in MissionGasCollection Safer handling, 2 new config entries: infinitemode and harvest multiplier. both of these are per mission. --- .../mission/MissionGasCollection.java | 51 ++++++++++++++++--- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/mission/MissionGasCollection.java b/src/main/java/zmaster587/advancedRocketry/mission/MissionGasCollection.java index 6c94b3d21..7e48311e5 100644 --- a/src/main/java/zmaster587/advancedRocketry/mission/MissionGasCollection.java +++ b/src/main/java/zmaster587/advancedRocketry/mission/MissionGasCollection.java @@ -22,7 +22,6 @@ public class MissionGasCollection extends MissionResourceCollection { - private Fluid gasFluid; public MissionGasCollection() { @@ -42,14 +41,49 @@ public String getName() { @Override public void onMissionComplete() { + Object ipObj = rocketStats.getStatTag("intakePower"); + int ip = (ipObj instanceof Number) ? Math.max(0, ((Number) ipObj).intValue()) : 0; + + if (ip > 0 && gasFluid != null) { + final Fluid type = gasFluid; + + // Planned harvest written by the rocket at launch + final boolean hasPlanned = missionPersistantNBT.hasKey("plannedHarvestMb"); + final long planned = hasPlanned ? Math.max(0L, missionPersistantNBT.getLong("plannedHarvestMb")) : -1L; + + // Config + final boolean infinite = ARConfiguration.getCurrentConfig().gasHarvestInfinite; + final double mult = Math.max(0.0, ARConfiguration.getCurrentConfig().gasHarvestAmountMultiplier); + final long basePerMission = 64_000L; // mB + + long remaining; + if (hasPlanned) { + remaining = Math.min(Integer.MAX_VALUE, planned); + } else { + remaining = infinite + ? Integer.MAX_VALUE + : Math.min(Integer.MAX_VALUE, Math.round(basePerMission * mult)); + } + + - if ((int) rocketStats.getStatTag("intakePower") > 0 && gasFluid != null) { - Fluid type = gasFluid;//FluidRegistry.getFluid("hydrogen"); - //Fill gas tanks for (TileEntity tile : this.rocketStorage.getFluidTiles()) { - tile.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, null).fill(new FluidStack(type, 64000), true); + net.minecraftforge.fluids.capability.IFluidHandler handler = + tile.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, null); + if (handler == null) continue; + + if (remaining <= 0) break; + + int want = (int)Math.min(Integer.MAX_VALUE, remaining); + int couldTake = handler.fill(new FluidStack(type, want), false); // simulate + if (couldTake > 0) { + int filled = handler.fill(new FluidStack(type, couldTake), true); + remaining -= Math.max(0, filled); + } } } + + World world = DimensionManager.getWorld(launchDimension); if (world == null) { @@ -89,12 +123,15 @@ public void onMissionComplete() { @Override public void writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); - nbt.setString("gas", gasFluid.getName()); + if (gasFluid != null) { + nbt.setString("gas", gasFluid.getName()); + } } @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); - gasFluid = FluidRegistry.getFluid(nbt.getString("gas")); + String name = nbt.getString("gas"); + gasFluid = name != null && !name.isEmpty() ? FluidRegistry.getFluid(name) : null; } } From 42670ab6229c9589bbc984e9ec89952d45a37d3c Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 5 Nov 2025 16:27:46 +0100 Subject: [PATCH 088/274] Fix typo in copy chip hint message From c7017b9bf3d8e0306b51908e8b6efbb506653747 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 5 Nov 2025 16:29:55 +0100 Subject: [PATCH 089/274] PerformanceTweaks --- .../TileStationAltitudeController.java | 148 ++++++++++++------ 1 file changed, 97 insertions(+), 51 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/station/TileStationAltitudeController.java b/src/main/java/zmaster587/advancedRocketry/tile/station/TileStationAltitudeController.java index 6ed4760ab..205fb7f5b 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/station/TileStationAltitudeController.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/station/TileStationAltitudeController.java @@ -1,6 +1,8 @@ package zmaster587.advancedRocketry.tile.station; import io.netty.buffer.ByteBuf; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.NetworkManager; @@ -30,10 +32,10 @@ public class TileStationAltitudeController extends TileEntity implements IModula int progress; private RedstoneState state = RedstoneState.OFF; - + private long lastAltSyncTick = -10; private ModuleText moduleGrav, numGravPylons, maxGravBuildSpeed, targetGrav; private ModuleRedstoneOutputButton redstoneControl; - + private boolean wasChanging = false; public TileStationAltitudeController() { moduleGrav = new ModuleText(6, 15, "Altitude: ", 0xaa2020); //numGravPylons = new ModuleText(10, 25, "Number Of Thrusters: ", 0xaa2020); @@ -54,7 +56,63 @@ public List getModules(int id, EntityPlayer player) { modules.add(new ModuleSlider(6, 60, 0, TextureResources.doubleWarningSideBarIndicator, this)); modules.add(redstoneControl); - updateText(); + // inline updater that runs only while GUI is open + modules.add(new ModuleBase(0, 0) { + private SpaceStationObject cached; + private int cachedId = Integer.MIN_VALUE; + + // last shown keys (ints in Km) + private int lastAltKm = Integer.MIN_VALUE; + private int lastTgtKm = Integer.MIN_VALUE; + + // localized prefixes (cache per GUI session) + private final String prefixAlt = LibVulpes.proxy.getLocalizedString("msg.stationaltctrl.alt"); + private final String prefixTgt = LibVulpes.proxy.getLocalizedString("msg.stationaltctrl.tgtalt"); + + private boolean ensureStation() { + if (cached == null) { + ISpaceObject so = SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(pos); + if (!(so instanceof SpaceStationObject)) return false; + cached = (SpaceStationObject) so; + cachedId = so.getId(); + return true; + } + ISpaceObject current = SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(pos); + if (!(current instanceof SpaceStationObject)) { cached = null; cachedId = Integer.MIN_VALUE; return false; } + if (current.getId() != cachedId) { + cached = (SpaceStationObject) current; + cachedId = current.getId(); + } + return true; + } + + @Override + public void renderBackground(GuiContainer gui, int x, int y, int mouseX, int mouseY, FontRenderer font) { + // Only runs while the GUI is visible → zero idle cost when closed. + if (!ensureStation()) return; + + // Compute display keys (Km as ints) + int curAltKm = (int)Math.round(cached.getOrbitalDistance() * 200.0 + 100.0); + int tgtAltKm = cached.targetOrbitalDistance * 200 + 100; + + // Update only when the visible value changes + if (curAltKm != lastAltKm) { + // "Altitude: XXXKm" + moduleGrav.setText(prefixAlt + " " + curAltKm + "Km"); + lastAltKm = curAltKm; + } + if (tgtAltKm != lastTgtKm) { + // "Target Altitude: YYY" + targetGrav.setText(prefixTgt + " " + tgtAltKm); + lastTgtKm = tgtAltKm; + } + } + + @Override public int getSizeX() { return 0; } + @Override public int getSizeY() { return 0; } + }); + + return modules; } @@ -83,62 +141,50 @@ public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) { readFromNBT(pkt.getNbtCompound()); } - private void updateText() { - if (world.isRemote) { - ISpaceObject spaceObject = SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(pos); - if (spaceObject != null) { - moduleGrav.setText(String.format("%s %.0fKm", LibVulpes.proxy.getLocalizedString("msg.stationaltctrl.alt"), spaceObject.getOrbitalDistance() * 200 + 100)); - //maxGravBuildSpeed.setText(String.format("%s%.1f", LibVulpes.proxy.getLocalizedString("msg.stationaltctrl.maxaltrate"), 7200D * spaceObject.getMaxRotationalAcceleration())); - targetGrav.setText(String.format("%s %d", LibVulpes.proxy.getLocalizedString("msg.stationaltctrl.tgtalt"), ((SpaceStationObject) spaceObject).targetOrbitalDistance * 200 + 100)); - } + @Override + public void update() { + if (!(world.provider instanceof WorldProviderSpace) || world.isRemote) return; + + ISpaceObject so = SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(pos); + if (so == null) return; + SpaceStationObject sso = (SpaceStationObject) so; - //numThrusters.setText("Number Of Thrusters: 0"); + // Redstone → target + if (redstoneControl.getState() == RedstoneState.ON) { + sso.targetOrbitalDistance = Math.max((world.getStrongPower(pos) * 13) + 4, 190); + } else if (redstoneControl.getState() == RedstoneState.INVERTED) { + sso.targetOrbitalDistance = Math.max(Math.abs(15 - world.getStrongPower(pos)) * 13 + 4, 190); } - } - @Override - public void update() { - if (this.world.provider instanceof WorldProviderSpace) { + progress = sso.targetOrbitalDistance; - if (!world.isRemote) { - ISpaceObject spaceObject = SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(pos); + // Converge with epsilon + double target = sso.targetOrbitalDistance; + double current = so.getOrbitalDistance(); + double diff = target - current; + double acc = 0.02D; + boolean changing = Math.abs(diff) >= 0.001D; - if (spaceObject != null) { - if (redstoneControl.getState() == RedstoneState.ON) - ((SpaceStationObject) spaceObject).targetOrbitalDistance = Math.max((world.getStrongPower(pos) * 13) + 4, 190); - else if (redstoneControl.getState() == RedstoneState.INVERTED) - ((SpaceStationObject) spaceObject).targetOrbitalDistance = Math.max(Math.abs(15 - world.getStrongPower(pos)) * 13 + 4, 190); - - progress = ((SpaceStationObject) spaceObject).targetOrbitalDistance; - - double targetGravity = ((SpaceStationObject) spaceObject).targetOrbitalDistance; - double angVel = spaceObject.getOrbitalDistance(); - double acc = 0.02;//0.1 * (getTotalProgress(0) - angVel + 1) / (float) getTotalProgress(0); - - double difference = targetGravity - angVel; - - if (difference != 0) { - double finalVel = angVel; - if (difference < 0) { - finalVel = angVel + Math.max(difference, -acc); - } else if (difference > 0) { - finalVel = angVel + Math.min(difference, acc); - } - - spaceObject.setOrbitalDistance((float) finalVel); - if (!world.isRemote) { - //PacketHandler.sendToNearby(new PacketStationUpdate(spaceObject, PacketStationUpdate.Type.ROTANGLE_UPDATE), this.worldObj.provider.dimensionId, this.xCoord, this.yCoord, this.zCoord, 1024); - PacketHandler.sendToAll(new PacketStationUpdate(spaceObject, PacketStationUpdate.Type.ALTITUDE_UPDATE)); - markDirty(); - } else - updateText(); - } - } - } else - updateText(); + if (changing) { + double next = current + (diff < 0 ? Math.max(diff, -acc) : Math.min(diff, acc)); + so.setOrbitalDistance((float) next); + + long wt = world.getTotalWorldTime(); + if (wt - lastAltSyncTick >= 10L) { // ~4 Hz while changing + PacketHandler.sendToAll(new PacketStationUpdate(so, PacketStationUpdate.Type.ALTITUDE_UPDATE)); + lastAltSyncTick = wt; + } + markDirty(); + } else if (wasChanging) { + // final flush on settle so clients end exactly on the last value + PacketHandler.sendToAll(new PacketStationUpdate(so, PacketStationUpdate.Type.ALTITUDE_UPDATE)); + markDirty(); } + + wasChanging = changing; } + @Override public String getModularInventoryName() { return AdvancedRocketryBlocks.blockAltitudeController.getLocalizedName(); From fea1fae07e426b408ab680c736231b318ab35390 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 5 Nov 2025 16:41:49 +0100 Subject: [PATCH 090/274] Improve rotation update handling in PacketStationUpdate Refactor ROTANGLE_UPDATE case to handle rotation updates more smoothly by checking proximity to server snapshot and adjusting velocities accordingly. --- .../network/PacketStationUpdate.java | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/network/PacketStationUpdate.java b/src/main/java/zmaster587/advancedRocketry/network/PacketStationUpdate.java index 21eb199fd..50ca374b1 100644 --- a/src/main/java/zmaster587/advancedRocketry/network/PacketStationUpdate.java +++ b/src/main/java/zmaster587/advancedRocketry/network/PacketStationUpdate.java @@ -75,6 +75,7 @@ public void write(ByteBuf out) { Logger.getLogger("advancedRocketry").warning("Dimension " + stationNumber + " has thrown an exception trying to write NBT, deleting!"); DimensionManager.getInstance().deleteDimension(stationNumber); } + break; default: } } @@ -128,7 +129,8 @@ public void read(ByteBuf in) { @Override public void executeClient(EntityPlayer thePlayer) { spaceObject = SpaceObjectManager.getSpaceManager().getSpaceStation(stationNumber); - + if (spaceObject == null) return; + switch (type) { case DEST_ORBIT_UPDATE: spaceObject.setDestOrbitingBody(destOrbitingBody); @@ -140,14 +142,32 @@ public void executeClient(EntityPlayer thePlayer) { if (spaceObject instanceof SpaceStationObject) ((SpaceStationObject) spaceObject).setFuelAmount(fuel); break; - case ROTANGLE_UPDATE: - spaceObject.setRotation(rx, EnumFacing.EAST); - spaceObject.setRotation(ry, EnumFacing.UP); - spaceObject.setRotation(rz, EnumFacing.NORTH); - spaceObject.setDeltaRotation(drx, EnumFacing.EAST); - spaceObject.setDeltaRotation(dry, EnumFacing.UP); - spaceObject.setDeltaRotation(drz, EnumFacing.NORTH); + case ROTANGLE_UPDATE: { + SpaceStationObject sso = (SpaceStationObject) spaceObject; + + // Current client-predicted angles + double crx = sso.getRotation(EnumFacing.EAST); + double cry = sso.getRotation(EnumFacing.UP); + double crz = sso.getRotation(EnumFacing.NORTH); + + // If we're close to server snapshot, avoid snapping: just update angular velocities + final double SNAP_DEG = 2.0; // small tolerance; tune 1–3° + boolean close = + Math.abs(crx - rx) < SNAP_DEG && + Math.abs(cry - ry) < SNAP_DEG && + Math.abs(crz - rz) < SNAP_DEG; + + if (close) { + // keep current pose, just update velocities (smooth, no blink) + sso.setDeltaRotation(drx, EnumFacing.EAST); + sso.setDeltaRotation(dry, EnumFacing.UP); + sso.setDeltaRotation(drz, EnumFacing.NORTH); + } else { + // we're far off: do a one-time snap + reset baseline + sso.applyRemoteRotationState(rx, ry, rz, drx, dry, drz); + } break; + } case SIGNAL_WHITE_BURST: PlanetEventHandler.runBurst(Minecraft.getMinecraft().world.getTotalWorldTime() + 20, 20); break; From 49670460de64faa74016d45678a07de991b33830 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 5 Nov 2025 16:42:23 +0100 Subject: [PATCH 091/274] Refactor GUI update logic in TileStationOrientationController Refactor TileStationOrientationController to improve GUI updates and synchronization with space station state. --- .../TileStationOrientationController.java | 156 +++++++++++------- 1 file changed, 100 insertions(+), 56 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/station/TileStationOrientationController.java b/src/main/java/zmaster587/advancedRocketry/tile/station/TileStationOrientationController.java index d3ed36055..11eaa29ed 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/station/TileStationOrientationController.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/station/TileStationOrientationController.java @@ -1,6 +1,8 @@ package zmaster587.advancedRocketry.tile.station; import io.netty.buffer.ByteBuf; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; @@ -26,6 +28,7 @@ public class TileStationOrientationController extends TileEntity implements ITickable, IModularInventory, INetworkMachine, ISliderBar, IButtonInventory { private int[] progress; + private long lastRotSyncTick = -5; private ModuleText moduleAngularVelocity, numThrusters, maxAngularAcceleration, targetRotations; @@ -56,70 +59,111 @@ public List getModules(int id, EntityPlayer player) { modules.add(new ModuleButton(25, 35, 2, LibVulpes.proxy.getLocalizedString("msg.spacelaser.reset"), this, zmaster587.libVulpes.inventory.TextureResources.buttonBuild, 36, 15)); //modules.add(new ModuleSlider(24, 35, 2, TextureResources.doubleWarningSideBarIndicator, (ISliderBar)this)); - updateText(); - return modules; - } + // inline updater that runs only while GUI is open + modules.add(new ModuleBase(0, 0) { + private SpaceStationObject cached; + private int cachedId = Integer.MIN_VALUE; - private void updateText() { - if (world.isRemote) { - ISpaceObject spaceObject = SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(pos); - if (spaceObject != null) { - moduleAngularVelocity.setText(String.format("%s%.1f %.1f %.1f", LibVulpes.proxy.getLocalizedString("msg.stationorientctrl.alt"), 72000D * spaceObject.getDeltaRotation(EnumFacing.EAST), 72000D * spaceObject.getDeltaRotation(EnumFacing.UP), 7200D * spaceObject.getDeltaRotation(EnumFacing.NORTH))); - //maxAngularAcceleration.setText(String.format("Maximum Angular Acceleration: %.1f", 7200D*object.getMaxRotationalAcceleration())); + private int lastVelX = Integer.MIN_VALUE, lastVelY = Integer.MIN_VALUE, lastVelZ = Integer.MIN_VALUE; + private int lastTgtX = Integer.MIN_VALUE, lastTgtY = Integer.MIN_VALUE, lastTgtZ = Integer.MIN_VALUE; - //numThrusters.setText("Number Of Thrusters: 0"); - int[] targetRotationsPerHour = ((SpaceStationObject) spaceObject).targetRotationsPerHour; - targetRotations.setText(String.format("%s%d %d %d", LibVulpes.proxy.getLocalizedString("msg.stationorientctrl.tgtalt"), targetRotationsPerHour[0], targetRotationsPerHour[1], targetRotationsPerHour[2])); + private final String prefixVel = LibVulpes.proxy.getLocalizedString("msg.stationorientctrl.alt"); + private final String prefixTgt = LibVulpes.proxy.getLocalizedString("msg.stationorientctrl.tgtalt"); + + private String oneDp(int key) { + int abs = Math.abs(key), whole = abs / 10, frac = abs % 10; + String s = whole + "." + frac; + return key < 0 ? "-" + s : s; } - } + + private boolean ensureStation() { + if (cached == null) { + ISpaceObject so = SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(pos); + if (!(so instanceof SpaceStationObject)) return false; + cached = (SpaceStationObject) so; + cachedId = so.getId(); + return true; + } + ISpaceObject current = SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(pos); + if (!(current instanceof SpaceStationObject)) { cached = null; cachedId = Integer.MIN_VALUE; return false; } + if (current.getId() != cachedId) { + cached = (SpaceStationObject) current; + cachedId = current.getId(); + } + return true; + } + + @Override + public void renderBackground(GuiContainer gui, int x, int y, int mouseX, int mouseY, FontRenderer font) { + if (!ensureStation()) return; + + double dX = cached.getDeltaRotation(EnumFacing.EAST); + double dY = cached.getDeltaRotation(EnumFacing.UP); + double dZ = cached.getDeltaRotation(EnumFacing.NORTH); + int[] tgt = cached.targetRotationsPerHour; + + int velX = (int)Math.round(72000D * dX * 10D); + int velY = (int)Math.round(72000D * dY * 10D); + int velZ = (int)Math.round( 7200D * dZ * 10D); + + if (velX != lastVelX || velY != lastVelY || velZ != lastVelZ) { + moduleAngularVelocity.setText(prefixVel + oneDp(velX) + " " + oneDp(velY) + " " + oneDp(velZ)); + lastVelX = velX; lastVelY = velY; lastVelZ = velZ; + } + + if (tgt[0] != lastTgtX || tgt[1] != lastTgtY || tgt[2] != lastTgtZ) { + targetRotations.setText(prefixTgt + tgt[0] + " " + tgt[1] + " " + tgt[2]); + lastTgtX = tgt[0]; lastTgtY = tgt[1]; lastTgtZ = tgt[2]; + } + } + + @Override public int getSizeX() { return 0; } + @Override public int getSizeY() { return 0; } + }); + + + return modules; } @Override public void update() { + // Only relevant in space + if (!(world.provider instanceof WorldProviderSpace)) return; + // Server-side only + if (world.isRemote) return; + + ISpaceObject spaceObject = SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(pos); + if (spaceObject == null) return; + + EnumFacing[] dirs = { EnumFacing.EAST, EnumFacing.UP, EnumFacing.NORTH }; + int[] targetRotationsPerHour = ((SpaceStationObject) spaceObject).targetRotationsPerHour; + + // keep sliders in sync with server state + for (int i = 0; i < 3; i++) { + setProgress(i, targetRotationsPerHour[i] + (getTotalProgress(i) / 2)); + } - if (this.world.provider instanceof WorldProviderSpace) { - if (!world.isRemote) { - ISpaceObject spaceObject = SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(pos); - boolean update = false; - - if (spaceObject != null) { - - EnumFacing[] dirs = {EnumFacing.EAST, EnumFacing.UP, EnumFacing.NORTH}; - int[] targetRotationsPerHour = ((SpaceStationObject) spaceObject).targetRotationsPerHour; - for (int i = 0; i < 3; i++) { - setProgress(i, targetRotationsPerHour[i] + (getTotalProgress(i) / 2)); - } - - - for (int i = 0; i < 3; i++) { - - double targetAngularVelocity = targetRotationsPerHour[i] / 72000D; - double angVel = spaceObject.getDeltaRotation(dirs[i]); - double acc = spaceObject.getMaxRotationalAcceleration(); - - double difference = targetAngularVelocity - angVel; - - if (difference != 0) { - double finalVel = angVel; - if (difference < 0) { - finalVel = angVel + Math.max(difference, -acc); - } else if (difference > 0) { - finalVel = angVel + Math.min(difference, acc); - } - - spaceObject.setDeltaRotation(finalVel, dirs[i]); - update = true; - } - } - - if (!world.isRemote && update) { - //PacketHandler.sendToNearby(new PacketStationUpdate(spaceObject, PacketStationUpdate.Type.ROTANGLE_UPDATE), this.worldObj.provider.dimensionId, this.xCoord, this.yCoord, this.zCoord, 1024); - PacketHandler.sendToAll(new PacketStationUpdate(spaceObject, PacketStationUpdate.Type.ROTANGLE_UPDATE)); - } - } else - updateText(); - } else - updateText(); + boolean updated = false; + + for (int i = 0; i < 3; i++) { + double targetAngularVelocity = targetRotationsPerHour[i] / 72000D; + double angVel = spaceObject.getDeltaRotation(dirs[i]); + double acc = spaceObject.getMaxRotationalAcceleration(); + + double difference = targetAngularVelocity - angVel; + if (difference != 0) { + double finalVel = angVel + (difference < 0 ? Math.max(difference, -acc) : Math.min(difference, acc)); + spaceObject.setDeltaRotation(finalVel, dirs[i]); + updated = true; + } + } + + if (updated) { + long t = world.getTotalWorldTime(); + if (t - lastRotSyncTick >= 5) { // ~4 Hz + PacketHandler.sendToAll(new PacketStationUpdate(spaceObject, PacketStationUpdate.Type.ROTANGLE_UPDATE)); + lastRotSyncTick = t; + } } } From b6e94459e74476349e5189d8734918848162c7f3 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 5 Nov 2025 16:44:49 +0100 Subject: [PATCH 092/274] Fix formatting issue in TileUnmannedVehicleAssembler From b98253c1a86b6fd9ac08743e13261b55a00e1482 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 5 Nov 2025 17:06:27 +0100 Subject: [PATCH 093/274] Refactor rotation and time modification handling fixes snaps and laggy resyncs when changing rotationvelocities in controller --- .../stations/SpaceStationObject.java | 48 ++++++++++++++----- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/stations/SpaceStationObject.java b/src/main/java/zmaster587/advancedRocketry/stations/SpaceStationObject.java index 10340153f..fc6b65544 100644 --- a/src/main/java/zmaster587/advancedRocketry/stations/SpaceStationObject.java +++ b/src/main/java/zmaster587/advancedRocketry/stations/SpaceStationObject.java @@ -57,9 +57,10 @@ public class SpaceStationObject implements ISpaceObject, IPlanetDefiner { private boolean isAnchored = false; private double[] rotation; private double[] angularVelocity; - private long lastTimeModification = 0; + private final long[] lastTimeModification = new long[3]; // one per axis private DimensionProperties properties; + public SpaceStationObject() { properties = (DimensionProperties) zmaster587.advancedRocketry.dimension.DimensionManager.defaultSpaceDimensionProperties.clone(); orbitalDistance = 50.0f; @@ -75,8 +76,12 @@ public SpaceStationObject() { knownPlanetList = new HashSet<>(); angularVelocity = new double[3]; rotation = new double[3]; - } - + long now = getWorldTime(); + lastTimeModification[0] = now; + lastTimeModification[1] = now; + lastTimeModification[2] = now; + } + public Set getKnownPlanetList() { return knownPlanetList; } @@ -110,6 +115,17 @@ public void discoverPlanet(int pid) { PacketHandler.sendToAll(new PacketSpaceStationInfo(getId(), this)); } + public void applyRemoteRotationState(double rx, double ry, double rz, + double drx, double dry, double drz) { + rotation[0] = rx; rotation[1] = ry; rotation[2] = rz; + angularVelocity[0] = drx; angularVelocity[1] = dry; angularVelocity[2] = drz; + long now = getWorldTime(); + lastTimeModification[0] = now; + lastTimeModification[1] = now; + lastTimeModification[2] = now; + } + + /** * @return id of the space object (NOT the DIMID) */ @@ -209,8 +225,12 @@ public int getAltitude() { * @return rotation of the station in degrees */ public double getRotation(EnumFacing dir) { - - return (rotation[getIDFromDir(dir)] + getDeltaRotation(dir) * (getWorldTime() - lastTimeModification)) % (360D); + int idx = getIDFromDir(dir); + long dt = getWorldTime() - lastTimeModification[idx]; + double a = rotation[idx] + angularVelocity[idx] * dt; + // keep modulo stable + a = ((a % 360D) + 360D) % 360D; + return a; } /** @@ -241,8 +261,10 @@ else if (facing == EnumFacing.UP) /** * @param rotation rotation of the station in degrees */ - public void setRotation(double rotation, EnumFacing facing) { - this.rotation[getIDFromDir(facing)] = rotation; + public void setRotation(double rotDeg, EnumFacing facing) { + int idx = getIDFromDir(facing); + rotation[idx] = rotDeg; + lastTimeModification[idx] = getWorldTime(); } /** @@ -255,15 +277,17 @@ public double getDeltaRotation(EnumFacing facing) { /** * @param rotation anglarVelocity of the station in degrees per tick */ - public void setDeltaRotation(double rotation, EnumFacing facing) { + public void setDeltaRotation(double newVel, EnumFacing facing) { if (!isAnchored()) { - this.rotation[getIDFromDir(facing)] = getRotation(facing); - this.lastTimeModification = getWorldTime(); - - this.angularVelocity[getIDFromDir(facing)] = rotation; + int idx = getIDFromDir(facing); + // capture current integrated angle as the new snapshot + rotation[idx] = getRotation(facing); + lastTimeModification[idx] = getWorldTime(); + angularVelocity[idx] = newVel; } } + public double getMaxRotationalAcceleration() { return 0.02D; } From 7097b9cd23325d347b05115849417829bceb3b4c Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 5 Nov 2025 17:07:16 +0100 Subject: [PATCH 094/274] Simplify rotation state application for space stations fixing snappy resyncs laggy stuff when changing rotationangles --- .../network/PacketStationUpdate.java | 26 +++---------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/network/PacketStationUpdate.java b/src/main/java/zmaster587/advancedRocketry/network/PacketStationUpdate.java index 50ca374b1..28182d281 100644 --- a/src/main/java/zmaster587/advancedRocketry/network/PacketStationUpdate.java +++ b/src/main/java/zmaster587/advancedRocketry/network/PacketStationUpdate.java @@ -143,29 +143,9 @@ public void executeClient(EntityPlayer thePlayer) { ((SpaceStationObject) spaceObject).setFuelAmount(fuel); break; case ROTANGLE_UPDATE: { - SpaceStationObject sso = (SpaceStationObject) spaceObject; - - // Current client-predicted angles - double crx = sso.getRotation(EnumFacing.EAST); - double cry = sso.getRotation(EnumFacing.UP); - double crz = sso.getRotation(EnumFacing.NORTH); - - // If we're close to server snapshot, avoid snapping: just update angular velocities - final double SNAP_DEG = 2.0; // small tolerance; tune 1–3° - boolean close = - Math.abs(crx - rx) < SNAP_DEG && - Math.abs(cry - ry) < SNAP_DEG && - Math.abs(crz - rz) < SNAP_DEG; - - if (close) { - // keep current pose, just update velocities (smooth, no blink) - sso.setDeltaRotation(drx, EnumFacing.EAST); - sso.setDeltaRotation(dry, EnumFacing.UP); - sso.setDeltaRotation(drz, EnumFacing.NORTH); - } else { - // we're far off: do a one-time snap + reset baseline - sso.applyRemoteRotationState(rx, ry, rz, drx, dry, drz); - } + ((SpaceStationObject) spaceObject).applyRemoteRotationState( + rx, ry, rz, drx, dry, drz + ); break; } case SIGNAL_WHITE_BURST: From fadb21261207a343b14e03259ef8c2c5f4c22170 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 6 Nov 2025 10:39:36 +0100 Subject: [PATCH 095/274] Add handling for nuclear working fluid in EntityRocket --- .../zmaster587/advancedRocketry/entity/EntityRocket.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java b/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java index 8310fcf3f..af41de4a1 100644 --- a/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java +++ b/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java @@ -752,6 +752,11 @@ public boolean canRocketFitFluid(FluidStack fluidStack) { if (stats.getOxidizerFluid().equals("null") && isCorrectFluid) stats.setOxidizerFluid(fluidStack.getFluid().getName()); return isCorrectFluid; + } else if (FuelRegistry.instance.isFuel(FuelType.NUCLEAR_WORKING_FLUID, fluidStack.getFluid())) { + boolean isCorrectFluid = stats.getWorkingFluid().equals("null") || fluidStack.getFluid() == FluidRegistry.getFluid(stats.getWorkingFluid()); + if (stats.getWorkingFluid().equals("null") && isCorrectFluid) + stats.setWorkingFluid(fluidStack.getFluid().getName()); + return isCorrectFluid; } return false; } From 3b35f5f0dc56c12798344112dc41f2dff2bcd7eb Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 6 Nov 2025 10:41:21 +0100 Subject: [PATCH 096/274] Fix nuclear working fluid --- .../infrastructure/TileFuelingStation.java | 56 ++++++++++++++----- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java index 06aa2a755..0ca2b7021 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java @@ -20,6 +20,7 @@ import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fluids.capability.IFluidTankProperties; import net.minecraftforge.fml.relauncher.Side; +import zmaster587.advancedRocketry.AdvancedRocketry; import zmaster587.advancedRocketry.api.*; import zmaster587.advancedRocketry.api.fuel.FuelRegistry; import zmaster587.advancedRocketry.api.fuel.FuelRegistry.FuelType; @@ -109,15 +110,15 @@ private void refreshFluidCachesIfNeeded() { if (!Objects.equals(f, lastFuelStr)) { lastFuelStr = f; - cachedFuelFluid = (f == null || "null".equals(f)) ? null : FluidRegistry.getFluid(f); + cachedFuelFluid = (f == null || "null".equals(f) || f.isEmpty()) ? null : FluidRegistry.getFluid(f); } if (!Objects.equals(o, lastOxStr)) { lastOxStr = o; - cachedOxFluid = (o == null || "null".equals(o)) ? null : FluidRegistry.getFluid(o); + cachedOxFluid = (o == null || "null".equals(o) || o.isEmpty()) ? null : FluidRegistry.getFluid(o); } if (!Objects.equals(w, lastWorkStr)) { lastWorkStr = w; - cachedWorkFluid = (w == null || "null".equals(w)) ? null : FluidRegistry.getFluid(w); + cachedWorkFluid = (w == null || "null".equals(w) || w.isEmpty()) ? null : FluidRegistry.getFluid(w); } } @@ -125,8 +126,17 @@ private boolean isStationFluidForThisRocket(Fluid current) { refreshFluidCachesIfNeeded(); if (current == null || linkedRocket == null) return false; - // If a specific fluid was already chosen, match directly. - if (current == cachedFuelFluid || current == cachedOxFluid || current == cachedWorkFluid) { + // --- compare by fluid name, not by instance --- + final String currentName = current.getName(); + + // If a specific fluid was already chosen, match directly by name. + if (lastFuelStr != null && !"null".equals(lastFuelStr) && !lastFuelStr.isEmpty() && currentName.equals(lastFuelStr)) { + return true; + } + if (lastOxStr != null && !"null".equals(lastOxStr) && !lastOxStr.isEmpty() && currentName.equals(lastOxStr)) { + return true; + } + if (lastWorkStr != null && !"null".equals(lastWorkStr) && !lastWorkStr.isEmpty() && currentName.equals(lastWorkStr)) { return true; } @@ -287,13 +297,26 @@ public void performFunction() { fuelingActive = false; return; } - // Bounded transfer scaled by throttle; drain exactly what was accepted + + // Bounded transfer scaled by throttle; drain exactly the delta that actually landed int step = ARConfiguration.getCurrentConfig().fuelPointsPer10Mb; int toOffer = Math.min(step * OP_THROTTLE_TICKS, tank.getFluidAmount()); if (toOffer > 0) { - int accepted = linkedRocket.addFuelAmount(typeToFill, toOffer); // assumes returns actual mB accepted - if (accepted > 0) { - tank.drain(accepted, true); + final int before = linkedRocket.getFuelAmount(typeToFill); + final int ret = linkedRocket.addFuelAmount(typeToFill, toOffer); + + // Be robust to either contract: + // - if ret == new total -> delta = ret - before + // - if ret == accepted -> delta = ret (clamped to toOffer) + int delta = Math.max(0, ret - before); + if (delta == 0) { + // Assume ret is "accepted amount" + delta = Math.min(toOffer, Math.max(0, ret)); + } + + if (delta > 0) { + tank.drain(delta, true); + int baseRate = linkedRocket.stats.getBaseFuelRate(typeToFill); if (baseRate > 0) { int multRate = (int)(FuelRegistry.instance.getMultiplier(typeToFill, currentFluid) * baseRate); @@ -304,6 +327,7 @@ public void performFunction() { } } + // Re-evaluate full; if full now, stop within this link boolean fullNow = !canRocketFitFluid(currentFluid); setRedstoneState(fullNow); @@ -362,19 +386,23 @@ public boolean canFill(Fluid fluid) { private boolean canRocketFitFluid(Fluid f) { if (f == null || linkedRocket == null) return false; + boolean fits = false; + + // Check every type the fluid qualifies for; OR the results. if (FuelRegistry.instance.isFuel(FuelType.LIQUID_OXIDIZER, f)) { - return linkedRocket.getFuelAmount(FuelType.LIQUID_OXIDIZER) < linkedRocket.getFuelCapacity(FuelType.LIQUID_OXIDIZER); + fits |= linkedRocket.getFuelAmount(FuelType.LIQUID_OXIDIZER) < linkedRocket.getFuelCapacity(FuelType.LIQUID_OXIDIZER); } if (FuelRegistry.instance.isFuel(FuelType.LIQUID_BIPROPELLANT, f)) { - return linkedRocket.getFuelAmount(FuelType.LIQUID_BIPROPELLANT) < linkedRocket.getFuelCapacity(FuelType.LIQUID_BIPROPELLANT); + fits |= linkedRocket.getFuelAmount(FuelType.LIQUID_BIPROPELLANT) < linkedRocket.getFuelCapacity(FuelType.LIQUID_BIPROPELLANT); } if (FuelRegistry.instance.isFuel(FuelType.LIQUID_MONOPROPELLANT, f)) { - return linkedRocket.getFuelAmount(FuelType.LIQUID_MONOPROPELLANT) < linkedRocket.getFuelCapacity(FuelType.LIQUID_MONOPROPELLANT); + fits |= linkedRocket.getFuelAmount(FuelType.LIQUID_MONOPROPELLANT) < linkedRocket.getFuelCapacity(FuelType.LIQUID_MONOPROPELLANT); } if (FuelRegistry.instance.isFuel(FuelType.NUCLEAR_WORKING_FLUID, f)) { - return linkedRocket.getFuelAmount(FuelType.NUCLEAR_WORKING_FLUID) < linkedRocket.getFuelCapacity(FuelType.NUCLEAR_WORKING_FLUID); + fits |= linkedRocket.getFuelAmount(FuelType.NUCLEAR_WORKING_FLUID) < linkedRocket.getFuelCapacity(FuelType.NUCLEAR_WORKING_FLUID); } - return false; + + return fits; } @Override From d0324231499e3e2770ff813df59787a303023208 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 6 Nov 2025 10:42:51 +0100 Subject: [PATCH 097/274] Nuclear Working Fluid fix --- .../advancedRocketry/api/StatsRocket.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/api/StatsRocket.java b/src/main/java/zmaster587/advancedRocketry/api/StatsRocket.java index 427f01ee4..eb292e2b0 100644 --- a/src/main/java/zmaster587/advancedRocketry/api/StatsRocket.java +++ b/src/main/java/zmaster587/advancedRocketry/api/StatsRocket.java @@ -145,6 +145,10 @@ public float getWeight() { Fluid f = FluidRegistry.getFluid(getOxidizerFluid()); fluidWeight += WeightEngine.INSTANCE.getWeight(f, getFuelAmount(FuelType.LIQUID_OXIDIZER)); } + if (FluidRegistry.isFluidRegistered(getWorkingFluid())) { + Fluid f = FluidRegistry.getFluid(getWorkingFluid()); + fluidWeight += WeightEngine.INSTANCE.getWeight(f, getFuelAmount(FuelType.NUCLEAR_WORKING_FLUID)); + } } return weight + fluidWeight; } @@ -554,6 +558,7 @@ public void reset() { weight = 0; fuelFluid = "null"; oxidizerFluid = "null"; + workingFluid = "null"; drillingPower = 0f; for (FuelType type : FuelType.values()) { @@ -720,12 +725,12 @@ public void readFromNBT(NBTTagCompound nbt) { this.fuelRateNuclearWorkingFluid = stats.getInteger("fuelRateNuclearWorkingFluid"); this.fuelRateWarp = stats.getInteger("fuelRateWarp"); - this.fuelBaseRateMonopropellant = stats.getInteger("fuelBaseRateMonopropellant"); - this.fuelBaseRateBipropellant = stats.getInteger("fuelBaseRateBipropellant"); - this.fuelBaseRateOxidizer = stats.getInteger("fuelBaseRateOxidizer"); + this.fuelBaseRateMonopropellant = (int)stats.getFloat("fuelBaseRateMonopropellant"); + this.fuelBaseRateBipropellant = (int)stats.getFloat("fuelBaseRateBipropellant"); + this.fuelBaseRateOxidizer = (int)stats.getFloat("fuelBaseRateOxidizer"); this.fuelBaseRateImpulse = stats.getInteger("fuelBaseRateImpulse"); this.fuelBaseRateIon = stats.getInteger("fuelBaseRateIon"); - this.fuelBaseRateNuclearWorkingFluid = stats.getInteger("fuelBaseRateNuclearWorkingFluid"); + this.fuelBaseRateNuclearWorkingFluid = (int)stats.getFloat("fuelBaseRateNuclearWorkingFluid"); this.fuelBaseRateWarp = stats.getInteger("fuelBaseRateWarp"); @@ -766,4 +771,4 @@ else if (obj instanceof NBTTagInt) } } } -} \ No newline at end of file +} From e08ffb83dc2462fae27e31cb147b58d52401579d Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 6 Nov 2025 10:43:29 +0100 Subject: [PATCH 098/274] Add newline at end of EntityStationDeployedRocket.java Fix missing newline at end of file. From 38ebc6837e2f41e6c8b487944130b6b3f2166290 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 6 Nov 2025 10:44:01 +0100 Subject: [PATCH 099/274] Fix formatting issue in TileUnmannedVehicleAssembler From d47c70304e8fff136bf88e99a0cce4f43e4c5ef2 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 6 Nov 2025 10:59:16 +0100 Subject: [PATCH 100/274] Add newline at end of EntityStationDeployedRocket.java Fix missing newline at end of file. From 620e62fc4528be1ebffbf151bd781c56b6737072 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 6 Nov 2025 11:43:20 +0100 Subject: [PATCH 101/274] Hide energy capability and prevent EnergyConnections UX: exposing 0 RF storage is just confusing. --- .../tile/atmosphere/TileGasChargePad.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/atmosphere/TileGasChargePad.java b/src/main/java/zmaster587/advancedRocketry/tile/atmosphere/TileGasChargePad.java index 503015a99..3537b10a5 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/atmosphere/TileGasChargePad.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/atmosphere/TileGasChargePad.java @@ -6,6 +6,8 @@ import net.minecraft.item.ItemStack; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.AxisAlignedBB; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.energy.CapabilityEnergy; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; @@ -19,6 +21,7 @@ import zmaster587.libVulpes.tile.TileInventoriedRFConsumerTank; import zmaster587.libVulpes.util.FluidUtils; import zmaster587.libVulpes.util.IconResource; +import zmaster587.libVulpes.cap.TeslaHandler; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -51,6 +54,30 @@ public int getPowerPerOperation() { return 0; } + @Override + public boolean hasCapability(Capability capability, @Nullable EnumFacing facing) { + // Hide Forge Energy capability + if (capability == CapabilityEnergy.ENERGY) return false; + // Hide any Tesla capability the base class would expose + if (TeslaHandler.hasTeslaCapability(this, capability)) return false; + return super.hasCapability(capability, facing); + } + + @Override + @Nullable + public T getCapability(Capability capability, @Nullable EnumFacing facing) { + // Don’t provide energy handlers to probes/pipes + if (capability == CapabilityEnergy.ENERGY) return null; + if (TeslaHandler.hasTeslaCapability(this, capability)) return null; + return super.getCapability(capability, facing); + } + + // Optional (extra safety for mods that query IPower-style methods directly) + @Override public boolean canConnectEnergy(EnumFacing side) { return false; } + @Override public boolean canReceive() { return false; } + @Override public int getEnergyStored(EnumFacing side) { return 0; } + @Override public int getMaxEnergyStored(EnumFacing side) { return 0; } + @Override public boolean canPerformFunction() { if (!world.isRemote) { From dcfdeff3b723a442c3566db480bf6be08443a56b Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 6 Nov 2025 14:18:57 +0100 Subject: [PATCH 102/274] Fix missing newline at end of TileUnmannedVehicleAssembler.java From c0308c743e0fac8bd236f9bc826d954cc9213df8 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 6 Nov 2025 14:20:09 +0100 Subject: [PATCH 103/274] Add newline at end of WeightEngine.java Fix missing newline at end of file From 04231758ce411a023a33bb9287d7213323e8b74e Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 6 Nov 2025 14:23:45 +0100 Subject: [PATCH 104/274] Fix duration check to prevent zero or negative values Ensure duration is at least 1 tick in MissionResourceCollection. --- .../advancedRocketry/mission/MissionResourceCollection.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/mission/MissionResourceCollection.java b/src/main/java/zmaster587/advancedRocketry/mission/MissionResourceCollection.java index 18fe4e55c..4c3e4f60f 100644 --- a/src/main/java/zmaster587/advancedRocketry/mission/MissionResourceCollection.java +++ b/src/main/java/zmaster587/advancedRocketry/mission/MissionResourceCollection.java @@ -48,6 +48,10 @@ public MissionResourceCollection(long duration, EntityRocket entity, LinkedList< startWorldTime = DimensionManager.getWorld(0).getTotalWorldTime(); this.duration = duration; + if (this.duration <= 0L) { + this.duration = 1L; // at least 1 tick + } + this.launchDimension = entity.world.provider.getDimension(); rocketStorage = entity.storage; rocketStats = entity.stats; @@ -64,6 +68,7 @@ public MissionResourceCollection(long duration, EntityRocket entity, LinkedList< @Override public double getProgress(World world) { + if (duration <= 0L) return 1.0d; return Math.max((AdvancedRocketry.proxy.getWorldTimeUniversal(0) - startWorldTime) / (double) duration, 0); } From 00fd0d0e903c985cd85d6aba91ada245276c73de Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 6 Nov 2025 14:25:20 +0100 Subject: [PATCH 105/274] Add newline at end of EntityStationDeployedRocket.java Fix formatting by adding a newline at the end of the file. From 87010e8a655f1e25c08cb17be2911cb46684c7eb Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 6 Nov 2025 14:28:06 +0100 Subject: [PATCH 106/274] Fix missing newline at end of file Add missing newline at the end of StatsRocket.java From 037c6f8fee8bdc7c9259086e35a8fb144e006203 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 6 Nov 2025 16:05:11 +0100 Subject: [PATCH 107/274] Enhance rocket pad handling in TileRocketAssemblingMachine Added logic to recompute rocket pad bounds and link infrastructure during onLoad and And properly clearing caches. --- .../tile/TileRocketAssemblingMachine.java | 44 +++++++++++++++---- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java b/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java index 1b05536af..88d14b92f 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java @@ -98,33 +98,61 @@ public TileRocketAssemblingMachine() { @Override public void onLoad() { - // Called after world is set and NBT is loaded; safe place to register (server only) if (!world.isRemote && !registeredBus) { MinecraftForge.EVENT_BUS.register(this); registeredBus = true; } - } + + if (world.isRemote) return; + + // Recompute pad bounds and relink infra to any rockets already on the pad + bbCache = getRocketPadBounds(world, pos); + if (bbCache != null) { + final AxisAlignedBB box = bbCache.grow(1.0E-4, 1.0E-4, 1.0E-4); + List rockets = world.getEntitiesWithinAABB(EntityRocketBase.class, box); + if (!rockets.isEmpty()) { + for (IInfrastructure infra : getConnectedInfrastructure()) { + for (EntityRocketBase r : rockets) { + r.linkInfrastructure(infra); + } + } + } + } + } @Override public void invalidate() { super.invalidate(); unregisterFromBus(); - if (world != null) - for (HashedBlockPosition pos : blockPos) { - TileEntity tile = world.getTileEntity(pos.getBlockPos()); - if (tile instanceof IMultiblock) { - ((IMultiblock) tile).setIncomplete(); + // Notify linked multiblocks BEFORE clearing (server only) + if (world != null && !world.isRemote) { + for (HashedBlockPosition p : blockPos) { + TileEntity te = world.getTileEntity(p.getBlockPos()); + if (te instanceof IMultiblock) { + ((IMultiblock) te).setIncomplete(); } + } } + + // Clear caches + bbCache = null; + stats.reset(); + blockPos.clear(); } @Override public void onChunkUnload() { super.onChunkUnload(); unregisterFromBus(); + + // Clear caches + bbCache = null; + stats.reset(); + blockPos.clear(); } + private void unregisterFromBus() { if (registeredBus) { MinecraftForge.EVENT_BUS.unregister(this); @@ -1171,7 +1199,7 @@ public void onRocketLand(RocketLandedEvent e) { if (e.world.isRemote || e.world != this.world) return; // Ensure we have pad bounds - if (bbCache == null) bbCache = getRocketPadBounds(world, pos); + bbCache = getRocketPadBounds(world, pos); if (bbCache == null) return; // Make sure the event entity is a rocket From 15ae3190c5d73dbcc3ffed2f69866fd2e28c8d40 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 6 Nov 2025 16:05:33 +0100 Subject: [PATCH 108/274] Clear caches in unlink and onChunkUnload methods Clear cached fuel and work strings on unlink and chunk unload. --- .../tile/infrastructure/TileFuelingStation.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java index 0ca2b7021..2bc3aa5c1 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java @@ -457,6 +457,8 @@ public void unlinkRocket() { this.linkedRocket = null; this.fuelingActive = false; this.lastRs = null; + lastFuelStr = lastOxStr = lastWorkStr = null; + cachedFuelFluid = cachedOxFluid = cachedWorkFluid = null; ((BlockTileRedstoneEmitter) AdvancedRocketryBlocks.blockFuelingStation) .setRedstoneState(world, world.getBlockState(pos), pos, false); markDirty(); @@ -516,7 +518,9 @@ public void invalidate() { if (linkedRocket != null) linkedRocket.unlinkInfrastructure(this); - // Hard-off to avoid stale output when chunk unload order is weird + // Clear caches + lastFuelStr = lastOxStr = lastWorkStr = null; + cachedFuelFluid = cachedOxFluid = cachedWorkFluid = null; lastRs = null; fuelingActive = false; @@ -670,6 +674,9 @@ public void onChunkUnload() { super.onChunkUnload(); if (world == null || world.isRemote) return; + // Clear caches + lastFuelStr = lastOxStr = lastWorkStr = null; + cachedFuelFluid = cachedOxFluid = cachedWorkFluid = null; lastRs = null; fuelingActive = false; if (AdvancedRocketryBlocks.blockFuelingStation instanceof BlockTileRedstoneEmitter) { From 7c1002f9432f4115a22b5028120fa162369c8976 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 6 Nov 2025 16:18:16 +0100 Subject: [PATCH 109/274] Implement cleanup in invalidate and onChunkUnload methods Clear data structures and reset variables on invalidation and chunk unload. --- .../tile/multiblock/TileObservatory.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java b/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java index 3f1e3dcc4..7a06f4df2 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/multiblock/TileObservatory.java @@ -819,6 +819,26 @@ public void clear() { } + @Override + public void invalidate() { + super.invalidate(); + dataCables.clear(); + buttonType.clear(); + printedButtonsThisSeed.clear(); + printedSetSeed = -1; + lastSeed = -1; + lastButton = -1; + lastType = ""; + ModuleContainerPanYOnlyWithScrollCache.clearScrollCache(); // static GUI cache + } + + @Override + public void onChunkUnload() { + super.onChunkUnload(); + dataCables.clear(); + ModuleContainerPanYOnlyWithScrollCache.clearScrollCache(); + } + @Override public void onModuleUpdated(ModuleBase module) { //ReopenUI on server From f556049077e2d5a7485040141872577a0ac0647b Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 6 Nov 2025 16:19:11 +0100 Subject: [PATCH 110/274] Update TileGasChargePad.java behave on idle .. --- .../tile/atmosphere/TileGasChargePad.java | 115 +++++++++++++----- 1 file changed, 82 insertions(+), 33 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/atmosphere/TileGasChargePad.java b/src/main/java/zmaster587/advancedRocketry/tile/atmosphere/TileGasChargePad.java index 3537b10a5..b5ecf46b3 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/atmosphere/TileGasChargePad.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/atmosphere/TileGasChargePad.java @@ -29,10 +29,23 @@ import java.util.List; public class TileGasChargePad extends TileInventoriedRFConsumerTank implements IModularInventory { + private static final int TICK_INTERVAL = 2; + // Avoid per-tick AABB allocation: cache lazily + @Nullable + private AxisAlignedBB cachedPlayerBox; + public TileGasChargePad() { super(0, 2, 16000); } + // Lazy AABB getter + private AxisAlignedBB getPlayerBox() { + if (cachedPlayerBox == null) { + cachedPlayerBox = new AxisAlignedBB(pos, pos.add(1, 2, 1)); + } + return cachedPlayerBox; + } + @Override @Nonnull public int[] getSlotsForFace(@Nullable EnumFacing side) { @@ -81,7 +94,18 @@ public T getCapability(Capability capability, @Nullable EnumFacing facing @Override public boolean canPerformFunction() { if (!world.isRemote) { - for (EntityPlayer player : this.world.getEntitiesWithinAABB(EntityPlayer.class, new AxisAlignedBB(pos, pos.add(1, 2, 1)))) { + + // Throttle: only run every TICK_INTERVAL ticks + if ((world.getTotalWorldTime() % TICK_INTERVAL) != 0) { + return false; + } + + FluidStack tf = this.tank.getFluid(); + if (tf == null || tf.amount <= 0) { + return false; + } + + for (EntityPlayer player : this.world.getEntitiesWithinAABB(EntityPlayer.class, getPlayerBox())) { ItemStack stack = player.getItemStackFromSlot(EntityEquipmentSlot.CHEST); if (!stack.isEmpty()) { @@ -94,15 +118,18 @@ else if (ItemAirUtils.INSTANCE.isStackValidAirContainer(stack)) //Check for O2 fill if (fillable != null) { - int amtFluid = fillable.getMaxAir(stack) - fillable.getAirRemaining(stack); - FluidStack fluidStack = this.drain(amtFluid, false); - - if (amtFluid > 0 && fluidStack != null && FluidUtils.areFluidsSameType(fluidStack.getFluid(), AdvancedRocketryFluids.fluidOxygen) && fluidStack.amount > 0) { - FluidStack fstack = this.drain(amtFluid, true); - this.markDirty(); - world.markChunkDirty(getPos(), this); - fillable.increment(stack, fstack.amount); - return true; + int deficit = fillable.getMaxAir(stack) - fillable.getAirRemaining(stack); + tf = this.tank.getFluid(); // refresh + if (deficit > 0 && tf != null + && FluidUtils.areFluidsSameType(tf.getFluid(), AdvancedRocketryFluids.fluidOxygen) + && tf.amount > 0) { + int toDrain = Math.min(deficit, tf.amount); + FluidStack drained = this.drain(toDrain, true); + if (drained != null && drained.amount > 0) { + fillable.increment(stack, drained.amount); + this.markDirty(); // no world.markChunkDirty + return true; + } } } } @@ -112,36 +139,39 @@ else if (ItemAirUtils.INSTANCE.isStackValidAirContainer(stack)) if (this.tank.getFluid() != null && !FluidUtils.areFluidsSameType(this.tank.getFluid().getFluid(), AdvancedRocketryFluids.fluidOxygen) && !stack.isEmpty() && stack.getItem() instanceof IModularArmor) { IInventory inv = ((IModularArmor) stack.getItem()).loadModuleInventory(stack); - FluidStack fluidStack = this.drain(100, false); - if (fluidStack != null) { + // Create a trial FluidStack up to available amount + final int perAttempt = 100 * TICK_INTERVAL; + int trialAmt = Math.min(perAttempt, this.tank.getFluid().amount); + if (trialAmt > 0) { + FluidStack trial = new FluidStack(this.tank.getFluid(), trialAmt); for (int i = 0; i < inv.getSizeInventory(); i++) { if (!((IModularArmor) stack.getItem()).canBeExternallyModified(stack, i)) continue; ItemStack module = inv.getStackInSlot(i); - if (FluidUtils.containsFluid(module)) { - int amtFilled = module.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, EnumFacing.UP).fill(fluidStack, true); - if (amtFilled == 100) { - this.drain(100, true); - - this.markDirty(); - world.markChunkDirty(getPos(), this); - - ((IModularArmor) stack.getItem()).saveModuleInventory(stack, inv); - - return true; - } + if (!FluidUtils.containsFluid(module)) continue; // fast path + net.minecraftforge.fluids.capability.IFluidHandlerItem fh = + module.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, EnumFacing.UP); + if (fh == null) continue; // null-guard + + int amtFilled = fh.fill(trial, true); + // Accept partial fills: drain exactly what was accepted + if (amtFilled > 0) { + this.drain(amtFilled, true); + this.markDirty(); // no world.markChunkDirty + ((IModularArmor) stack.getItem()).saveModuleInventory(stack, inv); + return true; } - } - } - } - - return false; - } - } - return false; - } + } + } + } + } + // no player matched this tick + return false; + } + return false; + } @Override public void performFunction() { @@ -188,4 +218,23 @@ private boolean useBucket(int slot, @Nonnull ItemStack stack) { public boolean isEmpty() { return inventory.isEmpty(); } + + @Override + public void invalidate() { + super.invalidate(); + cachedPlayerBox = null; // drop cached AABB + } + + @Override + public void onChunkUnload() { + super.onChunkUnload(); + cachedPlayerBox = null; // drop cached AABB + } + + @Override + public void onLoad() { + super.onLoad(); + // Ensure cache recomputes from the current pos after NBT load + cachedPlayerBox = null; + } } From d2278542f615af718240037f0fc9420ef6f231db Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 7 Nov 2025 18:21:40 +0100 Subject: [PATCH 111/274] hide unused datatypes in tooltips Limit data types to supported types in ItemMultiData --- .../advancedRocketry/item/ItemMultiData.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemMultiData.java b/src/main/java/zmaster587/advancedRocketry/item/ItemMultiData.java index b0b72a2bf..e9f48657b 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemMultiData.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemMultiData.java @@ -42,6 +42,14 @@ public int getData(@Nonnull ItemStack stack, DataStorage.DataType type) { public int getMaxData(@Nonnull ItemStack stack) { return getDataStorage(stack).getMaxData(); } + // Supported types for this item. Others will be ignored. + // FIX IF WE ADD MORE TYPES TO DataStorage.DataType + private static final java.util.EnumSet SUPPORTED_TYPES = + java.util.EnumSet.of( + DataStorage.DataType.COMPOSITION, + DataStorage.DataType.MASS, + DataStorage.DataType.DISTANCE + ); private MultiData getDataStorage(@Nonnull ItemStack item) { @@ -117,9 +125,9 @@ public void addInformation(@Nonnull ItemStack stack, World player, List MultiData data = getDataStorage(stack); - for (DataStorage.DataType type : DataStorage.DataType.values()) { - if (type != DataStorage.DataType.UNDEFINED) - list.add(data.getDataAmount(type) + " / " + data.getMaxData() + " " + I18n.format(type.toString(), new Object[0]) + " Data"); + for (DataStorage.DataType type : SUPPORTED_TYPES) { + final int amt = data.getDataAmount(type); + list.add(amt + " / " + data.getMaxData() + " " + I18n.format(type.toString()) + " Data"); } } } From 8df5c733e50830d0a8a668942e531d928371ae9c Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 7 Nov 2025 18:23:42 +0100 Subject: [PATCH 112/274] added public method to pass on to moniter Add method to generate a short display ID from UUID and type --- .../advancedRocketry/item/ItemAsteroidChip.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java b/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java index bddbf843e..d26d5bb00 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java @@ -23,7 +23,14 @@ public boolean isDamageable() { return false; } - + public static String shortDisplayId(Long uuid, String type) { + long base = (uuid == null) ? 0L : uuid; + long th = (type == null) ? 0L : Integer.toUnsignedLong(type.hashCode()); + long disp = mix64(base ^ (th << 1)); + String hex = Long.toUnsignedString(disp, 16).toUpperCase(); + int N = 6; + return (hex.length() > N) ? hex.substring(hex.length() - N) : hex; + } /** * Removes any Information and reset the stack to a default state * From f43b98f68ea62113b941b845b4c080735b98fe1c Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 7 Nov 2025 20:16:20 +0100 Subject: [PATCH 113/274] Update rocket error messages and add new messages --- .../assets/advancedrocketry/lang/en_US.lang | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/main/resources/assets/advancedrocketry/lang/en_US.lang b/src/main/resources/assets/advancedrocketry/lang/en_US.lang index 45a2887da..f7d174435 100644 --- a/src/main/resources/assets/advancedrocketry/lang/en_US.lang +++ b/src/main/resources/assets/advancedrocketry/lang/en_US.lang @@ -26,7 +26,6 @@ tile.turf.name=Moon Turf tile.turfDark.name=Dark Moon Turf tile.cuttingMachine.name=Cutting Machine tile.sawBlade.name=Saw Blade Assembly -tile.controlComp.name=Mission Control Computer tile.precisionAssemblingMachine.name=Precision Assembler tile.spaceLaser.name=Orbital Laser Drill tile.Crystallizer.name=Crystallizer @@ -228,9 +227,13 @@ fluid.enrichedLava=Enriched Lava mission.asteroidmining.name=Asteroid Mining mission.gascollection.name=Gas Collection -error.rocket.cannotGetThere=Destination Unreachable -error.rocket.destinationNotExist=Cannot launch: Destination does not exist -error.rocket.notSameSystem=Cannot launch: Destination is not in the same planet system +error.rocket.notEnoughMissionFuel=Not enough fuel! +error.rocket.tooHeavy=Rocket is too heavy to launch (insufficient thrust). +error.rocket.cannotGetThere=Selected destination cannot be reached from here. +error.rocket.destinationNotExist=Selected space station does not exist. +error.rocket.notSameSystem=Interstellar travel requires a nuclear rocket and a valid route. +error.rocket.partsWornOut=Critical parts are worn out — launch aborted. +error.rocket.aborted=Launch aborted. advancement.holographic=Holographic advancement.holographic.desc=Craft a Holo-Projector @@ -313,14 +316,30 @@ msg.spaceElevator.warning.anchored1=the station anchored! msg.spaceElevator.warning.unanchored=This elevator has no tether msg.spaceElevator.turnedOff=Elevator is turned off msg.fuelingStation.link=You program the linker with the fueling station at + +msg.monitoringStation.buttonLaunch=Launch! msg.monitoringStation.missionProgressNA=Mission Progress: N/A +msg.monitoringStation.missionNoActiveMission=No Active Missions.. +msg.monitoringStation.mission.type.gas=Gas Collection Mission +msg.monitoringStation.mission.type.ore=Asteroid Mining Mission +msg.monitoringStation.mission.target.default=Harvest: (pending) +msg.monitoringStation.mission.targetPrefix=Harvest: +msg.monitoringStation.mission.Asteroid.target.default=Asteroid: +msg.monitoringStation.mission.Asteroid.targetPrefix=Asteroid: +msg.monitoringStation.mission.asteroidIdPrefix=Type: +msg.monitoringStation.mission.plannedAmountPrefix=Amount: +msg.monitoringStation.mission.plannedAmountPending=Amount: (pending) +msg.monitoringStation.mission.asteroidType=Asteroid type: (shown on chip / mission) msg.monitoringStation.link=You program the linker with the monitoring station at -msg.monitoringStation.progress= Progress: +msg.monitoringStation.progress=ETA: msg.monitoringStation.prelaunch=Initiating... msg.monitoringStation.launching=Launching! -msg.monitoringStation.orbit=Reached orbit +msg.monitoringStation.orbit=Reached orbit! +msg.monitoringStation.deorbiting=Returned from orbit! msg.monitoringStation.landed=Landed -msg.monitoringStation.aborted=Aborted +msg.monitoringStation.aborted=Aborted! + + msg.guidanceComputerHatch.loadingState=Loading State: msg.guidanceComputerHatch.ejectonlanding=Auto Eject Upon Landing msg.guidanceComputerHatch.ejectonsatlanding=Allow Ejection of Satellite Chips From b89b3109514bbc2ea5dcbbaa62402fb263cd9ebe Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 7 Nov 2025 20:16:43 +0100 Subject: [PATCH 114/274] Add error handling and fuel checks for rocket launch --- .../advancedRocketry/entity/EntityRocket.java | 65 ++++++++++++++++++- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java b/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java index af41de4a1..cc75d2f74 100644 --- a/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java +++ b/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java @@ -427,6 +427,20 @@ else if (!isInFlight()) private void setError(String error) { this.errorStr = error; this.lastErrorTime = this.world.getTotalWorldTime(); + + if (!world.isRemote) { + // notify riders only + for (Entity e : this.getPassengers()) { + if (e instanceof EntityPlayerMP) { + ((EntityPlayerMP) e).sendMessage(new TextComponentString(error)); + } + } + // post an event the monitor already consumes + MinecraftForge.EVENT_BUS.post(new RocketEvent.RocketAbortEvent(this, error)); + + // stop countdown if it was running + this.dataManager.set(LAUNCH_COUNTER, -1); + } } @Override @@ -732,6 +746,45 @@ protected boolean canFitPassenger(Entity passenger) { return this.getPassengers().size() < stats.getNumPassengerSeats(); } + + // Check if we have enough fuel to reach orbit from our current position + private boolean hasMissionFuelFor(int destDimId) { + if (!ARConfiguration.getCurrentConfig().rocketRequireFuel) return true; + + final FuelRegistry.FuelType main = getRocketFuelType(); + if (main == null) return false; // no usable tanks + + if (isInOrbit()) return true; // already at orbit + + if (stats.getThrust() <= stats.getWeight()) return false; + + final DimensionProperties src = DimensionManager.getInstance() + .getDimensionProperties(this.world.provider.getDimension()); + final float gSrc = Math.max(0.01f, src.getGravitationalMultiplier()); + final double a = Math.max(0.0001d, stats.getAcceleration(gSrc)); + final double h = Math.max(0.0, stats.orbitHeight - this.posY); + + long nTicks = (long)Math.ceil(Math.sqrt(2.0 * h / a)); + nTicks += 2L; // small safety buffer + if (nTicks <= 0) nTicks = 1; + + int mainRate = Math.max(1, getFuelConsumptionRate(main)); + long mainNeeded = nTicks * (long)mainRate; + long mainHave = getFuelAmount(main); + if (mainHave < mainNeeded) return false; + + if (main == FuelRegistry.FuelType.LIQUID_BIPROPELLANT) { + int oxRate = Math.max(1, getFuelConsumptionRate(FuelRegistry.FuelType.LIQUID_OXIDIZER)); + long oxNeeded = nTicks * (long)oxRate; + long oxHave = getFuelAmount(FuelRegistry.FuelType.LIQUID_OXIDIZER); + if (oxHave < oxNeeded) return false; + } + + // Descent currently does not burn fuel in your code path. + return true; + } + + /** * @param fluidStack the stack to check whether the rocket can fit * @return boolean on whether said fluid stack can fit into the rocket's internal fuel point storage @@ -1910,14 +1963,20 @@ public void launch() { if (this.stats.getWeight() >= this.stats.getThrust()) { - allowLaunch = false; + setError(LibVulpes.proxy.getLocalizedString("error.rocket.tooHeavy")); + return; // hard stop; no silent fall-through } //Check to see what place we should be going to //This is bad but it works and is mostly intelligible so it's here for now stats.orbitHeight = (storage.getGuidanceComputer() == null) ? getEntryHeight(this.world.provider.getDimension()) : storage.getGuidanceComputer().getLaunchSequence(this.world.provider.getDimension(), this.getPosition()); - - + + // Enough fuel for the mission? + if (!hasMissionFuelFor(destinationDimId)) { + setError(LibVulpes.proxy.getLocalizedString("error.rocket.notEnoughMissionFuel")); + return; + } + //TODO: Clean this logic a bit? if (allowLaunch || !stats.hasSeat() || ((DimensionManager.getInstance().isDimensionCreated(destinationDimId)) || destinationDimId == ARConfiguration.getCurrentConfig().spaceDimId || destinationDimId == 0)) { setInFlight(true); From 7e0e9a58ad8c7dfefab49a3c25e3a4ae183e2939 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 7 Nov 2025 20:17:37 +0100 Subject: [PATCH 115/274] Add RocketAbortEvent class for rocket abort handling --- .../java/zmaster587/advancedRocketry/api/RocketEvent.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/api/RocketEvent.java b/src/main/java/zmaster587/advancedRocketry/api/RocketEvent.java index e4c3644fc..a93b79b26 100644 --- a/src/main/java/zmaster587/advancedRocketry/api/RocketEvent.java +++ b/src/main/java/zmaster587/advancedRocketry/api/RocketEvent.java @@ -35,6 +35,13 @@ public RocketPreLaunchEvent(Entity entity) { super(entity); } } + public static class RocketAbortEvent extends RocketEvent { + public final String reason; // optional, for GUIs/logs + public RocketAbortEvent(Entity entity, String reason) { + super(entity); + this.reason = reason; + } + } /** * Fired before the rocket is finished teleporting to the destination world on the Minecraft Forge EVENT_BUS From 3cc98a19f48e810ff60cd5f72c5184c67193bb76 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 7 Nov 2025 20:18:07 +0100 Subject: [PATCH 116/274] Add orbitEventPosted flag to prevent duplicate events Added a flag to track if the orbit event has been posted to prevent duplicate events. --- .../entity/EntityStationDeployedRocket.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/entity/EntityStationDeployedRocket.java b/src/main/java/zmaster587/advancedRocketry/entity/EntityStationDeployedRocket.java index 0f6f48d83..4516ffa9c 100644 --- a/src/main/java/zmaster587/advancedRocketry/entity/EntityStationDeployedRocket.java +++ b/src/main/java/zmaster587/advancedRocketry/entity/EntityStationDeployedRocket.java @@ -62,6 +62,8 @@ public class EntityStationDeployedRocket extends EntityRocket { private short gasId; private Ticket ticket; private long plannedHarvestMb = 0L; // planned total mB to attempt this mission + private boolean orbitEventPosted = false; // not persisted to NBT + public EntityStationDeployedRocket(World world) { super(world); @@ -393,13 +395,17 @@ else if (gasId > props.getHarvestableGasses().size() - 1) /** * Called when the rocket reaches orbit */ + @Override public void onOrbitReached() { - //make it 30 minutes with one drill + if (world.isRemote) return; // client should not run any of this - if (world.isRemote)System.out.println("this code should not run on client side!"); + // Fire the standard event exactly once for monitors + if (!orbitEventPosted) { + MinecraftForge.EVENT_BUS.post(new RocketEvent.RocketReachesOrbitEvent(this)); + orbitEventPosted = true; + } - if (this.isDead) - return; + if (this.isDead) return; //Check again to make sure we are around a gas giant ISpaceObject spaceObj; From 6903006165766068c1bc584c010ea3c5c7a24b4a Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 7 Nov 2025 20:18:25 +0100 Subject: [PATCH 117/274] Initialize missionPersistantNBT and add getter for harvest Initialize missionPersistantNBT in constructors and add method to retrieve planned harvest amount. --- .../mission/MissionResourceCollection.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/mission/MissionResourceCollection.java b/src/main/java/zmaster587/advancedRocketry/mission/MissionResourceCollection.java index 4c3e4f60f..6b4e20c68 100644 --- a/src/main/java/zmaster587/advancedRocketry/mission/MissionResourceCollection.java +++ b/src/main/java/zmaster587/advancedRocketry/mission/MissionResourceCollection.java @@ -37,6 +37,7 @@ public abstract class MissionResourceCollection extends SatelliteBase implements public MissionResourceCollection() { infrastructureCoords = new LinkedList<>(); + missionPersistantNBT = new NBTTagCompound(); } public MissionResourceCollection(long duration, EntityRocket entity, LinkedList infrastructureCoords) { @@ -66,6 +67,13 @@ public MissionResourceCollection(long duration, EntityRocket entity, LinkedList< this.infrastructureCoords.add(new HashedBlockPosition(((TileEntity) tile).getPos())); } + public long getPlannedHarvestMbOrDefault() { + if (missionPersistantNBT != null && missionPersistantNBT.hasKey("plannedHarvestMb")) { + return Math.max(0L, missionPersistantNBT.getLong("plannedHarvestMb")); + } + return -1L; // means "unknown/not provided" + } + @Override public double getProgress(World world) { if (duration <= 0L) return 1.0d; @@ -148,7 +156,8 @@ public void writeToNBT(NBTTagCompound nbt) { public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); - missionPersistantNBT = nbt.getCompoundTag("persist"); + missionPersistantNBT = nbt.hasKey("persist") ? nbt.getCompoundTag("persist") : new NBTTagCompound(); + rocketStats = new StatsRocket(); rocketStats.readFromNBT(nbt.getCompoundTag("rocketStats")); From a8b5cd34d78eaf481b4d163bd140c87f2a3258c3 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 7 Nov 2025 20:34:23 +0100 Subject: [PATCH 118/274] Add asteroid metadata persistence in MissionOreMining Persist asteroid metadata for the monitor UI, including asteroid type and UUID. --- .../mission/MissionOreMining.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/mission/MissionOreMining.java b/src/main/java/zmaster587/advancedRocketry/mission/MissionOreMining.java index 3e180f4fa..2f777071d 100644 --- a/src/main/java/zmaster587/advancedRocketry/mission/MissionOreMining.java +++ b/src/main/java/zmaster587/advancedRocketry/mission/MissionOreMining.java @@ -34,8 +34,38 @@ public MissionOreMining() { public MissionOreMining(long l, EntityRocket entityRocket, LinkedList connectedInfrastructure) { super(l, entityRocket, connectedInfrastructure); + + // Persist asteroid metadata for the monitor UI + try { + if (rocketStorage != null && rocketStorage.getGuidanceComputer() != null) { + ItemStack chip = rocketStorage.getGuidanceComputer().getStackInSlot(0); + if (!chip.isEmpty() && chip.getItem() instanceof ItemAsteroidChip) { + ItemAsteroidChip ac = (ItemAsteroidChip) chip.getItem(); + + String type = ac.getType(chip); + Long uuid = ac.getUUID(chip); + + if (type != null && !type.isEmpty()) + missionPersistantNBT.setString("asteroidType", type); + if (uuid != null) + missionPersistantNBT.setLong("asteroidUUID", uuid); + } + } + } catch (Throwable t) { + // leave fields unset; GUI will show defaults + } } + + public String getAsteroidTypeOrEmpty() { + return (missionPersistantNBT != null && missionPersistantNBT.hasKey("asteroidType")) + ? missionPersistantNBT.getString("asteroidType") : ""; + } + @javax.annotation.Nullable + public Long getAsteroidUUIDOrNull() { + return (missionPersistantNBT != null && missionPersistantNBT.hasKey("asteroidUUID")) + ? missionPersistantNBT.getLong("asteroidUUID") : null; + } @Override public void onMissionComplete() { From dc39cdba56db3444134fd269de6e25c516c39101 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 7 Nov 2025 20:34:50 +0100 Subject: [PATCH 119/274] Add getter for gasFluid in MissionGasCollection monitor update --- .../advancedRocketry/mission/MissionGasCollection.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/mission/MissionGasCollection.java b/src/main/java/zmaster587/advancedRocketry/mission/MissionGasCollection.java index 7e48311e5..6cb80d0cc 100644 --- a/src/main/java/zmaster587/advancedRocketry/mission/MissionGasCollection.java +++ b/src/main/java/zmaster587/advancedRocketry/mission/MissionGasCollection.java @@ -128,6 +128,10 @@ public void writeToNBT(NBTTagCompound nbt) { } } + public net.minecraftforge.fluids.Fluid getGasFluid() { + return gasFluid; + } + @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); From d11d90401cdc74887f4f152aacf77b456ed54802 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 7 Nov 2025 20:37:47 +0100 Subject: [PATCH 120/274] Refactor satellite resolution and caching logic --- .../tile/satellite/TileSatelliteTerminal.java | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java b/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java index 9346726cc..c930fc2c3 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/satellite/TileSatelliteTerminal.java @@ -124,17 +124,13 @@ private void maybeAutoDownloadFromSatellite(boolean force) { return; } - // Hoist satellite once - final SatelliteBase sat = getCachedSatellite(); + // Resolve satellite fresh from the chip each poll + SatelliteBase sat = resolveSatelliteFresh(); if (sat == null) { if (!force) autoDlInterval = Math.min(autoDlInterval << 1, AUTO_DL_MAX_INTERVAL_TICKS); nextAutoDlTick = now + autoDlInterval; return; } - - - - // No link or power → back off (unless forced) if (!hasLinkAndPower(sat)) { if (!force) autoDlInterval = Math.min(autoDlInterval << 1, AUTO_DL_MAX_INTERVAL_TICKS); nextAutoDlTick = now + autoDlInterval; @@ -245,21 +241,22 @@ public void useNetworkData(EntityPlayer player, Side side, byte id, NBTTagCompou } } - @Nullable private SatelliteBase cachedSat = null; + @Nullable + private SatelliteBase resolveSatelliteFresh() { + ItemStack s0 = getStackInSlot(0); + return (!s0.isEmpty() && s0.getItem() instanceof ItemSatelliteIdentificationChip) + ? ItemSatelliteIdentificationChip.getSatellite(s0) + : null; + } @Override public void setInventorySlotContents(int slot, @Nonnull ItemStack stack) { super.setInventorySlotContents(slot, stack); if (!world.isRemote && slot == 0) { - cachedSat = (!stack.isEmpty() && stack.getItem() instanceof ItemSatelliteIdentificationChip) - ? ItemSatelliteIdentificationChip.getSatellite(stack) - : null; maybeAutoDownloadFromSatellite(true); // force reset to base } } - private @Nullable SatelliteBase getCachedSatellite() { return cachedSat; } - public SatelliteBase getSatelliteFromSlot(int slot) { ItemStack stack = getStackInSlot(slot); if (!stack.isEmpty() && stack.getItem() instanceof ItemSatelliteIdentificationChip) { @@ -377,19 +374,27 @@ public int addData(int maxAmount, DataType type, EnumFacing dir, boolean commit) public void onLoad() { super.onLoad(); if (!world.isRemote) { - // Rebuild cache from current slot-0 - ItemStack s0 = getStackInSlot(0); - cachedSat = (!s0.isEmpty() && s0.getItem() instanceof ItemSatelliteIdentificationChip) - ? ItemSatelliteIdentificationChip.getSatellite(s0) - : null; - + // Reset backoff scheduler to a sane base state autoDlInterval = AUTO_DL_BASE_INTERVAL_TICKS; - nextAutoDlTick = Math.min(nextAutoDlTick, world.getTotalWorldTime() + AUTO_DL_MAX_INTERVAL_TICKS); - maybeAutoDownloadFromSatellite(false); + long now = world.getTotalWorldTime(); + // Warm-up so neighbors/registries settle (e.g. 80 ticks ~ 4s) + nextAutoDlTick = now + 80; } } + @Override + public void onChunkUnload() { + super.onChunkUnload(); + // Hard-clear any references and scheduling + autoDlInterval = AUTO_DL_BASE_INTERVAL_TICKS; + nextAutoDlTick = 0L; + } + // Clear caches if the block/TE is invalidated (broken/replaced) + @Override + public void invalidate() { + super.invalidate(); + } @Override From f37f59bf7b872b80fd383b971089697fe58b16b5 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 7 Nov 2025 20:38:48 +0100 Subject: [PATCH 121/274] Refactor network handling and UI synchronization --- .../tile/cables/TileWirelessTransciever.java | 79 ++++++++++++------- 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java b/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java index 1f8c9187a..b44255465 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java @@ -156,11 +156,21 @@ public boolean onLinkStart(@Nonnull ItemStack item, TileEntity entity, EntityPla @Override public void onChunkUnload() { super.onChunkUnload(); - if (networkID == -1) return; - if (NetworkRegistry.dataNetwork.doesNetworkExist(networkID)) + + // Leave the network cleanly if linked + if (networkID != -1 && NetworkRegistry.dataNetwork.doesNetworkExist(networkID)) { NetworkRegistry.dataNetwork.getNetwork(networkID).removeFromAll(this); + } + + // Clear per-instance caches + phase = -1; + + // Clear UI-only mirror (logic stays in 'data') + uiBuffer.setMaxData(data.getMaxData()); + uiBuffer.setData(0, DataType.UNDEFINED); } + @Override public boolean onLinkComplete(@Nonnull ItemStack item, TileEntity entity, EntityPlayer player, World world) { BlockPos pos = ItemLinker.getMasterCoords(item); @@ -303,17 +313,19 @@ public void readDataFromNetwork(ByteBuf in, byte packetId, public void useNetworkData(EntityPlayer player, Side side, byte id, NBTTagCompound nbt) { if (!side.isServer()) return; - if (id == 1) { // enable/disable toggle — always allowed + if (id == 1) { // enable/disable enabled = nbt.getBoolean("state"); + + // persist + push to clients + this.markDirty(); + world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3); return; } - if (id == 0) { // extract/insert toggle - // Always update local state so neighbors (like the terminal) can see it + if (id == 0) { // extract/insert extractMode = nbt.getBoolean("state"); updateToggleLabel(); - // Only touch the network if we are actually linked if (networkID != -1 && NetworkRegistry.dataNetwork.doesNetworkExist(networkID)) { NetworkRegistry.dataNetwork.getNetwork(networkID).removeFromAll(this); if (extractMode) { @@ -322,31 +334,39 @@ public void useNetworkData(EntityPlayer player, Side side, byte id, NBTTagCompou NetworkRegistry.dataNetwork.getNetwork(networkID).addSink(this, EnumFacing.UP); } } + + // persist + push to clients + this.markDirty(); + world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3); return; } } + @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); extractMode = nbt.getBoolean("mode"); - enabled = nbt.getBoolean("enabled"); - networkID = nbt.getInteger("networkID"); + enabled = nbt.getBoolean("enabled"); + networkID = nbt.getInteger("networkID"); data.readFromNBT(nbt); + syncUiBufferFromMultiData(); - //addToNetwork(); - toggle.setToggleState(extractMode); + // Mirror persisted booleans into UI widgets (guard null on client) + if (toggle != null) toggle.setToggleState(extractMode); + if (toggleSwitch != null) toggleSwitch.setToggleState(enabled); updateToggleLabel(); - toggleSwitch.setToggleState(enabled); + + // Client-only network label text if (world != null && world.isRemote && netIdLabel != null) { - String idStr = (networkID == -1) + String idStr = (networkID == -1) ? net.minecraft.client.resources.I18n.format("msg.wirelessTransciever.network.unlinked") : Integer.toString(networkID); - String label = LibVulpes.proxy.getLocalizedString("msg.wirelessTransciever.network"); - netIdLabel.setText(label + idStr); + String label = LibVulpes.proxy.getLocalizedString("msg.wirelessTransciever.network"); + netIdLabel.setText(label + idStr); } } @@ -386,31 +406,27 @@ public void onLoad() { super.onLoad(); if (!world.isRemote) { - syncUiBufferFromMultiData(); // ensures server-side mirror matches after load - // Ensure booleans reflect current UI widgets on server after load/place - extractMode = toggle.getState(); - enabled = toggleSwitch.getState(); + // Rebuild UI mirror from authoritative MultiData + syncUiBufferFromMultiData(); + + // Mirror persisted booleans -> widgets (do NOT read from widgets) + if (toggle != null) toggle.setToggleState(extractMode); + if (toggleSwitch != null) toggleSwitch.setToggleState(enabled); + updateToggleLabel(); } - // Server side only if (world == null || world.isRemote) return; - // Ensure sane interval before using it in modulo + // Recompute throttle phase after we cleared it if (transferIntervalTicks <= 0) transferIntervalTicks = 20; - - // Stable per-tile phase to spread work over time (no persistence needed) phase = (int) Math.floorMod(this.pos.toLong(), transferIntervalTicks); - // (Re)join the data network only if we’re actually linked to one + // Rejoin the network with the correct role (source/sink) if (networkID != -1) { if (!NetworkRegistry.dataNetwork.doesNetworkExist(networkID)) { - // Create (or re-create) this specific network id NetworkRegistry.dataNetwork.getNewNetworkID(networkID); } - - // Make sure we're not double-registered, then register with the right role NetworkRegistry.dataNetwork.getNetwork(networkID).removeFromAll(this); - if (extractMode) { NetworkRegistry.dataNetwork.getNetwork(networkID).addSource(this, EnumFacing.UP); } else { @@ -419,6 +435,8 @@ public void onLoad() { } } + + @Override public void update() { // Server only @@ -511,11 +529,14 @@ public void stateUpdated(ModuleBase module) { } @Override public void invalidate() { - // called when the TE is removed because the block changed/broke - if (!world.isRemote && NetworkRegistry.dataNetwork.doesNetworkExist(networkID)) { + if (!world.isRemote && networkID != -1 && NetworkRegistry.dataNetwork.doesNetworkExist(networkID)) { NetworkRegistry.dataNetwork.getNetwork(networkID).removeFromAll(this); } + // Clear per-instance caches + phase = -1; + super.invalidate(); } + } From f79383d113b82c2b57c689bfbec60e070dc4084e Mon Sep 17 00:00:00 2001 From: kaduvill Date: Fri, 7 Nov 2025 21:02:25 +0100 Subject: [PATCH 122/274] Improve AABB normalization and rocket assembly logic Refactor AABB handling and normalization in rocket assembly. --- .../tile/TileRocketAssemblingMachine.java | 76 ++++++++++++++----- 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java b/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java index 88d14b92f..18ee1b226 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java @@ -539,7 +539,20 @@ public AxisAlignedBB scanRocket(World world, BlockPos pos2, AxisAlignedBB bb) { status = ErrorCodes.SUCCESS; } } - return new AxisAlignedBB(actualMinX, actualMinY, actualMinZ, actualMaxX, actualMaxY, actualMaxZ); + + // Normalize integer mins/maxes first + int minXi = Math.min(actualMinX, actualMaxX); + int minYi = Math.min(actualMinY, actualMaxY); + int minZi = Math.min(actualMinZ, actualMaxZ); + int maxXi = Math.max(actualMinX, actualMaxX); + int maxYi = Math.max(actualMaxY, actualMinY); + int maxZi = Math.max(actualMinZ, actualMaxZ); + + // IMPORTANT: use BlockPos ctor so the AABB is [min, max+1) in block space + return new AxisAlignedBB( + new BlockPos(minXi, minYi, minZi), + new BlockPos(maxXi, maxYi, maxZi) + ); } protected void removeReplaceableBlocks(AxisAlignedBB bb) { @@ -562,37 +575,63 @@ protected void removeReplaceableBlocks(AxisAlignedBB bb) { } } + private static boolean isEmptyAABB(@Nullable AxisAlignedBB b) { + return b == null || b.maxX < b.minX || b.maxY < b.minY || b.maxZ < b.minZ; + } + + + private static AxisAlignedBB normalize(AxisAlignedBB b) { + double minX = Math.min(b.minX, b.maxX); + double minY = Math.min(b.minY, b.maxY); + double minZ = Math.min(b.minZ, b.maxZ); + double maxX = Math.max(b.minX, b.maxX); + double maxY = Math.max(b.minY, b.maxY); + double maxZ = Math.max(b.minZ, b.maxZ); + return new AxisAlignedBB(minX, minY, minZ, maxX, maxY, maxZ); + } + + public void assembleRocket() { + // server only + need a pad cache + if (world.isRemote || bbCache == null) return; - if (bbCache == null || world.isRemote) - return; - // Need to scan again b/c something may have changed - AxisAlignedBB rocketBB = scanRocket(world, pos, bbCache); + // Re-scan to get a *tight* non-air AABB and fresh stats/status + final AxisAlignedBB scanBB = scanRocket(world, pos, bbCache); + if (status != ErrorCodes.SUCCESS || scanBB == null) return; - if (status != ErrorCodes.SUCCESS) + // Normalize and defensively guard against degenerate boxes + final AxisAlignedBB rocketBB = normalize(scanBB); + if (isEmptyAABB(rocketBB)) { + status = ErrorCodes.FAIL_CUT; return; + } - // Remove replacable blocks that don't belong on the rocket - removeReplaceableBlocks(bbCache); + // Remove replaceable/blacklisted blocks *inside the tightened bounds* + removeReplaceableBlocks(rocketBB); - StorageChunk storageChunk; + // Cut the world using the tightened box (avoid pad air) + final StorageChunk storageChunk; try { - storageChunk = StorageChunk.cutWorldBB(world, bbCache); - } catch (NegativeArraySizeException e) { + storageChunk = StorageChunk.cutWorldBB(world, rocketBB); + } catch (Throwable t) { // covers NegativeArraySizeException & other edge errors + status = ErrorCodes.FAIL_CUT; return; } - EntityRocket rocket = new EntityRocket(world, storageChunk, stats.copy(), - rocketBB.minX + (rocketBB.maxX - rocketBB.minX) / 2f + .5f, - this.getPos().getY(), - rocketBB.minZ + (rocketBB.maxZ - rocketBB.minZ) / 2f + .5f); + // Center spawn on tightened AABB + final double cx = rocketBB.minX + (rocketBB.maxX - rocketBB.minX) / 2.0 + 0.5; + final double cz = rocketBB.minZ + (rocketBB.maxZ - rocketBB.minZ) / 2.0 + 0.5; + final double cy = this.getPos().getY(); + EntityRocket rocket = new EntityRocket(world, storageChunk, stats.copy(), cx, cy, cz); world.spawnEntity(rocket); - NBTTagCompound nbtdata = new NBTTagCompound(); + NBTTagCompound nbtdata = new NBTTagCompound(); rocket.writeToNBT(nbtdata); - PacketHandler.sendToNearby(new PacketEntity(rocket, (byte) 0, nbtdata), rocket.world.provider.getDimension(), this.pos, 64); + PacketHandler.sendToNearby(new PacketEntity(rocket, (byte) 0, nbtdata), + rocket.world.provider.getDimension(), this.pos, 64); + // Finish & link as before stats.reset(); this.status = ErrorCodes.FINISHED; this.markDirty(); @@ -602,7 +641,8 @@ public void assembleRocket() { rocket.linkInfrastructure(infrastructure); } - scanRocket(world, pos, bbCache); // to show stats + // Rescan so UI immediately reflects the post-build state + scanRocket(world, pos, bbCache); } /** From b23f175d71d92d1f9e8210455509bbe437f3a4a7 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 02:09:18 +0100 Subject: [PATCH 123/274] Add getActualState method for fuel tank detection Sticky rotation for all engines --- .../block/BlockBipropellantRocketMotor.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockBipropellantRocketMotor.java b/src/main/java/zmaster587/advancedRocketry/block/BlockBipropellantRocketMotor.java index 74d3d4a6b..d847191fd 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockBipropellantRocketMotor.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockBipropellantRocketMotor.java @@ -39,6 +39,23 @@ public int getThrust(World world, BlockPos pos) { return 10; } + @Override + public IBlockState getActualState(@Nonnull IBlockState state, IBlockAccess world, BlockPos pos) { + if (world.getBlockState(pos.up()).getBlock() instanceof BlockFuelTank) + return state.withProperty(FACING, EnumFacing.DOWN); + if (world.getBlockState(pos.down()).getBlock() instanceof BlockFuelTank) + return state.withProperty(FACING, EnumFacing.UP); + if (world.getBlockState(pos.east()).getBlock() instanceof BlockFuelTank) + return state.withProperty(FACING, EnumFacing.EAST); + if (world.getBlockState(pos.west()).getBlock() instanceof BlockFuelTank) + return state.withProperty(FACING, EnumFacing.WEST); + if (world.getBlockState(pos.south()).getBlock() instanceof BlockFuelTank) + return state.withProperty(FACING, EnumFacing.SOUTH); + if (world.getBlockState(pos.north()).getBlock() instanceof BlockFuelTank) + return state.withProperty(FACING, EnumFacing.NORTH); + return super.getActualState(state, world, pos); + } + @Override public int getFuelConsumptionRate(World world, int x, int y, int z) { return 1; From e259b7dfc18c718221a8766d8a1131274dd8d775 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 02:10:11 +0100 Subject: [PATCH 124/274] Implement facing logic for nuclear rocket motor Added logic to determine block facing based on adjacent nuclear cores. --- .../block/BlockNuclearRocketMotor.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearRocketMotor.java b/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearRocketMotor.java index ed84d34d5..0658b8725 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearRocketMotor.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearRocketMotor.java @@ -3,11 +3,15 @@ import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import zmaster587.advancedRocketry.api.ARConfiguration; +import zmaster587.advancedRocketry.api.IRocketNuclearCore; import zmaster587.advancedRocketry.tile.TileBrokenPart; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class BlockNuclearRocketMotor extends BlockRocketMotor { @@ -20,7 +24,23 @@ public BlockNuclearRocketMotor(Material mat) { public int getThrust(World world, BlockPos pos) { return 35; } - + @Override + public IBlockState getActualState(@Nonnull IBlockState state, IBlockAccess world, BlockPos pos) { + // Prefer nuclear core adjacency over tanks + if (world.getBlockState(pos.up()).getBlock() instanceof IRocketNuclearCore) + return state.withProperty(FACING, EnumFacing.DOWN); + if (world.getBlockState(pos.down()).getBlock() instanceof IRocketNuclearCore) + return state.withProperty(FACING, EnumFacing.UP); + if (world.getBlockState(pos.east()).getBlock() instanceof IRocketNuclearCore) + return state.withProperty(FACING, EnumFacing.EAST); + if (world.getBlockState(pos.west()).getBlock() instanceof IRocketNuclearCore) + return state.withProperty(FACING, EnumFacing.WEST); + if (world.getBlockState(pos.south()).getBlock() instanceof IRocketNuclearCore) + return state.withProperty(FACING, EnumFacing.SOUTH); + if (world.getBlockState(pos.north()).getBlock() instanceof IRocketNuclearCore) + return state.withProperty(FACING, EnumFacing.NORTH); + return state; + } @Override public int getFuelConsumptionRate(World world, int x, int y, int z) { return 1; From 18cb4ab107a5c3c40709eb6e4175f0ccc810db3b Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 02:11:12 +0100 Subject: [PATCH 125/274] branched for SDrockets Refactor engine eligibility checks for rockets --- .../advancedRocketry/util/StorageChunk.java | 54 ++++++++++++++----- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/util/StorageChunk.java b/src/main/java/zmaster587/advancedRocketry/util/StorageChunk.java index b61cbc90e..bce2ccd3f 100644 --- a/src/main/java/zmaster587/advancedRocketry/util/StorageChunk.java +++ b/src/main/java/zmaster587/advancedRocketry/util/StorageChunk.java @@ -172,7 +172,8 @@ public void recalculateStats(StatsRocket stats) { float drillPower = 0f; //stats.reset_no_fuel(); stats.reset_no_fuel();// Oh Quarter... you can not keep adding engine and seat locations every launch - + final boolean isSD = (this.entity instanceof zmaster587.advancedRocketry.entity.EntityStationDeployedRocket); + float weight = 0; for (int yCurr = 0; yCurr <= this.sizeY; yCurr++) { @@ -193,18 +194,33 @@ public void recalculateStats(StatsRocket stats) { } //If rocketEngine increaseThrust - if (block instanceof IRocketEngine && (world.getBlockState(belowPos).getBlock().isAir(world.getBlockState(belowPos), world, belowPos) || world.getBlockState(belowPos).getBlock() instanceof BlockLandingPad || world.getBlockState(belowPos).getBlock() == AdvancedRocketryBlocks.blockLaunchpad)) { - if (block instanceof BlockNuclearRocketMotor) { - nuclearWorkingFluidUseMax += ((IRocketEngine) block).getFuelConsumptionRate(world, xCurr, yCurr, zCurr); - thrustNuclearNozzleLimit += ((IRocketEngine) block).getThrust(world, currBlockPos); - } else if (block instanceof BlockBipropellantRocketMotor) { - bipropellantfuelUse += ((IRocketEngine) block).getFuelConsumptionRate(world, xCurr, yCurr, zCurr); - thrustBipropellant += ((IRocketEngine) block).getThrust(world, currBlockPos); - } else if (block instanceof BlockRocketMotor) { - monopropellantfuelUse += ((IRocketEngine) block).getFuelConsumptionRate(world, xCurr, yCurr, zCurr); - thrustMonopropellant += ((IRocketEngine) block).getThrust(world, currBlockPos); + if (block instanceof IRocketEngine) { + boolean eligible; + if (isSD) { + // SD rockets: skip vertical requirements + eligible = true; + } else { + // Legacy vertical rule + IBlockState belowState = world.getBlockState(belowPos); + Block below = belowState.getBlock(); + eligible = below.isAir(belowState, world, belowPos) + || below instanceof BlockLandingPad + || below == AdvancedRocketryBlocks.blockLaunchpad; + } + + if (eligible) { + if (block instanceof BlockNuclearRocketMotor) { + nuclearWorkingFluidUseMax += ((IRocketEngine) block).getFuelConsumptionRate(world, xCurr, yCurr, zCurr); + thrustNuclearNozzleLimit += ((IRocketEngine) block).getThrust(world, currBlockPos); + } else if (block instanceof BlockBipropellantRocketMotor) { + bipropellantfuelUse += ((IRocketEngine) block).getFuelConsumptionRate(world, xCurr, yCurr, zCurr); + thrustBipropellant += ((IRocketEngine) block).getThrust(world, currBlockPos); + } else if (block instanceof BlockRocketMotor) { + monopropellantfuelUse += ((IRocketEngine) block).getFuelConsumptionRate(world, xCurr, yCurr, zCurr); + thrustMonopropellant += ((IRocketEngine) block).getThrust(world, currBlockPos); + } + stats.addEngineLocation(xCurr - (float)this.sizeX/2 + 0.5f, yCurr+0.5f, zCurr - (float)this.sizeZ/2 + 0.5f); } - stats.addEngineLocation(xCurr - (float) this.sizeX /2+0.5f, yCurr+0.5f, zCurr- (float) this.sizeZ /2+0.5f); } if (block instanceof IFuelTank) { @@ -219,8 +235,18 @@ public void recalculateStats(StatsRocket stats) { } } - if (block instanceof IRocketNuclearCore && ((world.getBlockState(belowPos).getBlock() instanceof IRocketNuclearCore) || (world.getBlockState(belowPos).getBlock() instanceof IRocketEngine))) { - thrustNuclearReactorLimit += ((IRocketNuclearCore) block).getMaxThrust(world, currBlockPos); + if (block instanceof IRocketNuclearCore) { + boolean counts; + if (isSD) { + // SD rockets: no vertical stack requirement + counts = true; + } else { + Block below = world.getBlockState(belowPos).getBlock(); + counts = (below instanceof IRocketNuclearCore) || (below instanceof IRocketEngine); + } + if (counts) { + thrustNuclearReactorLimit += ((IRocketNuclearCore) block).getMaxThrust(world, currBlockPos); + } } if (block instanceof BlockSeat && world.getBlockState(abovePos).getBlock().isPassable(world, abovePos)) { From 7f4726d38f729339fc9d87aef45a3a8bd05425ac Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 02:11:59 +0100 Subject: [PATCH 126/274] strenghtened linking on load Add a flag to track if the landed event was posted after loading from NBT. --- .../advancedRocketry/entity/EntityRocket.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java b/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java index cc75d2f74..4945bc0b7 100644 --- a/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java +++ b/src/main/java/zmaster587/advancedRocketry/entity/EntityRocket.java @@ -130,6 +130,8 @@ public class EntityRocket extends EntityRocketBase implements INetworkEntity, IM protected ModulePlanetSelector container; boolean acceptedPacket = false; SpacePosition spacePosition; + //true if we have posted the landed event after loading from nbt + private transient boolean postedLandedAfterLoad = false; //true if the rocket is on decent private boolean isInOrbit; //True if the rocket isn't on the ground @@ -1088,7 +1090,15 @@ public void onUpdate() { super.onUpdate(); long deltaTime = world.getTotalWorldTime() - lastWorldTickTicked; lastWorldTickTicked = world.getTotalWorldTime(); - + if (!world.isRemote && !postedLandedAfterLoad && this.ticksExisted >= 5) { + // Consider "landed" = entity exists, NOT in flight, NOT in orbit + if (!isInFlight() && !isInOrbit()) { + net.minecraftforge.common.MinecraftForge.EVENT_BUS.post( + new zmaster587.advancedRocketry.api.RocketEvent.RocketLandedEvent(this) + ); + postedLandedAfterLoad = true; + } + } if (world.isRemote) { double ct = 50; From 2e27bfa98d29df6ee6ee95d95406d132c73ae14a Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 02:12:50 +0100 Subject: [PATCH 127/274] Fix missing newline at end of file Add missing newline at the end of StatsRocket.java From ed77b61d271b102188d5b1cd50d743c44cf2a4ac Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 02:13:37 +0100 Subject: [PATCH 128/274] Refactor bounding box handling in TileUnmannedVehicleAssembler Updated the bounding box calculations and entity checks for unmanned vehicle assembly. --- .../tile/TileUnmannedVehicleAssembler.java | 57 ++++++++++++------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/TileUnmannedVehicleAssembler.java b/src/main/java/zmaster587/advancedRocketry/tile/TileUnmannedVehicleAssembler.java index 2091c4a2c..7e5b26981 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/TileUnmannedVehicleAssembler.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/TileUnmannedVehicleAssembler.java @@ -109,14 +109,14 @@ public void assembleRocket() { AxisAlignedBB rocketBB = scanRocket(world, getPos(), bbCache); if (status != ErrorCodes.SUCCESS || rocketBB == null) return; - // 2) Remove replaceable/blacklisted blocks before cutting (uses parent’s helper) - removeReplaceableBlocks(bbCache); + // 2) Remove replaceables **inside the tight box** + removeReplaceableBlocks(rocketBB); - // 3) Cut the world into a storage chunk + // 3) Cut the world using the **tight** AABB final StorageChunk storageChunk; try { - storageChunk = StorageChunk.cutWorldBB(world, bbCache); - } catch (NegativeArraySizeException e) { + storageChunk = StorageChunk.cutWorldBB(world, rocketBB); + } catch (Throwable t) { // covers NegativeArraySizeException, etc. return; } @@ -180,22 +180,26 @@ public void assembleRocket() { @Override public AxisAlignedBB scanRocket(World world, BlockPos pos2, AxisAlignedBB bb) { + // Always refresh local bounds first + AxisAlignedBB fresh = getRocketPadBounds(world, getPos()); + if (fresh == null) { + status = ErrorCodes.INCOMPLETESTRCUTURE; // upstream typo + return null; // avoid using stale bb + } + bbCache = fresh; + bb = fresh; // ensure loops below use the fresh bounds // fast-path: rocket entity already present? - if (getBBCache() == null) bbCache = getRocketPadBounds(world, getPos()); - if (bbCache != null) { - final AxisAlignedBB buffered = bbCache.grow(1.0e-4, 1.0e-4, 1.0e-4); - - java.util.List sdr = - world.getEntitiesWithinAABB(EntityStationDeployedRocket.class, buffered); - if (sdr.size() == 1) { - EntityStationDeployedRocket r = sdr.get(0); - r.recalculateStats(); - this.stats = r.stats.copy(); - this.status = ErrorCodes.ALREADY_ASSEMBLED; - return null; - } - } + final AxisAlignedBB buffered = bb.grow(1.0e-4, 1.0e-4, 1.0e-4); + java.util.List sdr = + world.getEntitiesWithinAABB(EntityStationDeployedRocket.class, buffered); + if (sdr.size() == 1) { + EntityStationDeployedRocket r = sdr.get(0); + r.recalculateStats(); + this.stats = r.stats.copy(); + this.status = ErrorCodes.ALREADY_ASSEMBLED; + return null; + } int thrustMonopropellant = 0; int thrustBipropellant = 0; int thrustNuclearNozzleLimit = 0; @@ -399,7 +403,14 @@ public AxisAlignedBB scanRocket(World world, BlockPos pos2, AxisAlignedBB bb) { } } - return new AxisAlignedBB(actualMinX, actualMinY, actualMinZ, actualMaxX, actualMaxY, actualMaxZ); + // Normalize bounds to avoid inverted AABBs on edge cases + double minX = Math.min(actualMinX, actualMaxX); + double minY = Math.min(actualMinY, actualMaxY); + double minZ = Math.min(actualMinZ, actualMaxZ); + double maxX = Math.max(actualMinX, actualMaxX); + double maxY = Math.max(actualMaxY, actualMinY); + double maxZ = Math.max(actualMinZ, actualMaxZ); + return new AxisAlignedBB(minX, minY, minZ, maxX, maxY, maxZ); } @@ -450,9 +461,13 @@ private boolean hasEnoughFuelUnmanned(@Nonnull FuelType family) { return sCan >= targetS; } + @Override public void onLoad() { super.onLoad(); } + @Override public void invalidate() { super.invalidate(); } - //No additional scanning is needed + @Override public void onChunkUnload() { super.onChunkUnload(); } + + @Override protected boolean verifyScan(AxisAlignedBB bb, World world) { return true; From 8492e8a1e4fa813cdf8c1bf00750df56bb08c3cd Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 02:14:22 +0100 Subject: [PATCH 129/274] Implement relink retries for infrastructure linking Added relink retry logic for infrastructure linking in the rocket assembling machine. strengthening relinking onload avoiding races --- .../tile/TileRocketAssemblingMachine.java | 75 +++++++++++++++---- 1 file changed, 59 insertions(+), 16 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java b/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java index 18ee1b226..4620d22ff 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java @@ -82,6 +82,8 @@ public class TileRocketAssemblingMachine extends TileEntityRFConsumer implements private boolean building; //True is rocket is being built, false if only scanning or otherwise private int lastRocketID; private List blockPos; + private int relinkRetries = 0; // how many relinking tries left + private long nextRelinkAttempt = 0L; // world time for next try public TileRocketAssemblingMachine() { super(100000); @@ -102,7 +104,10 @@ public void onLoad() { MinecraftForge.EVENT_BUS.register(this); registeredBus = true; } - + if (!world.isRemote) { + relinkRetries = 10; // up to ~10 seconds + nextRelinkAttempt = world.getTotalWorldTime() + 20; // first retry in 1s + } if (world.isRemote) return; // Recompute pad bounds and relink infra to any rockets already on the pad @@ -124,7 +129,8 @@ public void onLoad() { public void invalidate() { super.invalidate(); unregisterFromBus(); - + relinkRetries = 0; + nextRelinkAttempt = 0L; // Notify linked multiblocks BEFORE clearing (server only) if (world != null && !world.isRemote) { for (HashedBlockPosition p : blockPos) { @@ -145,7 +151,8 @@ public void invalidate() { public void onChunkUnload() { super.onChunkUnload(); unregisterFromBus(); - + relinkRetries = 0; + nextRelinkAttempt = 0L; // Clear caches bbCache = null; stats.reset(); @@ -250,6 +257,44 @@ public int getPowerPerOperation() { @Override public void performFunction() { + // Retry linking infra for up to ~10s, but stop early once ALL are linked + if (!world.isRemote && relinkRetries > 0 && world.getTotalWorldTime() >= nextRelinkAttempt) { + + if (bbCache == null) bbCache = getRocketPadBounds(world, pos); + + int expected = blockPos.size(); // how many infra we remember from NBT + if (expected == 0) { relinkRetries = 0; return; } + int found = 0; // how many are currently loaded & obtainable + + if (bbCache != null) { + final AxisAlignedBB box = bbCache.grow(1.0E-4, 1.0E-4, 1.0E-4); + java.util.List rockets = world.getEntitiesWithinAABB(EntityRocketBase.class, box); + + // Only count + link if a rocket is actually on the pad + if (!rockets.isEmpty()) { + java.util.List infraNow = getConnectedInfrastructure(); // only returns loaded TEs + found = infraNow.size(); + + // Link them all (idempotent in AR) + for (EntityRocketBase r : rockets) { + for (IInfrastructure infra : infraNow) { + r.linkInfrastructure(infra); + } + } + } + } + + // Stop early only when we've linked ALL remembered infra positions + if (found >= expected && expected > 0) { + relinkRetries = 0; // done + } else { + relinkRetries--; // try again next second + nextRelinkAttempt = world.getTotalWorldTime() + 20; + } + } + + + if (!isScanning()) return; if (progress >= (totalProgress * MAXSCANDELAY)) { if (!world.isRemote) { if (building) @@ -913,6 +958,9 @@ public void useNetworkData(EntityPlayer player, Side side, byte id, } protected void updateText() { + if (thrustText == null || weightText == null || fuelText == null || accelerationText == null || errorText == null) { + return; + } thrustText.setText(isScanning() ? (LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.thrust") + ": ???") : String.format("%s: %dkN", LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.thrust"), getThrust())); weightText.setText(isScanning() ? (LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.weight") + ": ???") : String.format("%s: %.2fkN", LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.weight"), (getWeight() * getGravityMultiplier()))); fuelText.setText(isScanning() ? (LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.fuel") + ": ???") : String.format("%s: %dmb/s", LibVulpes.proxy.getLocalizedString("msg.rocketbuilder.fuel"), 20* getRocketStats().getFuelRate((stats.getFuelCapacity(FuelType.LIQUID_MONOPROPELLANT) > 0) ? FuelType.LIQUID_MONOPROPELLANT : (stats.getFuelCapacity(FuelType.NUCLEAR_WORKING_FLUID) > 0) ? FuelType.NUCLEAR_WORKING_FLUID : FuelType.LIQUID_BIPROPELLANT))); @@ -1217,20 +1265,15 @@ public void removeConnectedInfrastructure(TileEntity tile) { } public List getConnectedInfrastructure() { - List infrastructure = new LinkedList<>(); - - Iterator iter = blockPos.iterator(); - - while (iter.hasNext()) { - HashedBlockPosition position = iter.next(); - TileEntity tile = world.getTileEntity(position.getBlockPos()); - if (tile instanceof IInfrastructure) { - infrastructure.add((IInfrastructure) tile); - } else - iter.remove(); + List list = new LinkedList<>(); + // Don't mutate blockPos here; tiles may not be loaded yet + for (HashedBlockPosition position : blockPos) { + TileEntity te = world.getTileEntity(position.getBlockPos()); + if (te instanceof IInfrastructure) { + list.add((IInfrastructure) te); + } } - - return infrastructure; + return list; } @SubscribeEvent From c700cfd7addba9ab6becd9b77a6d58b98c823d33 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 02:14:45 +0100 Subject: [PATCH 130/274] Refactor rocket event posting logic --- .../entity/EntityStationDeployedRocket.java | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/entity/EntityStationDeployedRocket.java b/src/main/java/zmaster587/advancedRocketry/entity/EntityStationDeployedRocket.java index 4516ffa9c..831401cb6 100644 --- a/src/main/java/zmaster587/advancedRocketry/entity/EntityStationDeployedRocket.java +++ b/src/main/java/zmaster587/advancedRocketry/entity/EntityStationDeployedRocket.java @@ -62,9 +62,9 @@ public class EntityStationDeployedRocket extends EntityRocket { private short gasId; private Ticket ticket; private long plannedHarvestMb = 0L; // planned total mB to attempt this mission - private boolean orbitEventPosted = false; // not persisted to NBT - - + private transient boolean postedLandedAfterLoad = false; + private transient boolean postedDeorbit = false; + public EntityStationDeployedRocket(World world) { super(world); launchDirection = EnumFacing.DOWN; @@ -167,7 +167,15 @@ public void launch() { @Override public void onUpdate() { lastWorldTickTicked = world.getTotalWorldTime(); - + if (!world.isRemote && !postedLandedAfterLoad && this.ticksExisted >= 5) { + // Consider "landed" = entity exists, NOT in flight, NOT in orbit + if (!isInFlight() && !isInOrbit()) { + net.minecraftforge.common.MinecraftForge.EVENT_BUS.post( + new zmaster587.advancedRocketry.api.RocketEvent.RocketLandedEvent(this) + ); + postedLandedAfterLoad = true; + } + } if (this.ticksExisted == 20) { //problems with loading on other world then where the infrastructure was set? for (HashedBlockPosition temp : new LinkedList<>(infrastructureCoords)) { @@ -241,6 +249,13 @@ public void onUpdate() { //Returning if (isInOrbit()) { //For unmanned rockets + // Post deorbit once, as we start the return phase + if (!world.isRemote && !postedDeorbit) { + net.minecraftforge.common.MinecraftForge.EVENT_BUS.post( + new zmaster587.advancedRocketry.api.RocketEvent.RocketDeOrbitingEvent(this) + ); + postedDeorbit = true; + } EnumFacing dir; isCoasting = Math.abs(this.posX - actualLaunchLocation.x) < 0.01 && Math.abs(this.posZ - actualLaunchLocation.z) < 0.01; @@ -398,15 +413,13 @@ else if (gasId > props.getHarvestableGasses().size() - 1) @Override public void onOrbitReached() { if (world.isRemote) return; // client should not run any of this - - // Fire the standard event exactly once for monitors - if (!orbitEventPosted) { - MinecraftForge.EVENT_BUS.post(new RocketEvent.RocketReachesOrbitEvent(this)); - orbitEventPosted = true; - } - + // Emit the “reached orbit” event directly so monitors update. + net.minecraftforge.common.MinecraftForge.EVENT_BUS.post( + new zmaster587.advancedRocketry.api.RocketEvent.RocketReachesOrbitEvent(this) + ); if (this.isDead) return; + //Check again to make sure we are around a gas giant ISpaceObject spaceObj; setInOrbit(true); @@ -461,7 +474,7 @@ public void onOrbitReached() { final long durationSeconds; if (intake <= 0 || this.plannedHarvestMb <= 0) { - durationSeconds = 360L; // safety default + durationSeconds = 180L; // safety default } else { // IMPORTANT: cap the capacity used by the curve to the harvest cap, // so durations match the table when harvest is smaller than tank size. @@ -594,7 +607,7 @@ private static double computeEffectiveCapacityMb(int liquidCapacity) { private static long computeMissionDurationSeconds(int liquidCapacity, int intakePower) { // default fallback if bad data - if (intakePower <= 0) return 360L; // 6 minutes safety default + if (intakePower <= 0) return 180L; // 3 minutes safety default // scale in double to avoid precision loss, clamp ratio >= 1 to avoid shrinking below base double ratio = Math.max(1.0d, ((double) liquidCapacity) / (double) BASE_CAP); From 595b6aa8811226937cb199ecd6e82abecd53c00d Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 02:16:38 +0100 Subject: [PATCH 131/274] Refactor TileRocketMonitoringStation class split GUI into tabs to show the player why launches failed. statustext + reason if status=abort --- .../TileRocketMonitoringStation.java | 426 ++++++++++++++---- 1 file changed, 341 insertions(+), 85 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java index 4f07181fc..15bd688a7 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java @@ -33,6 +33,7 @@ import zmaster587.libVulpes.client.util.ProgressBarImage; import zmaster587.libVulpes.interfaces.ILinkableTile; import zmaster587.libVulpes.inventory.modules.*; +import zmaster587.libVulpes.inventory.GuiHandler; import zmaster587.libVulpes.items.ItemLinker; import zmaster587.libVulpes.network.PacketHandler; import zmaster587.libVulpes.network.PacketMachine; @@ -44,8 +45,10 @@ import java.util.LinkedList; import java.util.List; -public class TileRocketMonitoringStation extends TileEntity implements IModularInventory, ITickable, IAdjBlockUpdate, IInfrastructure, ILinkableTile, INetworkMachine, IButtonInventory, IProgressBar, IComparatorOverride { - +public class TileRocketMonitoringStation extends TileEntity + implements IModularInventory, ITickable, IAdjBlockUpdate, IInfrastructure, + ILinkableTile, INetworkMachine, IButtonInventory, IProgressBar, + IComparatorOverride, IGuiCallback { // ==== TUNABLE TICK THROTTLES ==== // 2–3 ticks for height/vel feels live; 5–10 ticks is fine for fuel. private static final int T_HEIGHTVEL_TICKS = 3; // ~6.7 Hz @@ -78,15 +81,22 @@ public class TileRocketMonitoringStation extends TileEntity implements IModularI int fuelLevel, maxFuelLevel; int oxidizerFuelLevel; + // === GUI event status (server -> client via TE update) === - // 0=idle, 1=prelaunch, 2=launching, 3=orbit, 4=landed, 5=aborted + // 0=idle, 1=prelaunch, 2=launching, 3=orbit, 4=deorbiting, 5=landed, 6=aborted + private int uiStatus = 0; private transient ModuleText launchStatus; // client-only widget + private transient ModuleText abortDetail; private transient int lastUiStatusShown = -1; // client change-detect // How long a status is considered fresh after the last event (in ticks) - private static final long STATUS_STALE_TICKS = 400L; // over 20 seconds is outdated + private static final long STATUS_STALE_TICKS = 600L; // over 30 seconds is outdated private long lastStatusTick = 0L; // server-only; persisted - + private String lastAbortReason = ""; + + // Tabs (client-only) + private static final byte TAB_SWITCH = 10; + private ModuleTab tabModule; // Event bus registration flag private boolean registeredBus = false; @@ -99,13 +109,26 @@ private void pushState() { private void clearUiStatus() { uiStatus = 0; + lastAbortReason = ""; lastUiStatusShown = -1; // force client label to refresh to empty pushState(); } public TileRocketMonitoringStation() { mission = null; - missionText = new ModuleText(20, 90, LibVulpes.proxy.getLocalizedString("msg.monitoringStation.missionProgressNA"), 0x2b2b2b); + missionText = null; + + tabModule = new ModuleTab( + 4, 0, 0, this, 2, + new String[] { + LibVulpes.proxy.getLocalizedString("msg.monitoringStation.tab.status"), + LibVulpes.proxy.getLocalizedString("msg.monitoringStation.tab.mission") + }, + new net.minecraft.util.ResourceLocation[][] { + TextureResources.tabPlanet, + TextureResources.tabPlanetTracking + } + ); } // --- Lifecycle / bus registration --- @@ -127,11 +150,11 @@ public void onLoad() { boolean stale = lastStatusTick == 0L || (world.getTotalWorldTime() - lastStatusTick) > STATUS_STALE_TICKS; - if (stale || linkedRocket == null) { + if (stale || (linkedRocket == null && mission == null)) { clearUiStatus(); - lastStatusTick = 0L; // reset tick + lastStatusTick = 0L; } else { - pushState(); // keep fresh status visible + pushState(); } } @@ -214,9 +237,21 @@ public boolean linkRocket(EntityRocketBase rocket) { this.linkedRocket = rocket; this.lastComparator = -1; + // Haxy gas mission returning case if (!world.isRemote) { - clearUiStatus(); - lastStatusTick = 0L; // reset tick + boolean returning = + (rocket instanceof EntityRocket) + && ((EntityRocket) rocket).isInOrbit() + && ((EntityRocket) rocket).isInFlight(); + + if (returning) { + uiStatus = 4; // deorbiting + lastStatusTick = world.getTotalWorldTime(); + pushState(); + } else { + clearUiStatus(); + lastStatusTick = 0L; + } } return true; } @@ -234,8 +269,12 @@ public void unlinkRocket() { if (!world.isRemote) { lastComparator = 0; world.updateComparatorOutputLevel(pos, world.getBlockState(pos).getBlock()); - clearUiStatus(); - lastStatusTick = 0L; // reset tick + + // Keep "Reached orbit" visible while the mission is active. + if (mission == null) { + clearUiStatus(); + lastStatusTick = 0L; // reset tick + } } } @@ -244,6 +283,11 @@ public void unlinkRocket() { @Override public void update() { + // ensure we are listening on the bus --- + if (!world.isRemote && !registeredBus) { + MinecraftForge.EVENT_BUS.register(this); + registeredBus = true; + } if (world.isRemote) return; // One-time prime (in case no neighbor event has fired yet) @@ -252,6 +296,18 @@ public void update() { initPower = true; } + if (!world.isRemote) { + long age = world.getTotalWorldTime() - lastStatusTick; + + // Aborted + if (uiStatus == 6 && age > STATUS_STALE_TICKS) clearUiStatus(); + + // Reached orbit — only time out when no mission is linked + if (uiStatus == 3 && mission == null && age > STATUS_STALE_TICKS) clearUiStatus(); + + // Landed + if (uiStatus == 5 && age > STATUS_STALE_TICKS) clearUiStatus(); + } // Runs infrequently to recover from any missed neighbor events. if (world.getTotalWorldTime() % 100 == 0) { // every 100 ticks boolean polled = world.isBlockIndirectlyGettingPowered(pos) > 0; @@ -288,8 +344,8 @@ public void update() { // - id=2 shows the *active* rocket fuel // - id=6 shows oxidizer independently final FuelRegistry.FuelType active = linkedRocket.getRocketFuelType(); - snapFuel = linkedRocket.getFuelAmount(active); - snapFuelCap = linkedRocket.getFuelCapacity(active); + snapFuel = (active != null) ? linkedRocket.getFuelAmount(active) : 0; + snapFuelCap = (active != null) ? linkedRocket.getFuelCapacity(active) : 0; snapOx = linkedRocket.getFuelAmount(FuelRegistry.FuelType.LIQUID_OXIDIZER); snapOxCap = linkedRocket.getFuelCapacity(FuelRegistry.FuelType.LIQUID_OXIDIZER); @@ -302,9 +358,10 @@ public void update() { public void onPreLaunch(RocketEvent.RocketPreLaunchEvent e) { if (world == null || world.isRemote) return; if (linkedRocket != null && e.getEntity() == linkedRocket) { - uiStatus = e.isCanceled() ? 5 : 1; // aborted or prelaunch + uiStatus = e.isCanceled() ? 6 : 1; + if (!e.isCanceled()) lastAbortReason = ""; // fresh launch, drop old reason lastStatusTick = world.getTotalWorldTime(); - pushState(); // single place to mark+notify + pushState(); } } @@ -328,11 +385,32 @@ public void onOrbit(RocketEvent.RocketReachesOrbitEvent e) { } } + @SubscribeEvent + public void onDeorbit(RocketEvent.RocketDeOrbitingEvent e) { + if (world == null || world.isRemote) return; + if (linkedRocket != null && e.getEntity() == linkedRocket) { + uiStatus = 4; // reuse “landed”/returning state + lastStatusTick = world.getTotalWorldTime(); + pushState(); + } + } + @SubscribeEvent public void onLanded(RocketEvent.RocketLandedEvent e) { if (world == null || world.isRemote) return; if (linkedRocket != null && e.getEntity() == linkedRocket) { - uiStatus = 4; + uiStatus = 5; + lastStatusTick = world.getTotalWorldTime(); + pushState(); + } + } + + @SubscribeEvent + public void onAbort(RocketEvent.RocketAbortEvent e) { + if (world == null || world.isRemote) return; + if (linkedRocket != null && e.getEntity() == linkedRocket) { + uiStatus = 6; // “aborted” + lastAbortReason = (e.reason == null) ? "" : e.reason; lastStatusTick = world.getTotalWorldTime(); pushState(); } @@ -401,6 +479,12 @@ public void readFromNBT(NBTTagCompound nbt) { } uiStatus = nbt.getInteger("uiStatus"); lastStatusTick = nbt.getLong("lastStatusTick"); + lastAbortReason = nbt.hasKey("abortReason") ? nbt.getString("abortReason") : ""; + + // --- client: force GUI labels to refresh next frame --- + if (world != null && world.isRemote) { + lastUiStatusShown = -1; // guarantees next render tick will reapply the text + } } @Override @@ -413,6 +497,7 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { } nbt.setInteger("uiStatus", uiStatus); nbt.setLong("lastStatusTick", lastStatusTick); + nbt.setString("abortReason", lastAbortReason == null ? "" : lastAbortReason); return nbt; } @@ -420,17 +505,15 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { @Override public void writeDataToNetwork(ByteBuf out, byte id) { - if (id == 1) - out.writeLong(mission == null ? -1 : mission.getMissionId()); + if (id == 1) out.writeLong(mission == null ? -1 : mission.getMissionId()); + else if (id == TAB_SWITCH) out.writeShort(tabModule.getTab()); } @Override public void readDataFromNetwork(ByteBuf in, byte packetId, NBTTagCompound nbt) { - if (packetId == 1) { - nbt.setLong("id", in.readLong()); - } else if (packetId == 2) { - nbt.setByte("state", in.readByte()); - } + if (packetId == 1) nbt.setLong("id", in.readLong()); + else if (packetId == 2) nbt.setByte("state", in.readByte()); + else if (packetId == TAB_SWITCH) nbt.setShort("tab", in.readShort()); } @Override @@ -439,17 +522,23 @@ public void useNetworkData(EntityPlayer player, Side side, byte id, NBTTagCompou long idNum = nbt.getLong("id"); if (idNum == -1) { mission = null; - setMissionText(); + if (world.isRemote && missionText != null) setMissionText(); } else { SatelliteBase base = DimensionManager.getInstance().getSatellite(idNum); if (base instanceof IMission) { mission = (IMission) base; - setMissionText(); + if (world.isRemote && missionText != null) setMissionText(); } } - } else if (id == 2) { + } + else if (id == 2) { // redstone control path was commented in original; preserved } + else if (id == TAB_SWITCH && !world.isRemote) { + tabModule.setTab(nbt.getShort("tab")); + player.openGui(LibVulpes.instance, GuiHandler.guiId.MODULARNOINV.ordinal(), + getWorld(), pos.getX(), pos.getY(), pos.getZ()); + } if (id == 100) { if (linkedRocket != null) linkedRocket.prepareLaunch(); @@ -457,55 +546,189 @@ public void useNetworkData(EntityPlayer player, Side side, byte id, NBTTagCompou } // --- GUI / Modules --- - @Override public List getModules(int ID, EntityPlayer player) { LinkedList modules = new LinkedList<>(); - modules.add(new ModuleButton(20, 40, 0, "Launch!", this, zmaster587.libVulpes.inventory.TextureResources.buttonBuild)); + // Tabs control + modules.add(tabModule); - // Status line for rocket events (client only) - if (world.isRemote) { - launchStatus = new ModuleText(10, 30, "", 0xFFFFFF22); - modules.add(launchStatus); + if (tabModule.getTab() == 0) { + // === STATUS TAB === + modules.add(new ModuleButton(20, 40, 0, "Launch!", this, zmaster587.libVulpes.inventory.TextureResources.buttonBuild)); - // Force the label to refresh on this GUI open - lastUiStatusShown = -1; - } + if (world.isRemote) { + launchStatus = new ModuleText(88, 92, "", 0xFFFFFF22, true); // centered + modules.add(launchStatus); + abortDetail = new ModuleText(88, 108, "", 0xFF4444, true); // centered + modules.add(abortDetail); - modules.add(new ModuleProgress(98, 4, 0, new IndicatorBarImage(2, 7, 12, 81, 17, 0, 6, 6, 1, 0, EnumFacing.UP, TextureResources.rocketHud), this)); - modules.add(new ModuleProgress(120, 14, 1, new IndicatorBarImage(2, 95, 12, 71, 17, 0, 6, 6, 1, 0, EnumFacing.UP, TextureResources.rocketHud), this)); - modules.add(new ModuleProgress(142, 14, 2, new ProgressBarImage(2, 173, 12, 71, 17, 6, 3, 69, 1, 1, EnumFacing.UP, TextureResources.rocketHud), this)); - modules.add(new ModuleProgress(148, 14, 6, new ProgressBarImage(2, 173, 12, 71, 17, 75, 3, 69, 1, 1, EnumFacing.UP, TextureResources.rocketHud), this)); + lastUiStatusShown = -1; + } - setMissionText(); - modules.add(missionText); - modules.add(new ModuleProgress(30, 110, 3, TextureResources.progressToMission, this)); - modules.add(new ModuleProgress(30, 120, 4, TextureResources.workMission, this)); - modules.add(new ModuleProgress(30, 130, 5, TextureResources.progressFromMission, this)); + modules.add(new ModuleProgress(98, 4, 0, new IndicatorBarImage(2, 7, 12, 81, 17, 0, 6, 6, 1, 0, EnumFacing.UP, TextureResources.rocketHud), this)); + modules.add(new ModuleProgress(120, 14, 1, new IndicatorBarImage(2, 95, 12, 71, 17, 0, 6, 6, 1, 0, EnumFacing.UP, TextureResources.rocketHud), this)); + modules.add(new ModuleProgress(142, 14, 2, new ProgressBarImage(2,173, 12, 71, 17, 6, 3, 69, 1, 1, EnumFacing.UP, TextureResources.rocketHud), this)); + modules.add(new ModuleProgress(148, 14, 6, new ProgressBarImage(2,173, 12, 71, 17,75, 3, 69, 1, 1, EnumFacing.UP, TextureResources.rocketHud), this)); - if (!world.isRemote) { - PacketHandler.sendToPlayer(new PacketMachine(this, (byte) 1), player); // mission sync - pushState(); // TE sync (includes cleared/derived uiStatus) + if (!world.isRemote) { + PacketHandler.sendToPlayer(new PacketMachine(this, (byte)1), player); + pushState(); + } + return modules; + } + + // === MISSION TAB === + { + final boolean hasMission = mission != null; + + // If there is NO mission: show a single centered line and exit early + if (!hasMission) { + modules.add(new ModuleText( + 88, 72, + LibVulpes.proxy.getLocalizedString("msg.monitoringStation.missionNoActiveMission"), + 0x2b2b2b, // color + true // centered + )); + if (!world.isRemote) { + PacketHandler.sendToPlayer(new PacketMachine(this, (byte)1), player); + pushState(); + } + return modules; + } + + // ---- Has mission: structured list ---- + final String typeLine; + { + String cls = mission.getClass().getSimpleName().toLowerCase(); + typeLine = cls.contains("gas") + ? LibVulpes.proxy.getLocalizedString("msg.monitoringStation.mission.type.gas") // "Gas Collection Mission" + : LibVulpes.proxy.getLocalizedString("msg.monitoringStation.mission.type.ore"); // "Asteroid Mining Mission" + } + + + modules.add(new ModuleText( + 88, 16, net.minecraft.util.text.TextFormatting.BOLD + typeLine + net.minecraft.util.text.TextFormatting.RESET, + 0x2b2b2b, + true // centered + )); + + // Decide mission type once (use the text you already built) + final boolean isGas = typeLine.toLowerCase().contains("gas"); + + // Target: if GAS mission, show the chosen fluid; otherwise keep default + if (isGas) { + String gasLabel = ""; + try { + if (mission instanceof zmaster587.advancedRocketry.mission.MissionGasCollection) { + net.minecraftforge.fluids.Fluid f = + ((zmaster587.advancedRocketry.mission.MissionGasCollection) mission).getGasFluid(); + if (f != null) { + gasLabel = new net.minecraftforge.fluids.FluidStack(f, 1).getLocalizedName(); + } + } + } catch (Throwable t) { /* be defensive */ } + + modules.add(new ModuleText( + 10, 39, + (gasLabel.isEmpty() + ? LibVulpes.proxy.getLocalizedString("msg.monitoringStation.mission.target.default") + : LibVulpes.proxy.getLocalizedString("msg.monitoringStation.mission.targetPrefix") + " " + gasLabel), + 0x2b2b2b + )); + } else { + // ---------- NON-GAS (ORE) SECTION — single, minimal block ---------- + String oreType = ""; + String shortId = ""; + + try { + if (mission instanceof zmaster587.advancedRocketry.mission.MissionOreMining) { + zmaster587.advancedRocketry.mission.MissionOreMining m = + (zmaster587.advancedRocketry.mission.MissionOreMining) mission; + + oreType = m.getAsteroidTypeOrEmpty(); + Long aUuid = m.getAsteroidUUIDOrNull(); + + if (aUuid != null) { + long base = aUuid; + long th = Integer.toUnsignedLong((oreType == null ? "" : oreType).hashCode()); + long z = base ^ (th << 1); + z += 0x9E3779B97F4A7C15L; + z = (z ^ (z >>> 30)) * 0xBF58476D1CE4E5B9L; + z = (z ^ (z >>> 27)) * 0x94D049BB133111EBL; + z = (z ^ (z >>> 31)); + String hex = Long.toUnsignedString(z, 16).toUpperCase(); + shortId = (hex.length() > 6) ? hex.substring(hex.length() - 6) : hex; + } + } + } catch (Throwable t) { /* defensive */ } + + // Line 1: Asteroid: (or just "Asteroid:" if id missing) + String lineAsteroid = LibVulpes.proxy.getLocalizedString("msg.monitoringStation.mission.Asteroid.targetPrefix") + + (shortId.isEmpty() ? "" : " " + shortId); + modules.add(new ModuleText(10, 39, lineAsteroid, 0x2b2b2b)); + + // Line 2: Type: (omit if unknown) + if (oreType != null && !oreType.isEmpty()) { + String lineType = LibVulpes.proxy.getLocalizedString("msg.monitoringStation.mission.asteroidIdPrefix") + + " " + oreType; + modules.add(new ModuleText(10, 53, lineType, 0x2b2b2b)); + } + } + + + // --- Specific line per mission type --- + if (isGas) { + // Read planned harvest written by the rocket into the mission's persist NBT + long plannedMb = -1L; + try { + if (mission instanceof zmaster587.advancedRocketry.mission.MissionResourceCollection) { + plannedMb = ((zmaster587.advancedRocketry.mission.MissionResourceCollection) mission) + .getPlannedHarvestMbOrDefault(); + } + } catch (Throwable t) { /* be defensive */ } + + final String plannedText = (plannedMb >= 0) + ? (LibVulpes.proxy.getLocalizedString("msg.monitoringStation.mission.plannedAmountPrefix") + " " + plannedMb + " mB") + : LibVulpes.proxy.getLocalizedString("msg.monitoringStation.mission.plannedAmountPending"); + + modules.add(new ModuleText(10, 53, plannedText, 0x2b2b2b)); + } + //else { if we want to add ore-specific lines later, show loot etc. } + + // Duration text (above the stage bars, like original) + missionText = new ModuleText(88, 94, "", 0x2b2b2b, true); + setMissionText(); + modules.add(missionText); + // Stage bars just above the time block + modules.add(new ModuleProgress(30, 110, 3, TextureResources.progressToMission, this)); + modules.add(new ModuleProgress(30, 120, 4, TextureResources.workMission, this)); + modules.add(new ModuleProgress(30, 130, 5, TextureResources.progressFromMission, this)); + + if (!world.isRemote) { + PacketHandler.sendToPlayer(new PacketMachine(this, (byte)1), player); + pushState(); + } + return modules; } + } - return modules; - } private void setMissionText() { + // If the text widget isn’t built yet (e.g., GUI closed or on other tab), just bail out. + if (missionText == null) return; + if (mission != null) { int time = mission.getTimeRemainingInSeconds(); int seconds = time % 60; int minutes = (time / 60) % 60; int hours = time / 3600; - String name = (mission instanceof SatelliteBase) - ? ((SatelliteBase) mission).getName() - : LibVulpes.proxy.getLocalizedString("msg.monitoringStation.mission"); - - missionText.setText(name + LibVulpes.proxy.getLocalizedString("msg.monitoringStation.progress") - + String.format("\n%02dhr:%02dm:%02ds", hours, minutes, seconds)); + missionText.setText( + LibVulpes.proxy.getLocalizedString("msg.monitoringStation.progress") + + String.format(" %02d:%02d:%02d", hours, minutes, seconds) + ); } else { missionText.setText(LibVulpes.proxy.getLocalizedString("msg.monitoringStation.missionProgressNA")); } @@ -514,9 +737,16 @@ private void setMissionText() { @Override public void onInventoryButtonPressed(int buttonId) { if (buttonId != -1) - PacketHandler.sendToServer(new PacketMachine(this, (byte) (buttonId + 100))); + PacketHandler.sendToServer(new PacketMachine(this, (byte)(buttonId + 100))); else - PacketHandler.sendToServer(new PacketMachine(this, (byte) 2)); + PacketHandler.sendToServer(new PacketMachine(this, (byte)2)); + } + + private static String wrapToWidthClient(String s, int maxWidthPx) { + if (s == null || s.isEmpty()) return ""; + net.minecraft.client.gui.FontRenderer fr = net.minecraft.client.Minecraft.getMinecraft().fontRenderer; + java.util.List lines = fr.listFormattedStringToWidth(s, Math.max(1, maxWidthPx)); + return String.join("\n", lines); } @Override @@ -526,44 +756,55 @@ public String getModularInventoryName() { @Override public float getNormallizedProgress(int id) { + if (world.isRemote) { + // Status tab label + if (launchStatus != null && uiStatus != lastUiStatusShown) { + lastUiStatusShown = uiStatus; + + String header = ""; + String detail = ""; + + switch (uiStatus) { + case 1: header = LibVulpes.proxy.getLocalizedString("msg.monitoringStation.prelaunch"); break; + case 2: header = LibVulpes.proxy.getLocalizedString("msg.monitoringStation.launching"); break; + case 3: header = LibVulpes.proxy.getLocalizedString("msg.monitoringStation.orbit"); break; + case 4: header = LibVulpes.proxy.getLocalizedString("msg.monitoringStation.deorbiting"); break; + case 5: header = LibVulpes.proxy.getLocalizedString("msg.monitoringStation.landed"); break; + case 6: header = LibVulpes.proxy.getLocalizedString("msg.monitoringStation.aborted"); + if (lastAbortReason != null && !lastAbortReason.isEmpty()) {detail = lastAbortReason;} break; + default: + header = ""; + } + launchStatus.setText(header); + if (abortDetail != null) { + final int ABORT_WRAP_WIDTH = 150; + abortDetail.setText(wrapToWidthClient(detail, ABORT_WRAP_WIDTH)); + } + } + + // Mission tab duration label (make it live) + if (mission != null && missionText != null) { + setMissionText(); + } + } + if (id == 1) { return Math.max(Math.min(0.5f + (getProgress(id) / (float) getTotalProgress(id)), 1), 0f); } else if (id == 3) { - if (mission == null) - return 0f; + if (mission == null) return 0f; return (float) Math.min(3f * mission.getProgress(this.world), 1f); } else if (id == 4) { - if (mission == null) - return 0f; + if (mission == null) return 0f; return (float) Math.min(Math.max(3f * (mission.getProgress(this.world) - 0.333f), 0f), 1f); } else if (id == 5) { - if (mission == null) - return 0f; + if (mission == null) return 0f; return (float) Math.min(Math.max(3f * (mission.getProgress(this.world) - 0.666f), 0f), 1f); } - // Client: reflect server-driven rocket event status in the GUI text - if (world.isRemote && launchStatus != null && uiStatus != lastUiStatusShown) { - lastUiStatusShown = uiStatus; - String msg; - switch (uiStatus) { - case 1: msg = LibVulpes.proxy.getLocalizedString("msg.monitoringStation.prelaunch"); break; // "Pre-launch checks…" - case 2: msg = LibVulpes.proxy.getLocalizedString("msg.monitoringStation.launching"); break; // "Launching!" - case 3: msg = LibVulpes.proxy.getLocalizedString("msg.monitoringStation.orbit"); break; // "Reached orbit" - case 4: msg = LibVulpes.proxy.getLocalizedString("msg.monitoringStation.landed"); break; // "Landed" - case 5: msg = LibVulpes.proxy.getLocalizedString("msg.monitoringStation.aborted"); break; // "Launch aborted" - default: msg = ""; break; - } - launchStatus.setText(msg); - } - - // Keep mission text updated on client - if (world.isRemote && mission != null) - setMissionText(); - return Math.min(getProgress(id) / (float) getTotalProgress(id), 1.0f); } + @Override public void setProgress(int id, int progress) { if (id == 0) @@ -619,10 +860,25 @@ public void setTotalProgress(int id, int progress) { public boolean canInteractWithContainer(EntityPlayer entity) { return true; } + + @Override + public void onModuleUpdated(ModuleBase module) { + PacketHandler.sendToServer(new PacketMachine(this, TAB_SWITCH)); + } @Override public boolean linkMission(IMission mission) { this.mission = mission; + // If we don’t already have a status, show “in orbit” while mission runs. + if (!world.isRemote) { + // If we were at idle/prelaunch/launching, move to "reached orbit" now. + if (uiStatus < 3) { + uiStatus = 3; + lastStatusTick = world.getTotalWorldTime(); + pushState(); + } + } + PacketHandler.sendToNearby(new PacketMachine(this, (byte) 1), world.provider.getDimension(), getPos(), 16); return true; } @@ -630,7 +886,7 @@ public boolean linkMission(IMission mission) { @Override public void unlinkMission() { mission = null; - setMissionText(); + if (missionText != null) setMissionText(); // guard PacketHandler.sendToNearby(new PacketMachine(this, (byte) 1), world.provider.getDimension(), getPos(), 16); } From cf0bc37b618da96a0d68d736a72b5ea9ff57ab54 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 02:17:09 +0100 Subject: [PATCH 132/274] Add new localization entries for monitoring station --- src/main/resources/assets/advancedrocketry/lang/en_US.lang | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/assets/advancedrocketry/lang/en_US.lang b/src/main/resources/assets/advancedrocketry/lang/en_US.lang index f7d174435..ca09d5df2 100644 --- a/src/main/resources/assets/advancedrocketry/lang/en_US.lang +++ b/src/main/resources/assets/advancedrocketry/lang/en_US.lang @@ -338,6 +338,7 @@ msg.monitoringStation.orbit=Reached orbit! msg.monitoringStation.deorbiting=Returned from orbit! msg.monitoringStation.landed=Landed msg.monitoringStation.aborted=Aborted! +msg.monitoringStation.returningToDock=Returning to dock msg.guidanceComputerHatch.loadingState=Loading State: From aac52d6e0e80f89bc5e5de7fc3f37bf701487339 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 13:27:57 +0100 Subject: [PATCH 133/274] Add fueling station integration to ARPlugin --- .../integration/jei/ARPlugin.java | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/ARPlugin.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/ARPlugin.java index e934a949b..b07be2bc2 100644 --- a/src/main/java/zmaster587/advancedRocketry/integration/jei/ARPlugin.java +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/ARPlugin.java @@ -23,6 +23,9 @@ import zmaster587.advancedRocketry.integration.jei.electrolyser.ElectrolyzerCategory; import zmaster587.advancedRocketry.integration.jei.electrolyser.ElectrolyzerRecipeHandler; import zmaster587.advancedRocketry.integration.jei.electrolyser.ElectrolyzerRecipeMaker; +import zmaster587.advancedRocketry.integration.jei.fuelingStation.FuelingStationCategory; +import zmaster587.advancedRocketry.integration.jei.fuelingStation.FuelingStationRecipeHandler; +import zmaster587.advancedRocketry.integration.jei.fuelingStation.FuelingStationRecipeMaker; import zmaster587.advancedRocketry.integration.jei.lathe.LatheCategory; import zmaster587.advancedRocketry.integration.jei.lathe.LatheRecipeHandler; import zmaster587.advancedRocketry.integration.jei.lathe.LatheRecipeMaker; @@ -44,7 +47,9 @@ import zmaster587.advancedRocketry.integration.jei.satelliteBuilder.SatelliteBuilderCategory; import zmaster587.advancedRocketry.integration.jei.satelliteBuilder.SatelliteBuilderRecipeHandler; import zmaster587.advancedRocketry.integration.jei.satelliteBuilder.SatelliteBuilderRecipeMaker; +import zmaster587.advancedRocketry.tile.infrastructure.TileFuelingStation; import zmaster587.advancedRocketry.tile.multiblock.machine.*; +import zmaster587.advancedRocketry.tile.satellite.TileSatelliteBuilder; import zmaster587.libVulpes.inventory.GuiModular; import javax.annotation.Nonnull; @@ -65,6 +70,7 @@ public class ARPlugin implements IModPlugin { public static final String centrifugeUUID = "zmaster587.AR.centrifuge"; public static final String precisionLaserEngraverUUID = "zmaster587.AR.precisionlaseretcher"; public static final String satelliteBuilderUUID = "zmaster587.AR.satelliteBuilder"; + public static final String fuelingStationUUID = "zmaster587.AR.fuelingStation"; public static IJeiHelpers jeiHelpers; //AR machines can reload recipes. We still need this for JEI to be up-to-date @@ -90,7 +96,8 @@ public void registerCategories(IRecipeCategoryRegistration registry) { new PlatePressCategory(guiHelper), new CentrifugeCategory(guiHelper), new PrecisionLaserEtcherCategory(guiHelper), - new SatelliteBuilderCategory(guiHelper) + new SatelliteBuilderCategory(guiHelper), + new FuelingStationCategory(guiHelper) ); } @@ -136,7 +143,8 @@ public Object getIngredientUnderMouse(GuiModular guiContainer, new PlatePressRecipeHandler(), new CentrifugeRecipeHandler(), new PrecisionLaserEtcherRecipeHandler(), - new SatelliteBuilderRecipeHandler() + new SatelliteBuilderRecipeHandler(), + new FuelingStationRecipeHandler() ); registry.addRecipes(RollingMachineRecipeMaker.getMachineRecipes(jeiHelpers, TileRollingMachine.class), rollingMachineUUID); @@ -150,8 +158,8 @@ public Object getIngredientUnderMouse(GuiModular guiContainer, registry.addRecipes(ChemicalReactorRecipeMaker.getMachineRecipes(jeiHelpers, TileChemicalReactor.class), chemicalReactorUUID); registry.addRecipes(CentrifugeRecipeMaker.getMachineRecipes(jeiHelpers, TileCentrifuge.class), centrifugeUUID); registry.addRecipes(PrecisionLaserEtcherRecipeMaker.getMachineRecipes(jeiHelpers, TilePrecisionLaserEtcher.class), precisionLaserEngraverUUID); - registry.addRecipes(SatelliteBuilderRecipeMaker.getMachineRecipes(jeiHelpers, null), satelliteBuilderUUID); - + registry.addRecipes(SatelliteBuilderRecipeMaker.getMachineRecipes(jeiHelpers, TileSatelliteBuilder.class), satelliteBuilderUUID); + registry.addRecipes(FuelingStationRecipeMaker.getMachineRecipes(jeiHelpers, TileFuelingStation.class), fuelingStationUUID); registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockRollingMachine), rollingMachineUUID); registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockLathe), latheUUID); @@ -165,5 +173,14 @@ public Object getIngredientUnderMouse(GuiModular guiContainer, registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockCentrifuge), centrifugeUUID); registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockPrecisionLaserEngraver), precisionLaserEngraverUUID); registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockSatelliteBuilder), satelliteBuilderUUID); + + + // One tab: Fueling Station + Tank-type catalysts (mono / biprop fuel / oxidizer / working fluid) + registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockFuelingStation), fuelingStationUUID); + registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockFuelTank), fuelingStationUUID); // mono + registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockBipropellantFuelTank), fuelingStationUUID); // biprop fuel + registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockOxidizerFuelTank), fuelingStationUUID); // oxidizer + registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockNuclearFuelTank), fuelingStationUUID); // working fluid + } } From 6c7429945c3bb4097ba1f783b6a3a9fb8ed485e3 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 13:29:18 +0100 Subject: [PATCH 134/274] Add FuelingStationCategory for JEI integration --- ...elingStation\\FuelingStationCategory.java" | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 "src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation\\FuelingStationCategory.java" diff --git "a/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation\\FuelingStationCategory.java" "b/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation\\FuelingStationCategory.java" new file mode 100644 index 000000000..1124851b1 --- /dev/null +++ "b/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation\\FuelingStationCategory.java" @@ -0,0 +1,98 @@ +package zmaster587.advancedRocketry.integration.jei.fuelingStation; + +import mezz.jei.api.IGuiHelper; +import mezz.jei.api.gui.*; +import mezz.jei.api.ingredients.IIngredients; +import mezz.jei.api.recipe.IRecipeCategory; +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemStack; +import zmaster587.advancedRocketry.api.AdvancedRocketryBlocks; +import zmaster587.advancedRocketry.integration.jei.ARPlugin; +import zmaster587.libVulpes.gui.CommonResources; + +public class FuelingStationCategory implements IRecipeCategory { + + private final IDrawable background; + private final IDrawable icon; + private final IDrawable tankFrame; // 14x54 bezel from generic background + private final IDrawable slotFrame; // JEI’s standard slot look + + // --- compact but accurate: 150 x 56 so 4 recipes fit on one JEI page --- + public FuelingStationCategory(IGuiHelper gui) { + this.background = gui.createBlankDrawable(150, 56); + this.icon = gui.createDrawableIngredient(new ItemStack(AdvancedRocketryBlocks.blockFuelingStation)); + + // exact bezel the in-game ModuleLiquidIndicator draws: u=176,v=58,w=14,h=54 + this.tankFrame = gui.createDrawable(CommonResources.genericBackground, 176, 58, 14, 54); + + // vanilla-looking slot border + this.slotFrame = gui.getSlotDrawable(); + } + + @Override public String getUid() { return ARPlugin.fuelingStationUUID; } + @Override public String getTitle() { return new ItemStack(AdvancedRocketryBlocks.blockFuelingStation).getDisplayName(); } + @Override public String getModName() { return "Advanced Rocketry"; } + @Override public IDrawable getBackground(){ return background; } + @Override public IDrawable getIcon() { return icon; } + + @Override + public void setRecipe(IRecipeLayout layout, FuelingStationWrapper wrapper, IIngredients ing) { + // Fluid gauge (inside the real bezel) + IGuiFluidStackGroup fluids = layout.getFluidStacks(); + fluids.init(0, true, 28, 3, 12, 52, 1000, false, null); + fluids.set(0, wrapper.getFluid()); + + IGuiItemStackGroup items = layout.getItemStacks(); + + // ITEM inputs come as two lists: [ [bucket?], [role tank] ] + java.util.List> itemInputs = + ing.getInputs(mezz.jei.api.ingredients.VanillaTypes.ITEM); + + // Slot 0: bucket INPUT (if present) + items.init(0, true, 45, 6); + if (!itemInputs.isEmpty() && !itemInputs.get(0).isEmpty() + && itemInputs.get(0).get(0).getItem() == wrapper.getFilledContainer().getItem()) { + items.set(0, itemInputs.get(0)); + } else { + items.set(0, java.util.Collections.emptyList()); + } + items.addTooltipCallback((slotIndex, input, stack, tooltip) -> { + if (slotIndex != 0 || stack == null || stack.isEmpty()) return; + + // Only decorate the bucket input slot + tooltip.add(""); + tooltip.add(net.minecraft.util.text.TextFormatting.YELLOW + + zmaster587.libVulpes.LibVulpes.proxy.getLocalizedString( + "jei.ar.fuel.role." + wrapper.getRole().langKey() + )); + }); + + // Slot 1: ROLE TANK + items.init(1, true, 120, 6); + // The role tank will be the other input list + if (itemInputs.size() >= 2) { + items.set(1, itemInputs.get(1)); + } else if (!wrapper.getRoleTankStack().isEmpty()) { + // fallback if bucket missing → the only input is the role tank + items.set(1, java.util.Collections.singletonList(wrapper.getRoleTankStack())); + } + fluids.addTooltipCallback((slotIndex, input, fluid, tooltip) -> { + if (slotIndex != 0 || fluid == null) return; + + // Blank spacer then role + usage + tooltip.add(""); + tooltip.add(net.minecraft.util.text.TextFormatting.YELLOW + + zmaster587.libVulpes.LibVulpes.proxy.getLocalizedString( + "jei.ar.fuel.role." + wrapper.getRole().langKey() + )); + }); + } + + @Override + public void drawExtras(Minecraft mc) { + // Draw tank bezel and slot frames so it looks like the real GUI + tankFrame.draw(mc, 27, 2); // 14x54 bezel + slotFrame.draw(mc, 45, 6); // bucket slot + } + +} From 2442bd48b956aa9359d07d8f90ffd0dcc658a8a5 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 13:31:00 +0100 Subject: [PATCH 135/274] Delete src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation\FuelingStationCategory.java --- ...elingStation\\FuelingStationCategory.java" | 98 ------------------- 1 file changed, 98 deletions(-) delete mode 100644 "src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation\\FuelingStationCategory.java" diff --git "a/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation\\FuelingStationCategory.java" "b/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation\\FuelingStationCategory.java" deleted file mode 100644 index 1124851b1..000000000 --- "a/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation\\FuelingStationCategory.java" +++ /dev/null @@ -1,98 +0,0 @@ -package zmaster587.advancedRocketry.integration.jei.fuelingStation; - -import mezz.jei.api.IGuiHelper; -import mezz.jei.api.gui.*; -import mezz.jei.api.ingredients.IIngredients; -import mezz.jei.api.recipe.IRecipeCategory; -import net.minecraft.client.Minecraft; -import net.minecraft.item.ItemStack; -import zmaster587.advancedRocketry.api.AdvancedRocketryBlocks; -import zmaster587.advancedRocketry.integration.jei.ARPlugin; -import zmaster587.libVulpes.gui.CommonResources; - -public class FuelingStationCategory implements IRecipeCategory { - - private final IDrawable background; - private final IDrawable icon; - private final IDrawable tankFrame; // 14x54 bezel from generic background - private final IDrawable slotFrame; // JEI’s standard slot look - - // --- compact but accurate: 150 x 56 so 4 recipes fit on one JEI page --- - public FuelingStationCategory(IGuiHelper gui) { - this.background = gui.createBlankDrawable(150, 56); - this.icon = gui.createDrawableIngredient(new ItemStack(AdvancedRocketryBlocks.blockFuelingStation)); - - // exact bezel the in-game ModuleLiquidIndicator draws: u=176,v=58,w=14,h=54 - this.tankFrame = gui.createDrawable(CommonResources.genericBackground, 176, 58, 14, 54); - - // vanilla-looking slot border - this.slotFrame = gui.getSlotDrawable(); - } - - @Override public String getUid() { return ARPlugin.fuelingStationUUID; } - @Override public String getTitle() { return new ItemStack(AdvancedRocketryBlocks.blockFuelingStation).getDisplayName(); } - @Override public String getModName() { return "Advanced Rocketry"; } - @Override public IDrawable getBackground(){ return background; } - @Override public IDrawable getIcon() { return icon; } - - @Override - public void setRecipe(IRecipeLayout layout, FuelingStationWrapper wrapper, IIngredients ing) { - // Fluid gauge (inside the real bezel) - IGuiFluidStackGroup fluids = layout.getFluidStacks(); - fluids.init(0, true, 28, 3, 12, 52, 1000, false, null); - fluids.set(0, wrapper.getFluid()); - - IGuiItemStackGroup items = layout.getItemStacks(); - - // ITEM inputs come as two lists: [ [bucket?], [role tank] ] - java.util.List> itemInputs = - ing.getInputs(mezz.jei.api.ingredients.VanillaTypes.ITEM); - - // Slot 0: bucket INPUT (if present) - items.init(0, true, 45, 6); - if (!itemInputs.isEmpty() && !itemInputs.get(0).isEmpty() - && itemInputs.get(0).get(0).getItem() == wrapper.getFilledContainer().getItem()) { - items.set(0, itemInputs.get(0)); - } else { - items.set(0, java.util.Collections.emptyList()); - } - items.addTooltipCallback((slotIndex, input, stack, tooltip) -> { - if (slotIndex != 0 || stack == null || stack.isEmpty()) return; - - // Only decorate the bucket input slot - tooltip.add(""); - tooltip.add(net.minecraft.util.text.TextFormatting.YELLOW + - zmaster587.libVulpes.LibVulpes.proxy.getLocalizedString( - "jei.ar.fuel.role." + wrapper.getRole().langKey() - )); - }); - - // Slot 1: ROLE TANK - items.init(1, true, 120, 6); - // The role tank will be the other input list - if (itemInputs.size() >= 2) { - items.set(1, itemInputs.get(1)); - } else if (!wrapper.getRoleTankStack().isEmpty()) { - // fallback if bucket missing → the only input is the role tank - items.set(1, java.util.Collections.singletonList(wrapper.getRoleTankStack())); - } - fluids.addTooltipCallback((slotIndex, input, fluid, tooltip) -> { - if (slotIndex != 0 || fluid == null) return; - - // Blank spacer then role + usage - tooltip.add(""); - tooltip.add(net.minecraft.util.text.TextFormatting.YELLOW + - zmaster587.libVulpes.LibVulpes.proxy.getLocalizedString( - "jei.ar.fuel.role." + wrapper.getRole().langKey() - )); - }); - } - - @Override - public void drawExtras(Minecraft mc) { - // Draw tank bezel and slot frames so it looks like the real GUI - tankFrame.draw(mc, 27, 2); // 14x54 bezel - slotFrame.draw(mc, 45, 6); // bucket slot - } - -} From 8adb4044cf1961b339695f14667df4745dd425c2 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 13:31:35 +0100 Subject: [PATCH 136/274] Add FuelingStationCategory for JEI integration --- .../FuelingStationCategory.java | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationCategory.java diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationCategory.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationCategory.java new file mode 100644 index 000000000..1124851b1 --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationCategory.java @@ -0,0 +1,98 @@ +package zmaster587.advancedRocketry.integration.jei.fuelingStation; + +import mezz.jei.api.IGuiHelper; +import mezz.jei.api.gui.*; +import mezz.jei.api.ingredients.IIngredients; +import mezz.jei.api.recipe.IRecipeCategory; +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemStack; +import zmaster587.advancedRocketry.api.AdvancedRocketryBlocks; +import zmaster587.advancedRocketry.integration.jei.ARPlugin; +import zmaster587.libVulpes.gui.CommonResources; + +public class FuelingStationCategory implements IRecipeCategory { + + private final IDrawable background; + private final IDrawable icon; + private final IDrawable tankFrame; // 14x54 bezel from generic background + private final IDrawable slotFrame; // JEI’s standard slot look + + // --- compact but accurate: 150 x 56 so 4 recipes fit on one JEI page --- + public FuelingStationCategory(IGuiHelper gui) { + this.background = gui.createBlankDrawable(150, 56); + this.icon = gui.createDrawableIngredient(new ItemStack(AdvancedRocketryBlocks.blockFuelingStation)); + + // exact bezel the in-game ModuleLiquidIndicator draws: u=176,v=58,w=14,h=54 + this.tankFrame = gui.createDrawable(CommonResources.genericBackground, 176, 58, 14, 54); + + // vanilla-looking slot border + this.slotFrame = gui.getSlotDrawable(); + } + + @Override public String getUid() { return ARPlugin.fuelingStationUUID; } + @Override public String getTitle() { return new ItemStack(AdvancedRocketryBlocks.blockFuelingStation).getDisplayName(); } + @Override public String getModName() { return "Advanced Rocketry"; } + @Override public IDrawable getBackground(){ return background; } + @Override public IDrawable getIcon() { return icon; } + + @Override + public void setRecipe(IRecipeLayout layout, FuelingStationWrapper wrapper, IIngredients ing) { + // Fluid gauge (inside the real bezel) + IGuiFluidStackGroup fluids = layout.getFluidStacks(); + fluids.init(0, true, 28, 3, 12, 52, 1000, false, null); + fluids.set(0, wrapper.getFluid()); + + IGuiItemStackGroup items = layout.getItemStacks(); + + // ITEM inputs come as two lists: [ [bucket?], [role tank] ] + java.util.List> itemInputs = + ing.getInputs(mezz.jei.api.ingredients.VanillaTypes.ITEM); + + // Slot 0: bucket INPUT (if present) + items.init(0, true, 45, 6); + if (!itemInputs.isEmpty() && !itemInputs.get(0).isEmpty() + && itemInputs.get(0).get(0).getItem() == wrapper.getFilledContainer().getItem()) { + items.set(0, itemInputs.get(0)); + } else { + items.set(0, java.util.Collections.emptyList()); + } + items.addTooltipCallback((slotIndex, input, stack, tooltip) -> { + if (slotIndex != 0 || stack == null || stack.isEmpty()) return; + + // Only decorate the bucket input slot + tooltip.add(""); + tooltip.add(net.minecraft.util.text.TextFormatting.YELLOW + + zmaster587.libVulpes.LibVulpes.proxy.getLocalizedString( + "jei.ar.fuel.role." + wrapper.getRole().langKey() + )); + }); + + // Slot 1: ROLE TANK + items.init(1, true, 120, 6); + // The role tank will be the other input list + if (itemInputs.size() >= 2) { + items.set(1, itemInputs.get(1)); + } else if (!wrapper.getRoleTankStack().isEmpty()) { + // fallback if bucket missing → the only input is the role tank + items.set(1, java.util.Collections.singletonList(wrapper.getRoleTankStack())); + } + fluids.addTooltipCallback((slotIndex, input, fluid, tooltip) -> { + if (slotIndex != 0 || fluid == null) return; + + // Blank spacer then role + usage + tooltip.add(""); + tooltip.add(net.minecraft.util.text.TextFormatting.YELLOW + + zmaster587.libVulpes.LibVulpes.proxy.getLocalizedString( + "jei.ar.fuel.role." + wrapper.getRole().langKey() + )); + }); + } + + @Override + public void drawExtras(Minecraft mc) { + // Draw tank bezel and slot frames so it looks like the real GUI + tankFrame.draw(mc, 27, 2); // 14x54 bezel + slotFrame.draw(mc, 45, 6); // bucket slot + } + +} From f2f60f50f2889dc3defddd0fe8fcf14745592dbf Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 13:32:01 +0100 Subject: [PATCH 137/274] Implement FuelingStationRecipeHandler class --- .../fuelingStation/FuelingStationRecipeHandler.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationRecipeHandler.java diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationRecipeHandler.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationRecipeHandler.java new file mode 100644 index 000000000..efc87ce5d --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationRecipeHandler.java @@ -0,0 +1,12 @@ +package zmaster587.advancedRocketry.integration.jei.fuelingStation; + +import mezz.jei.api.recipe.IRecipeHandler; +import mezz.jei.api.recipe.IRecipeWrapper; +import zmaster587.advancedRocketry.integration.jei.ARPlugin; + +public class FuelingStationRecipeHandler implements IRecipeHandler { + @Override public Class getRecipeClass() { return FuelingStationWrapper.class; } + @Override public String getRecipeCategoryUid(FuelingStationWrapper r) { return ARPlugin.fuelingStationUUID; } + @Override public IRecipeWrapper getRecipeWrapper(FuelingStationWrapper r) { return r; } + @Override public boolean isRecipeValid(FuelingStationWrapper r) { return r != null; } +} From 1b286eb18b8ac00537f263892af94d583267f0a7 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 13:32:23 +0100 Subject: [PATCH 138/274] Implement FuelingStationRecipeMaker class --- .../FuelingStationRecipeMaker.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationRecipeMaker.java diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationRecipeMaker.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationRecipeMaker.java new file mode 100644 index 000000000..76bc797ec --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationRecipeMaker.java @@ -0,0 +1,42 @@ +package zmaster587.advancedRocketry.integration.jei.fuelingStation; + +import mezz.jei.api.IJeiHelpers; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import zmaster587.advancedRocketry.api.fuel.FuelRegistry; +import zmaster587.advancedRocketry.api.fuel.FuelRegistry.FuelType; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class FuelingStationRecipeMaker { + + public static List getRecipes(IJeiHelpers helpers) { + List out = new ArrayList<>(); + + add(out, FuelType.LIQUID_MONOPROPELLANT, FuelingStationWrapper.Role.MONO); + add(out, FuelType.LIQUID_BIPROPELLANT, FuelingStationWrapper.Role.BIPROP_FUEL); + add(out, FuelType.LIQUID_OXIDIZER, FuelingStationWrapper.Role.OXIDIZER); + add(out, FuelType.NUCLEAR_WORKING_FLUID, FuelingStationWrapper.Role.WORKING_FLUID); + + return out; + } + + private static void add(List list, + FuelType type, + FuelingStationWrapper.Role role) { + // Avoid name clash with AR’s FuelRegistry by fully-qualifying Forge’s registry here. + for (Map.Entry e : net.minecraftforge.fluids.FluidRegistry.getRegisteredFluids().entrySet()) { + Fluid f = e.getValue(); + if (f != null && FuelRegistry.instance.isFuel(type, f)) { + list.add(new FuelingStationWrapper(new FluidStack(f, 1000), role)); + } + } + } + + // Optional: keep this to match your existing makers + public static List getMachineRecipes(IJeiHelpers helpers, Class ignored) { + return getRecipes(helpers); + } +} From a14bf826905a6bb6758c146ca1eead6898e8f8c2 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 13:32:45 +0100 Subject: [PATCH 139/274] Add FuelingStationWrapper for JEI integration --- .../fuelingStation/FuelingStationWrapper.java | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationWrapper.java diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationWrapper.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationWrapper.java new file mode 100644 index 000000000..2f0af02ef --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationWrapper.java @@ -0,0 +1,96 @@ +package zmaster587.advancedRocketry.integration.jei.fuelingStation; + +import mezz.jei.api.ingredients.IIngredients; +import mezz.jei.api.recipe.IRecipeWrapper; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidUtil; +import zmaster587.advancedRocketry.api.AdvancedRocketryBlocks; + +import java.util.Collections; + +public class FuelingStationWrapper implements IRecipeWrapper { + + public enum Role { + MONO("monopropellant"), BIPROP_FUEL("biprop_fuel"), + OXIDIZER("oxidizer"), WORKING_FLUID("working_fluid"); + private final String key; Role(String k){ this.key = k; } + public String langKey(){ return key; } + } + + private final FluidStack fluid; + private final Role role; + + public FuelingStationWrapper(FluidStack fluid, Role role) { + this.fluid = fluid; + this.role = role; + } + + public Role getRole() { return role; } + public FluidStack getFluid() { return fluid; } + + @Override + public void getIngredients(IIngredients ing) { + // Fluid input (internal tank) + ing.setInputs(mezz.jei.api.ingredients.VanillaTypes.FLUID, + java.util.Collections.singletonList(fluid)); + + // ITEM inputs in order: + // 0: [filled bucket?] + // 1: [role tank] + // 2: [fueling station] <-- hidden, just for discoverability via U/R on the block + java.util.List> itemInputs = new java.util.ArrayList<>(3); + + // 0) filled bucket (if present) + ItemStack filled = getFilledContainer(); + if (!filled.isEmpty()) { + itemInputs.add(java.util.Collections.singletonList(filled)); + } + + // 1) role tank (always try to include) + ItemStack roleTank = getRoleTankStack(); + if (!roleTank.isEmpty()) { + itemInputs.add(java.util.Collections.singletonList(roleTank)); + } + + // 2) fueling station (hidden ingredient so U/R on the block opens this tab) + ItemStack station = new ItemStack(zmaster587.advancedRocketry.api.AdvancedRocketryBlocks.blockFuelingStation); + itemInputs.add(java.util.Collections.singletonList(station)); + + // commit item inputs + ing.setInputLists(mezz.jei.api.ingredients.VanillaTypes.ITEM, itemInputs); + + // Outputs: keep role tank (if present) and ALSO the station (so R on the block opens this tab) + java.util.List outs = new java.util.ArrayList<>(2); + if (!roleTank.isEmpty()) outs.add(roleTank); + outs.add(station); + ing.setOutputs(mezz.jei.api.ingredients.VanillaTypes.ITEM, outs); + } + + + public ItemStack getRoleTankStack() { + switch (role) { + case MONO: + return AdvancedRocketryBlocks.blockFuelTank != null ? new ItemStack(AdvancedRocketryBlocks.blockFuelTank) : ItemStack.EMPTY; + case BIPROP_FUEL: + return AdvancedRocketryBlocks.blockBipropellantFuelTank != null ? new ItemStack(AdvancedRocketryBlocks.blockBipropellantFuelTank) : ItemStack.EMPTY; + case OXIDIZER: + return AdvancedRocketryBlocks.blockOxidizerFuelTank != null ? new ItemStack(AdvancedRocketryBlocks.blockOxidizerFuelTank) : ItemStack.EMPTY; + case WORKING_FLUID: + return AdvancedRocketryBlocks.blockNuclearFuelTank != null ? new ItemStack(AdvancedRocketryBlocks.blockNuclearFuelTank) : ItemStack.EMPTY; + default: + return ItemStack.EMPTY; + } + } + + // keep this helper; category uses it conditionally + public ItemStack getFilledContainer() { + ItemStack is = net.minecraftforge.fluids.FluidUtil.getFilledBucket(fluid); + return is == null ? ItemStack.EMPTY : is; + } + + static ItemStack fuelStationDisplayStack() { + return new ItemStack(AdvancedRocketryBlocks.blockFuelingStation); + } +} From a3b80b2bee6c37378aa3dd3742fd6b0dcc035b57 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 13:33:14 +0100 Subject: [PATCH 140/274] Increase max stack size of ItemPressureTank --- .../advancedRocketry/item/components/ItemPressureTank.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/components/ItemPressureTank.java b/src/main/java/zmaster587/advancedRocketry/item/components/ItemPressureTank.java index 0f727dc9c..d5e2f9815 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/components/ItemPressureTank.java +++ b/src/main/java/zmaster587/advancedRocketry/item/components/ItemPressureTank.java @@ -34,7 +34,7 @@ public class ItemPressureTank extends ItemIngredient implements IArmorComponent public ItemPressureTank(int number, int capacity) { super(number); this.capacity = capacity; - this.maxStackSize = 1; + this.maxStackSize = 8; } @Override From b15ad956ea22827bfdef0b63ebfcf74899cfb20b Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 14:49:07 +0100 Subject: [PATCH 141/274] Implement Co2ScrubberCategory for JEI integration --- .../jei/co2scrubber/Co2ScrubberCategory.java | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberCategory.java diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberCategory.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberCategory.java new file mode 100644 index 000000000..7d9dc22b0 --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberCategory.java @@ -0,0 +1,67 @@ +package zmaster587.advancedRocketry.integration.jei.co2scrubber; + +import mezz.jei.api.IGuiHelper; +import mezz.jei.api.gui.IDrawable; +import mezz.jei.api.gui.IGuiItemStackGroup; +import mezz.jei.api.ingredients.IIngredients; +import mezz.jei.api.recipe.IRecipeCategory; +import mezz.jei.api.gui.IRecipeLayout; +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemStack; +import zmaster587.advancedRocketry.api.AdvancedRocketryBlocks; +import zmaster587.advancedRocketry.integration.jei.ARPlugin; + +public class Co2ScrubberCategory implements IRecipeCategory { + + private final IDrawable bg; + private final IDrawable icon; + private final IDrawable slot; + + // Compact like your fueling station: 150x40 + public Co2ScrubberCategory(IGuiHelper gui) { + this.bg = gui.createBlankDrawable(150, 40); + this.icon = gui.createDrawableIngredient(new ItemStack(AdvancedRocketryBlocks.blockCO2Scrubber)); + this.slot = gui.getSlotDrawable(); + } + + @Override public String getUid() { return ARPlugin.co2ScrubberUUID; } + @Override public String getTitle() { return new ItemStack(AdvancedRocketryBlocks.blockCO2Scrubber).getDisplayName(); } + @Override public String getModName() { return "Advanced Rocketry"; } + @Override public IDrawable getBackground(){ return bg; } + @Override public IDrawable getIcon() { return icon; } + + @Override + public void setRecipe(IRecipeLayout layout, Co2ScrubberWrapper wrapper, IIngredients ing) { + IGuiItemStackGroup items = layout.getItemStacks(); + + // Register tooltip handler first + items.addTooltipCallback((slotIndex, isInput, stack, tooltip) -> { + if (stack == null || stack.isEmpty()) return; + + if (slotIndex == 0) { + // Cartridge (left) + tooltip.add(net.minecraft.util.text.TextFormatting.YELLOW + + zmaster587.libVulpes.LibVulpes.proxy.getLocalizedString("jei.ar.scrubber.cartridge")); + } else if (slotIndex == 1) { + // Oxygen Vent ghost (right) + tooltip.add(net.minecraft.util.text.TextFormatting.YELLOW + + zmaster587.libVulpes.LibVulpes.proxy.getLocalizedString("jei.ar.scrubber.info_compact")); + } + }); + + // One input slot (cartridge), left side + items.init(0, true, 20, 11); + items.set(0, ing.getInputs(mezz.jei.api.ingredients.VanillaTypes.ITEM).get(0)); + + // Oxygen Vent ghost on the right + items.init(1, false, 120, 11); + items.set(1, new ItemStack(AdvancedRocketryBlocks.blockOxygenVent)); + } + + + @Override + public void drawExtras(Minecraft mc) { + // Draw the slot frame behind the cartridge + slot.draw(mc, 20, 11); + } +} From f74fb2e8598911390e79dec6b06ceba5d5b71c05 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 14:49:30 +0100 Subject: [PATCH 142/274] Implement Co2ScrubberRecipeHandler class --- .../co2scrubber/Co2ScrubberRecipeHandler.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberRecipeHandler.java diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberRecipeHandler.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberRecipeHandler.java new file mode 100644 index 000000000..5ebc0a039 --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberRecipeHandler.java @@ -0,0 +1,28 @@ +package zmaster587.advancedRocketry.integration.jei.co2scrubber; + +import mezz.jei.api.recipe.IRecipeHandler; +import mezz.jei.api.recipe.IRecipeWrapper; +import zmaster587.advancedRocketry.integration.jei.ARPlugin; + +public class Co2ScrubberRecipeHandler implements IRecipeHandler { + + @Override + public Class getRecipeClass() { + return Co2ScrubberWrapper.class; + } + + @Override + public String getRecipeCategoryUid(Co2ScrubberWrapper recipe) { + return ARPlugin.co2ScrubberUUID; + } + + @Override + public IRecipeWrapper getRecipeWrapper(Co2ScrubberWrapper recipe) { + return recipe; + } + + @Override + public boolean isRecipeValid(Co2ScrubberWrapper recipe) { + return recipe != null && !recipe.getCartridgeStack().isEmpty(); + } +} From 14809e6ec70aefa80d05a8d19b991836512ae513 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 14:50:18 +0100 Subject: [PATCH 143/274] Add Co2ScrubberRecipeMaker class for recipe handling --- .../co2scrubber/Co2ScrubberRecipeMaker.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberRecipeMaker.java diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberRecipeMaker.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberRecipeMaker.java new file mode 100644 index 000000000..a8354d898 --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberRecipeMaker.java @@ -0,0 +1,19 @@ +package zmaster587.advancedRocketry.integration.jei.co2scrubber; + +import mezz.jei.api.IJeiHelpers; +import net.minecraft.item.ItemStack; +import zmaster587.advancedRocketry.api.AdvancedRocketryItems; + +import java.util.ArrayList; +import java.util.List; + +public class Co2ScrubberRecipeMaker { + public static List getRecipes(IJeiHelpers helpers) { + List list = new ArrayList<>(); + + ItemStack cart = new ItemStack(AdvancedRocketryItems.itemCarbonScrubberCartridge, 1, net.minecraftforge.oredict.OreDictionary.WILDCARD_VALUE); + list.add(new Co2ScrubberWrapper(cart)); + + return list; + } +} From 11993721358be461429358d628cf946f01b4b222 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 14:51:01 +0100 Subject: [PATCH 144/274] Implement Co2ScrubberWrapper for JEI integration --- .../jei/co2scrubber/Co2ScrubberWrapper.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberWrapper.java diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberWrapper.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberWrapper.java new file mode 100644 index 000000000..cbddae11f --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberWrapper.java @@ -0,0 +1,34 @@ +package zmaster587.advancedRocketry.integration.jei.co2scrubber; + +import mezz.jei.api.ingredients.IIngredients; +import mezz.jei.api.recipe.BlankRecipeWrapper; +import net.minecraft.item.ItemStack; +import java.util.Collections; + +public class Co2ScrubberWrapper extends BlankRecipeWrapper { + private final ItemStack cartridge; + + public Co2ScrubberWrapper(ItemStack cartridge) { + this.cartridge = cartridge; + } + + @Override + public void getIngredients(IIngredients ing) { + // INPUTS: the cartridge (as a list-of-lists) + ing.setInputLists(mezz.jei.api.ingredients.VanillaTypes.ITEM, + java.util.Collections.singletonList( + java.util.Collections.singletonList(cartridge))); + + // OUTPUTS: expose BOTH blocks + the cartridge + java.util.List outs = new java.util.ArrayList<>(3); + outs.add(new net.minecraft.item.ItemStack(zmaster587.advancedRocketry.api.AdvancedRocketryBlocks.blockCO2Scrubber)); + outs.add(new net.minecraft.item.ItemStack(zmaster587.advancedRocketry.api.AdvancedRocketryBlocks.blockOxygenVent)); + outs.add(cartridge); + ing.setOutputs(mezz.jei.api.ingredients.VanillaTypes.ITEM, outs); + } + + // Used by the recipe handler's isRecipeValid + public ItemStack getCartridgeStack() { + return cartridge; + } +} From aee6916c8e05259f9d9f4fb97859f6d37f32b5ef Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 14:54:53 +0100 Subject: [PATCH 145/274] Add CO2 Scrubber integration to ARPlugin --- .../integration/jei/ARPlugin.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/ARPlugin.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/ARPlugin.java index b07be2bc2..57302621c 100644 --- a/src/main/java/zmaster587/advancedRocketry/integration/jei/ARPlugin.java +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/ARPlugin.java @@ -17,6 +17,9 @@ import zmaster587.advancedRocketry.integration.jei.chemicalReactor.ChemicalReactorCategory; import zmaster587.advancedRocketry.integration.jei.chemicalReactor.ChemicalReactorRecipeHandler; import zmaster587.advancedRocketry.integration.jei.chemicalReactor.ChemicalReactorRecipeMaker; +import zmaster587.advancedRocketry.integration.jei.co2scrubber.Co2ScrubberCategory; +import zmaster587.advancedRocketry.integration.jei.co2scrubber.Co2ScrubberRecipeHandler; +import zmaster587.advancedRocketry.integration.jei.co2scrubber.Co2ScrubberRecipeMaker; import zmaster587.advancedRocketry.integration.jei.crystallizer.CrystallizerCategory; import zmaster587.advancedRocketry.integration.jei.crystallizer.CrystallizerRecipeHandler; import zmaster587.advancedRocketry.integration.jei.crystallizer.CrystallizerRecipeMaker; @@ -71,6 +74,7 @@ public class ARPlugin implements IModPlugin { public static final String precisionLaserEngraverUUID = "zmaster587.AR.precisionlaseretcher"; public static final String satelliteBuilderUUID = "zmaster587.AR.satelliteBuilder"; public static final String fuelingStationUUID = "zmaster587.AR.fuelingStation"; + public static final String co2ScrubberUUID = "zmaster587.AR.co2scrubber"; public static IJeiHelpers jeiHelpers; //AR machines can reload recipes. We still need this for JEI to be up-to-date @@ -97,7 +101,8 @@ public void registerCategories(IRecipeCategoryRegistration registry) { new CentrifugeCategory(guiHelper), new PrecisionLaserEtcherCategory(guiHelper), new SatelliteBuilderCategory(guiHelper), - new FuelingStationCategory(guiHelper) + new FuelingStationCategory(guiHelper), + new Co2ScrubberCategory(guiHelper) ); } @@ -144,7 +149,8 @@ public Object getIngredientUnderMouse(GuiModular guiContainer, new CentrifugeRecipeHandler(), new PrecisionLaserEtcherRecipeHandler(), new SatelliteBuilderRecipeHandler(), - new FuelingStationRecipeHandler() + new FuelingStationRecipeHandler(), + new Co2ScrubberRecipeHandler() ); registry.addRecipes(RollingMachineRecipeMaker.getMachineRecipes(jeiHelpers, TileRollingMachine.class), rollingMachineUUID); @@ -160,6 +166,8 @@ public Object getIngredientUnderMouse(GuiModular guiContainer, registry.addRecipes(PrecisionLaserEtcherRecipeMaker.getMachineRecipes(jeiHelpers, TilePrecisionLaserEtcher.class), precisionLaserEngraverUUID); registry.addRecipes(SatelliteBuilderRecipeMaker.getMachineRecipes(jeiHelpers, TileSatelliteBuilder.class), satelliteBuilderUUID); registry.addRecipes(FuelingStationRecipeMaker.getMachineRecipes(jeiHelpers, TileFuelingStation.class), fuelingStationUUID); + registry.addRecipes(Co2ScrubberRecipeMaker.getRecipes(jeiHelpers), co2ScrubberUUID); + registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockRollingMachine), rollingMachineUUID); registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockLathe), latheUUID); @@ -173,7 +181,10 @@ public Object getIngredientUnderMouse(GuiModular guiContainer, registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockCentrifuge), centrifugeUUID); registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockPrecisionLaserEngraver), precisionLaserEngraverUUID); registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockSatelliteBuilder), satelliteBuilderUUID); - + + // Co2 Scrubber catalysts + registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockCO2Scrubber), co2ScrubberUUID); + registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockOxygenVent), co2ScrubberUUID); // One tab: Fueling Station + Tank-type catalysts (mono / biprop fuel / oxidizer / working fluid) registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockFuelingStation), fuelingStationUUID); From 2446992882adf48651999345e9163989be55425e Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 17:25:58 +0100 Subject: [PATCH 146/274] Enhance tooltip information for Launchpad Add tooltip information --- .../block/BlockLinkedHorizontalTexture.java | 54 ++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockLinkedHorizontalTexture.java b/src/main/java/zmaster587/advancedRocketry/block/BlockLinkedHorizontalTexture.java index 7e9153b17..71be73a13 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockLinkedHorizontalTexture.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockLinkedHorizontalTexture.java @@ -1,13 +1,25 @@ package zmaster587.advancedRocketry.block; +import java.util.List; + +import javax.annotation.Nullable; + import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.properties.PropertyEnum; import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.resources.I18n; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.item.ItemStack; import net.minecraft.util.IStringSerializable; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TextFormatting; import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; public class BlockLinkedHorizontalTexture extends Block { @@ -84,4 +96,44 @@ public String getName() { return suffix; } } -} \ No newline at end of file + + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.launchpad")); + + final boolean shift = GuiScreen.isShiftKeyDown(); + final boolean alt = isAltDown(); + + if (alt) { + // Advanced details + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.launchpad.alt.1")); + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.launchpad.alt.2")); + } else if (shift) { + // More info + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.launchpad.shift.1")); + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.launchpad.shift.2")); + if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) + tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); + } else { + // Hints + if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) + tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_shift")); + if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) + tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); + } + } + + @SideOnly(Side.CLIENT) + private static boolean isAltDown() { + try { + // Works on Forge 1.12.x; LWJGL fallback for safety + return GuiScreen.isAltKeyDown() + || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_LMENU) + || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_RMENU); + } catch (Throwable t) { + return false; + } + } + +} From 408be66df0742d5739897f61d9a261b4c6d3eb40 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 17:27:52 +0100 Subject: [PATCH 147/274] Enhance tooltip information for BlockLandingPad Added tooltip information for the landing pad block, including advanced details and hints based on key presses. --- .../block/BlockLandingPad.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockLandingPad.java b/src/main/java/zmaster587/advancedRocketry/block/BlockLandingPad.java index 4eb73f072..170ed0bb8 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockLandingPad.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockLandingPad.java @@ -1,14 +1,25 @@ package zmaster587.advancedRocketry.block; +import java.util.List; + +import javax.annotation.Nullable; + import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.resources.I18n; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TextFormatting; import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.advancedRocketry.tile.station.TileLandingPad; import zmaster587.libVulpes.LibVulpes; import zmaster587.libVulpes.inventory.GuiHandler; @@ -48,6 +59,46 @@ public boolean onBlockActivated(World world, BlockPos pos, return true; } + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.landingpad")); + + final boolean shift = GuiScreen.isShiftKeyDown(); + final boolean alt = isAltDown(); + + if (alt) { + // Advanced details + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.landingpad.alt.1")); + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.landingpad.alt.2")); + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.landingpad.alt.3")); + } else if (shift) { + // More info + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.landingpad.shift.1")); + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.landingpad.shift.2")); + if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) + tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); + } else { + // Hints + if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) + tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_shift")); + if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) + tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); + } + } + + @SideOnly(Side.CLIENT) + private static boolean isAltDown() { + try { + // Works on Forge 1.12.x; LWJGL fallback for safety + return GuiScreen.isAltKeyDown() + || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_LMENU) + || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_RMENU); + } catch (Throwable t) { + return false; + } + } + @Override public void breakBlock(World world, BlockPos pos, IBlockState state) { TileEntity tile = world.getTileEntity(pos); From a8f1a451cbaa4e72d9ed250aab4f827e46bbf91e Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 17:32:58 +0100 Subject: [PATCH 148/274] Enhance tooltip information for BlockNuclearCore Added tooltip information for the Nuclear Core block, including advanced details and hints based on key presses. --- .../block/BlockNuclearCore.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearCore.java b/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearCore.java index 7cdc3d25b..a1359d23b 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearCore.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearCore.java @@ -2,11 +2,21 @@ import net.minecraft.block.Block; import net.minecraft.block.material.Material; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.resources.I18n; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.item.ItemStack; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TextFormatting; import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.advancedRocketry.api.ARConfiguration; import zmaster587.advancedRocketry.api.IRocketNuclearCore; +import javax.annotation.Nullable; +import java.util.List; + public class BlockNuclearCore extends Block implements IRocketNuclearCore { public BlockNuclearCore(Material mat) { @@ -18,5 +28,42 @@ public int getMaxThrust(World world, BlockPos pos) { return (int) (1000 * ARConfiguration.getCurrentConfig().nuclearCoreThrustRatio); } + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearcore")); + + final boolean shift = GuiScreen.isShiftKeyDown(); + final boolean alt = isAltDown(); + if (alt) { + // Advanced details + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearcore.alt.1")); + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearcore.alt.2")); + } else if (shift) { + // More info + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearcore.shift.1")); + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearcore.shift.2")); + if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) + tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); + } else { + // Hints + if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) + tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_shift")); + if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) + tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); + } + } + + @SideOnly(Side.CLIENT) + private static boolean isAltDown() { + try { + // Works on Forge 1.12.x; LWJGL fallback for safety + return GuiScreen.isAltKeyDown() + || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_LMENU) + || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_RMENU); + } catch (Throwable t) { + return false; + } + } } From 55f15be55c79d59dc3b287b71b4f3b2c908a4568 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 17:39:40 +0100 Subject: [PATCH 149/274] Enhance tooltip information for BlockRocketMotor Added tooltip information for the BlockRocketMotor class, providing advanced details based on key presses. --- .../block/BlockRocketMotor.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockRocketMotor.java b/src/main/java/zmaster587/advancedRocketry/block/BlockRocketMotor.java index 088ac702e..7ae489ab2 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockRocketMotor.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockRocketMotor.java @@ -2,6 +2,9 @@ import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.resources.I18n; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; @@ -11,14 +14,19 @@ import net.minecraft.util.EnumFacing; import net.minecraft.util.NonNullList; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TextFormatting; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.advancedRocketry.api.ARConfiguration; import zmaster587.advancedRocketry.api.IRocketEngine; import zmaster587.advancedRocketry.tile.TileBrokenPart; import zmaster587.advancedRocketry.util.IBrokenPartBlock; import zmaster587.libVulpes.block.BlockFullyRotatable; +import java.util.List; + import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -137,4 +145,42 @@ public ItemStack getDropItem(final IBlockState state, final World world, final @ } return drop; } + + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.monopropmotor")); + + final boolean shift = GuiScreen.isShiftKeyDown(); + final boolean alt = isAltDown(); + + if (alt) { + // Advanced details + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.monopropmotor.alt.1")); + } else if (shift) { + // More info + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.monopropmotor.shift.1")); + if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) + tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); + } else { + // Hints + if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) + tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_shift")); + if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) + tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); + } + } + + @SideOnly(Side.CLIENT) + private static boolean isAltDown() { + try { + // Works on Forge 1.12.x; LWJGL fallback for safety + return GuiScreen.isAltKeyDown() + || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_LMENU) + || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_RMENU); + } catch (Throwable t) { + return false; + } + } + } From 04128cb0ab2427f2922ab6dbd47cefa7c7a293f0 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 17:41:37 +0100 Subject: [PATCH 150/274] Enhance tooltip details for rocket motor block Add tooltip information for BlockBipropellantRocketMotor --- .../block/BlockBipropellantRocketMotor.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockBipropellantRocketMotor.java b/src/main/java/zmaster587/advancedRocketry/block/BlockBipropellantRocketMotor.java index d847191fd..66c6efe5c 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockBipropellantRocketMotor.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockBipropellantRocketMotor.java @@ -2,6 +2,9 @@ import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.resources.I18n; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; @@ -11,14 +14,19 @@ import net.minecraft.util.EnumFacing; import net.minecraft.util.NonNullList; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TextFormatting; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.advancedRocketry.api.ARConfiguration; import zmaster587.advancedRocketry.api.IRocketEngine; import zmaster587.advancedRocketry.tile.TileBrokenPart; import zmaster587.advancedRocketry.util.IBrokenPartBlock; import zmaster587.libVulpes.block.BlockFullyRotatable; +import java.util.List; + import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -119,6 +127,44 @@ public TileEntity createTileEntity(final World worldIn, final IBlockState state) return new TileBrokenPart(10, (float) ARConfiguration.getCurrentConfig().increaseWearIntensityProb); } + + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.bipropmotor")); + + final boolean shift = GuiScreen.isShiftKeyDown(); + final boolean alt = isAltDown(); + + if (alt) { + // Advanced details + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.bipropmotor.alt.1")); + } else if (shift) { + // More info + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.bipropmotor.shift.1")); + if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) + tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); + } else { + // Hints + if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) + tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_shift")); + if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) + tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); + } + } + + @SideOnly(Side.CLIENT) + private static boolean isAltDown() { + try { + // Works on Forge 1.12.x; LWJGL fallback for safety + return GuiScreen.isAltKeyDown() + || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_LMENU) + || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_RMENU); + } catch (Throwable t) { + return false; + } + } + @Override public ItemStack getDropItem(final IBlockState state, final World world, final @Nullable TileBrokenPart te) { ItemStack drop = new ItemStack(this.getItemDropped(state, world.rand, 0)); From b3f51ce0abdfc29fe9bd9b146d3e10c66686c368 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 17:41:59 +0100 Subject: [PATCH 151/274] Enhance tooltip for BlockNuclearRocketMotor Added tooltip information for the nuclear rocket motor, including advanced details and hints based on key presses. --- .../block/BlockNuclearRocketMotor.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearRocketMotor.java b/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearRocketMotor.java index 0658b8725..acfd046aa 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearRocketMotor.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearRocketMotor.java @@ -2,15 +2,24 @@ import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.resources.I18n; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TextFormatting; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.advancedRocketry.api.ARConfiguration; import zmaster587.advancedRocketry.api.IRocketNuclearCore; import zmaster587.advancedRocketry.tile.TileBrokenPart; +import java.util.List; + import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -51,4 +60,42 @@ public int getFuelConsumptionRate(World world, int x, int y, int z) { public TileEntity createTileEntity(final World worldIn, final IBlockState state) { return new TileBrokenPart(10, 4 * (float) ARConfiguration.getCurrentConfig().increaseWearIntensityProb); } + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearmotor")); + + final boolean shift = GuiScreen.isShiftKeyDown(); + final boolean alt = isAltDown(); + + if (alt) { + // Advanced details + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearmotor.alt.1")); + } else if (shift) { + // More info + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearmotor.shift.1")); + tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearmotor.shift.2")); + if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) + tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); + } else { + // Hints + if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) + tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_shift")); + if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) + tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); + } + } + + @SideOnly(Side.CLIENT) + private static boolean isAltDown() { + try { + // Works on Forge 1.12.x; LWJGL fallback for safety + return GuiScreen.isAltKeyDown() + || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_LMENU) + || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_RMENU); + } catch (Throwable t) { + return false; + } + } } + From f09271c988cab55d8c9eacb90c93452bbb032547 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 18:45:28 +0100 Subject: [PATCH 152/274] Update tooltip formatting for nuclear rocket motor --- .../advancedRocketry/block/BlockNuclearRocketMotor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearRocketMotor.java b/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearRocketMotor.java index acfd046aa..830433b5f 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearRocketMotor.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearRocketMotor.java @@ -70,7 +70,7 @@ public void addInformation(ItemStack stack, @Nullable World world, List if (alt) { // Advanced details - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearmotor.alt.1")); + tooltip.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.nuclearmotor.alt.1")); } else if (shift) { // More info tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearmotor.shift.1")); From 08b3d61593f80c30a150e595bf833de0ea6d8094 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 18:45:43 +0100 Subject: [PATCH 153/274] Change tooltip text color for nuclear core details --- .../zmaster587/advancedRocketry/block/BlockNuclearCore.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearCore.java b/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearCore.java index a1359d23b..0cf140dc6 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearCore.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearCore.java @@ -38,8 +38,8 @@ public void addInformation(ItemStack stack, @Nullable World world, List if (alt) { // Advanced details - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearcore.alt.1")); - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearcore.alt.2")); + tooltip.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.nuclearcore.alt.1")); + tooltip.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.nuclearcore.alt.2")); } else if (shift) { // More info tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearcore.shift.1")); From e96f6503a30c3b1f85b2e0a73e4c68369d2f2548 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 18:46:11 +0100 Subject: [PATCH 154/274] Change tooltip color for alt key details --- .../advancedRocketry/block/BlockBipropellantRocketMotor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockBipropellantRocketMotor.java b/src/main/java/zmaster587/advancedRocketry/block/BlockBipropellantRocketMotor.java index 66c6efe5c..a63f09c1c 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockBipropellantRocketMotor.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockBipropellantRocketMotor.java @@ -138,7 +138,7 @@ public void addInformation(ItemStack stack, @Nullable World world, List if (alt) { // Advanced details - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.bipropmotor.alt.1")); + tooltip.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.bipropmotor.alt.1")); } else if (shift) { // More info tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.bipropmotor.shift.1")); From 2b7ef2943c3faf93a61135cbc66470301df293c3 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 18:46:41 +0100 Subject: [PATCH 155/274] Change tooltip formatting for alt key details --- .../zmaster587/advancedRocketry/block/BlockRocketMotor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockRocketMotor.java b/src/main/java/zmaster587/advancedRocketry/block/BlockRocketMotor.java index 7ae489ab2..567701c5c 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockRocketMotor.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockRocketMotor.java @@ -156,7 +156,7 @@ public void addInformation(ItemStack stack, @Nullable World world, List if (alt) { // Advanced details - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.monopropmotor.alt.1")); + tooltip.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.monopropmotor.alt.1")); } else if (shift) { // More info tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.monopropmotor.shift.1")); From f64ddaca04c8c1a69458e1891dd94b6856846364 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 18:48:10 +0100 Subject: [PATCH 156/274] Change tooltip text color for landing pad details --- .../zmaster587/advancedRocketry/block/BlockLandingPad.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockLandingPad.java b/src/main/java/zmaster587/advancedRocketry/block/BlockLandingPad.java index 170ed0bb8..b738003fb 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockLandingPad.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockLandingPad.java @@ -69,9 +69,9 @@ public void addInformation(ItemStack stack, @Nullable World world, List if (alt) { // Advanced details - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.landingpad.alt.1")); - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.landingpad.alt.2")); - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.landingpad.alt.3")); + tooltip.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.landingpad.alt.1")); + tooltip.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.landingpad.alt.2")); + tooltip.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.landingpad.alt.3")); } else if (shift) { // More info tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.landingpad.shift.1")); From a0d7e605a185467a16a319f9b8a33595eea52d00 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 18:48:43 +0100 Subject: [PATCH 157/274] Change tooltip text color for alt key Updated tooltip text color for advanced details. --- .../advancedRocketry/block/BlockLinkedHorizontalTexture.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockLinkedHorizontalTexture.java b/src/main/java/zmaster587/advancedRocketry/block/BlockLinkedHorizontalTexture.java index 71be73a13..5c5e574ba 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockLinkedHorizontalTexture.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockLinkedHorizontalTexture.java @@ -107,8 +107,8 @@ public void addInformation(ItemStack stack, @Nullable World world, List if (alt) { // Advanced details - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.launchpad.alt.1")); - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.launchpad.alt.2")); + tooltip.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.launchpad.alt.1")); + tooltip.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.launchpad.alt.2")); } else if (shift) { // More info tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.launchpad.shift.1")); From 10588e9dc533994566dcc2e9d91da5479f765f12 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 20:00:33 +0100 Subject: [PATCH 158/274] Remove tooltip callback from Co2ScrubberCategory Removed tooltip handler for item stacks in Co2ScrubberCategory. --- .../jei/co2scrubber/Co2ScrubberCategory.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberCategory.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberCategory.java index 7d9dc22b0..6aac19c5c 100644 --- a/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberCategory.java +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberCategory.java @@ -34,21 +34,6 @@ public Co2ScrubberCategory(IGuiHelper gui) { public void setRecipe(IRecipeLayout layout, Co2ScrubberWrapper wrapper, IIngredients ing) { IGuiItemStackGroup items = layout.getItemStacks(); - // Register tooltip handler first - items.addTooltipCallback((slotIndex, isInput, stack, tooltip) -> { - if (stack == null || stack.isEmpty()) return; - - if (slotIndex == 0) { - // Cartridge (left) - tooltip.add(net.minecraft.util.text.TextFormatting.YELLOW + - zmaster587.libVulpes.LibVulpes.proxy.getLocalizedString("jei.ar.scrubber.cartridge")); - } else if (slotIndex == 1) { - // Oxygen Vent ghost (right) - tooltip.add(net.minecraft.util.text.TextFormatting.YELLOW + - zmaster587.libVulpes.LibVulpes.proxy.getLocalizedString("jei.ar.scrubber.info_compact")); - } - }); - // One input slot (cartridge), left side items.init(0, true, 20, 11); items.set(0, ing.getInputs(mezz.jei.api.ingredients.VanillaTypes.ITEM).get(0)); From 8847357c5544645f07b19628f3f631c7a01d29a5 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 20:34:41 +0100 Subject: [PATCH 159/274] Implement tooltip for ItemAtmosphereAnalyzer Added tooltip information display for ItemAtmosphereAnalyzer. --- .../advancedRocketry/item/ItemAtmosphereAnalzer.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemAtmosphereAnalzer.java b/src/main/java/zmaster587/advancedRocketry/item/ItemAtmosphereAnalzer.java index e02ffccf4..eec4f7ef9 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemAtmosphereAnalzer.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemAtmosphereAnalzer.java @@ -6,6 +6,7 @@ import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.EntityEquipmentSlot; @@ -26,6 +27,7 @@ import org.lwjgl.opengl.GL11; import zmaster587.advancedRocketry.atmosphere.AtmosphereHandler; import zmaster587.advancedRocketry.atmosphere.AtmosphereType; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.advancedRocketry.dimension.DimensionManager; import zmaster587.advancedRocketry.event.RocketEventHandler; import zmaster587.advancedRocketry.inventory.TextureResources; @@ -107,6 +109,14 @@ public boolean isAllowedInSlot(@Nonnull ItemStack componentStack, EntityEquipmen return targetSlot == EntityEquipmentSlot.HEAD; } + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.atmanalyzer", insertAt); + } + + @Override @SideOnly(Side.CLIENT) public void renderScreen(@Nonnull ItemStack componentStack, List modules, From d77c430c749141e81c2eee869d3d934c9f88396e Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 21:39:40 +0100 Subject: [PATCH 160/274] Implement tooltip for BlockTileRedstoneEmitter Added tooltip information for the Redstone Emitter block. --- .../block/BlockTileRedstoneEmitter.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockTileRedstoneEmitter.java b/src/main/java/zmaster587/advancedRocketry/block/BlockTileRedstoneEmitter.java index b59042f81..8d0604a0d 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockTileRedstoneEmitter.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockTileRedstoneEmitter.java @@ -1,13 +1,23 @@ package zmaster587.advancedRocketry.block; +import javax.annotation.Nullable; + import net.minecraft.block.state.IBlockState; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.libVulpes.block.BlockTile; +import javax.annotation.Nullable; +import java.util.List; + // Fueling Station block public class BlockTileRedstoneEmitter extends BlockTile { @@ -25,6 +35,13 @@ public int getStrongPower(IBlockState state, IBlockAccess world, BlockPos pos, E return getWeakPower(state, world, pos, side); } + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.fuelingstation", insertAt); + } + @Override public boolean canProvidePower(IBlockState state) { return true; From 244a7292ff920fbc49dec25fb3b19af3314bae3d Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 22:18:20 +0100 Subject: [PATCH 161/274] Implement tooltip for ItemBeaconFinder Add tooltip information for ItemBeaconFinder. --- .../advancedRocketry/item/ItemBeaconFinder.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemBeaconFinder.java b/src/main/java/zmaster587/advancedRocketry/item/ItemBeaconFinder.java index 3c385c1ad..27e263ec9 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemBeaconFinder.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemBeaconFinder.java @@ -6,6 +6,7 @@ import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.EntityEquipmentSlot; @@ -19,6 +20,8 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import org.lwjgl.opengl.GL11; + +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.advancedRocketry.dimension.DimensionManager; import zmaster587.libVulpes.api.IArmorComponent; import zmaster587.libVulpes.client.ResourceIcon; @@ -27,6 +30,8 @@ import zmaster587.libVulpes.util.HashedBlockPosition; import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import java.util.List; public class ItemBeaconFinder extends Item implements IArmorComponent { @@ -95,6 +100,13 @@ public void renderScreen(@Nonnull ItemStack componentStack, List modu } } + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.beaconfinder", insertAt); + } + @Override public ResourceIcon getComponentIcon(@Nonnull ItemStack armorStack) { return null; From 479636fd9d43e649de7ff9a6f625605ee9021895 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 22:37:08 +0100 Subject: [PATCH 162/274] Refactor BlockPressurizedFluidTank methods for clarity --- .../advancedRocketry/block/BlockPressurizedFluidTank.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockPressurizedFluidTank.java b/src/main/java/zmaster587/advancedRocketry/block/BlockPressurizedFluidTank.java index ed15835d6..53cc745a2 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockPressurizedFluidTank.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockPressurizedFluidTank.java @@ -95,7 +95,7 @@ public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, En @Override public void onBlockAdded(World world, BlockPos pos, IBlockState state) { super.onBlockAdded(world, pos, state); - if (world.isRemote) return; // <- add this + if (world.isRemote) return; TileEntity teAbove = world.getTileEntity(pos.up()); if (teAbove instanceof TileFluidTank) { ((TileFluidTank) teAbove).onAdjacentBlockUpdated(EnumFacing.DOWN); @@ -122,7 +122,6 @@ public List getDrops(IBlockAccess world, BlockPos pos, IBlockState st if (te instanceof TileFluidTank) { net.minecraftforge.fluids.FluidStack own = ((TileFluidTank) te).getOwnContentsCopy(); - // 1.12: FluidStack has no isEmpty(); guard on null and amount > 0 if (own != null && own.amount > 0) { ((ItemBlockFluidTank) out.getItem()).fill(out, own); } @@ -138,7 +137,7 @@ public boolean removedByPlayer(IBlockState state, World world, BlockPos pos, Ent if (!world.isRemote) { TileEntity te = world.getTileEntity(pos); if (te instanceof TileFluidTank) { - ((TileFluidTank) te).setRemoving(true); // <- you’ll add this setter in the tile + ((TileFluidTank) te).setRemoving(true); } } // Let vanilla handle removal; we’ll control drops in harvestBlock @@ -168,12 +167,10 @@ public void harvestBlock(World world, EntityPlayer player, BlockPos pos, IBlockS } } - // Spawn our single, correct drop EntityItem ei = new EntityItem(world, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, drop); world.spawnEntity(ei); - // Finally remove the block (this will call breakBlock and clear TE) world.setBlockToAir(pos); } From 1f6b5f61620a6132343119308facce2e1b5a15dd Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 22:38:40 +0100 Subject: [PATCH 163/274] Fix guard condition for fluid draining --- .../zmaster587/advancedRocketry/item/ItemBlockFluidTank.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java b/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java index f034a86ad..ec57cc084 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java @@ -72,7 +72,7 @@ public boolean placeBlockAt(@Nonnull ItemStack stack, EntityPlayer player, World ItemStack one = stack.copy(); one.setCount(1); FluidStack drained = drain(one, Integer.MAX_VALUE); - if (drained != null && drained.amount > 0) { // <- guard + if (drained != null && drained.amount > 0) { handler.fill(drained, true); } } From be3489dd9767f9fd5432e681a90e33c4eda92c0e Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 23:21:18 +0100 Subject: [PATCH 164/274] Refactor addInformation method for clarity --- .../item/components/ItemPressureTank.java | 49 +++++++++++++++---- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/components/ItemPressureTank.java b/src/main/java/zmaster587/advancedRocketry/item/components/ItemPressureTank.java index d5e2f9815..96d87b60f 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/components/ItemPressureTank.java +++ b/src/main/java/zmaster587/advancedRocketry/item/components/ItemPressureTank.java @@ -1,7 +1,9 @@ package zmaster587.advancedRocketry.item.components; import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.client.resources.I18n; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.EntityEquipmentSlot; @@ -9,12 +11,14 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; +import net.minecraft.util.text.TextFormatting; import net.minecraft.world.World; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import org.lwjgl.input.Keyboard; import zmaster587.advancedRocketry.capability.TankCapabilityItemStack; import zmaster587.libVulpes.LibVulpes; import zmaster587.libVulpes.api.IArmorComponent; @@ -23,6 +27,8 @@ import zmaster587.libVulpes.util.FluidUtils; import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import java.util.List; public class ItemPressureTank extends ItemIngredient implements IArmorComponent { @@ -36,24 +42,45 @@ public ItemPressureTank(int number, int capacity) { this.capacity = capacity; this.maxStackSize = 8; } - + + @SideOnly(Side.CLIENT) @Override - public void addInformation(@Nonnull ItemStack stack, World player, List list, ITooltipFlag bool) { - super.addInformation(stack, player, list, bool); - - FluidStack fluidStack = FluidUtils.getFluidForItem(stack); + public void addInformation(@Nonnull ItemStack stack, @Nullable World world, + List list, ITooltipFlag flag) { + super.addInformation(stack, world, list, flag); + + final int capMb = Math.max(0, getCapacity(stack)); + final net.minecraftforge.fluids.FluidStack fs = zmaster587.libVulpes.util.FluidUtils.getFluidForItem(stack); + + final String fluidName = (fs != null && fs.getFluid() != null) ? fs.getLocalizedName() : "Empty"; + final int amount = (fs != null) ? fs.amount : 0; + + // Match main tank style + list.add("Fluid: " + fluidName); + list.add("Level: " + amount + "/" + capMb + " mB"); + + // SHIFT block + if (GuiScreen.isShiftKeyDown()) { + list.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.pressuretank.shift.1")); + list.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.pressuretank.shift.2")); + } else if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) { + list.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + + I18n.format("tooltip.advancedrocketry.hold_shift")); + } - if (fluidStack == null) { - list.add(LibVulpes.proxy.getLocalizedString("msg.empty")); - } else { - list.add(fluidStack.getLocalizedName() + ": " + fluidStack.amount); + // ALT block (independent of SHIFT) + if (Keyboard.isKeyDown(Keyboard.KEY_LMENU) || Keyboard.isKeyDown(Keyboard.KEY_RMENU)) { + list.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.pressuretank.alt.1")); + list.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.pressuretank.alt.2")); + } else if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) { + list.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + + I18n.format("tooltip.advancedrocketry.hold_alt")); } } @Override public void onTick(World world, EntityPlayer player, @Nonnull ItemStack armorStack, IInventory inv, @Nonnull ItemStack componentStack) { - } @Override @@ -93,6 +120,8 @@ public void renderScreen(@Nonnull ItemStack componentStack, List modu } + + @Override public ICapabilityProvider initCapabilities(@Nonnull ItemStack stack, NBTTagCompound nbt) { return new TankCapabilityItemStack(stack, getCapacity(stack)); From 0890ada6a212a5ed7eaccbae1cb1c7d5965a58de Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sat, 8 Nov 2025 23:21:43 +0100 Subject: [PATCH 165/274] Enhance fluid tank item tooltips with localization Added localization support and tooltip enhancements for the fluid tank item. --- .../item/ItemBlockFluidTank.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java b/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java index ec57cc084..40600e989 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java @@ -3,6 +3,7 @@ import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.resources.I18n; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemBlock; @@ -17,6 +18,9 @@ import net.minecraftforge.fluids.FluidTank; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import org.lwjgl.input.Keyboard; import zmaster587.advancedRocketry.api.ARConfiguration; import zmaster587.advancedRocketry.tile.TileFluidTank; @@ -26,6 +30,9 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; + +import org.lwjgl.input.Keyboard; + import java.util.List; public class ItemBlockFluidTank extends ItemBlock { @@ -56,6 +63,15 @@ public void addInformation(@Nonnull ItemStack stack, @Nullable World world, List list.add("Fluid: " + fluidName); list.add("Level: " + amount + "/" + capMb + " mB"); + + // --- SHIFT for more info (adds two short lines) --- + if (GuiScreen.isShiftKeyDown()) { + list.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.fluidtank.shift.1")); + list.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.fluidtank.shift.2")); + } else if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) { + list.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + + I18n.format("tooltip.advancedrocketry.hold_shift")); + } } @Override From 223b0da54ef556e547efe690e0f650b8b591e9bf Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 9 Nov 2025 00:04:17 +0100 Subject: [PATCH 166/274] Implement tooltip for BlockIntake class Added tooltip information for BlockIntake. --- .../advancedRocketry/block/BlockIntake.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockIntake.java b/src/main/java/zmaster587/advancedRocketry/block/BlockIntake.java index 33a7260fe..652466352 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockIntake.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockIntake.java @@ -1,15 +1,32 @@ package zmaster587.advancedRocketry.block; +import java.util.List; + +import javax.annotation.Nullable; + import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.advancedRocketry.api.IIntake; +import zmaster587.advancedRocketry.client.TooltipInjector; public class BlockIntake extends Block implements IIntake { public BlockIntake(Material material) { super(material); } + + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.intake", insertAt); + } @Override public int getIntakeAmt(IBlockState state) { From 6be0bb1037bb8e1bf80f76a415cb372cda6c41b0 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 9 Nov 2025 00:04:37 +0100 Subject: [PATCH 167/274] Implement tooltip for BlockMiningDrill Added tooltip information for BlockMiningDrill. --- .../advancedRocketry/block/BlockMiningDrill.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockMiningDrill.java b/src/main/java/zmaster587/advancedRocketry/block/BlockMiningDrill.java index 432bf6dac..db5141062 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockMiningDrill.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockMiningDrill.java @@ -1,10 +1,19 @@ package zmaster587.advancedRocketry.block; +import java.util.List; + +import javax.annotation.Nullable; + import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.item.ItemStack; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.advancedRocketry.api.IMiningDrill; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.libVulpes.block.BlockFullyRotatable; public class BlockMiningDrill extends BlockFullyRotatable implements IMiningDrill { @@ -24,6 +33,13 @@ public float getMiningSpeed(World world, BlockPos pos) { return world.isAirBlock(pos.add(0, 1, 0)) && world.isAirBlock(pos.add(0, 2, 0)) ? 0.02f : 0.01f; } + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.drill", insertAt); + } + @Override public int powerConsumption() { return 0; From 6abe8a1841b6ff33163ab2fc36836b17517a598c Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 9 Nov 2025 00:54:45 +0100 Subject: [PATCH 168/274] Implement tooltip for BlockLens class Added tooltip information for BlockLens in the client. --- .../advancedRocketry/block/BlockLens.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockLens.java b/src/main/java/zmaster587/advancedRocketry/block/BlockLens.java index 6807ad386..4e71391ad 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockLens.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockLens.java @@ -1,8 +1,18 @@ package zmaster587.advancedRocketry.block; +import java.util.List; + +import javax.annotation.Nullable; + import net.minecraft.block.BlockGlass; import net.minecraft.block.SoundType; import net.minecraft.block.material.Material; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import zmaster587.advancedRocketry.client.TooltipInjector; /** * Yes, this class may seem useless, but setSoundType can't be run in the registry, only by a subclass of Block. @@ -12,4 +22,11 @@ public BlockLens() { super(Material.GLASS, true); setSoundType(SoundType.GLASS); } + + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.lens", insertAt); + } } From 64632bc1fefd0cb62644efa9b2ecd7686628b600 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 9 Nov 2025 00:55:05 +0100 Subject: [PATCH 169/274] Implement tooltip for BlockTransciever Added tooltip information for BlockTransciever. --- .../advancedRocketry/block/BlockTransciever.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java b/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java index a83b44248..9dd359601 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java @@ -4,6 +4,7 @@ import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.EntityLivingBase; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; @@ -18,6 +19,14 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.libVulpes.block.BlockTile; +import zmaster587.advancedRocketry.client.TooltipInjector; + +import javax.annotation.Nullable; +import java.util.List; + + + + public class BlockTransciever extends BlockTile { @@ -138,6 +147,13 @@ public boolean rotateBlock(World world, BlockPos pos, EnumFacing axis) { return false; } + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.transciever", insertAt); + } + public static EnumFacing getFront(IBlockState state) { if (state == null || !state.getPropertyKeys().contains(FACING)) return EnumFacing.NORTH; return state.getValue(FACING); From b27ad63d2427debdd7958e442efb6a3c63c20ac0 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 9 Nov 2025 00:55:24 +0100 Subject: [PATCH 170/274] Implement tooltip for BlockSeat item Added tooltip information for BlockSeat. --- .../advancedRocketry/block/BlockSeat.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockSeat.java b/src/main/java/zmaster587/advancedRocketry/block/BlockSeat.java index ea2676456..0e3a63004 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockSeat.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockSeat.java @@ -3,8 +3,10 @@ import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; import net.minecraft.util.BlockRenderLayer; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; @@ -13,6 +15,9 @@ import net.minecraft.world.Explosion; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.advancedRocketry.entity.EntityDummy; import javax.annotation.Nonnull; @@ -107,4 +112,12 @@ public boolean onBlockActivated(World world, BlockPos pos, return true; } + + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.seat", insertAt); + } + } From 6bde1836324f2817cd9bba94d6d7ee5c74830925 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 9 Nov 2025 01:24:37 +0100 Subject: [PATCH 171/274] Adjust panning container dimensions in TileAtmosphereDetector fixes GUI overlapping hotbar.... --- .../tile/atmosphere/TileAtmosphereDetector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/atmosphere/TileAtmosphereDetector.java b/src/main/java/zmaster587/advancedRocketry/tile/atmosphere/TileAtmosphereDetector.java index 169933db3..a18de9642 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/atmosphere/TileAtmosphereDetector.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/atmosphere/TileAtmosphereDetector.java @@ -80,7 +80,7 @@ public List getModules(int id, EntityPlayer player) { i++; } - ModuleContainerPan panningContainer = new ModuleContainerPan(5, 20, btns, new LinkedList<>(), zmaster587.libVulpes.inventory.TextureResources.starryBG, 165, 120, 0, 500); + ModuleContainerPan panningContainer = new ModuleContainerPan(5, 20, btns, new LinkedList<>(), zmaster587.libVulpes.inventory.TextureResources.starryBG, 160, 100, 0, 500); modules.add(panningContainer); return modules; } From a251eb93bb6c3172d47ccbc2286e897584744597 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 9 Nov 2025 01:25:13 +0100 Subject: [PATCH 172/274] Implement tooltip for Atmospheredetector Implement tooltip for Atmospheredetector --- .../block/BlockRedstoneEmitter.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockRedstoneEmitter.java b/src/main/java/zmaster587/advancedRocketry/block/BlockRedstoneEmitter.java index 99720b44b..94131b83a 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockRedstoneEmitter.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockRedstoneEmitter.java @@ -5,20 +5,28 @@ import net.minecraft.block.properties.PropertyBool; import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.advancedRocketry.tile.atmosphere.TileAtmosphereDetector; import zmaster587.libVulpes.LibVulpes; import zmaster587.libVulpes.inventory.GuiHandler; +import java.util.List; + import javax.annotation.Nonnull; +import javax.annotation.Nullable; import javax.annotation.ParametersAreNullableByDefault; - +// Atmosphere Detector that emits redstone signal when a specific atmosphere is detected public class BlockRedstoneEmitter extends Block { public static final PropertyBool POWERED = PropertyBool.create("powered"); @@ -86,6 +94,13 @@ public int getWeakPower(IBlockState blockState, IBlockAccess blockAccess, return blockState.getValue(POWERED) ? 15 : 0; } + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.atmosphereDetector", insertAt); + } + @Override public boolean canProvidePower(IBlockState state) { return true; From d6f8edd9f619d3603ec69f781c66883670f7127c Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 9 Nov 2025 01:57:14 +0100 Subject: [PATCH 173/274] Add tooltip information to BlockSuitWorkstation --- .../block/BlockSuitWorkstation.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockSuitWorkstation.java b/src/main/java/zmaster587/advancedRocketry/block/BlockSuitWorkstation.java index f51998463..84cca8f0e 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockSuitWorkstation.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockSuitWorkstation.java @@ -1,12 +1,20 @@ package zmaster587.advancedRocketry.block; +import java.util.List; + +import javax.annotation.Nullable; + import net.minecraft.block.state.IBlockState; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.item.EntityItem; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.libVulpes.block.BlockTile; public class BlockSuitWorkstation extends BlockTile { @@ -54,4 +62,12 @@ public void breakBlock(World world, BlockPos pos, IBlockState state) { world.removeTileEntity(pos); } + + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.suitworkingstation", insertAt); + } + } From 8395506c8ef8d0aebc9744902525b03e2695b1c4 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 9 Nov 2025 03:40:59 +0100 Subject: [PATCH 174/274] Implement tooltip for BlockStationModuleDockingPort Added tooltip information for the docking port block. --- .../block/BlockStationModuleDockingPort.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockStationModuleDockingPort.java b/src/main/java/zmaster587/advancedRocketry/block/BlockStationModuleDockingPort.java index 7cec3efe0..168a9d20e 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockStationModuleDockingPort.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockStationModuleDockingPort.java @@ -2,6 +2,7 @@ import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; @@ -10,13 +11,19 @@ import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.advancedRocketry.tile.station.TileDockingPort; import zmaster587.advancedRocketry.tile.station.TileLandingPad; import zmaster587.libVulpes.LibVulpes; import zmaster587.libVulpes.block.BlockFullyRotatable; import zmaster587.libVulpes.inventory.GuiHandler; +import java.util.List; + import javax.annotation.Nonnull; +import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNullableByDefault; @@ -56,6 +63,13 @@ public void onBlockPlacedBy(World world, BlockPos pos, IBlockState state, } } + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.dockingport", insertAt); + } + @Override @ParametersAreNonnullByDefault public void breakBlock(World world, BlockPos pos, IBlockState state) { From 3aaee158baf8f8c05c753ba62501fa964d4d6735 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 9 Nov 2025 03:55:40 +0100 Subject: [PATCH 175/274] Implement tooltip for BlockSeal item Add tooltip information for BlockSeal in client-side. --- .../advancedRocketry/block/BlockSeal.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockSeal.java b/src/main/java/zmaster587/advancedRocketry/block/BlockSeal.java index 894c1028a..f19828940 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockSeal.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockSeal.java @@ -3,13 +3,18 @@ import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.advancedRocketry.api.AreaBlob; import zmaster587.advancedRocketry.api.util.IBlobHandler; import zmaster587.advancedRocketry.atmosphere.AtmosphereHandler; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.advancedRocketry.tile.atmosphere.TileSeal; import zmaster587.libVulpes.util.HashedBlockPosition; @@ -18,6 +23,7 @@ import javax.annotation.ParametersAreNonnullByDefault; import java.util.HashMap; import java.util.LinkedList; +import java.util.List; public class BlockSeal extends Block { @@ -196,4 +202,12 @@ public int getTraceDistance() { return -1; } } + + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.pipeseal", insertAt); + } + } From d812a4195602262a3522dd57bef38306e5e0770e Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 9 Nov 2025 04:32:32 +0100 Subject: [PATCH 176/274] Implement tooltip for BlockTileTerraformer Add tooltip information for BlockTileTerraformer. --- .../block/BlockTileTerraformer.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockTileTerraformer.java b/src/main/java/zmaster587/advancedRocketry/block/BlockTileTerraformer.java index 824464b51..55f038c9a 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockTileTerraformer.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockTileTerraformer.java @@ -8,6 +8,7 @@ import net.minecraft.block.properties.PropertyBool; import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; @@ -21,8 +22,12 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + import org.lwjgl.Sys; import scala.tools.nsc.doc.base.comment.EntityLink; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.advancedRocketry.dimension.DimensionManager; import zmaster587.advancedRocketry.dimension.DimensionProperties; import zmaster587.advancedRocketry.tile.satellite.TileTerraformingTerminal; @@ -31,7 +36,10 @@ import zmaster587.libVulpes.block.RotatableBlock; import zmaster587.libVulpes.util.IAdjBlockUpdate; +import java.util.List; + import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class BlockTileTerraformer extends RotatableBlock { protected Class tileClass; @@ -163,4 +171,11 @@ public void breakBlock(World world, BlockPos pos, IBlockState state) { super.breakBlock(world, pos, state); } + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.terraformer", insertAt); + } + } From 1f204bde89d2115a1b05bacaffc3e5a478ac73f6 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 9 Nov 2025 05:18:32 +0100 Subject: [PATCH 177/274] Add tooltip information to BlockWarpController --- .../block/BlockWarpController.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockWarpController.java b/src/main/java/zmaster587/advancedRocketry/block/BlockWarpController.java index 6d02996fb..227058aa7 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockWarpController.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockWarpController.java @@ -1,17 +1,24 @@ package zmaster587.advancedRocketry.block; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.EntityLivingBase; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.advancedRocketry.api.stations.ISpaceObject; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.advancedRocketry.stations.SpaceObjectManager; import zmaster587.advancedRocketry.stations.SpaceStationObject; import zmaster587.libVulpes.block.BlockTile; +import java.util.List; + import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class BlockWarpController extends BlockTile { @@ -30,4 +37,12 @@ public void onBlockPlacedBy(World world, BlockPos pos, IBlockState state, ((SpaceStationObject) spaceObject).setForwardDirection(getFront(state).getOpposite()); } } + + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.warpcontroller", insertAt); + } + } From 620a003d3e424d92591cba513f6d75b5f3e633da Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 9 Nov 2025 12:48:15 +0100 Subject: [PATCH 178/274] Implement tooltip for ItemJetpack Added tooltip information for the ItemJetpack. --- .../item/components/ItemJetpack.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/item/components/ItemJetpack.java b/src/main/java/zmaster587/advancedRocketry/item/components/ItemJetpack.java index fc219584b..1e41e822d 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/components/ItemJetpack.java +++ b/src/main/java/zmaster587/advancedRocketry/item/components/ItemJetpack.java @@ -2,6 +2,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Gui; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.EntityEquipmentSlot; @@ -22,6 +23,7 @@ import zmaster587.advancedRocketry.api.ARConfiguration; import zmaster587.advancedRocketry.api.AdvancedRocketryFluids; import zmaster587.advancedRocketry.api.AdvancedRocketryItems; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.advancedRocketry.event.RocketEventHandler; import zmaster587.advancedRocketry.inventory.TextureResources; import zmaster587.libVulpes.api.IArmorComponent; @@ -32,6 +34,8 @@ import zmaster587.libVulpes.util.InputSyncHandler; import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import java.util.List; public class ItemJetpack extends Item implements IArmorComponent, IJetPack { @@ -345,4 +349,12 @@ private enum MODES { NORMAL, HOVER } + + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.jetpack", insertAt); + } + } From 34b0975d3279ea228c0b2fa138c5b76f62792e42 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 9 Nov 2025 14:16:19 +0100 Subject: [PATCH 179/274] Implement tooltip for ItemSealDetector Added tooltip information for ItemSealDetector. --- .../advancedRocketry/item/ItemSealDetector.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemSealDetector.java b/src/main/java/zmaster587/advancedRocketry/item/ItemSealDetector.java index b01a05aa2..cace938ce 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemSealDetector.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemSealDetector.java @@ -1,7 +1,12 @@ package zmaster587.advancedRocketry.item; +import java.util.List; + +import javax.annotation.Nullable; + import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -13,6 +18,9 @@ import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; import net.minecraftforge.fluids.IFluidBlock; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.advancedRocketry.util.SealableBlockHandler; /** @@ -20,7 +28,6 @@ * Created by Dark(DarkGuardsman, Robert) on 1/6/2016. */ public class ItemSealDetector extends Item { - //TODO make consume power? @Override public ActionResult onItemRightClick(World worldIn, EntityPlayer playerIn, EnumHand hand) { @@ -53,4 +60,10 @@ public EnumActionResult onItemUse(EntityPlayer player, return EnumActionResult.SUCCESS; } + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.sealdetector", insertAt); + } } From 7651f06bfb755101ed4bf133ab38798d9287b88d Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 9 Nov 2025 14:17:39 +0100 Subject: [PATCH 180/274] Add tooltip information for ItemData when shift is held --- .../zmaster587/advancedRocketry/item/ItemData.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemData.java b/src/main/java/zmaster587/advancedRocketry/item/ItemData.java index 61ee7848f..ec625eefd 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemData.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemData.java @@ -1,9 +1,11 @@ package zmaster587.advancedRocketry.item; +import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.resources.I18n; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.text.TextFormatting; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @@ -96,7 +98,13 @@ public void addInformation(@Nonnull ItemStack stack, World player, List list.add(data.getData() + " / " + data.getMaxData() + " Data"); list.add(I18n.format(data.getDataType().toString())); - + // --- SHIFT for more info (adds two short lines) --- + if (GuiScreen.isShiftKeyDown()) { + list.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.itemdataunit.shift.1")); + list.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.itemdataunit.shift.2")); + } else if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) { + list.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + + I18n.format("tooltip.advancedrocketry.hold_shift")); + } } - } From 0fe789fce4892d802e6c4b588d509e09eaeb81ba Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 9 Nov 2025 15:09:52 +0100 Subject: [PATCH 181/274] Improve tooltip display for ItemAsteroidChip Enhanced tooltip information for ItemAsteroidChip. --- .../advancedRocketry/item/ItemAsteroidChip.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java b/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java index d26d5bb00..ece6bb14d 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java @@ -1,9 +1,13 @@ package zmaster587.advancedRocketry.item; import com.mojang.realmsclient.gui.ChatFormatting; + +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.resources.I18n; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.text.TextFormatting; import net.minecraft.world.World; import zmaster587.libVulpes.LibVulpes; @@ -94,6 +98,15 @@ private static long makeDisplayId(Long uuid, String type) { public void addInformation(@Nonnull ItemStack stack, World world, List list, ITooltipFlag flag) { if (!stack.hasTagCompound()) { list.add(LibVulpes.proxy.getLocalizedString("msg.unprogrammed")); + + // --- SHIFT for more info (adds two short lines) --- + if (GuiScreen.isShiftKeyDown()) { + list.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.asteroidchip.shift.1")); + list.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.asteroidchip.shift.2")); + } else if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) { + list.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + + I18n.format("tooltip.advancedrocketry.hold_shift")); + } return; } if (stack.getItemDamage() == 0) { @@ -116,8 +129,7 @@ public void addInformation(@Nonnull ItemStack stack, World world, List l list.add(LibVulpes.proxy.getLocalizedString("msg.asteroidChip.asteroid") + ": " + ChatFormatting.DARK_GREEN + shortHex); - super.addInformation(stack, world, list, flag); + super.addInformation(stack, world, list, flag); } } - } From d358febcabcb33a06cd2d72e6644bb06ae2642bf Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 10 Nov 2025 12:27:57 +0100 Subject: [PATCH 182/274] Fix missing newline at end of TileSatelliteTerminal.java From 4640565943bbafb2cdca7ae5319c8d31addc49a7 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 10 Nov 2025 12:33:42 +0100 Subject: [PATCH 183/274] moved tooltip to centralized injector --- .../block/BlockNuclearCore.java | 37 ++----------------- 1 file changed, 3 insertions(+), 34 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearCore.java b/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearCore.java index 0cf140dc6..1664ad679 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearCore.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearCore.java @@ -13,6 +13,7 @@ import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.advancedRocketry.api.ARConfiguration; import zmaster587.advancedRocketry.api.IRocketNuclearCore; +import zmaster587.advancedRocketry.client.TooltipInjector; import javax.annotation.Nullable; import java.util.List; @@ -31,39 +32,7 @@ public int getMaxThrust(World world, BlockPos pos) { @SideOnly(Side.CLIENT) @Override public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearcore")); - - final boolean shift = GuiScreen.isShiftKeyDown(); - final boolean alt = isAltDown(); - - if (alt) { - // Advanced details - tooltip.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.nuclearcore.alt.1")); - tooltip.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.nuclearcore.alt.2")); - } else if (shift) { - // More info - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearcore.shift.1")); - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearcore.shift.2")); - if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) - tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); - } else { - // Hints - if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) - tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_shift")); - if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) - tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); - } - } - - @SideOnly(Side.CLIENT) - private static boolean isAltDown() { - try { - // Works on Forge 1.12.x; LWJGL fallback for safety - return GuiScreen.isAltKeyDown() - || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_LMENU) - || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_RMENU); - } catch (Throwable t) { - return false; - } + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.nuclearcore", insertAt); } } From 6802d853950fc3cb5d38aec5bf1dcde97c788747 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 10 Nov 2025 12:52:32 +0100 Subject: [PATCH 184/274] Refactor tooltip information handling in BlockLandingPad --- .../block/BlockLandingPad.java | 38 ++----------------- 1 file changed, 3 insertions(+), 35 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockLandingPad.java b/src/main/java/zmaster587/advancedRocketry/block/BlockLandingPad.java index b738003fb..d559f1835 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockLandingPad.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockLandingPad.java @@ -20,6 +20,7 @@ import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.advancedRocketry.tile.station.TileLandingPad; import zmaster587.libVulpes.LibVulpes; import zmaster587.libVulpes.inventory.GuiHandler; @@ -62,41 +63,8 @@ public boolean onBlockActivated(World world, BlockPos pos, @SideOnly(Side.CLIENT) @Override public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.landingpad")); - - final boolean shift = GuiScreen.isShiftKeyDown(); - final boolean alt = isAltDown(); - - if (alt) { - // Advanced details - tooltip.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.landingpad.alt.1")); - tooltip.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.landingpad.alt.2")); - tooltip.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.landingpad.alt.3")); - } else if (shift) { - // More info - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.landingpad.shift.1")); - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.landingpad.shift.2")); - if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) - tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); - } else { - // Hints - if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) - tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_shift")); - if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) - tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); - } - } - - @SideOnly(Side.CLIENT) - private static boolean isAltDown() { - try { - // Works on Forge 1.12.x; LWJGL fallback for safety - return GuiScreen.isAltKeyDown() - || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_LMENU) - || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_RMENU); - } catch (Throwable t) { - return false; - } + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.landingpad", insertAt); } @Override From 385a9f6969a3b7aa8e74a2debd76a4bf07d4022e Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 10 Nov 2025 12:55:56 +0100 Subject: [PATCH 185/274] Refactor tooltip information handling in BlockNuclearRocketMotor --- .../block/BlockNuclearRocketMotor.java | 38 ++----------------- 1 file changed, 4 insertions(+), 34 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearRocketMotor.java b/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearRocketMotor.java index 830433b5f..604f1321b 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearRocketMotor.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockNuclearRocketMotor.java @@ -16,6 +16,7 @@ import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.advancedRocketry.api.ARConfiguration; import zmaster587.advancedRocketry.api.IRocketNuclearCore; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.advancedRocketry.tile.TileBrokenPart; import java.util.List; @@ -60,42 +61,11 @@ public int getFuelConsumptionRate(World world, int x, int y, int z) { public TileEntity createTileEntity(final World worldIn, final IBlockState state) { return new TileBrokenPart(10, 4 * (float) ARConfiguration.getCurrentConfig().increaseWearIntensityProb); } + @SideOnly(Side.CLIENT) @Override public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearmotor")); - - final boolean shift = GuiScreen.isShiftKeyDown(); - final boolean alt = isAltDown(); - - if (alt) { - // Advanced details - tooltip.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.nuclearmotor.alt.1")); - } else if (shift) { - // More info - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearmotor.shift.1")); - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.nuclearmotor.shift.2")); - if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) - tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); - } else { - // Hints - if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) - tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_shift")); - if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) - tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); - } - } - - @SideOnly(Side.CLIENT) - private static boolean isAltDown() { - try { - // Works on Forge 1.12.x; LWJGL fallback for safety - return GuiScreen.isAltKeyDown() - || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_LMENU) - || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_RMENU); - } catch (Throwable t) { - return false; - } + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.nuclearmotor", insertAt); } } - From ebb0bc486401744fee3eb5792fb2b3c5c6568283 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 10 Nov 2025 14:08:37 +0100 Subject: [PATCH 186/274] Simplify tooltip display logic in BlockBipropellantRocketMotor Refactor tooltip information handling for bipropellant rocket motor. --- .../block/BlockBipropellantRocketMotor.java | 36 ++----------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockBipropellantRocketMotor.java b/src/main/java/zmaster587/advancedRocketry/block/BlockBipropellantRocketMotor.java index a63f09c1c..e9342d566 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockBipropellantRocketMotor.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockBipropellantRocketMotor.java @@ -21,6 +21,7 @@ import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.advancedRocketry.api.ARConfiguration; import zmaster587.advancedRocketry.api.IRocketEngine; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.advancedRocketry.tile.TileBrokenPart; import zmaster587.advancedRocketry.util.IBrokenPartBlock; import zmaster587.libVulpes.block.BlockFullyRotatable; @@ -127,42 +128,11 @@ public TileEntity createTileEntity(final World worldIn, final IBlockState state) return new TileBrokenPart(10, (float) ARConfiguration.getCurrentConfig().increaseWearIntensityProb); } - @SideOnly(Side.CLIENT) @Override public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.bipropmotor")); - - final boolean shift = GuiScreen.isShiftKeyDown(); - final boolean alt = isAltDown(); - - if (alt) { - // Advanced details - tooltip.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.bipropmotor.alt.1")); - } else if (shift) { - // More info - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.bipropmotor.shift.1")); - if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) - tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); - } else { - // Hints - if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) - tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_shift")); - if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) - tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); - } - } - - @SideOnly(Side.CLIENT) - private static boolean isAltDown() { - try { - // Works on Forge 1.12.x; LWJGL fallback for safety - return GuiScreen.isAltKeyDown() - || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_LMENU) - || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_RMENU); - } catch (Throwable t) { - return false; - } + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.bipropmotor", insertAt); } @Override From e2a5ea099cd4f22dfc3d6ec5b299ef56ff1c4b82 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 10 Nov 2025 14:09:26 +0100 Subject: [PATCH 187/274] Refactor tooltip information handling in BlockRocketMotor --- .../block/BlockRocketMotor.java | 36 ++----------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockRocketMotor.java b/src/main/java/zmaster587/advancedRocketry/block/BlockRocketMotor.java index 567701c5c..cba1024bc 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockRocketMotor.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockRocketMotor.java @@ -21,6 +21,7 @@ import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.advancedRocketry.api.ARConfiguration; import zmaster587.advancedRocketry.api.IRocketEngine; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.advancedRocketry.tile.TileBrokenPart; import zmaster587.advancedRocketry.util.IBrokenPartBlock; import zmaster587.libVulpes.block.BlockFullyRotatable; @@ -149,38 +150,7 @@ public ItemStack getDropItem(final IBlockState state, final World world, final @ @SideOnly(Side.CLIENT) @Override public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.monopropmotor")); - - final boolean shift = GuiScreen.isShiftKeyDown(); - final boolean alt = isAltDown(); - - if (alt) { - // Advanced details - tooltip.add(TextFormatting.DARK_GRAY + I18n.format("tooltip.advancedrocketry.monopropmotor.alt.1")); - } else if (shift) { - // More info - tooltip.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.monopropmotor.shift.1")); - if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) - tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); - } else { - // Hints - if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) - tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_shift")); - if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) - tooltip.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_alt")); - } - } - - @SideOnly(Side.CLIENT) - private static boolean isAltDown() { - try { - // Works on Forge 1.12.x; LWJGL fallback for safety - return GuiScreen.isAltKeyDown() - || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_LMENU) - || org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_RMENU); - } catch (Throwable t) { - return false; - } + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.monopropmotor", insertAt); } - } From 43fcc74509f26059feea8bb033939afd6b8a0918 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 10 Nov 2025 17:52:54 +0100 Subject: [PATCH 188/274] Remove shift key tooltip from ItemAsteroidChip Removed shift key information display from addInformation method. --- .../advancedRocketry/item/ItemAsteroidChip.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java b/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java index ece6bb14d..d2fbad2d1 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java @@ -98,15 +98,6 @@ private static long makeDisplayId(Long uuid, String type) { public void addInformation(@Nonnull ItemStack stack, World world, List list, ITooltipFlag flag) { if (!stack.hasTagCompound()) { list.add(LibVulpes.proxy.getLocalizedString("msg.unprogrammed")); - - // --- SHIFT for more info (adds two short lines) --- - if (GuiScreen.isShiftKeyDown()) { - list.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.asteroidchip.shift.1")); - list.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.asteroidchip.shift.2")); - } else if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) { - list.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + - I18n.format("tooltip.advancedrocketry.hold_shift")); - } return; } if (stack.getItemDamage() == 0) { From 93b9e1311b6245629641dd25751c9fe303ec1e9f Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 10 Nov 2025 17:53:23 +0100 Subject: [PATCH 189/274] Fix missing newline at end of ItemStationChip.java From 18e7dc143d1fbb86e7fbfc62e3234c96dc48ba55 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 10 Nov 2025 17:54:07 +0100 Subject: [PATCH 190/274] Fix missing newline at end of ItemSatelliteIdentificationChip.java Added a newline at the end of the file. From 1ab910e762b76a81f7889fbbf77fd3f015f830b8 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 10 Nov 2025 23:58:54 +0100 Subject: [PATCH 191/274] Refactor addInformation to enhance tooltip display Updated addInformation method to include type and formatted data display. --- .../advancedRocketry/item/ItemData.java | 38 +++++++++++++------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemData.java b/src/main/java/zmaster587/advancedRocketry/item/ItemData.java index ec625eefd..6c9408082 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemData.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemData.java @@ -13,6 +13,8 @@ import zmaster587.libVulpes.items.ItemIngredient; import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import java.util.List; public class ItemData extends ItemIngredient { @@ -91,20 +93,32 @@ public void setData(@Nonnull ItemStack item, int amount, DataStorage.DataType da @Override @SideOnly(Side.CLIENT) - public void addInformation(@Nonnull ItemStack stack, World player, List list, ITooltipFlag bool) { - super.addInformation(stack, player, list, bool); + public void addInformation(@Nonnull ItemStack stack, @Nullable World world, List list, ITooltipFlag flag) { + super.addInformation(stack, world, list, flag); DataStorage data = getDataStorage(stack); - list.add(data.getData() + " / " + data.getMaxData() + " Data"); - list.add(I18n.format(data.getDataType().toString())); - // --- SHIFT for more info (adds two short lines) --- - if (GuiScreen.isShiftKeyDown()) { - list.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.itemdataunit.shift.1")); - list.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.itemdataunit.shift.2")); - } else if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) { - list.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + - I18n.format("tooltip.advancedrocketry.hold_shift")); - } + // 1) Type: + String typeText = net.minecraft.client.resources.I18n.format(data.getDataType().toString()); + list.add("Type: " + typeText); + + // 2) §fData stored: §6 §f/§6 + list.add(net.minecraft.util.text.TextFormatting.WHITE + "Data stored: " + + net.minecraft.util.text.TextFormatting.GOLD + data.getData() + + net.minecraft.util.text.TextFormatting.WHITE + " / " + + net.minecraft.util.text.TextFormatting.GOLD + data.getMaxData()); + + // 3) Hold Shift for more info + if (net.minecraft.client.gui.GuiScreen.isShiftKeyDown()) { + list.add(net.minecraft.util.text.TextFormatting.GRAY + + net.minecraft.client.resources.I18n.format("tooltip.advancedrocketry.itemdataunit.shift.1")); + list.add(net.minecraft.util.text.TextFormatting.GRAY + + net.minecraft.client.resources.I18n.format("tooltip.advancedrocketry.itemdataunit.shift.2")); + } else if (net.minecraft.client.resources.I18n.hasKey("tooltip.advancedrocketry.hold_shift")) { + list.add(net.minecraft.util.text.TextFormatting.DARK_GRAY.toString() + + net.minecraft.util.text.TextFormatting.ITALIC + + net.minecraft.client.resources.I18n.format("tooltip.advancedrocketry.hold_shift")); + } } + } From c62e305e866f9be4356867a68fcd0b904d3b77e6 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 10 Nov 2025 23:59:34 +0100 Subject: [PATCH 192/274] Implement tooltip for BlockSolarGenerator Added tooltip information for the solar generator block. --- .../block/BlockSolarGenerator.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockSolarGenerator.java b/src/main/java/zmaster587/advancedRocketry/block/BlockSolarGenerator.java index 32e58c13f..23f15865d 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockSolarGenerator.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockSolarGenerator.java @@ -1,7 +1,17 @@ package zmaster587.advancedRocketry.block; +import java.util.List; + +import javax.annotation.Nullable; + import net.minecraft.block.state.IBlockState; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.libVulpes.block.BlockTile; /** @@ -22,4 +32,10 @@ public boolean isBlockNormalCube(IBlockState state) { public boolean isOpaqueCube(IBlockState state) { return true; } + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.solargenerator", insertAt); + } } From ac06d6b4753d5fbd8b9413a9b5bbbe0181d897f6 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Tue, 11 Nov 2025 01:17:21 +0100 Subject: [PATCH 193/274] Add JEI wrapper for Station Assembler --- .../StationAssemblerWrapper.java | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerWrapper.java diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerWrapper.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerWrapper.java new file mode 100644 index 000000000..803ac3d15 --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerWrapper.java @@ -0,0 +1,67 @@ +package zmaster587.advancedRocketry.integration.jei.stationAssembler; + +import mezz.jei.api.ingredients.IIngredients; +import mezz.jei.api.recipe.IRecipeWrapper; +import net.minecraft.item.ItemStack; +import zmaster587.advancedRocketry.api.AdvancedRocketryBlocks; +import zmaster587.advancedRocketry.api.AdvancedRocketryItems; + +/** + * JEI wrapper for the Station Assembler flow shown in TileStationAssembler. + * Inputs (by code): + * - slot 0: AdvancedRocketryBlocks.blockLoader (meta 1) -> Satellite Loading Hatch + * - slot 1: AdvancedRocketryItems.itemSpaceStationChip -> Station Chip (can be blank or programmed) + * Outputs (by code): + * - slot 2: AdvancedRocketryItems.itemSpaceStation -> Packed station (ItemPackedStructure) + * - slot 3: AdvancedRocketryItems.itemSpaceStationChip -> New chip ONLY when making a brand-new station + * + * We present both outputs (JEI is illustrative, not conditional). + */ +public class StationAssemblerWrapper implements IRecipeWrapper { + + private final ItemStack inputHatch; + private final ItemStack inputChip; + private final ItemStack outStation; + private final ItemStack outChipMaybe; + + public StationAssemblerWrapper() { + // Input 0: blockLoader with meta 1 + this.inputHatch = new ItemStack(AdvancedRocketryBlocks.blockLoader, 1, 1); + + // Input 1: station chip item (no NBT required for JEI showcase) + this.inputChip = new ItemStack(AdvancedRocketryItems.itemSpaceStationChip); + + // Output 2: station item + this.outStation = new ItemStack(AdvancedRocketryItems.itemSpaceStation); + + // Output 3: station chip (appears when creating a new station) + this.outChipMaybe = new ItemStack(AdvancedRocketryItems.itemSpaceStationChip); + } + + @Override + public void getIngredients(IIngredients ing) { + // No fluids; only items. + java.util.List> inputs = new java.util.ArrayList<>(2); + inputs.add(java.util.Collections.singletonList(inputHatch)); + inputs.add(java.util.Collections.singletonList(inputChip)); + ing.setInputLists(mezz.jei.api.ingredients.VanillaTypes.ITEM, inputs); + + // Show both outputs to reflect possible results of "Build". + java.util.List outs = new java.util.ArrayList<>(2); + outs.add(outStation); + outs.add(outChipMaybe); + ing.setOutputs(mezz.jei.api.ingredients.VanillaTypes.ITEM, outs); + } + + // Convenience accessors (used by Category layout) + public ItemStack getInputHatch() { return inputHatch; } + public ItemStack getInputChip() { return inputChip; } + public ItemStack getOutStation() { return outStation; } + public ItemStack getOutChipMaybe() { return outChipMaybe; } + + // Optional: a display/catalyst icon you can use if you decide later. + static ItemStack iconStack() { + // Safe: chip exists and isn’t blacklisted in your ARPlugin snippet. + return new ItemStack(AdvancedRocketryItems.itemSpaceStationChip); + } +} From 636f6ef8015512d2c239cc159c4b2f6053ec1097 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Tue, 11 Nov 2025 01:18:01 +0100 Subject: [PATCH 194/274] Add StationAssemblerRecipeMaker for JEI integration --- .../StationAssemblerRecipeMaker.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerRecipeMaker.java diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerRecipeMaker.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerRecipeMaker.java new file mode 100644 index 000000000..2209d379c --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerRecipeMaker.java @@ -0,0 +1,17 @@ +package zmaster587.advancedRocketry.integration.jei.stationAssembler; + +import mezz.jei.api.IJeiHelpers; +import java.util.Collections; +import java.util.List; + +/** Single illustrative entry: the Station Assembler has no craft-list; it’s a process gate. */ +public class StationAssemblerRecipeMaker { + public static List getRecipes(IJeiHelpers helpers) { + return java.util.Collections.singletonList(new StationAssemblerWrapper()); + } + + // Keep this to match existing pattern in your makers + public static List getMachineRecipes(IJeiHelpers helpers, Class ignored) { + return getRecipes(helpers); + } +} From 0f1adf6814129a55bd9f56bd9ced110fcc0f35b0 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Tue, 11 Nov 2025 01:18:44 +0100 Subject: [PATCH 195/274] Implement StationAssemblerRecipeHandler class --- .../StationAssemblerRecipeHandler.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerRecipeHandler.java diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerRecipeHandler.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerRecipeHandler.java new file mode 100644 index 000000000..8ff1af524 --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerRecipeHandler.java @@ -0,0 +1,12 @@ +package zmaster587.advancedRocketry.integration.jei.stationAssembler; + +import mezz.jei.api.recipe.IRecipeHandler; +import mezz.jei.api.recipe.IRecipeWrapper; +import zmaster587.advancedRocketry.integration.jei.ARPlugin; + +public class StationAssemblerRecipeHandler implements IRecipeHandler { + @Override public Class getRecipeClass() { return StationAssemblerWrapper.class; } + @Override public String getRecipeCategoryUid(StationAssemblerWrapper r) { return ARPlugin.stationAssemblerUUID; } + @Override public IRecipeWrapper getRecipeWrapper(StationAssemblerWrapper r) { return r; } + @Override public boolean isRecipeValid(StationAssemblerWrapper r) { return r != null; } +} From ec20523eeaa6293d686f5c7f1fd718a326be55f5 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Tue, 11 Nov 2025 01:23:34 +0100 Subject: [PATCH 196/274] Implement tooltip for BlockForceFieldProjector Added tooltip information for BlockForceFieldProjector. --- .../block/BlockForceFieldProjector.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockForceFieldProjector.java b/src/main/java/zmaster587/advancedRocketry/block/BlockForceFieldProjector.java index 59958642e..513c5e741 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockForceFieldProjector.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockForceFieldProjector.java @@ -1,10 +1,19 @@ package zmaster587.advancedRocketry.block; +import java.util.List; + +import javax.annotation.Nullable; + import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.advancedRocketry.tile.TileForceFieldProjector; import zmaster587.libVulpes.block.BlockFullyRotatable; @@ -33,5 +42,11 @@ public void breakBlock(World worldIn, BlockPos pos, IBlockState state) { public TileEntity createTileEntity(World world, IBlockState state) { return new TileForceFieldProjector(); } + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.forcefieldprojector", insertAt); + } } From 6f3ede6e59edd3dce4c99b2abcd7558eff82fded Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 12 Nov 2025 10:12:33 +0100 Subject: [PATCH 197/274] Fix typo in tooltip for BlockTransciever --- .../zmaster587/advancedRocketry/block/BlockTransciever.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java b/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java index 9dd359601..a7a966723 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java @@ -151,7 +151,7 @@ public boolean rotateBlock(World world, BlockPos pos, EnumFacing axis) { @Override public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); - TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.transciever", insertAt); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.transceiver", insertAt); } public static EnumFacing getFront(IBlockState state) { From 03c8f76225afc003866326ce9c2f429014f3bb29 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 12 Nov 2025 10:53:49 +0100 Subject: [PATCH 198/274] Remove second SHIFT tooltip line from fluid tank Removed the second tooltip line when SHIFT is pressed. --- .../zmaster587/advancedRocketry/item/ItemBlockFluidTank.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java b/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java index 40600e989..4b19ff280 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java @@ -67,7 +67,6 @@ public void addInformation(@Nonnull ItemStack stack, @Nullable World world, List // --- SHIFT for more info (adds two short lines) --- if (GuiScreen.isShiftKeyDown()) { list.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.fluidtank.shift.1")); - list.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.fluidtank.shift.2")); } else if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) { list.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_shift")); From c94bf939b5f52799d8e72d34f563644e9bf5d365 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 12 Nov 2025 12:40:29 +0100 Subject: [PATCH 199/274] Add BlockPump class for fluid handling --- .../advancedRocketry/block/BlockPump.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/block/BlockPump.java diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockPump.java b/src/main/java/zmaster587/advancedRocketry/block/BlockPump.java new file mode 100644 index 000000000..94a888dc9 --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockPump.java @@ -0,0 +1,28 @@ +package zmaster587.advancedRocketry.block; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.fluids.FluidUtil; +import zmaster587.libVulpes.block.BlockTile; + +public class BlockPump extends BlockTile { + + public BlockPump(Class tileClass, int guiId) { + super(tileClass, guiId); + } + + @Override + public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, + EntityPlayer player, EnumHand hand, + EnumFacing side, float hitX, float hitY, float hitZ) { + // Try container <-> TE interaction first (handles buckets both directions). + if (FluidUtil.interactWithFluidHandler(player, hand, world, pos, side)) { + return true; + } + return super.onBlockActivated(world, pos, state, player, hand, side, hitX, hitY, hitZ); + } +} From c0244ebc027d980789f58d61e3e13af44731e67d Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 12 Nov 2025 13:09:16 +0100 Subject: [PATCH 200/274] Remove redundant tooltip line from pressure tank Removed a tooltip line for the pressure tank item. --- .../advancedRocketry/item/components/ItemPressureTank.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/components/ItemPressureTank.java b/src/main/java/zmaster587/advancedRocketry/item/components/ItemPressureTank.java index 96d87b60f..39007f1b0 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/components/ItemPressureTank.java +++ b/src/main/java/zmaster587/advancedRocketry/item/components/ItemPressureTank.java @@ -56,13 +56,13 @@ public void addInformation(@Nonnull ItemStack stack, @Nullable World world, final int amount = (fs != null) ? fs.amount : 0; // Match main tank style + list.add(TextFormatting.DARK_PURPLE + "Space Suit Component"); list.add("Fluid: " + fluidName); list.add("Level: " + amount + "/" + capMb + " mB"); // SHIFT block if (GuiScreen.isShiftKeyDown()) { list.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.pressuretank.shift.1")); - list.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.pressuretank.shift.2")); } else if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) { list.add(TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + I18n.format("tooltip.advancedrocketry.hold_shift")); From 907a63cde58875f27dda681d8d82de02c2c2ae99 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 12 Nov 2025 13:20:41 +0100 Subject: [PATCH 201/274] Update ItemData.java --- src/main/java/zmaster587/advancedRocketry/item/ItemData.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemData.java b/src/main/java/zmaster587/advancedRocketry/item/ItemData.java index 6c9408082..ccd62a615 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemData.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemData.java @@ -99,8 +99,9 @@ public void addInformation(@Nonnull ItemStack stack, @Nullable World world, List DataStorage data = getDataStorage(stack); // 1) Type: + list.add(TextFormatting.DARK_PURPLE + "Space Suit Component"); String typeText = net.minecraft.client.resources.I18n.format(data.getDataType().toString()); - list.add("Type: " + typeText); + list.add(net.minecraft.util.text.TextFormatting.WHITE + "Type: " + typeText); // 2) §fData stored: §6 §f/§6 list.add(net.minecraft.util.text.TextFormatting.WHITE + "Data stored: " @@ -112,8 +113,6 @@ public void addInformation(@Nonnull ItemStack stack, @Nullable World world, List if (net.minecraft.client.gui.GuiScreen.isShiftKeyDown()) { list.add(net.minecraft.util.text.TextFormatting.GRAY + net.minecraft.client.resources.I18n.format("tooltip.advancedrocketry.itemdataunit.shift.1")); - list.add(net.minecraft.util.text.TextFormatting.GRAY + - net.minecraft.client.resources.I18n.format("tooltip.advancedrocketry.itemdataunit.shift.2")); } else if (net.minecraft.client.resources.I18n.hasKey("tooltip.advancedrocketry.hold_shift")) { list.add(net.minecraft.util.text.TextFormatting.DARK_GRAY.toString() + net.minecraft.util.text.TextFormatting.ITALIC + From 1f0c7cbcf450565714708671b0c33993f47408b1 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 12 Nov 2025 13:41:32 +0100 Subject: [PATCH 202/274] Enhance fluid handling in TilePump class Refactor TilePump class to improve fluid handling and add new utility methods for fluid checks. --- .../advancedRocketry/tile/TilePump.java | 273 ++++++++++++++---- 1 file changed, 214 insertions(+), 59 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/TilePump.java b/src/main/java/zmaster587/advancedRocketry/tile/TilePump.java index 59c57298f..3d487d76c 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/TilePump.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/TilePump.java @@ -1,8 +1,11 @@ package zmaster587.advancedRocketry.tile; import net.minecraft.block.Block; +import net.minecraft.block.BlockLiquid; import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; @@ -11,6 +14,7 @@ import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTank; +import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.IFluidBlock; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler; @@ -22,6 +26,9 @@ import zmaster587.libVulpes.network.PacketHandler; import zmaster587.libVulpes.tile.TileEntityRFConsumer; + + + import java.util.*; public class TilePump extends TileEntityRFConsumer implements IFluidHandler, IModularInventory { @@ -29,6 +36,7 @@ public class TilePump extends TileEntityRFConsumer implements IFluidHandler, IMo private final int RANGE = 64; private FluidTank tank; private List cache; + private Fluid lastFluidType = null; public TilePump() { super(1000); @@ -36,6 +44,15 @@ public TilePump() { cache = new LinkedList<>(); } + private static final int PUMP_INTERVAL_TICKS = 25; // ~1 Hz + private static final int EJECT_INTERVAL_TICKS = 20; // 1 Hz + private final IFluidHandler fluidCap = new FluidCapability(this); + + private boolean shouldRunThisTick(int interval) { + // world time is long; 0 mod interval fires once per interval + return interval <= 1 || (world.getWorldTime() % interval) == 0; + } + public int getPowerPerOperation() { return 100; } @@ -50,132 +67,242 @@ public boolean hasCapability(Capability capability, EnumFacing facing) { @Override public T getCapability(Capability capability, EnumFacing facing) { if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { - return (T) new FluidCapability(this); + return CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY.cast(fluidCap); } return super.getCapability(capability, facing); } @Override public void update() { + if (world.isRemote) return; + + // Drop stale plan if accepted fluid changed + Fluid cur = tank.getFluid() == null ? null : tank.getFluid().getFluid(); + if (cur != lastFluidType) { + if (!cache.isEmpty()) cache.clear(); + lastFluidType = cur; + } + + if (isRedstoneDisabled()) { + // optional: cache.clear(); + return; + } + super.update(); - //Attempt fluid Eject - if (!world.isRemote && tank.getFluid() != null) { - for (EnumFacing direction : EnumFacing.values()) { - BlockPos newBlock = getPos().offset(direction); - TileEntity tile = world.getTileEntity(newBlock); - if (tile != null && tile.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, direction.getOpposite())) { - IFluidHandler cap = tile.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, direction.getOpposite()); - FluidStack stack = tank.getFluid().copy(); - stack.amount = Math.min(tank.getFluid().amount, 1000); - //Perform the drain - cap.fill(tank.drain(cap.fill(stack, false), true), true); - - //Abort if we run out of fluid - if (tank.getFluid() == null) - break; + // Attempt fluid Eject (throttled; see section 3) + if (shouldRunThisTick(EJECT_INTERVAL_TICKS) && tank.getFluid() != null) { + final FluidStack src = tank.getFluid(); + final int toOffer = Math.min(src.amount, 1000); + if (toOffer > 0) { + for (EnumFacing dir : EnumFacing.values()) { + TileEntity te = world.getTileEntity(pos.offset(dir)); + if (te == null || !te.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, dir.getOpposite())) + continue; + + IFluidHandler out = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, dir.getOpposite()); + if (out == null) continue; + + int simAccepted = out.fill(new FluidStack(src, toOffer), false); + if (simAccepted > 0) { + FluidStack drained = tank.drain(simAccepted, true); + if (drained != null && drained.amount > 0) { + out.fill(drained, true); + if (tank.getFluid() == null) break; // ran out + } + } } } } } - private int getFrequencyFromPower() { - float ratio = energy.getUniversalEnergyStored() / (float) energy.getMaxEnergyStored(); - if (ratio > 0.5) - return 1; - return 10; + private boolean isVanillaLiquid(BlockPos pos) { + IBlockState state = world.getBlockState(pos); + Material mat = state.getMaterial(); + return mat == Material.WATER || mat == Material.LAVA; + } + + private boolean isVanillaSource(BlockPos pos) { + IBlockState state = world.getBlockState(pos); + Block block = state.getBlock(); + if (block instanceof BlockLiquid) { + // 0 == source, 1..7 flowing (or up to 15, depending) + Integer lvl = state.getValue(BlockLiquid.LEVEL); + return lvl != null && lvl == 0; + } + return false; + } + + private Fluid getVanillaFluid(BlockPos pos) { + Material mat = world.getBlockState(pos).getMaterial(); + if (mat == Material.WATER) return FluidRegistry.WATER; + if (mat == Material.LAVA) return FluidRegistry.LAVA; + return null; } + + @Override public void performFunction() { - if (!world.isRemote) { - //Do we have room? if (tank.getCapacity() - 1000 < tank.getFluidAmount()) return; BlockPos nextPos = getNextBlockLocation(); - if (nextPos != null) { - if (canFitFluid(nextPos)) { - Block worldBlock = world.getBlockState(nextPos).getBlock(); - Material mat = world.getBlockState(nextPos).getMaterial(); - if (worldBlock instanceof IFluidBlock) { - FluidStack fStack = ((IFluidBlock) worldBlock).drain(world, nextPos, true); - - if (fStack != null) - tank.fill(fStack, true); - int colour = ((IFluidBlock) worldBlock).getFluid().getColor(); - if (mat == Material.LAVA) - colour = 0xFFbd3718; - - PacketHandler.sendToNearby(new PacketFluidParticle(nextPos, this.pos, 200, colour), world.provider.getDimension(), this.pos, 128); + if (nextPos != null && canFitFluid(nextPos)) { + IBlockState state = world.getBlockState(nextPos); + Block worldBlock = state.getBlock(); + Material mat = state.getMaterial(); + + if (worldBlock instanceof IFluidBlock) { + FluidStack fStack = ((IFluidBlock) worldBlock).drain(world, nextPos, true); + if (fStack != null) tank.fill(fStack, true); + + int colour = ((IFluidBlock) worldBlock).getFluid().getColor(); + if (mat == Material.LAVA) colour = 0xFFbd3718; + PacketHandler.sendToNearby(new PacketFluidParticle(nextPos, this.pos, 200, colour), world.provider.getDimension(), this.pos, 128); + } else if (isVanillaLiquid(nextPos) && isVanillaSource(nextPos)) { + Fluid f = getVanillaFluid(nextPos); + if (f != null) { + FluidStack stack = new FluidStack(f, 1000); + int filled = tank.fill(stack, true); + if (filled == 1000) { + world.setBlockToAir(nextPos); // remove the source + int colour = (mat == Material.LAVA) ? 0xFFbd3718 : 0xFF3F76E4; // MC-ish tint + PacketHandler.sendToNearby(new PacketFluidParticle(nextPos, this.pos, 200, colour), world.provider.getDimension(), this.pos, 128); + } } } } } } + private boolean canFitFluid(BlockPos pos) { Block worldBlock = world.getBlockState(pos).getBlock(); if (worldBlock instanceof IFluidBlock) { - // Can we put it into the tank? return tank.getFluid() == null || tank.getFluid().getFluid() == ((IFluidBlock) worldBlock).getFluid(); } + if (isVanillaLiquid(pos)) { + Fluid f = getVanillaFluid(pos); + return f != null && (tank.getFluid() == null || tank.getFluid().getFluid() == f); + } return false; } - private BlockPos getNextBlockLocation() { + private BlockPos getNextBlockLocation() { if (!cache.isEmpty()) return cache.remove(0); BlockPos currentPos = new MutableBlockPos(getPos().down()); - while (world.isAirBlock(currentPos)) currentPos = currentPos.down(); - // We found a fluid Block worldBlock = world.getBlockState(currentPos).getBlock(); - if (canFitFluid(currentPos)) - findFluidAtOrAbove(currentPos, ((IFluidBlock) worldBlock).getFluid()); + if (canFitFluid(currentPos)) { + Fluid target = null; + if (worldBlock instanceof IFluidBlock) { + target = ((IFluidBlock) worldBlock).getFluid(); + } else if (isVanillaLiquid(currentPos)) { + target = getVanillaFluid(currentPos); + } + findFluidAtOrAbove(currentPos, target); + } if (!cache.isEmpty()) return cache.remove(0); return null; } - private void findFluidAtOrAbove(BlockPos pos, Fluid fluid) { + + private void findFluidAtOrAbove(BlockPos pos, Fluid targetFluid) { Queue queue = new LinkedList<>(); Set visited = new HashSet<>(); queue.add(pos); while (!queue.isEmpty()) { - BlockPos nextElement = queue.poll(); - if (visited.contains(nextElement) || nextElement.getDistance(pos.getX(), nextElement.getY(), pos.getZ()) > RANGE) + BlockPos next = queue.poll(); + if (visited.contains(next) || next.getDistance(pos.getX(), pos.getY(), pos.getZ()) > RANGE) continue; - Block worldBlock = world.getBlockState(nextElement).getBlock(); - if (worldBlock instanceof IFluidBlock) { - if (fluid == null || ((IFluidBlock) worldBlock).getFluid() == fluid) { - //only add drainable fluids, allow chaining along flowing fluid tho - if (((IFluidBlock) worldBlock).canDrain(world, nextElement)) - cache.add(0, nextElement); - visited.add(nextElement); - queue.add(nextElement.west()); - queue.add(nextElement.east()); - queue.add(nextElement.north()); - queue.add(nextElement.south()); - queue.add(nextElement.up()); + IBlockState state = world.getBlockState(next); + Block block = state.getBlock(); + + // Case 1: IFluidBlock (existing behavior) + if (block instanceof IFluidBlock) { + IFluidBlock fb = (IFluidBlock) block; + Fluid f = fb.getFluid(); + if (targetFluid == null || f == targetFluid) { + if (fb.canDrain(world, next)) { + cache.add(0, next); // drainable + } + visited.add(next); + queue.add(next.west()); + queue.add(next.east()); + queue.add(next.north()); + queue.add(next.south()); + queue.add(next.up()); + } + continue; + } + + // Case 2: Vanilla BlockLiquid + if (isVanillaLiquid(next)) { + Fluid f = getVanillaFluid(next); + if (f != null && (targetFluid == null || f == targetFluid)) { + // Only sources are drainable; but we still traverse through flowing + if (isVanillaSource(next)) { + cache.add(0, next); + } + visited.add(next); + queue.add(next.west()); + queue.add(next.east()); + queue.add(next.north()); + queue.add(next.south()); + queue.add(next.up()); } } } } + private boolean isRedstoneDisabled() { + return world.isBlockPowered(pos); + } + @Override public boolean canPerformFunction() { - return tank.getFluidAmount() <= tank.getCapacity() && world.getWorldTime() % getFrequencyFromPower() == 0; + if (isRedstoneDisabled()) return false; + if (!shouldRunThisTick(PUMP_INTERVAL_TICKS)) return false; + + // must have at least 100 RF for one bucket operation + if (energy.getUniversalEnergyStored() < getPowerPerOperation()) return false; + + // must be able to accept a full bucket + if ((tank.getCapacity() - tank.getFluidAmount()) < 1000) return false; + + // must have a drainable source available; if not, try to populate cache now (cheap probe) + if (cache.isEmpty()) { + // very small, one-shot version of your getNextBlockLocation() to populate cache + BlockPos currentPos = new MutableBlockPos(getPos().down()); + while (world.isAirBlock(currentPos)) + currentPos = ((MutableBlockPos) currentPos).down(); + + if (canFitFluid(currentPos)) { + Fluid target = null; + Block worldBlock = world.getBlockState(currentPos).getBlock(); + if (worldBlock instanceof IFluidBlock) { + target = ((IFluidBlock) worldBlock).getFluid(); + } else if (isVanillaLiquid(currentPos)) { + target = getVanillaFluid(currentPos); + } + findFluidAtOrAbove(currentPos, target); + } + } + return !cache.isEmpty(); // only authorize (and thus spend 100 RF) if we have a source to drain } + @Override public IFluidTankProperties[] getTankProperties() { return tank.getTankProperties(); @@ -207,6 +334,34 @@ public String getModularInventoryName() { return "tile.pump.name"; } + @Override + public void onLoad() { + super.onLoad(); + lastFluidType = tank.getFluid() == null ? null : tank.getFluid().getFluid(); + } + + @Override + public void onChunkUnload() { + super.onChunkUnload(); + if (!cache.isEmpty()) cache.clear(); + } + + @Override + public void invalidate() { + super.invalidate(); + if (!cache.isEmpty()) cache.clear(); + } + + @Override public NBTTagCompound writeToNBT(NBTTagCompound nbt) { + super.writeToNBT(nbt); + nbt.setTag("tank", tank.writeToNBT(new NBTTagCompound())); + return nbt; + } + @Override public void readFromNBT(NBTTagCompound nbt) { + super.readFromNBT(nbt); + tank.readFromNBT(nbt.getCompoundTag("tank")); + } + @Override public boolean canInteractWithContainer(EntityPlayer entity) { return false; From d90dce2fab01f182383208f4ce2a80cc5056c532 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 12 Nov 2025 13:44:02 +0100 Subject: [PATCH 203/274] Replace BlockTile with BlockPump for pump block --- src/main/java/zmaster587/advancedRocketry/AdvancedRocketry.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/AdvancedRocketry.java b/src/main/java/zmaster587/advancedRocketry/AdvancedRocketry.java index 77d37f955..ffb6b7127 100644 --- a/src/main/java/zmaster587/advancedRocketry/AdvancedRocketry.java +++ b/src/main/java/zmaster587/advancedRocketry/AdvancedRocketry.java @@ -628,7 +628,7 @@ public void registerBlocks(RegistryEvent.Register evt) { AdvancedRocketryBlocks.blockForceFieldProjector = new BlockForceFieldProjector(Material.IRON).setUnlocalizedName("forceFieldProjector").setCreativeTab(tabAdvRocketry).setHardness(3f); AdvancedRocketryBlocks.blockForceField = new BlockForceField(Material.BARRIER).setBlockUnbreakable().setResistance(6000000.0F).setUnlocalizedName("forceField"); AdvancedRocketryBlocks.blockVacuumLaser = new BlockFullyRotatable(Material.IRON).setUnlocalizedName("vacuumLaser").setCreativeTab(tabAdvRocketry).setHardness(4f); - AdvancedRocketryBlocks.blockPump = new BlockTile(TilePump.class, GuiHandler.guiId.MODULAR.ordinal()).setUnlocalizedName("pump").setCreativeTab(tabAdvRocketry).setHardness(3f); + AdvancedRocketryBlocks.blockPump = new BlockPump(TilePump.class, GuiHandler.guiId.MODULAR.ordinal()).setUnlocalizedName("pump").setCreativeTab(tabAdvRocketry).setHardness(3f); AdvancedRocketryBlocks.blockSuitWorkStation = new BlockSuitWorkstation(TileSuitWorkStation.class, GuiHandler.guiId.MODULAR.ordinal()).setUnlocalizedName("suitWorkStation").setCreativeTab(tabAdvRocketry).setHardness(3f); AdvancedRocketryBlocks.blockPressureTank = new BlockPressurizedFluidTank(Material.IRON).setUnlocalizedName("pressurizedTank").setCreativeTab(tabAdvRocketry).setHardness(3f); AdvancedRocketryBlocks.blockSolarGenerator = new BlockSolarGenerator(TileSolarPanel.class, GuiHandler.guiId.MODULAR.ordinal()).setCreativeTab(tabAdvRocketry).setHardness(3f).setUnlocalizedName("solarGenerator"); From 3f2d61546db6aac58d87f54bef200582ffa542d6 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 12 Nov 2025 13:49:53 +0100 Subject: [PATCH 204/274] Refactor TileMicrowaveReciever for robustness and clarity --- .../energy/TileMicrowaveReciever.java | 133 +++++++++++++----- 1 file changed, 96 insertions(+), 37 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/multiblock/energy/TileMicrowaveReciever.java b/src/main/java/zmaster587/advancedRocketry/tile/multiblock/energy/TileMicrowaveReciever.java index 9d33963a5..6957636ea 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/multiblock/energy/TileMicrowaveReciever.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/multiblock/energy/TileMicrowaveReciever.java @@ -2,6 +2,7 @@ import io.netty.buffer.ByteBuf; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; @@ -14,15 +15,18 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.advancedRocketry.api.ARConfiguration; import zmaster587.advancedRocketry.api.AdvancedRocketryBlocks; import zmaster587.advancedRocketry.api.SatelliteRegistry; import zmaster587.advancedRocketry.api.satellite.SatelliteBase; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.advancedRocketry.dimension.DimensionManager; import zmaster587.advancedRocketry.dimension.DimensionProperties; import zmaster587.advancedRocketry.item.ItemSatelliteIdentificationChip; import zmaster587.advancedRocketry.stations.SpaceObjectManager; import zmaster587.advancedRocketry.stations.SpaceStationObject; +import zmaster587.advancedRocketry.util.PlanetaryTravelHelper; import zmaster587.libVulpes.LibVulpes; import zmaster587.libVulpes.api.IUniversalEnergyTransmitter; import zmaster587.libVulpes.block.BlockMeta; @@ -34,9 +38,12 @@ import zmaster587.libVulpes.tile.multiblock.TileMultiPowerProducer; import zmaster587.libVulpes.util.Vector3F; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; +import javax.annotation.Nullable; + public class TileMicrowaveReciever extends TileMultiPowerProducer implements ITickable { static final BlockMeta iron_block = new BlockMeta(AdvancedRocketryBlocks.blockSolarPanel); @@ -113,18 +120,17 @@ public void onInventoryUpdated() { List list = new LinkedList<>(); - for (IInventory inv : itemInPorts) { - for (int i = 0; i < inv.getSizeInventory(); i++) { - ItemStack stack = inv.getStackInSlot(i); - if (!stack.isEmpty() && stack.getItem() instanceof ItemSatelliteIdentificationChip) { - list.add(SatelliteRegistry.getSatelliteId(stack)); + if (itemInPorts != null) { // <--- guard + for (IInventory inv : itemInPorts) { + for (int i = 0; i < inv.getSizeInventory(); i++) { + ItemStack stack = inv.getStackInSlot(i); + if (!stack.isEmpty() && stack.getItem() instanceof ItemSatelliteIdentificationChip) { + list.add(SatelliteRegistry.getSatelliteId(stack)); + } } } } - - - connectedSatellites = list; - + connectedSatellites = new LinkedList<>(new LinkedHashSet<>(list)); } @Override @@ -137,13 +143,40 @@ public void update() { } //Checks whenever a station changes dimensions or when the multiblock is intialized - ie any time the multipler could concieveably change - if (insolationPowerMultiplier == 0 || ((world.provider.getDimension() == ARConfiguration.getCurrentConfig().spaceDimId) && (powerSourceDimensionID != SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(this.pos).getOrbitingPlanetId()))) { - DimensionProperties properties = DimensionManager.getInstance().getDimensionProperties(world.provider.getDimension()); - insolationPowerMultiplier = (world.provider.getDimension() == ARConfiguration.getCurrentConfig().spaceDimId) ? SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(this.pos).getInsolationMultiplier() : properties.getPeakInsolationMultiplierWithoutAtmosphere(); - //Sets the ID of the place it's sourcing power from so it does not have to recheck - if (world.provider.getDimension() == ARConfiguration.getCurrentConfig().spaceDimId) - powerSourceDimensionID = SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(this.pos).getOrbitingPlanetId(); + // --- BEGIN robust insolation block (mirror SatelliteTerminal style) --- + final int curDim = world.provider.getDimension(); + final int spaceDim = ARConfiguration.getCurrentConfig().spaceDimId; + + // Cache station once; can be null + final zmaster587.advancedRocketry.stations.SpaceStationObject station = + (curDim == spaceDim) + ? (zmaster587.advancedRocketry.stations.SpaceStationObject) + zmaster587.advancedRocketry.stations.SpaceObjectManager.getSpaceManager() + .getSpaceStationFromBlockCoords(this.pos) + : null; + + // Recompute when uninitialized OR (in space AND orbiting planet changed and station exists) + final boolean needRecompute = + (insolationPowerMultiplier == 0) + || (curDim == spaceDim && station != null && powerSourceDimensionID != station.getOrbitingPlanetId()); + + if (needRecompute) { + if (curDim == spaceDim && station != null) { + insolationPowerMultiplier = station.getInsolationMultiplier(); + powerSourceDimensionID = station.getOrbitingPlanetId(); + } else { + final zmaster587.advancedRocketry.dimension.DimensionProperties props = + zmaster587.advancedRocketry.dimension.DimensionManager.getInstance() + .getDimensionProperties(curDim); + insolationPowerMultiplier = (props != null) + ? props.getPeakInsolationMultiplierWithoutAtmosphere() + : 1.0; // safe fallback + powerSourceDimensionID = curDim; + } } + // If we're in space but station==null (early ticks), keep previous multiplier and carry on. + // --- END robust insolation block --- + if (!isComplete()) return; @@ -174,37 +207,66 @@ public void update() { } } - DimensionProperties properties; - int dimId = world.provider.getDimension(); - SpaceStationObject spaceStation = (SpaceStationObject) SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(this.pos); - if (!world.isRemote && (DimensionManager.getInstance().isDimensionCreated(dimId) || world.provider.getDimension() == 0)) { - //This way we check to see if it's on a station, and if so, if it has any satellites in orbit around the planet the station is around to pull from - properties = (spaceStation != null) ? spaceStation.getOrbitingPlanet() : DimensionManager.getInstance().getDimensionProperties(dimId); + // --- BEGIN robust energy gather (mirrors SatelliteTerminal) --- + final int dimId = world.provider.getDimension(); + final boolean dimOk = DimensionManager.getInstance().isDimensionCreated(dimId) || dimId == 0; + + if (!world.isRemote && dimOk) { + // If we’re on a station, prefer its orbiting planet; otherwise use the local dim props + final SpaceStationObject stationHere = (dimId == ARConfiguration.getCurrentConfig().spaceDimId) + ? (SpaceStationObject) SpaceObjectManager.getSpaceManager().getSpaceStationFromBlockCoords(this.pos) + : null; + + final DimensionProperties props = (stationHere != null) + ? stationHere.getOrbitingPlanet() + : DimensionManager.getInstance().getDimensionProperties(dimId); + int energyReceived = 0; - if (enabled) { - for (long lng : connectedSatellites) { - SatelliteBase satellite = properties.getSatellite(lng); - if (satellite instanceof IUniversalEnergyTransmitter) { - energyReceived += ((IUniversalEnergyTransmitter) satellite).transmitEnergy(EnumFacing.UP, false); + if (enabled && props != null && connectedSatellites != null && !connectedSatellites.isEmpty()) { + // Snapshot to avoid concurrent modification + final LinkedHashSet sats = new LinkedHashSet<>(connectedSatellites); + + // Resolve “here” dim exactly like SatelliteTerminal + final int hereDim = DimensionManager.getEffectiveDimId(world, pos).getId(); + + for (long lng : sats) { + final SatelliteBase sat = props.getSatellite(lng); + if (sat == null) continue; + + // Range/link check (same logic as Terminal) + final int satDim = sat.getDimensionId(); + final boolean inRange = PlanetaryTravelHelper.isTravelAnywhereInPlanetarySystem(satDim, hereDim); + if (!inRange) continue; + + if (sat instanceof IUniversalEnergyTransmitter) { + energyReceived += ((IUniversalEnergyTransmitter) sat).transmitEnergy(EnumFacing.UP, false); } } - //Multiplied by two for 520W = 1 RF/t becoming 2 RF/t @ 100% efficiency, and by insolation mult for solar stuff - energyReceived *= 2 * insolationPowerMultiplier; + // 520W = 1 RF/t -> 2 RF/t @ 100%; scale by insolation + energyReceived = (int) Math.round(energyReceived * (2 * insolationPowerMultiplier)); } + powerMadeLastTick = energyReceived; if (powerMadeLastTick != prevPowerMadeLastTick) { prevPowerMadeLastTick = powerMadeLastTick; - PacketHandler.sendToNearby(new PacketMachine(this, (byte) 1), world.provider.getDimension(), pos, 128); - + PacketHandler.sendToNearby(new PacketMachine(this, (byte) 1), + world.provider.getDimension(), pos, 128); } producePower(powerMadeLastTick); } - if (world.isRemote) - textModule.setText(LibVulpes.proxy.getLocalizedString("msg.microwaverec.generating") + " " + powerMadeLastTick + " " + LibVulpes.proxy.getLocalizedString("msg.powerunit.rfpertick")); - } + + if (world.isRemote) { + textModule.setText( + LibVulpes.proxy.getLocalizedString("msg.microwaverec.generating") + " " + + powerMadeLastTick + " " + + LibVulpes.proxy.getLocalizedString("msg.powerunit.rfpertick")); + } + // --- END robust energy gather --- + } + @Override public SPacketUpdateTileEntity getUpdatePacket() { @@ -287,13 +349,10 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); - int[] intArray = nbt.getIntArray("satilliteList"); connectedSatellites.clear(); - for (int i = 0; i < intArray.length / 2; i += 2) { + for (int i = 0; i < intArray.length; i += 2) { connectedSatellites.add(intArray[i] | (((long) intArray[i + 1]) << 32)); } - } - } From 4620cde4f49d993b7ba2e8685699973ba7edce9a Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 12 Nov 2025 14:09:44 +0100 Subject: [PATCH 205/274] Implement tooltip for ItemPackedStructure Add tooltip information for ItemPackedStructure. --- .../item/ItemPackedStructure.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemPackedStructure.java b/src/main/java/zmaster587/advancedRocketry/item/ItemPackedStructure.java index 70e68cae1..3bb596dac 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemPackedStructure.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemPackedStructure.java @@ -1,11 +1,19 @@ package zmaster587.advancedRocketry.item; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import zmaster587.advancedRocketry.client.TooltipInjector; import zmaster587.advancedRocketry.util.StorageChunk; +import java.util.List; + import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class ItemPackedStructure extends Item { @@ -38,4 +46,11 @@ public StorageChunk getStructure(@Nonnull ItemStack stack) { } return null; } + + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.packedstructure", insertAt); + } } From a3aa73e417fd61f70d4e27869d7a168ffd675bac Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 12 Nov 2025 14:53:14 +0100 Subject: [PATCH 206/274] Implement hatch inventory snapshot and restore Added functionality to snapshot and restore hatch inventories during multiblock structure formation and deconstruction. --- .../energy/TileMicrowaveReciever.java | 361 +++++++++++++++++- 1 file changed, 352 insertions(+), 9 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/multiblock/energy/TileMicrowaveReciever.java b/src/main/java/zmaster587/advancedRocketry/tile/multiblock/energy/TileMicrowaveReciever.java index 6957636ea..9ead1c15a 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/multiblock/energy/TileMicrowaveReciever.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/multiblock/energy/TileMicrowaveReciever.java @@ -4,12 +4,15 @@ import net.minecraft.block.state.IBlockState; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.Entity; +import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; import net.minecraft.network.NetworkManager; import net.minecraft.network.play.server.SPacketUpdateTileEntity; +import net.minecraft.tileentity.TileEntity; import net.minecraft.util.*; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; @@ -34,18 +37,25 @@ import zmaster587.libVulpes.inventory.modules.ModuleText; import zmaster587.libVulpes.network.PacketHandler; import zmaster587.libVulpes.network.PacketMachine; +import zmaster587.libVulpes.tile.multiblock.TilePlaceholder; +import zmaster587.libVulpes.tile.multiblock.hatch.TileInventoryHatch; import zmaster587.libVulpes.tile.multiblock.TileMultiBlock; import zmaster587.libVulpes.tile.multiblock.TileMultiPowerProducer; import zmaster587.libVulpes.util.Vector3F; +import javax.annotation.Nullable; +import java.util.HashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; +import java.util.Map; -import javax.annotation.Nullable; public class TileMicrowaveReciever extends TileMultiPowerProducer implements ITickable { + // key: BlockPos.toLong(), value: saved non-empty stacks for that hatch (slot order preserved) + private final Map> savedHatchInv = new HashMap<>(); + static final BlockMeta iron_block = new BlockMeta(AdvancedRocketryBlocks.blockSolarPanel); static final Object[][][] structure = new Object[][][]{ { @@ -120,7 +130,7 @@ public void onInventoryUpdated() { List list = new LinkedList<>(); - if (itemInPorts != null) { // <--- guard + if (itemInPorts != null) { for (IInventory inv : itemInPorts) { for (int i = 0; i < inv.getSizeInventory(); i++) { ItemStack stack = inv.getStackInSlot(i); @@ -133,6 +143,41 @@ public void onInventoryUpdated() { connectedSatellites = new LinkedList<>(new LinkedHashSet<>(list)); } + @Override + public boolean attemptCompleteStructure(IBlockState state) { + if (!world.isRemote) { + // Snapshot BEFORE formation (real hatches) + snapshotHatchInventories(); + } + boolean ok = super.attemptCompleteStructure(state); + + if (!world.isRemote) { + if (ok) { + // Formation succeeded → push snapshot into placeholders (alive state) + writeSnapshotIntoPlaceholders(); + } else { + // Formation failed → discard + savedHatchInv.clear(); + } + } + return ok; + } + + + @Override + public void deconstructMultiBlock(World worldIn, BlockPos destroyedPos, boolean blockBroken, IBlockState state) { + if (!worldIn.isRemote) { + snapshotFromPlaceholders(); + } + + super.deconstructMultiBlock(worldIn, destroyedPos, blockBroken, state); + + if (!worldIn.isRemote) { + restoreHatchInventories(); + } + } + + @Override public void update() { @@ -143,7 +188,7 @@ public void update() { } //Checks whenever a station changes dimensions or when the multiblock is intialized - ie any time the multipler could concieveably change - // --- BEGIN robust insolation block (mirror SatelliteTerminal style) --- + // --- BEGIN mirror SatelliteTerminal style) --- final int curDim = world.provider.getDimension(); final int spaceDim = ARConfiguration.getCurrentConfig().spaceDimId; @@ -207,7 +252,7 @@ public void update() { } } - // --- BEGIN robust energy gather (mirrors SatelliteTerminal) --- + // --- BEGIN (mirrors SatelliteTerminal) --- final int dimId = world.provider.getDimension(); final boolean dimOk = DimensionManager.getInstance().isDimensionCreated(dimId) || dimId == 0; @@ -264,7 +309,6 @@ public void update() { powerMadeLastTick + " " + LibVulpes.proxy.getLocalizedString("msg.powerunit.rfpertick")); } - // --- END robust energy gather --- } @@ -334,25 +378,324 @@ public void useNetworkData(EntityPlayer player, Side side, byte id, NBTTagCompou public NBTTagCompound writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); + // ---- satellites ---- int[] intArray = new int[connectedSatellites.size() * 2]; - for (int i = 0; i < connectedSatellites.size() * 2; i += 2) { - intArray[i] = (connectedSatellites.get(i / 2)).intValue(); - intArray[i + 1] = (int) ((connectedSatellites.get(i / 2) >>> 32)); + intArray[i] = (connectedSatellites.get(i / 2)).intValue(); + intArray[i+1] = (int)((connectedSatellites.get(i / 2) >>> 32)); } - nbt.setIntArray("satilliteList", intArray); + // ---- saved hatch inventories ---- + NBTTagList hatchList = new NBTTagList(); + if (savedHatchInv != null && !savedHatchInv.isEmpty()) { + for (Map.Entry> e : savedHatchInv.entrySet()) { + NBTTagCompound entry = new NBTTagCompound(); + entry.setLong("pos", e.getKey()); + + NBTTagList items = new NBTTagList(); + NonNullList arr = e.getValue(); + for (int slot = 0; slot < arr.size(); slot++) { + ItemStack s = arr.get(slot); + if (s.isEmpty()) continue; + NBTTagCompound it = new NBTTagCompound(); + it.setInteger("slot", slot); + s.writeToNBT(it); + items.appendTag(it); + } + entry.setTag("items", items); + hatchList.appendTag(entry); + } + } + nbt.setTag("savedHatchInv", hatchList); + return nbt; } @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); + + // ---- satellites ---- int[] intArray = nbt.getIntArray("satilliteList"); connectedSatellites.clear(); for (int i = 0; i < intArray.length; i += 2) { connectedSatellites.add(intArray[i] | (((long) intArray[i + 1]) << 32)); } + + // ---- saved hatch inventories ---- + savedHatchInv.clear(); + + NBTTagList hatchList = nbt.getTagList("savedHatchInv", 10); + for (int i = 0; i < hatchList.tagCount(); i++) { + NBTTagCompound entry = hatchList.getCompoundTagAt(i); + long posKey = entry.getLong("pos"); + NBTTagList items = entry.getTagList("items", 10); + + int maxSlot = -1; + for (int j = 0; j < items.tagCount(); j++) { + int slot = items.getCompoundTagAt(j).getInteger("slot"); + if (slot > maxSlot) maxSlot = slot; + } + NonNullList arr = NonNullList.withSize(Math.max(maxSlot + 1, 1), ItemStack.EMPTY); + + for (int j = 0; j < items.tagCount(); j++) { + NBTTagCompound it = items.getCompoundTagAt(j); + int slot = it.getInteger("slot"); + arr.set(slot, new ItemStack(it)); + } + savedHatchInv.put(posKey, arr); + } } + + // Push the pre-formation snapshot into the placeholders' replaced inventories (after formation) + private void writeSnapshotIntoPlaceholders() { + if (world == null || savedHatchInv.isEmpty()) return; + + final Object[][][] struct = getStructure(); + if (struct == null) return; + + final Vector3F off = getControllerOffset(struct); + final EnumFacing front = getFrontDirection(world.getBlockState(pos)); + + for (int y = 0; y < struct.length; y++) { + for (int z = 0; z < struct[0].length; z++) { + for (int x = 0; x < struct[0][0].length; x++) { + if (struct[y][z][x] == null) continue; + + int gx = pos.getX() + (x - off.x) * front.getFrontOffsetZ() - (z - off.z) * front.getFrontOffsetX(); + int gy = pos.getY() - y + off.y; + int gz = pos.getZ() - (x - off.x) * front.getFrontOffsetX() - (z - off.z) * front.getFrontOffsetZ(); + BlockPos bp = new BlockPos(gx, gy, gz); + + TileEntity te = world.getTileEntity(bp); + if (!(te instanceof TilePlaceholder)) continue; + + NonNullList snapshot = savedHatchInv.get(bp.toLong()); + if (snapshot == null || snapshot.isEmpty()) continue; + + TileEntity rep = ((TilePlaceholder) te).getReplacedTileEntity(); + if (!(rep instanceof IInventory)) continue; + + IInventory inv = (IInventory) rep; + + // First try to restore to original slots + for (int i = 0; i < snapshot.size(); i++) { + ItemStack src = snapshot.get(i); + if (src.isEmpty()) continue; + ItemStack cur = (i < inv.getSizeInventory()) ? inv.getStackInSlot(i) : ItemStack.EMPTY; + if (i < inv.getSizeInventory() && cur.isEmpty()) { + inv.setInventorySlotContents(i, src.copy()); + snapshot.set(i, ItemStack.EMPTY); + } + } + // Then merge leftovers + for (int i = 0; i < snapshot.size(); i++) { + ItemStack left = snapshot.get(i); + if (left.isEmpty()) continue; + + ItemStack rem = left.copy(); + // merge into existing stacks + for (int slot = 0; slot < inv.getSizeInventory() && !rem.isEmpty(); slot++) { + ItemStack dst = inv.getStackInSlot(slot); + if (dst.isEmpty()) continue; + if (ItemStack.areItemsEqual(dst, rem) && ItemStack.areItemStackTagsEqual(dst, rem)) { + int can = Math.min(inv.getInventoryStackLimit(), dst.getMaxStackSize()) - dst.getCount(); + if (can > 0) { + int move = Math.min(can, rem.getCount()); + dst.grow(move); + rem.shrink(move); + inv.setInventorySlotContents(slot, dst); + } + } + } + // fill empties + for (int slot = 0; slot < inv.getSizeInventory() && !rem.isEmpty(); slot++) { + if (inv.getStackInSlot(slot).isEmpty()) { + int put = Math.min(inv.getInventoryStackLimit(), rem.getMaxStackSize()); + ItemStack putStack = rem.splitStack(put); + inv.setInventorySlotContents(slot, putStack); + } + } + // any remainder stays in snapshot (shouldn’t normally happen) + snapshot.set(i, rem.isEmpty() ? ItemStack.EMPTY : rem); + } + inv.markDirty(); + } + } + } + + // After pushing into placeholders, discard snapshot + savedHatchInv.clear(); + } + + // Pull current contents back out of placeholders' replaced inventories (before teardown) + private void snapshotFromPlaceholders() { + savedHatchInv.clear(); + if (world == null) return; + + final Object[][][] struct = getStructure(); + if (struct == null) return; + + final Vector3F off = getControllerOffset(struct); + final EnumFacing front = getFrontDirection(world.getBlockState(pos)); + + for (int y = 0; y < struct.length; y++) { + for (int z = 0; z < struct[0].length; z++) { + for (int x = 0; x < struct[0][0].length; x++) { + if (struct[y][z][x] == null) continue; + + int gx = pos.getX() + (x - off.x) * front.getFrontOffsetZ() - (z - off.z) * front.getFrontOffsetX(); + int gy = pos.getY() - y + off.y; + int gz = pos.getZ() - (x - off.x) * front.getFrontOffsetX() - (z - off.z) * front.getFrontOffsetZ(); + BlockPos bp = new BlockPos(gx, gy, gz); + + TileEntity te = world.getTileEntity(bp); + + // Prefer the underlying hatch if this position is a placeholder + IInventory inv = null; + if (te instanceof TilePlaceholder) { + TileEntity rep = ((TilePlaceholder) te).getReplacedTileEntity(); + if (rep instanceof TileInventoryHatch) inv = (IInventory) rep; + } else if (te instanceof TileInventoryHatch) { + // Real multiblock component hatch (hidden block), still a live TE + inv = (IInventory) te; + } + + if (inv != null) { + NonNullList copy = NonNullList.withSize(inv.getSizeInventory(), ItemStack.EMPTY); + boolean any = false; + for (int i = 0; i < inv.getSizeInventory(); i++) { + ItemStack s = inv.getStackInSlot(i); + if (!s.isEmpty()) { + copy.set(i, s.copy()); + any = true; + } + } + if (any) savedHatchInv.put(bp.toLong(), copy); + } + } + } + } + } + + + + + private void snapshotHatchInventories() { + savedHatchInv.clear(); + final Object[][][] struct = getStructure(); + if (struct == null || world == null) return; + + final Vector3F off = getControllerOffset(struct); + final EnumFacing front = getFrontDirection(world.getBlockState(pos)); + + for (int y = 0; y < struct.length; y++) { + for (int z = 0; z < struct[0].length; z++) { + for (int x = 0; x < struct[0][0].length; x++) { + if (struct[y][z][x] == null) continue; + + int gx = pos.getX() + (x - off.x) * front.getFrontOffsetZ() - (z - off.z) * front.getFrontOffsetX(); + int gy = pos.getY() - y + off.y; + int gz = pos.getZ() - (x - off.x) * front.getFrontOffsetX() - (z - off.z) * front.getFrontOffsetZ(); + BlockPos bp = new BlockPos(gx, gy, gz); + + if (!world.getChunkFromBlockCoords(bp).isLoaded()) continue; + + TileEntity te = world.getTileEntity(bp); + + // If already replaced, pull from the placeholder’s replaced tile + if (te instanceof TilePlaceholder) te = ((TilePlaceholder) te).getReplacedTileEntity(); + + if (te instanceof IInventory) { + IInventory inv = (IInventory) te; + NonNullList copy = NonNullList.withSize(inv.getSizeInventory(), ItemStack.EMPTY); + boolean any = false; + for (int i = 0; i < inv.getSizeInventory(); i++) { + ItemStack s = inv.getStackInSlot(i); + if (!s.isEmpty()) { + copy.set(i, s.copy()); + any = true; + } + } + if (any) savedHatchInv.put(bp.toLong(), copy); + } + } + } + } + } + + private void restoreHatchInventories() { + if (world == null || savedHatchInv.isEmpty()) return; + + for (Map.Entry> e : savedHatchInv.entrySet()) { + BlockPos bp = BlockPos.fromLong(e.getKey()); + TileEntity te = world.getTileEntity(bp); + + // If placeholder is still present for any reason, restore into the underlying replaced tile + if (te instanceof TilePlaceholder) te = ((TilePlaceholder) te).getReplacedTileEntity(); + + if (te instanceof IInventory) { + IInventory inv = (IInventory) te; + NonNullList items = e.getValue(); + + // naive merge: try to put stacks back in their original slots first, then merge to any slot + // 1) original slots + for (int i = 0; i < items.size(); i++) { + ItemStack src = items.get(i); + if (src.isEmpty()) continue; + ItemStack cur = inv.getStackInSlot(i); + if (cur.isEmpty()) { + inv.setInventorySlotContents(i, src.copy()); + items.set(i, ItemStack.EMPTY); + } + } + // 2) merge leftovers anywhere they fit, otherwise drop + for (int i = 0; i < items.size(); i++) { + ItemStack left = items.get(i); + if (left.isEmpty()) continue; + + ItemStack rem = left.copy(); + // try merging into existing stacks + for (int slot = 0; slot < inv.getSizeInventory() && !rem.isEmpty(); slot++) { + ItemStack dst = inv.getStackInSlot(slot); + if (dst.isEmpty()) continue; + if (ItemStack.areItemsEqual(dst, rem) && ItemStack.areItemStackTagsEqual(dst, rem)) { + int can = Math.min(inv.getInventoryStackLimit(), dst.getMaxStackSize()) - dst.getCount(); + if (can > 0) { + int move = Math.min(can, rem.getCount()); + dst.grow(move); + rem.shrink(move); + inv.setInventorySlotContents(slot, dst); + } + } + } + // fill empty slots + for (int slot = 0; slot < inv.getSizeInventory() && !rem.isEmpty(); slot++) { + if (inv.getStackInSlot(slot).isEmpty()) { + int put = Math.min(inv.getInventoryStackLimit(), rem.getMaxStackSize()); + ItemStack putStack = rem.splitStack(put); + inv.setInventorySlotContents(slot, putStack); + } + } + // drop remainder to world + if (!rem.isEmpty()) { + world.spawnEntity(new EntityItem(world, bp.getX() + 0.5, bp.getY() + 0.5, bp.getZ() + 0.5, rem)); + } + items.set(i, ItemStack.EMPTY); + } + inv.markDirty(); + } else { + // no inventory to restore into → drop all + for (ItemStack s : e.getValue()) { + if (!s.isEmpty()) { + world.spawnEntity(new EntityItem(world, bp.getX() + 0.5, bp.getY() + 0.5, bp.getZ() + 0.5, s.copy())); + } + } + } + } + savedHatchInv.clear(); + } + + } From 3f586e54f7a0e4d1ec6a36d68f892d1810a8fc08 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 12 Nov 2025 15:09:49 +0100 Subject: [PATCH 207/274] Add newline at end of TileMicrowaveReciever.java Fix missing newline at the end of the file. From df18b0d609d6e9b04d378027b4e0f5a8b1dea6d0 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 12 Nov 2025 15:26:27 +0100 Subject: [PATCH 208/274] Update StationAssemblerWrapper to include station block --- .../StationAssemblerWrapper.java | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerWrapper.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerWrapper.java index 803ac3d15..496a26307 100644 --- a/src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerWrapper.java +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerWrapper.java @@ -40,28 +40,29 @@ public StationAssemblerWrapper() { @Override public void getIngredients(IIngredients ing) { - // No fluids; only items. - java.util.List> inputs = new java.util.ArrayList<>(2); - inputs.add(java.util.Collections.singletonList(inputHatch)); - inputs.add(java.util.Collections.singletonList(inputChip)); + // --- Inputs (your two visible inputs) --- + java.util.List> inputs = new java.util.ArrayList<>(3); + inputs.add(java.util.Collections.singletonList(inputHatch)); // bay (loader meta 1) + inputs.add(java.util.Collections.singletonList(inputChip)); // empty chip + + // --- Hidden machine block for discoverability (so R/U on block opens this page) --- + ItemStack stationBlock = new ItemStack( + zmaster587.advancedRocketry.api.AdvancedRocketryBlocks.blockStationBuilder + ); + inputs.add(java.util.Collections.singletonList(stationBlock)); + ing.setInputLists(mezz.jei.api.ingredients.VanillaTypes.ITEM, inputs); - // Show both outputs to reflect possible results of "Build". - java.util.List outs = new java.util.ArrayList<>(2); + // --- Outputs (show both possible results of "Build") --- + java.util.List outs = new java.util.ArrayList<>(3); outs.add(outStation); - outs.add(outChipMaybe); - ing.setOutputs(mezz.jei.api.ingredients.VanillaTypes.ITEM, outs); - } + if (outChipMaybe != null && !outChipMaybe.isEmpty()) { + outs.add(outChipMaybe); + } - // Convenience accessors (used by Category layout) - public ItemStack getInputHatch() { return inputHatch; } - public ItemStack getInputChip() { return inputChip; } - public ItemStack getOutStation() { return outStation; } - public ItemStack getOutChipMaybe() { return outChipMaybe; } + // Also include the block as an output so R on the block finds this page too + outs.add(stationBlock); - // Optional: a display/catalyst icon you can use if you decide later. - static ItemStack iconStack() { - // Safe: chip exists and isn’t blacklisted in your ARPlugin snippet. - return new ItemStack(AdvancedRocketryItems.itemSpaceStationChip); + ing.setOutputs(mezz.jei.api.ingredients.VanillaTypes.ITEM, outs); } } From d3aea73048b443ef9c9a1ba24cfad147c1cfcb66 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 12 Nov 2025 15:27:07 +0100 Subject: [PATCH 209/274] Add Station Assembler integration to ARPlugin --- .../integration/jei/ARPlugin.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/ARPlugin.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/ARPlugin.java index 57302621c..addaa0c5d 100644 --- a/src/main/java/zmaster587/advancedRocketry/integration/jei/ARPlugin.java +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/ARPlugin.java @@ -50,6 +50,10 @@ import zmaster587.advancedRocketry.integration.jei.satelliteBuilder.SatelliteBuilderCategory; import zmaster587.advancedRocketry.integration.jei.satelliteBuilder.SatelliteBuilderRecipeHandler; import zmaster587.advancedRocketry.integration.jei.satelliteBuilder.SatelliteBuilderRecipeMaker; +import zmaster587.advancedRocketry.integration.jei.stationAssembler.StationAssemblerCategory; +import zmaster587.advancedRocketry.integration.jei.stationAssembler.StationAssemblerRecipeHandler; +import zmaster587.advancedRocketry.integration.jei.stationAssembler.StationAssemblerRecipeMaker; +import zmaster587.advancedRocketry.tile.TileStationAssembler; import zmaster587.advancedRocketry.tile.infrastructure.TileFuelingStation; import zmaster587.advancedRocketry.tile.multiblock.machine.*; import zmaster587.advancedRocketry.tile.satellite.TileSatelliteBuilder; @@ -75,6 +79,7 @@ public class ARPlugin implements IModPlugin { public static final String satelliteBuilderUUID = "zmaster587.AR.satelliteBuilder"; public static final String fuelingStationUUID = "zmaster587.AR.fuelingStation"; public static final String co2ScrubberUUID = "zmaster587.AR.co2scrubber"; + public static final String stationAssemblerUUID = "zmaster587.AR.stationAssembler"; public static IJeiHelpers jeiHelpers; //AR machines can reload recipes. We still need this for JEI to be up-to-date @@ -102,7 +107,8 @@ public void registerCategories(IRecipeCategoryRegistration registry) { new PrecisionLaserEtcherCategory(guiHelper), new SatelliteBuilderCategory(guiHelper), new FuelingStationCategory(guiHelper), - new Co2ScrubberCategory(guiHelper) + new Co2ScrubberCategory(guiHelper), + new StationAssemblerCategory(guiHelper) ); } @@ -150,7 +156,8 @@ public Object getIngredientUnderMouse(GuiModular guiContainer, new PrecisionLaserEtcherRecipeHandler(), new SatelliteBuilderRecipeHandler(), new FuelingStationRecipeHandler(), - new Co2ScrubberRecipeHandler() + new Co2ScrubberRecipeHandler(), + new StationAssemblerRecipeHandler() ); registry.addRecipes(RollingMachineRecipeMaker.getMachineRecipes(jeiHelpers, TileRollingMachine.class), rollingMachineUUID); @@ -167,7 +174,7 @@ public Object getIngredientUnderMouse(GuiModular guiContainer, registry.addRecipes(SatelliteBuilderRecipeMaker.getMachineRecipes(jeiHelpers, TileSatelliteBuilder.class), satelliteBuilderUUID); registry.addRecipes(FuelingStationRecipeMaker.getMachineRecipes(jeiHelpers, TileFuelingStation.class), fuelingStationUUID); registry.addRecipes(Co2ScrubberRecipeMaker.getRecipes(jeiHelpers), co2ScrubberUUID); - + registry.addRecipes(StationAssemblerRecipeMaker.getMachineRecipes(jeiHelpers, TileStationAssembler.class),stationAssemblerUUID); registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockRollingMachine), rollingMachineUUID); registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockLathe), latheUUID); @@ -181,7 +188,9 @@ public Object getIngredientUnderMouse(GuiModular guiContainer, registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockCentrifuge), centrifugeUUID); registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockPrecisionLaserEngraver), precisionLaserEngraverUUID); registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockSatelliteBuilder), satelliteBuilderUUID); - + // Station Assembler catalyst + registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockStationBuilder), stationAssemblerUUID); + registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryItems.itemSpaceStationChip), stationAssemblerUUID); // Co2 Scrubber catalysts registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockCO2Scrubber), co2ScrubberUUID); registry.addRecipeCatalyst(new ItemStack(AdvancedRocketryBlocks.blockOxygenVent), co2ScrubberUUID); From 55185add8f2af404dabc1c618b2831374358f11e Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 12 Nov 2025 15:27:42 +0100 Subject: [PATCH 210/274] Implement StationAssemblerCategory for JEI integration --- .../StationAssemblerCategory.java | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerCategory.java diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerCategory.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerCategory.java new file mode 100644 index 000000000..0b3bfcff8 --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/stationAssembler/StationAssemblerCategory.java @@ -0,0 +1,156 @@ +package zmaster587.advancedRocketry.integration.jei.stationAssembler; + +import mezz.jei.api.IGuiHelper; +import mezz.jei.api.gui.IGuiItemStackGroup; +import mezz.jei.api.gui.IRecipeLayout; +import mezz.jei.api.gui.IDrawable; +import mezz.jei.api.gui.IDrawableAnimated; +import mezz.jei.api.gui.IDrawableAnimated.StartDirection; +import mezz.jei.api.gui.IDrawableStatic; +import mezz.jei.api.ingredients.IIngredients; +import mezz.jei.api.recipe.IRecipeCategory; +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import zmaster587.advancedRocketry.integration.jei.ARPlugin; +import zmaster587.libVulpes.LibVulpes; + +/** + * Compact layout, mirroring the simple two-input / two-output flow: + * Inputs: [Satellite Loader (meta 1)] [Station Chip] + * Outputs: [Packed Station] [Station Chip (when new station)] + */ +public class StationAssemblerCategory implements IRecipeCategory { + + private final IDrawable background; + private final IDrawable icon; + private final IDrawable slotFrame; + private static final int BG_W = 180; + private static final int BG_H = 90; + + private static final ResourceLocation ROCKET_BUILDER_PNG = + new ResourceLocation("advancedrocketry", "textures/gui/rocketBuilder.png"); + + private static final int PB_BACK_U = 76, PB_BACK_V = 93, PB_BACK_W = 8, PB_BACK_H = 52; + private static final int PB_FILL_U = 176, PB_FILL_V = 15, PB_FILL_W = 2, PB_FILL_H = 38; + private static final int PB_INSET_X = 3, PB_INSET_Y = 2; + private static final int ANIM_MS = 100; + private final IDrawable backBar; // background frame (8x52) + private final IDrawableStatic fillStatic; // fill slice (2x38) + private final IDrawableAnimated fillAnim; // animated fill (bottom→top) + private int _x0, _x1, _y0, _y1; + private final int barX; + private final int barY; + + public StationAssemblerCategory(IGuiHelper gui) { + this.background = gui.createBlankDrawable(BG_W, BG_H); + this.icon = gui.createDrawableIngredient( + new net.minecraft.item.ItemStack(zmaster587.advancedRocketry.api.AdvancedRocketryBlocks.blockStationBuilder)); + this.slotFrame = gui.getSlotDrawable(); + + // build drawables from the exact atlas slices + this.backBar = gui.createDrawable(ROCKET_BUILDER_PNG, PB_BACK_U, PB_BACK_V, PB_BACK_W, PB_BACK_H); + this.fillStatic = gui.createDrawable(ROCKET_BUILDER_PNG, PB_FILL_U, PB_FILL_V, PB_FILL_W, PB_FILL_H); + this.fillAnim = gui.createAnimatedDrawable(fillStatic, ANIM_MS, StartDirection.BOTTOM, /*inverted*/ false); + + // position: right edge, centered Y + this.barX = BG_W - PB_BACK_W; + this.barY = (BG_H - PB_BACK_H) / 2; + } + + @Override public String getUid() { return ARPlugin.stationAssemblerUUID; } + @Override + public String getTitle() { + return new net.minecraft.item.ItemStack( + zmaster587.advancedRocketry.api.AdvancedRocketryBlocks.blockStationBuilder + ).getDisplayName(); + } + @Override public String getModName() { return "Advanced Rocketry"; } + @Override public IDrawable getBackground(){ return background; } + @Override public IDrawable getIcon() { return icon; } + + // keep your BG_W, BG_H, progress bar fields as-is... + + @Override + public void setRecipe(IRecipeLayout layout, StationAssemblerWrapper wrapper, IIngredients ing) { + IGuiItemStackGroup items = layout.getItemStacks(); + + // compact columns; roomy rows + final int SLOT = 18; + final int COL_GAP = 2; // close together horizontally + final int ROW_GAP = 24; // more empty space vertically + + final int widthNeeded = SLOT * 2 + COL_GAP; // 38 + final int heightNeeded = SLOT * 2 + ROW_GAP; // 60 + final int left = (BG_W - widthNeeded) / 2; + final int top = (BG_H - heightNeeded) / 2; + + final int x0 = left; + final int x1 = left + SLOT + COL_GAP; + final int y0 = top; + final int y1 = top + SLOT + ROW_GAP; + + // row 1: [ bay | empty chip ] + items.init(0, true, x0, y0); // bay (Satellite Loader meta 1) + items.init(1, true, x1, y0); // empty chip + + // row 2: [ packed item | programmed chip ] + items.init(2, false, x0, y1); // packed station + items.init(3, false, x1, y1); // programmed chip + + // bind ingredients + java.util.List> inLists = + ing.getInputs(mezz.jei.api.ingredients.VanillaTypes.ITEM); + java.util.List> outLists = + ing.getOutputs(mezz.jei.api.ingredients.VanillaTypes.ITEM); + + if (inLists.size() >= 1) items.set(0, inLists.get(0)); + if (inLists.size() >= 2) items.set(1, inLists.get(1)); + if (outLists.size() >= 1) items.set(2, outLists.get(0)); + if (outLists.size() >= 2) items.set(3, outLists.get(1)); + + // programmed chip: strip original tooltip, show only our hint + items.addTooltipCallback((slot, input, stack, tooltip) -> { + if (slot != 3 || stack == null || stack.isEmpty() + || !(stack.getItem() instanceof zmaster587.advancedRocketry.item.ItemStationChip)) return; + + // Only when chip is unprogrammed + if (zmaster587.advancedRocketry.item.ItemStationChip.getUUID(stack) == 0) { + // Vanilla "unprogrammed" text (with and without gray formatting) + final String vanilla = zmaster587.libVulpes.LibVulpes.proxy.getLocalizedString("msg.unprogrammed"); + final String vanillaGray = net.minecraft.util.text.TextFormatting.GRAY + vanilla; + + // Strip just that line (handle formatting/no-format) + tooltip.removeIf(line -> + line.equals(vanillaGray) || + line.equals(vanilla) || + net.minecraft.util.text.TextFormatting.getTextWithoutFormattingCodes(line).equals(vanilla) + ); + + // Insert our JEI-specific hint + tooltip.add(net.minecraft.util.text.TextFormatting.GRAY + + zmaster587.libVulpes.LibVulpes.proxy.getLocalizedString( + "jei.ar.stationAssembler.newStationChipHint" + ) + ); + } + }); + + + // keep for drawing slot frames + this._x0 = x0; this._x1 = x1; this._y0 = y0; this._y1 = y1; + } + + @Override + public void drawExtras(Minecraft mc) { + // progress bar (exact sprite, right-aligned, centered Y) + backBar.draw(mc, barX, barY); + fillAnim.draw(mc, barX + PB_INSET_X, barY + PB_INSET_Y); + + // draw slot frames at the centered positions + slotFrame.draw(mc, _x0, _y0); + slotFrame.draw(mc, _x1, _y0); + slotFrame.draw(mc, _x0, _y1); + slotFrame.draw(mc, _x1, _y1); + } +} From 403e2aacaad9ce1b4fd29c46c5ca3fc587211636 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Wed, 12 Nov 2025 15:42:39 +0100 Subject: [PATCH 211/274] Implement TooltipInjector for item tooltips This class handles tooltips for various items in the Advanced Rocketry mod, mapping registry IDs and suffixes to localization keys, and providing dynamic arguments for formatted tooltip lines. --- .../client/TooltipInjector.java | 522 ++++++++++++++++++ 1 file changed, 522 insertions(+) create mode 100644 src/main/java/zmaster587/advancedRocketry/client/TooltipInjector.java diff --git a/src/main/java/zmaster587/advancedRocketry/client/TooltipInjector.java b/src/main/java/zmaster587/advancedRocketry/client/TooltipInjector.java new file mode 100644 index 000000000..b2fa67284 --- /dev/null +++ b/src/main/java/zmaster587/advancedRocketry/client/TooltipInjector.java @@ -0,0 +1,522 @@ +package zmaster587.advancedRocketry.client; + +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.resources.I18n; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.client.event.ModelRegistryEvent; +import net.minecraftforge.event.entity.player.ItemTooltipEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import org.lwjgl.input.Keyboard; +import zmaster587.advancedRocketry.api.Constants; +import zmaster587.advancedRocketry.api.ARConfiguration; + +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidRegistry; +import zmaster587.advancedRocketry.api.fuel.FuelRegistry; +import zmaster587.advancedRocketry.api.fuel.FuelRegistry.FuelType; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Mod.EventBusSubscriber(modid = Constants.modId, value = Side.CLIENT) +public final class TooltipInjector { + + private TooltipInjector() {} + + /** Maps exact registry IDs -> base tooltip lang key */ + private static final Map KEY_BY_ID = new HashMap<>(); + /** Fallback: maps the unlocalized-name tail -> base tooltip lang key */ + private static final Map KEY_BY_SUFFIX = new HashMap<>(); + /** Optional: dynamic args for formatted lines (usually used in .alt.2) */ + @FunctionalInterface interface ArgProvider { Object[] get(ItemStack s); } + private static final Map ARGS_BY_BASEKEY = new HashMap<>(); + /** For items that need per-stack (e.g., meta) keys */ + private static final Map> KEY_RESOLVER_BY_ID = new HashMap<>(); + + + static { + // ---- CO2 Scrubber ---- + KEY_BY_ID.put("advancedrocketry:scrubber", "tooltip.advancedrocketry.scrubber"); + KEY_BY_SUFFIX.put("scrubber", "tooltip.advancedrocketry.scrubber"); + + // ---- Oxygen Vent ---- + KEY_BY_ID.put("advancedrocketry:oxygenvent", "tooltip.advancedrocketry.oxygenvent"); + KEY_BY_SUFFIX.put("oxygenVent", "tooltip.advancedrocketry.oxygenvent"); + + ARGS_BY_BASEKEY.put("tooltip.advancedrocketry.oxygenvent", + s -> new Object[] { ARConfiguration.getCurrentConfig().oxygenVentSize }); + + // ---- Carbon Scrubber Cartridge ---- + KEY_BY_ID.put("advancedrocketry:carbonscrubbercartridge", "tooltip.advancedrocketry.scrubbercart"); + KEY_BY_SUFFIX.put("carbonScrubberCartridge", "tooltip.advancedrocketry.scrubbercart"); + + // ---- Structure Tower ---- + KEY_BY_ID.put("advancedrocketry:structuretower", "tooltip.advancedrocketry.structuretower"); + KEY_BY_SUFFIX.put("structuretower", "tooltip.advancedrocketry.structuretower"); + + // --- ItemUpgrade (meta-based) 6 Space Suit Components--- + KEY_RESOLVER_BY_ID.put("advancedrocketry:itemupgrade", + s -> "tooltip.advancedrocketry.itemupgrade." + s.getItemDamage()); + KEY_RESOLVER_BY_ID.put("advancedrocketry:item_upgrade", + s -> "tooltip.advancedrocketry.itemupgrade." + s.getItemDamage()); + + // ---- Guidance Computer ---- + KEY_BY_ID.put("advancedrocketry:guidancecomputer", "tooltip.advancedrocketry.guidancecomputer"); + KEY_BY_ID.put("advancedrocketry:guidance_computer", "tooltip.advancedrocketry.guidancecomputer"); // just in case + KEY_BY_SUFFIX.put("guidanceComputer", "tooltip.advancedrocketry.guidancecomputer"); + + // ---- Service Monitor ---- + KEY_BY_ID.put("advancedrocketry:servicemonitor", "tooltip.advancedrocketry.servicemonitor"); + KEY_BY_SUFFIX.put("servicemonitor", "tooltip.advancedrocketry.servicemonitor"); + + // ---- Service Station ---- + KEY_BY_ID.put("advancedrocketry:servicestation", "tooltip.advancedrocketry.servicestation"); + KEY_BY_ID.put("advancedrocketry:serviceStation", "tooltip.advancedrocketry.servicestation"); + KEY_BY_SUFFIX.put("serviceStation", "tooltip.advancedrocketry.servicestation"); + + // ---- Gas Charge Pad ---- + KEY_BY_ID.put("advancedrocketry:oxygenCharger", "tooltip.advancedrocketry.oxygencharger"); + KEY_BY_SUFFIX.put("oxygenCharger", "tooltip.advancedrocketry.oxygencharger"); + + // --- Station Controllers + KEY_BY_ID.put("advancedrocketry:orientationcontroller", "tooltip.advancedrocketry.orientationctrl"); + KEY_BY_SUFFIX.put("orientationcontroller", "tooltip.advancedrocketry.orientationctrl"); + KEY_BY_SUFFIX.put("orientationController", "tooltip.advancedrocketry.orientationctrl"); + + KEY_BY_SUFFIX.put("gravityController", "tooltip.advancedrocketry.gravityctrl"); + KEY_BY_ID.put("advancedrocketry:gravitycontroller", "tooltip.advancedrocketry.gravityctrl"); + KEY_BY_SUFFIX.put("gravitycontroller", "tooltip.advancedrocketry.gravityctrl"); + + KEY_BY_ID.put("advancedrocketry:altitudecontroller", "tooltip.advancedrocketry.altitudectrl"); + KEY_BY_SUFFIX.put("altitudeController", "tooltip.advancedrocketry.altitudectrl"); + KEY_BY_SUFFIX.put("altitudecontroller", "tooltip.advancedrocketry.altitudectrl"); + + // ---- Small Airlock Door (ItemDoor tied to blockAirLock) ---- + KEY_BY_ID.put("advancedrocketry:smallairlockdoor", "tooltip.advancedrocketry.smallairlock"); + // Fallback by unloc tail (you set setUnlocalizedName("smallAirlock")) + KEY_BY_SUFFIX.put("smallAirlock", "tooltip.advancedrocketry.smallairlock"); + + // Planet Selectors + KEY_BY_ID.put("advancedrocketry:planetselector", "tooltip.advancedrocketry.planetselector"); + KEY_BY_SUFFIX.put("planetSelector", "tooltip.advancedrocketry.planetselector"); + + KEY_BY_ID.put("advancedrocketry:planetholoselector", "tooltip.advancedrocketry.planetholoselector"); + KEY_BY_SUFFIX.put("planetHoloSelector", "tooltip.advancedrocketry.planetholoselector"); + + // ---- Station Light ---- + KEY_BY_ID.put("advancedrocketry:circlelight", "tooltip.advancedrocketry.circlelight"); + KEY_BY_SUFFIX.put("circleLight", "tooltip.advancedrocketry.circlelight"); + + // ---- Monitoring Station ---- + KEY_BY_ID.put("advancedrocketry:monitoringstation", "tooltip.advancedrocketry.monitoringstation"); + KEY_BY_ID.put("advancedrocketry:monitoring_station", "tooltip.advancedrocketry.monitoringstation"); + KEY_BY_SUFFIX.put("monitoringstation", "tooltip.advancedrocketry.monitoringstation"); + + // ---- Satellite Builder ---- + KEY_BY_ID.put("advancedrocketry:satellitebuilder", "tooltip.advancedrocketry.satellitebuilder"); + KEY_BY_SUFFIX.put("satelliteBuilder", "tooltip.advancedrocketry.satellitebuilder"); + + // ---- Satellite Control Terminal ---- + KEY_BY_ID.put("advancedrocketry:satellitemonitor", "tooltip.advancedrocketry.satellitemonitor"); + KEY_BY_ID.put("advancedrocketry:satellite_monitor", "tooltip.advancedrocketry.satellitemonitor"); + KEY_BY_SUFFIX.put("satelliteMonitor", "tooltip.advancedrocketry.satellitemonitor"); + + // --- Satellite Primary Function (metas 0..6) + KEY_RESOLVER_BY_ID.put("advancedrocketry:satelliteprimaryfunction", s -> { + switch (s.getMetadata() & 7) { + case 0: return "tooltip.advancedrocketry.satfunc.optical"; + case 1: return "tooltip.advancedrocketry.satfunc.composition"; + case 2: return "tooltip.advancedrocketry.satfunc.mass"; + case 3: return "tooltip.advancedrocketry.satfunc.microwave"; + case 4: return "tooltip.advancedrocketry.satfunc.oremapping"; + case 5: return "tooltip.advancedrocketry.satfunc.biomechanger"; + case 6: return "tooltip.advancedrocketry.satfunc.weather"; + default: return null; + } + }); + // (optional camelCase fallback if you ever see it) + KEY_RESOLVER_BY_ID.put("advancedrocketry:satellitePrimaryFunction", + KEY_RESOLVER_BY_ID.get("advancedrocketry:satelliteprimaryfunction")); + + // --- Satellite Power Source (metas 0..1) + KEY_RESOLVER_BY_ID.put("advancedrocketry:satellitepowersource", s -> { + switch (s.getMetadata() & 1) { + case 0: return "tooltip.advancedrocketry.satpower.0"; // Basic solar + case 1: return "tooltip.advancedrocketry.satpower.1"; // Advanced solar + default: return null; + } + }); + KEY_RESOLVER_BY_ID.put("advancedrocketry:satellitePowerSource", + KEY_RESOLVER_BY_ID.get("advancedrocketry:satellitepowersource")); + + // ---- LibVulpes Battery (meta 0..1) ---- + KEY_RESOLVER_BY_ID.put("libvulpes:battery", s -> "tooltip.libvulpes.battery." + (s.getMetadata() & 1)); + + // ---- ID Chips / Chips ---- + KEY_BY_ID.put("advancedrocketry:satelliteidchip", "tooltip.advancedrocketry.satidchip"); + KEY_BY_SUFFIX.put("satelliteIdChip", "tooltip.advancedrocketry.satidchip"); + + KEY_BY_ID.put("advancedrocketry:planetidchip", "tooltip.advancedrocketry.planetidchip"); + KEY_BY_SUFFIX.put("planetIdChip", "tooltip.advancedrocketry.planetidchip"); + + KEY_BY_ID.put("advancedrocketry:stationchip", "tooltip.advancedrocketry.stationchip"); + KEY_BY_SUFFIX.put("stationChip", "tooltip.advancedrocketry.stationchip"); + // registry sometimes: spaceStationChip + KEY_BY_ID.put("advancedrocketry:spacestationchip", "tooltip.advancedrocketry.stationchip"); + KEY_BY_SUFFIX.put("spaceStationChip", "tooltip.advancedrocketry.stationchip"); + + KEY_BY_ID.put("advancedrocketry:elevatorchip", "tooltip.advancedrocketry.elevatorchip"); + KEY_BY_SUFFIX.put("elevatorChip", "tooltip.advancedrocketry.elevatorchip"); + + KEY_BY_ID.put("advancedrocketry:asteroidchip", "tooltip.advancedrocketry.asteroidchip"); + KEY_BY_SUFFIX.put("asteroidChip", "tooltip.advancedrocketry.asteroidchip"); + + // ---- Energy multiblocks ---- + + // Black Hole Generator + KEY_BY_ID.put("advancedrocketry:blackholegenerator", "tooltip.advancedrocketry.blackholegen"); + KEY_BY_SUFFIX.put("blackholegenerator", "tooltip.advancedrocketry.blackholegen"); + + // Microwave Receiver (note: source uses the misspelling "Reciever"; cover both) + KEY_BY_ID.put("advancedrocketry:microwavereciever", "tooltip.advancedrocketry.microwavereceiver"); + KEY_BY_ID.put("advancedrocketry:microwaveReciever", "tooltip.advancedrocketry.microwavereceiver"); + KEY_BY_SUFFIX.put("microwavereciever", "tooltip.advancedrocketry.microwavereceiver"); + KEY_BY_SUFFIX.put("microwaveReciever", "tooltip.advancedrocketry.microwavereceiver"); + // (optional safety if it ever gets corrected) + KEY_BY_ID.put("advancedrocketry:microwavereceiver", "tooltip.advancedrocketry.microwavereceiver"); + KEY_BY_SUFFIX.put("microwaveReceiver", "tooltip.advancedrocketry.microwavereceiver"); + + // ---- Solar Panel (part of multiblock) ---- + KEY_BY_ID.put("advancedrocketry:solarpanel", "tooltip.advancedrocketry.solarpanel"); + KEY_BY_ID.put("advancedrocketry:solarPanel", "tooltip.advancedrocketry.solarpanel"); // just in case + KEY_BY_SUFFIX.put("solarpanel", "tooltip.advancedrocketry.solarpanel"); + KEY_BY_SUFFIX.put("solarPanel", "tooltip.advancedrocketry.solarpanel"); + + // Solar Array + KEY_BY_ID.put("advancedrocketry:solararray", "tooltip.advancedrocketry.solararray"); + KEY_BY_SUFFIX.put("solararray", "tooltip.advancedrocketry.solararray"); + // Solar Array Panel + KEY_BY_ID.put("advancedrocketry:solararraypanel", "tooltip.advancedrocketry.solararraypanel"); + KEY_BY_SUFFIX.put("solararraypanel", "tooltip.advancedrocketry.solararraypanel"); + + // ---- BlockARHatch (registered as advancedrocketry:loader), meta 0..6 ---- + KEY_RESOLVER_BY_ID.put("advancedrocketry:loader", s -> { + final int v = s.getMetadata() & 7; // strip redstone/state bit + switch (v) { + case 0: return "tooltip.advancedrocketry.hatch.databus"; + case 1: return "tooltip.advancedrocketry.hatch.satellite"; + case 2: return "tooltip.advancedrocketry.hatch.item_unloader"; + case 3: return "tooltip.advancedrocketry.hatch.item_loader"; + case 4: return "tooltip.advancedrocketry.hatch.fluid_unloader"; + case 5: return "tooltip.advancedrocketry.hatch.fluid_loader"; + case 6: return "tooltip.advancedrocketry.hatch.gca"; + default: return null; + } + }); + + // ---- Processing / Machines / Multiblocks---- + KEY_BY_ID.put("advancedrocketry:electricarcfurnace", "tooltip.advancedrocketry.arcfurnace"); + KEY_BY_SUFFIX.put("electricArcFurnace", "tooltip.advancedrocketry.arcfurnace"); + + KEY_BY_ID.put("advancedrocketry:rollingmachine", "tooltip.advancedrocketry.rollingmachine"); + KEY_BY_SUFFIX.put("rollingMachine", "tooltip.advancedrocketry.rollingmachine"); + + KEY_BY_ID.put("advancedrocketry:lathe", "tooltip.advancedrocketry.lathe"); + KEY_BY_SUFFIX.put("lathe", "tooltip.advancedrocketry.lathe"); + + KEY_BY_ID.put("advancedrocketry:crystallizer", "tooltip.advancedrocketry.crystallizer"); + KEY_BY_SUFFIX.put("Crystallizer", "tooltip.advancedrocketry.crystallizer"); // note capital C + + KEY_BY_ID.put("advancedrocketry:cuttingmachine", "tooltip.advancedrocketry.cuttingmachine"); + KEY_BY_SUFFIX.put("cuttingMachine", "tooltip.advancedrocketry.cuttingmachine"); + + KEY_BY_ID.put("advancedrocketry:precisionassemblingmachine", "tooltip.advancedrocketry.precisionassembler"); + KEY_BY_SUFFIX.put("precisionAssemblingMachine", "tooltip.advancedrocketry.precisionassembler"); + + KEY_BY_ID.put("advancedrocketry:electrolyser", "tooltip.advancedrocketry.electrolyser"); + KEY_BY_SUFFIX.put("electrolyser", "tooltip.advancedrocketry.electrolyser"); + + KEY_BY_ID.put("advancedrocketry:chemreactor", "tooltip.advancedrocketry.chemreactor"); + KEY_BY_SUFFIX.put("chemreactor", "tooltip.advancedrocketry.chemreactor"); + + KEY_BY_ID.put("advancedrocketry:precisionlaseretcher","tooltip.advancedrocketry.precisionlaseretcher"); + KEY_BY_SUFFIX.put("precisionlaseretcher", "tooltip.advancedrocketry.precisionlaseretcher"); + + KEY_BY_ID.put("advancedrocketry:observatory", "tooltip.advancedrocketry.observatory"); + KEY_BY_SUFFIX.put("observatory", "tooltip.advancedrocketry.observatory"); + + KEY_BY_ID.put("advancedrocketry:planetanalyser", "tooltip.advancedrocketry.planetanalyser"); + KEY_BY_SUFFIX.put("planetanalyser", "tooltip.advancedrocketry.planetanalyser"); + + KEY_BY_ID.put("advancedrocketry:centrifuge", "tooltip.advancedrocketry.centrifuge"); + KEY_BY_SUFFIX.put("centrifuge", "tooltip.advancedrocketry.centrifuge"); + + // ---- Aux / Huge ---- + KEY_BY_ID.put("advancedrocketry:warpcore", "tooltip.advancedrocketry.warpcore"); + KEY_BY_SUFFIX.put("warpCore", "tooltip.advancedrocketry.warpcore"); + + KEY_BY_ID.put("advancedrocketry:beacon", "tooltip.advancedrocketry.beacon"); + KEY_BY_SUFFIX.put("beacon", "tooltip.advancedrocketry.beacon"); + + KEY_BY_ID.put("advancedrocketry:biomescanner", "tooltip.advancedrocketry.biomescan"); + KEY_BY_SUFFIX.put("biomeScanner", "tooltip.advancedrocketry.biomescan"); + + KEY_BY_ID.put("advancedrocketry:railgun", "tooltip.advancedrocketry.railgun"); + KEY_BY_SUFFIX.put("railgun", "tooltip.advancedrocketry.railgun"); + + KEY_BY_ID.put("advancedrocketry:spaceelevatorcontroller", "tooltip.advancedrocketry.spaceelevatorctrl"); + KEY_BY_SUFFIX.put("spaceElevatorController", "tooltip.advancedrocketry.spaceelevatorctrl"); + + // ---- Building / components ---- + KEY_BY_ID.put("advancedrocketry:concrete", "tooltip.advancedrocketry.concrete"); + KEY_BY_SUFFIX.put("concrete", "tooltip.advancedrocketry.concrete"); + + KEY_BY_ID.put("advancedrocketry:blastbrick", "tooltip.advancedrocketry.blastbrick"); + KEY_BY_ID.put("advancedrocketry:blastBrick", "tooltip.advancedrocketry.blastbrick"); + KEY_BY_SUFFIX.put("blastbrick", "tooltip.advancedrocketry.blastbrick"); + KEY_BY_SUFFIX.put("blastBrick", "tooltip.advancedrocketry.blastbrick"); + + // Machines / misc + KEY_BY_ID.put("advancedrocketry:qcrucible", "tooltip.advancedrocketry.qcrucible"); + KEY_BY_SUFFIX.put("qcrucible", "tooltip.advancedrocketry.qcrucible"); + + KEY_BY_ID.put("advancedrocketry:sawblade", "tooltip.advancedrocketry.sawblade"); + KEY_BY_ID.put("advancedrocketry:sawBlade", "tooltip.advancedrocketry.sawblade"); + KEY_BY_SUFFIX.put("sawblade", "tooltip.advancedrocketry.sawblade"); + KEY_BY_SUFFIX.put("sawBlade", "tooltip.advancedrocketry.sawblade"); + + // Atmosphere Terraformer + KEY_BY_ID.put("advancedrocketry:terraformer", "tooltip.advancedrocketry.atmosterraformer"); + KEY_BY_SUFFIX.put("terraformer", "tooltip.advancedrocketry.atmosterraformer"); + + // Area Gravity Controller + KEY_BY_ID.put("advancedrocketry:gravitymachine", "tooltip.advancedrocketry.gravitymachine"); + KEY_BY_SUFFIX.put("gravityMachine", "tooltip.advancedrocketry.gravitymachine"); + KEY_BY_SUFFIX.put("gravitymachine", "tooltip.advancedrocketry.gravitymachine"); + + // Orbital Laser Drill (space laser) + KEY_BY_ID.put("advancedrocketry:spacelaser", "tooltip.advancedrocketry.spacelaser"); + KEY_BY_SUFFIX.put("spaceLaser", "tooltip.advancedrocketry.spacelaser"); + KEY_BY_SUFFIX.put("spacelaser", "tooltip.advancedrocketry.spacelaser"); + + // ---- Vacuum Laser ---- + KEY_BY_ID.put("advancedrocketry:vacuumlaser", "tooltip.advancedrocketry.vacuumlaser"); + KEY_BY_SUFFIX.put("vacuumLaser", "tooltip.advancedrocketry.vacuumlaser"); + KEY_BY_SUFFIX.put("vacuumlaser", "tooltip.advancedrocketry.vacuumlaser"); + + // ---- Pump ---- + KEY_BY_ID.put("advancedrocketry:pump", "tooltip.advancedrocketry.pump"); + KEY_BY_SUFFIX.put("pump", "tooltip.advancedrocketry.pump"); + + // ---- Assemblers ---- + // Rocket Assembler + KEY_BY_ID.put("advancedrocketry:rocketbuilder", "tooltip.advancedrocketry.rocketassembler"); + KEY_BY_SUFFIX.put("rocketbuilder", "tooltip.advancedrocketry.rocketassembler"); // safety + KEY_BY_SUFFIX.put("rocketAssembler", "tooltip.advancedrocketry.rocketassembler"); + + // Space Station Assembler + KEY_BY_ID.put("advancedrocketry:stationbuilder", "tooltip.advancedrocketry.stationassembler"); + KEY_BY_SUFFIX.put("stationbuilder", "tooltip.advancedrocketry.stationassembler"); + KEY_BY_SUFFIX.put("stationAssembler", "tooltip.advancedrocketry.stationassembler"); + + // Deployable Rocket Assembler (unmanned vehicle) + KEY_BY_ID.put("advancedrocketry:deployablerocketbuilder", "tooltip.advancedrocketry.deployablerocketassembler"); + KEY_BY_SUFFIX.put("deployablerocketbuilder", "tooltip.advancedrocketry.deployablerocketassembler"); + KEY_BY_SUFFIX.put("deployableRocketAssembler", "tooltip.advancedrocketry.deployablerocketassembler"); + + // ---- Fuel Tanks ---- + // Monopropellant Fuel Tank + KEY_BY_ID.put("advancedrocketry:fueltank", "tooltip.advancedrocketry.fueltank"); + KEY_BY_ID.put("advancedrocketry:fuelTank", "tooltip.advancedrocketry.fueltank"); + KEY_BY_SUFFIX.put("fuelTank", "tooltip.advancedrocketry.fueltank"); + + // Bipropellant Fuel Tank + KEY_BY_ID.put("advancedrocketry:bipropellantfueltank", "tooltip.advancedrocketry.bipropfueltank"); + KEY_BY_SUFFIX.put("bipropellantfueltank", "tooltip.advancedrocketry.bipropfueltank"); + + // Oxidizer Fuel Tank + KEY_BY_ID.put("advancedrocketry:oxidizerfueltank", "tooltip.advancedrocketry.oxidizerfueltank"); + KEY_BY_SUFFIX.put("oxidizerfueltank", "tooltip.advancedrocketry.oxidizerfueltank"); + + // Nuclear Fuel Tank + KEY_BY_ID.put("advancedrocketry:nuclearfueltank", "tooltip.advancedrocketry.nuclearfueltank"); + KEY_BY_SUFFIX.put("nuclearfueltank", "tooltip.advancedrocketry.nuclearfueltank"); + + // Monoprop tank + ARGS_BY_BASEKEY.put("tooltip.advancedrocketry.fueltank", + s -> new Object[]{ listFluidsFor(FuelType.LIQUID_MONOPROPELLANT, 6) }); + // Biprop fuel tank + ARGS_BY_BASEKEY.put("tooltip.advancedrocketry.bipropfueltank", + s -> new Object[]{ listFluidsFor(FuelType.LIQUID_BIPROPELLANT, 6) }); + // Oxidizer tank + ARGS_BY_BASEKEY.put("tooltip.advancedrocketry.oxidizerfueltank", + s -> new Object[]{ listFluidsFor(FuelType.LIQUID_OXIDIZER, 6) }); + // Nuclear working fluid tank + ARGS_BY_BASEKEY.put("tooltip.advancedrocketry.nuclearfueltank", + s -> new Object[]{ listFluidsFor(FuelType.NUCLEAR_WORKING_FLUID, 6) }); + + // Example for adding more items later (no code changes beyond these lines): + // KEY_BY_ID.put("advancedrocketry:carbonscrubbercartridge", "tooltip.advancedrocketry.scrubbercart"); + // KEY_BY_SUFFIX.put("carbonScrubberCartridge", "tooltip.advancedrocketry.scrubbercart"); + // ARGS_BY_BASEKEY.put("tooltip.advancedrocketry.scrubbercart", s -> new Object[]{ Math.max(0, s.getMaxDamage() - s.getItemDamage()) }); + } + + @SubscribeEvent + public static void onModels(ModelRegistryEvent e) { /* no-op */ } + + @SubscribeEvent + public static void onTooltip(ItemTooltipEvent e) { + final ItemStack stack = e.getItemStack(); + if (stack.isEmpty()) return; + + final List tooltip = e.getToolTip(); + + // Insert before the advanced "modid:item" line when advanced tooltips are on + final int insertAt = (e.getFlags().isAdvanced() && tooltip.size() > 1) + ? tooltip.size() - 1 + : tooltip.size(); + + final Item item = stack.getItem(); + @Nullable final ResourceLocation id = item.getRegistryName(); + String baseKey = null; + + if (id != null) { + java.util.function.Function res = KEY_RESOLVER_BY_ID.get(id.toString()); + if (res != null) { + baseKey = res.apply(stack); // e.g., tooltip.advancedrocketry.itemupgrade.3 + } + if (baseKey == null) { + baseKey = KEY_BY_ID.get(id.toString()); + } + } + + // Fallback: tail of unlocalized name (1.12 style) + if (baseKey == null) { + final String transKey = item.getUnlocalizedName(stack); + final int dot = transKey.lastIndexOf('.'); + if (dot > 0) { + final String tail = transKey.substring(dot + 1); + baseKey = KEY_BY_SUFFIX.get(tail); + } + } + + if (baseKey != null) { + renderShiftAlt(stack, tooltip, baseKey, insertAt); + } + } + + // ----- Generic renderer for base/shift/alt blocks ----- + @SideOnly(Side.CLIENT) + public static void renderShiftAlt(ItemStack s, List t, String baseKey, int idx) { + final ArgProvider ap = ARGS_BY_BASEKEY.get(baseKey); + final boolean hasShift = I18n.hasKey(baseKey + ".shift.1"); + final boolean hasAlt = I18n.hasKey(baseKey + ".alt.1") || ap != null; + + // Base block: base, base.1, base.2, ... + for (int i = 0; i <= 8; i++) { + final String k = (i == 0) ? baseKey : (baseKey + "." + i); + if (!I18n.hasKey(k)) { + if (i == 0) continue; // no bare base line; try .1 anyway + break; // stop when sequence ends + } + t.add(idx++, TextFormatting.GRAY + (ap != null ? I18n.format(k, ap.get(s)) : I18n.format(k))); + } + + // Shift block (shift.1..N) + if (hasShift) { + if (GuiScreen.isShiftKeyDown()) { + for (int i = 1; i <= 8; i++) { + final String k = baseKey + ".shift." + i; + if (!I18n.hasKey(k)) break; + t.add(idx++, TextFormatting.GRAY + (ap != null ? I18n.format(k, ap.get(s)) : I18n.format(k))); + } + } else if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) { + t.add(idx++, TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + + I18n.format("tooltip.advancedrocketry.hold_shift")); + } + } + + // Alt block (alt.1..N) + if (hasAlt) { + if (isAltDown()) { + for (int i = 1; i <= 8; i++) { + final String k = baseKey + ".alt." + i; + if (!I18n.hasKey(k)) break; + t.add(idx++, TextFormatting.GRAY + (ap != null ? I18n.format(k, ap.get(s)) : I18n.format(k))); + } + } else if (I18n.hasKey("tooltip.advancedrocketry.hold_alt")) { + t.add(idx++, TextFormatting.DARK_GRAY.toString() + TextFormatting.ITALIC + + I18n.format("tooltip.advancedrocketry.hold_alt")); + } + } + } + + + + // ----- Helpers ----- + + @SideOnly(Side.CLIENT) + private static String listFluidsFor(FuelType type, int max) { + java.util.List names = new java.util.ArrayList<>(); + for (net.minecraftforge.fluids.Fluid f : FluidRegistry.getRegisteredFluids().values()) { + try { + if (FuelRegistry.instance.isFuel(type, f)) { + // Localized name (1 bucket) + names.add(new FluidStack(f, 1000).getLocalizedName()); + if (names.size() >= max) break; + } + } catch (Throwable t) { + // be defensive against any odd registry states + } + } + if (names.isEmpty()) return I18n.hasKey("tooltip.advancedrocketry.none") ? I18n.format("tooltip.advancedrocketry.none") : "None"; + // if there are more than max, add an ellipsis + int total = 0; + for (net.minecraftforge.fluids.Fluid f : FluidRegistry.getRegisteredFluids().values()) + if (FuelRegistry.instance.isFuel(type, f)) total++; + String s = String.join(", ", names); + return (total > names.size()) ? (s + ", …") : s; + } + + private static int addIfPresentGray(List t, String key, int idx) { + if (I18n.hasKey(key)) { + t.add(idx, TextFormatting.GRAY + I18n.format(key)); + return idx + 1; + } + return idx; + } + + private static int addIfPresentDarkGray(List t, String key, int idx) { + if (I18n.hasKey(key)) { + t.add(idx, TextFormatting.DARK_GRAY + I18n.format(key)); + return idx + 1; + } + return idx; + } + + private static int addIfPresentDarkGrayFmt(List t, String key, int idx, Object... args) { + if (I18n.hasKey(key)) { + t.add(idx, TextFormatting.DARK_GRAY + I18n.format(key, args)); + return idx + 1; + } + return idx; + } + + @SideOnly(Side.CLIENT) + public static int computeInsertIndex(List tooltip, boolean advanced) { + return (advanced && tooltip.size() > 1) ? tooltip.size() - 1 : tooltip.size(); + } + + @SideOnly(Side.CLIENT) + public static boolean isAltDown() { + return Keyboard.isKeyDown(Keyboard.KEY_LMENU) || Keyboard.isKeyDown(Keyboard.KEY_RMENU); + } +} From e8a2ff8255cadd8af82d78c91997e9fd6b57fa19 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 16 Nov 2025 15:53:18 +0100 Subject: [PATCH 212/274] Implement IMultiblock interface in TileRocketMonitoringStation --- .../TileRocketMonitoringStation.java | 347 +++++++++++++++--- 1 file changed, 297 insertions(+), 50 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java index 15bd688a7..b847aed6a 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java @@ -10,13 +10,14 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.ITickable; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.eventhandler.EventPriority; - +import zmaster587.libVulpes.tile.IMultiblock; import zmaster587.advancedRocketry.api.ARConfiguration; import zmaster587.advancedRocketry.api.EntityRocketBase; import zmaster587.advancedRocketry.api.IInfrastructure; @@ -26,8 +27,10 @@ import zmaster587.advancedRocketry.api.satellite.SatelliteBase; import zmaster587.advancedRocketry.dimension.DimensionManager; import zmaster587.advancedRocketry.entity.EntityRocket; +import zmaster587.advancedRocketry.entity.EntityStationDeployedRocket; import zmaster587.advancedRocketry.inventory.TextureResources; - +import zmaster587.advancedRocketry.tile.TileRocketAssemblingMachine; +import zmaster587.advancedRocketry.tile.TileUnmannedVehicleAssembler; import zmaster587.libVulpes.LibVulpes; import zmaster587.libVulpes.client.util.IndicatorBarImage; import zmaster587.libVulpes.client.util.ProgressBarImage; @@ -38,6 +41,7 @@ import zmaster587.libVulpes.network.PacketHandler; import zmaster587.libVulpes.network.PacketMachine; import zmaster587.libVulpes.tile.IComparatorOverride; +import zmaster587.libVulpes.util.HashedBlockPosition; import zmaster587.libVulpes.util.IAdjBlockUpdate; import zmaster587.libVulpes.util.INetworkMachine; @@ -48,14 +52,25 @@ public class TileRocketMonitoringStation extends TileEntity implements IModularInventory, ITickable, IAdjBlockUpdate, IInfrastructure, ILinkableTile, INetworkMachine, IButtonInventory, IProgressBar, - IComparatorOverride, IGuiCallback { - // ==== TUNABLE TICK THROTTLES ==== + IComparatorOverride, IGuiCallback, IMultiblock { + // 2–3 ticks for height/vel feels live; 5–10 ticks is fine for fuel. private static final int T_HEIGHTVEL_TICKS = 3; // ~6.7 Hz private static final int T_FUEL_TICKS = 10; // ~2 Hz private static final int T_COMPARATOR_TICKS = 3; // match height cadence // ================================= + // Server-only: assembler-driven claim window + private int expectedRocketId = -1; + private long expectedRocketExpiry = 0L; + + // "this rocket belongs to me" + public void markRocketFromAssembler(EntityRocketBase rocket) { + if (world == null || world.isRemote || rocket == null) return; + this.expectedRocketId = rocket.getEntityId(); + this.expectedRocketExpiry = world.getTotalWorldTime() + 40; // ~2 seconds + } + EntityRocketBase linkedRocket; IMission mission; ModuleText missionText; @@ -73,6 +88,9 @@ public class TileRocketMonitoringStation extends TileEntity private int snapHeight = 0, snapVel = 0; private int snapFuel = 0, snapFuelCap = 0; // active fuel (id=2 semantics) private int snapOx = 0, snapOxCap = 0; // oxidizer (id=6 semantics) + private int lastKnownFuelCap = 0; // active fuel cap (mono/bi/nuclear) + private int lastKnownOxCap = 0; // oxidizer cap + // GUI cached fields (client) boolean was_powered = false; @@ -107,6 +125,33 @@ private void pushState() { } } + private boolean isRocketAllowedForMaster(@Nonnull EntityRocketBase rocket) { + // if something is weird, don't block linking + if (world == null || rocket == null) { + return true; + } + + // Free-floating monitor with no master: no restriction + if (!hasMaster()) { + return true; + } + + TileEntity master = getMasterBlock(); + if (!(master instanceof TileUnmannedVehicleAssembler)) { + // Master is some other assembler type: no SD-only restriction + return true; + } + + // From here: this monitor is owned by an *unmanned* vehicle assembler. + // Only accept SD rockets. + if (rocket instanceof EntityStationDeployedRocket) { + return true; + } + + // Anything else is not allowed for this master + return false; + } + private void clearUiStatus() { uiStatus = 0; lastAbortReason = ""; @@ -130,25 +175,59 @@ public TileRocketMonitoringStation() { } ); } + // --- Master / assembler association --- + private HashedBlockPosition masterBlock = new HashedBlockPosition(0, -1, 0); + + @Override + public boolean hasMaster() { + return masterBlock.y > -1; + } + + @Override + public TileEntity getMasterBlock() { + return world == null ? null : world.getTileEntity( + new BlockPos(masterBlock.x, masterBlock.y, masterBlock.z) + ); + } + + @Override + public void setMasterBlock(BlockPos pos) { + masterBlock = new HashedBlockPosition(pos); + } + + @Override + public void setComplete(BlockPos pos) { + } + + @Override + public void setIncomplete() { + masterBlock.y = -1; + } // --- Lifecycle / bus registration --- @Override public void onLoad() { - if (!world.isRemote && !registeredBus) { - MinecraftForge.EVENT_BUS.register(this); - registeredBus = true; - } - if (!world.isRemote && !initPower) { - boolean now = world.isBlockIndirectlyGettingPowered(pos) > 0; - isPoweredCached = now; - was_powered = now; - initPower = true; - } + if (world == null) return; if (!world.isRemote) { - boolean stale = lastStatusTick == 0L || - (world.getTotalWorldTime() - lastStatusTick) > STATUS_STALE_TICKS; + // Only listen to rocket events if we actually have a rocket + if (linkedRocket != null && !registeredBus) { + MinecraftForge.EVENT_BUS.register(this); + registeredBus = true; + primeSnapshotsFromRocket(); // immediate stats/fuel refresh + } + + if (!initPower) { + boolean now = world.isBlockIndirectlyGettingPowered(pos) > 0; + isPoweredCached = now; + was_powered = now; + initPower = true; + } + + // Status staleness handling unchanged: + boolean stale = lastStatusTick == 0L + || (world.getTotalWorldTime() - lastStatusTick) > STATUS_STALE_TICKS; if (stale || (linkedRocket == null && mission == null)) { clearUiStatus(); @@ -157,22 +236,27 @@ public void onLoad() { pushState(); } } - - } + @Override public void invalidate() { super.invalidate(); - // Unregister bus if (!world.isRemote && registeredBus) { MinecraftForge.EVENT_BUS.unregister(this); registeredBus = false; } - // Preserve original unlink-on-destroy semantics + // Tell the assembler that this infra is gone + if (!world.isRemote && hasMaster()) { + TileEntity master = getMasterBlock(); + if (master instanceof TileRocketAssemblingMachine) { + ((TileRocketAssemblingMachine) master).removeConnectedInfrastructure(this); + } + } + if (linkedRocket != null) { linkedRocket.unlinkInfrastructure(this); unlinkRocket(); @@ -183,17 +267,18 @@ public void invalidate() { } } + @Override public void onChunkUnload() { super.onChunkUnload(); - // IMPORTANT: do NOT unlink here — preserve original behavior: - // this tile remains linked across unload/reload and during flight/space. + // This tile remains linked across unload/reload and during flight/space. if (!world.isRemote && registeredBus) { MinecraftForge.EVENT_BUS.unregister(this); registeredBus = false; } } + // --- Redstone power caching via block neighbor callbacks --- @Deprecated @@ -210,10 +295,10 @@ public void onAdjacentBlockUpdated() { // Update cache first so it stays correct even with no rocket linked isPoweredCached = now; - was_powered = now; // optional if you surface this elsewhere + was_powered = now; if (rising && linkedRocket != null) { - linkedRocket.prepareLaunch(); // only on true 0->1 edge + linkedRocket.prepareLaunch(); markDirty(); } } @@ -234,15 +319,104 @@ public boolean disconnectOnLiftOff() { @Override public boolean linkRocket(EntityRocketBase rocket) { + if (rocket == null || world == null) { + return false; + } + + // If we are bound to an assembler, we only trust: + // - the rocket we already own, or + // - a rocket that the assembler just claimed for us. + if (!world.isRemote && hasMaster()) { + final int rocketId = rocket.getEntityId(); + + boolean allowed = false; + + // 1) Already our rocket? Always allow re-connect (teleports, dim changes). + if (this.linkedRocket != null && this.linkedRocket == rocket) { + allowed = true; + } else { + // 2) Else, require a fresh assembler claim. + boolean haveClaim = + (expectedRocketId == rocketId) && + (world.getTotalWorldTime() <= expectedRocketExpiry); + + if (haveClaim) { + allowed = true; + } + } + + if (!allowed) { + // This rocket has us in its infra list, but assembler did NOT bless it. + // Clean its list and refuse. + rocket.unlinkInfrastructure(this); + System.out.println( + "[Monitor] Rejecting rocket EID=" + rocket.getEntityId() + + " for monitor " + pos + + " (no assembler claim; master-bound monitor)" + ); + return false; + } + if (!isRocketAllowedForMaster(rocket)) { + rocket.unlinkInfrastructure(this); + System.out.println( + "[Monitor] Rejecting rocket EID=" + rocket.getEntityId() + + " for monitor " + pos + + " (rocket type not allowed for this master)" + ); + return false; + } + } + + // From here: either we have no master (free-floating infra), + // or the assembler/owner check passed. this.linkedRocket = rocket; - this.lastComparator = -1; - // Haxy gas mission returning case + // Always listen to events on the server + if (!world.isRemote && !registeredBus) { + MinecraftForge.EVENT_BUS.register(this); + registeredBus = true; + } + + // --- debug: monitor <- rocket link (kept) -------------------------- if (!world.isRemote) { - boolean returning = - (rocket instanceof EntityRocket) - && ((EntityRocket) rocket).isInOrbit() - && ((EntityRocket) rocket).isInFlight(); + final int dim = rocket.world.provider.getDimension(); + final int eid = rocket.getEntityId(); + final double rx = rocket.posX, ry = rocket.posY, rz = rocket.posZ; + + final zmaster587.advancedRocketry.api.fuel.FuelRegistry.FuelType ft = + rocket.getRocketFuelType(); + final int fAmt = (ft != null) ? rocket.getFuelAmount(ft) : 0; + final int fCap = (ft != null) ? rocket.getFuelCapacity(ft) : 0; + + int thrust = -1, weight = -1; + if (rocket instanceof zmaster587.advancedRocketry.entity.EntityRocket) { + try { + zmaster587.advancedRocketry.entity.EntityRocket er = + (zmaster587.advancedRocketry.entity.EntityRocket) rocket; + zmaster587.advancedRocketry.api.StatsRocket stats = er.getRocketStats(); + if (stats != null) { + thrust = (int) stats.getThrust(); + weight = (int) stats.getWeight(); + } + } catch (Throwable t) { /* keep simple */ } + } + + System.out.println( + "[Monitor] Linked @ " + pos + + " -> Rocket EID=" + eid + + " dim=" + dim + + " pos=(" + String.format("%.1f, %.1f, %.1f", rx, ry, rz) + ")" + + " fuel=" + (ft == null ? "NONE" : ft.name()) + " " + fAmt + "/" + fCap + + (thrust >= 0 ? (" thrust=" + thrust) : "") + + (weight >= 0 ? (" weight=" + weight) : "") + ); + + // Fresh snapshot + UI as before + primeSnapshotsFromRocket(); + + boolean returning = (rocket instanceof EntityRocket) + && ((EntityRocket) rocket).isInOrbit() + && ((EntityRocket) rocket).isInFlight(); if (returning) { uiStatus = 4; // deorbiting @@ -253,10 +427,13 @@ public boolean linkRocket(EntityRocketBase rocket) { lastStatusTick = 0L; } } + // ------------------------------------------------------------------- + return true; } + @Override public void unlinkRocket() { linkedRocket = null; @@ -283,11 +460,6 @@ public void unlinkRocket() { @Override public void update() { - // ensure we are listening on the bus --- - if (!world.isRemote && !registeredBus) { - MinecraftForge.EVENT_BUS.register(this); - registeredBus = true; - } if (world.isRemote) return; // One-time prime (in case no neighbor event has fired yet) @@ -316,6 +488,9 @@ public void update() { // Idle fast-exit if (linkedRocket == null) { return; } + if (snapFuelCap == 0 && linkedRocket.getRocketFuelType() != null) { + primeSnapshotsFromRocket(); + } // ---- height + velocity snapshots, every T_HEIGHTVEL_TICKS ---- if (++heightVelTick >= Math.max(1, T_HEIGHTVEL_TICKS)) { heightVelTick = 0; @@ -349,6 +524,8 @@ public void update() { snapOx = linkedRocket.getFuelAmount(FuelRegistry.FuelType.LIQUID_OXIDIZER); snapOxCap = linkedRocket.getFuelCapacity(FuelRegistry.FuelType.LIQUID_OXIDIZER); + + refreshCapsFromRocket(); } } @@ -465,6 +642,17 @@ public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) { readFromNBT(pkt.getNbtCompound()); } + private void refreshCapsFromRocket() { + if (linkedRocket == null) return; + final zmaster587.advancedRocketry.api.fuel.FuelRegistry.FuelType active = linkedRocket.getRocketFuelType(); + snapFuelCap = (active != null) ? linkedRocket.getFuelCapacity(active) : 0; + snapOxCap = linkedRocket.getFuelCapacity(FuelRegistry.FuelType.LIQUID_OXIDIZER); + + // persist fallbacks so a restart still has sane totals + if (snapFuelCap > 0) lastKnownFuelCap = snapFuelCap; + if (snapOxCap > 0) lastKnownOxCap = snapOxCap; + } + @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); @@ -480,13 +668,23 @@ public void readFromNBT(NBTTagCompound nbt) { uiStatus = nbt.getInteger("uiStatus"); lastStatusTick = nbt.getLong("lastStatusTick"); lastAbortReason = nbt.hasKey("abortReason") ? nbt.getString("abortReason") : ""; + lastKnownFuelCap = nbt.getInteger("lastFuelCap"); + lastKnownOxCap = nbt.getInteger("lastOxCap"); + + if (nbt.hasKey("masterY") && nbt.getInteger("masterY") > -1) { + int mx = nbt.getInteger("masterX"); + int my = nbt.getInteger("masterY"); + int mz = nbt.getInteger("masterZ"); + masterBlock = new HashedBlockPosition(mx, my, mz); + } - // --- client: force GUI labels to refresh next frame --- + // client: force GUI labels to refresh if (world != null && world.isRemote) { - lastUiStatusShown = -1; // guarantees next render tick will reapply the text + lastUiStatusShown = -1; } } + @Override public NBTTagCompound writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); @@ -498,9 +696,18 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { nbt.setInteger("uiStatus", uiStatus); nbt.setLong("lastStatusTick", lastStatusTick); nbt.setString("abortReason", lastAbortReason == null ? "" : lastAbortReason); + nbt.setInteger("lastFuelCap", lastKnownFuelCap); + nbt.setInteger("lastOxCap", lastKnownOxCap); + + if (hasMaster()) { + nbt.setInteger("masterX", masterBlock.x); + nbt.setInteger("masterY", masterBlock.y); + nbt.setInteger("masterZ", masterBlock.z); + } return nbt; } + // --- LibVulpes network bridge --- @Override @@ -540,11 +747,24 @@ else if (id == TAB_SWITCH && !world.isRemote) { getWorld(), pos.getX(), pos.getY(), pos.getZ()); } if (id == 100) { - if (linkedRocket != null) + if (linkedRocket != null) { + System.out.println("[MS] Launch clicked @ " + pos + ", linked? " + (linkedRocket!=null)); + // always re-prime before launch to avoid stale weight/fuel decisions + if (linkedRocket instanceof EntityRocket) { + ((EntityRocket) linkedRocket).recalculateStats(); + } + refreshCapsFromRocket(); + primeSnapshotsFromRocket(); // reflect any last-second loading linkedRocket.prepareLaunch(); + } else { + if (!world.isRemote) { + player.sendMessage(new TextComponentTranslation("msg.monitoringStation.noLinkedRocket")); + } + } } } + // --- GUI / Modules --- @Override public List getModules(int ID, EntityPlayer player) { @@ -817,6 +1037,40 @@ else if (id == 6) oxidizerFuelLevel = progress; } + /** Pulls a full, fresh snapshot from the linked rocket and pushes a TE update. */ + private void primeSnapshotsFromRocket() { + if (world == null || world.isRemote) return; + if (linkedRocket == null) return; + + // 1) make sure the rocket’s internal stats are up to date + if (linkedRocket instanceof EntityRocket) { + ((EntityRocket) linkedRocket).recalculateStats(); // calls storage.recalculateStats(stats) + } + + // 2) fresh fuel types/capacities + final zmaster587.advancedRocketry.api.fuel.FuelRegistry.FuelType active = linkedRocket.getRocketFuelType(); + snapFuel = (active != null) ? linkedRocket.getFuelAmount(active) : 0; + snapFuelCap = (active != null) ? linkedRocket.getFuelCapacity(active) : 0; + + snapOx = linkedRocket.getFuelAmount(zmaster587.advancedRocketry.api.fuel.FuelRegistry.FuelType.LIQUID_OXIDIZER); + snapOxCap = linkedRocket.getFuelCapacity(zmaster587.advancedRocketry.api.fuel.FuelRegistry.FuelType.LIQUID_OXIDIZER); + + // keep persisted fallbacks up to date + if (snapFuelCap > 0) lastKnownFuelCap = snapFuelCap; + if (snapOxCap > 0) lastKnownOxCap = snapOxCap; + + // 3) height/velocity + snapHeight = (int) linkedRocket.posY; + snapVel = (int) (linkedRocket.motionY * 100); + + // 4) make comparator reflect fresh height right away + lastComparator = -1; + world.updateComparatorOutputLevel(pos, world.getBlockState(pos).getBlock()); + + // 5) tell clients now (no waiting for the periodic tick) + pushState(); + } + @Override public int getProgress(int id) { // Client: use client-side cached fields (preserve original mission/height quirk) @@ -838,14 +1092,10 @@ public int getProgress(int id) { @Override public int getTotalProgress(int id) { - if (id == 0) - return ARConfiguration.getCurrentConfig().orbit; - else if (id == 1) - return 1000; - else if (id == 2) - return world.isRemote ? maxFuelLevel : snapFuelCap; - else if (id == 6) - return world.isRemote ? maxFuelLevel : snapOxCap; + if (id == 0) return ARConfiguration.getCurrentConfig().orbit; + if (id == 1) return 1000; + if (id == 2) return (world.isRemote ? maxFuelLevel : (snapFuelCap > 0 ? snapFuelCap : lastKnownFuelCap)); + if (id == 6) return (world.isRemote ? maxFuelLevel : (snapOxCap > 0 ? snapOxCap : lastKnownOxCap)); return 1; } @@ -878,16 +1128,13 @@ public boolean linkMission(IMission mission) { pushState(); } } - - PacketHandler.sendToNearby(new PacketMachine(this, (byte) 1), world.provider.getDimension(), getPos(), 16); return true; } @Override public void unlinkMission() { mission = null; - if (missionText != null) setMissionText(); // guard - PacketHandler.sendToNearby(new PacketMachine(this, (byte) 1), world.provider.getDimension(), getPos(), 16); + if (missionText != null) setMissionText(); } @Override From 51399d315656fabe16d3d4fc31698cf9989cbbbc Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 16 Nov 2025 15:53:43 +0100 Subject: [PATCH 213/274] Add newline at end of TileUnmannedVehicleAssembler.java Fix missing newline at end of file. From c1dd8b384fe1b79c9e24ae89249db97e7c2e182f Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 16 Nov 2025 15:54:05 +0100 Subject: [PATCH 214/274] Implement ITickable in TileRocketAssemblingMachine Added ITickable interface to TileRocketAssemblingMachine and implemented update method for relinking infrastructure. --- .../tile/TileRocketAssemblingMachine.java | 96 +++++++++++-------- 1 file changed, 57 insertions(+), 39 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java b/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java index 4620d22ff..26884dc4a 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java @@ -14,6 +14,7 @@ import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; +import net.minecraft.util.ITickable; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; @@ -59,7 +60,7 @@ * changed to complete the rocket structure * Also will be used to "build" the rocket components from the placed frames, control fuel flow etc **/ -public class TileRocketAssemblingMachine extends TileEntityRFConsumer implements IButtonInventory, INetworkMachine, IDataSync, IModularInventory, IProgressBar, ILinkableTile { +public class TileRocketAssemblingMachine extends TileEntityRFConsumer implements ITickable, IButtonInventory, INetworkMachine, IDataSync, IModularInventory, IProgressBar, ILinkableTile { protected static final ResourceLocation backdrop = new ResourceLocation("advancedrocketry", "textures/gui/rocketBuilder.png"); protected static final ProgressBarImage verticalProgressBar = new ProgressBarImage(76, 93, 8, 52, 176, 15, 2, 38, 3, 2, EnumFacing.UP, backdrop); @@ -105,8 +106,9 @@ public void onLoad() { registeredBus = true; } if (!world.isRemote) { - relinkRetries = 10; // up to ~10 seconds - nextRelinkAttempt = world.getTotalWorldTime() + 20; // first retry in 1s + relinkRetries = 15; // give it time + nextRelinkAttempt = world.getTotalWorldTime() + 20; + tryRelinkNow(); // best-effort first shot } if (world.isRemote) return; @@ -118,6 +120,10 @@ public void onLoad() { if (!rockets.isEmpty()) { for (IInfrastructure infra : getConnectedInfrastructure()) { for (EntityRocketBase r : rockets) { + if (infra instanceof zmaster587.advancedRocketry.tile.infrastructure.TileRocketMonitoringStation) { + ((zmaster587.advancedRocketry.tile.infrastructure.TileRocketMonitoringStation) infra) + .markRocketFromAssembler(r); + } r.linkInfrastructure(infra); } } @@ -257,42 +263,6 @@ public int getPowerPerOperation() { @Override public void performFunction() { - // Retry linking infra for up to ~10s, but stop early once ALL are linked - if (!world.isRemote && relinkRetries > 0 && world.getTotalWorldTime() >= nextRelinkAttempt) { - - if (bbCache == null) bbCache = getRocketPadBounds(world, pos); - - int expected = blockPos.size(); // how many infra we remember from NBT - if (expected == 0) { relinkRetries = 0; return; } - int found = 0; // how many are currently loaded & obtainable - - if (bbCache != null) { - final AxisAlignedBB box = bbCache.grow(1.0E-4, 1.0E-4, 1.0E-4); - java.util.List rockets = world.getEntitiesWithinAABB(EntityRocketBase.class, box); - - // Only count + link if a rocket is actually on the pad - if (!rockets.isEmpty()) { - java.util.List infraNow = getConnectedInfrastructure(); // only returns loaded TEs - found = infraNow.size(); - - // Link them all (idempotent in AR) - for (EntityRocketBase r : rockets) { - for (IInfrastructure infra : infraNow) { - r.linkInfrastructure(infra); - } - } - } - } - - // Stop early only when we've linked ALL remembered infra positions - if (found >= expected && expected > 0) { - relinkRetries = 0; // done - } else { - relinkRetries--; // try again next second - nextRelinkAttempt = world.getTotalWorldTime() + 20; - } - } - if (!isScanning()) return; if (progress >= (totalProgress * MAXSCANDELAY)) { @@ -683,9 +653,14 @@ public void assembleRocket() { world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3); for (IInfrastructure infrastructure : getConnectedInfrastructure()) { + if (infrastructure instanceof zmaster587.advancedRocketry.tile.infrastructure.TileRocketMonitoringStation) { + ((zmaster587.advancedRocketry.tile.infrastructure.TileRocketMonitoringStation) infrastructure) + .markRocketFromAssembler(rocket); + } rocket.linkInfrastructure(infrastructure); } + // Rescan so UI immediately reflects the post-build state scanRocket(world, pos, bbCache); } @@ -1297,9 +1272,14 @@ public void onRocketLand(RocketLandedEvent e) { // Track rocket id and (re)link infra lastRocketID = landed.getEntityId(); for (IInfrastructure infra : getConnectedInfrastructure()) { + if (infra instanceof zmaster587.advancedRocketry.tile.infrastructure.TileRocketMonitoringStation) { + ((zmaster587.advancedRocketry.tile.infrastructure.TileRocketMonitoringStation) infra) + .markRocketFromAssembler(landed); + } landed.linkInfrastructure(infra); } + // Maintain original semantics: only fast-path when exactly one rocket in the pad List rockets = world.getEntitiesWithinAABB(EntityRocket.class, box); if (rockets.size() == 1) { @@ -1351,4 +1331,42 @@ public String getErrorCode() { return code; } } + + @Override + public void update() { + super.update(); // << keep RFConsumer’s normal ticking/performFunction() + if (world.isRemote) return; + + if (relinkRetries > 0 && world.getTotalWorldTime() >= nextRelinkAttempt) { + if (tryRelinkNow()) { + relinkRetries = 0; + } else { + relinkRetries--; + nextRelinkAttempt = world.getTotalWorldTime() + 20; // 1s + } + } + } + + private boolean tryRelinkNow() { + if (bbCache == null) bbCache = getRocketPadBounds(world, pos); + if (bbCache == null) return false; + + AxisAlignedBB box = bbCache.grow(1.0e-4,1.0e-4,1.0e-4); + java.util.List rockets = world.getEntitiesWithinAABB(EntityRocketBase.class, box); + if (rockets.isEmpty()) return false; + + java.util.List infraNow = getConnectedInfrastructure(); + if (infraNow.isEmpty()) return false; + + for (EntityRocketBase r : rockets) { + for (IInfrastructure i : infraNow) { + if (i instanceof zmaster587.advancedRocketry.tile.infrastructure.TileRocketMonitoringStation) { + ((zmaster587.advancedRocketry.tile.infrastructure.TileRocketMonitoringStation) i) + .markRocketFromAssembler(r); + } + r.linkInfrastructure(i); + } + } + return true; + } } From 439aa5219a997ccbdc0e6d50d388642e12bf17f0 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 16 Nov 2025 15:58:07 +0100 Subject: [PATCH 215/274] Refactor TileRocketAssemblingMachine for clarity --- .../tile/TileRocketAssemblingMachine.java | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java b/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java index 26884dc4a..719945150 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/TileRocketAssemblingMachine.java @@ -325,10 +325,10 @@ public AxisAlignedBB scanRocket(World world, BlockPos pos2, AxisAlignedBB bb) { double buffer = 0.0001; AxisAlignedBB bufferedBB = bbCache.grow(buffer, buffer, buffer); List rockets = world.getEntitiesWithinAABB(EntityRocket.class, bufferedBB); - if (rockets.size() == 1){ // only if exactly one rocket is here + if (rockets.size() == 1){ rockets.get(0).recalculateStats(); this.stats = rockets.get(0).stats; - status = ErrorCodes.ALREADY_ASSEMBLED; // to prevent assembly + status = ErrorCodes.ALREADY_ASSEMBLED; return null; } } @@ -514,10 +514,10 @@ public AxisAlignedBB scanRocket(World world, BlockPos pos2, AxisAlignedBB bb) { int totalFuelUse = bipropellantfuelUse + nuclearWorkingFluidUse + monopropellantfuelUse; //System.out.println("rocket fuel use:"+totalFuelUse); - // --- Biprop requirement: if any bipropellant thrust exists, require both tanks --- + // Biprop requirement: if any bipropellant thrust exists, require both tanks if (thrustBipropellant > 0) { if (fuelCapacityBipropellant <= 0 || fuelCapacityOxidizer <= 0) { - status = ErrorCodes.NOFUEL; // or a dedicated error if you add one + status = ErrorCodes.NOFUEL; return new AxisAlignedBB(actualMinX, actualMinY, actualMinZ, actualMaxX, actualMaxY, actualMaxZ); } } @@ -563,7 +563,7 @@ public AxisAlignedBB scanRocket(World world, BlockPos pos2, AxisAlignedBB bb) { int maxYi = Math.max(actualMaxY, actualMinY); int maxZi = Math.max(actualMinZ, actualMaxZ); - // IMPORTANT: use BlockPos ctor so the AABB is [min, max+1) in block space + // use BlockPos ctor so the AABB is [min, max+1) in block space return new AxisAlignedBB( new BlockPos(minXi, minYi, minZi), new BlockPos(maxXi, maxYi, maxZi) @@ -610,7 +610,7 @@ public void assembleRocket() { // server only + need a pad cache if (world.isRemote || bbCache == null) return; - // Re-scan to get a *tight* non-air AABB and fresh stats/status + // Re-scan to get a tight non-air AABB and fresh stats/status final AxisAlignedBB scanBB = scanRocket(world, pos, bbCache); if (status != ErrorCodes.SUCCESS || scanBB == null) return; @@ -628,7 +628,7 @@ public void assembleRocket() { final StorageChunk storageChunk; try { storageChunk = StorageChunk.cutWorldBB(world, rocketBB); - } catch (Throwable t) { // covers NegativeArraySizeException & other edge errors + } catch (Throwable t) { // cover NegativeArraySizeException & other edge errors status = ErrorCodes.FAIL_CUT; return; } @@ -1118,7 +1118,7 @@ public int getData(int id) { switch (id) { case 0: - return (int)(getRocketStats().getWeight_NoFuel()*1000);// because it is a float really so take it *1000 + return (int)(getRocketStats().getWeight_NoFuel()*1000); case 1: return getRocketStats().getThrust(); case 2: @@ -1160,7 +1160,6 @@ public int getData(int id) { @Override public void onInventoryButtonPressed(int buttonId) { PacketHandler.sendToServer(new PacketMachine(this, (byte) (buttonId))); - //updateText(); } @Override @@ -1241,7 +1240,6 @@ public void removeConnectedInfrastructure(TileEntity tile) { public List getConnectedInfrastructure() { List list = new LinkedList<>(); - // Don't mutate blockPos here; tiles may not be loaded yet for (HashedBlockPosition position : blockPos) { TileEntity te = world.getTileEntity(position.getBlockPos()); if (te instanceof IInfrastructure) { @@ -1280,7 +1278,7 @@ public void onRocketLand(RocketLandedEvent e) { } - // Maintain original semantics: only fast-path when exactly one rocket in the pad + // only fast-path when exactly one rocket in the pad List rockets = world.getEntitiesWithinAABB(EntityRocket.class, box); if (rockets.size() == 1) { EntityRocket r = rockets.get(0); @@ -1293,8 +1291,6 @@ public void onRocketLand(RocketLandedEvent e) { // Fallback: rescan if something odd happens scanRocket(world, pos, bbCache); } - - // Preserve original networking PacketHandler.sendToPlayersTrackingEntity(new PacketMachine(this, (byte)3), landed); } @@ -1334,7 +1330,7 @@ public String getErrorCode() { @Override public void update() { - super.update(); // << keep RFConsumer’s normal ticking/performFunction() + super.update(); if (world.isRemote) return; if (relinkRetries > 0 && world.getTotalWorldTime() >= nextRelinkAttempt) { From 5c40c623d06efb6c614a43873dfb8cc022f35fba Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 16 Nov 2025 16:07:14 +0100 Subject: [PATCH 216/274] Remove debug logging from TileRocketMonitoringStation Removed debug print statements related to rocket monitoring. --- .../TileRocketMonitoringStation.java | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java index b847aed6a..8630d1b6c 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileRocketMonitoringStation.java @@ -349,20 +349,10 @@ public boolean linkRocket(EntityRocketBase rocket) { // This rocket has us in its infra list, but assembler did NOT bless it. // Clean its list and refuse. rocket.unlinkInfrastructure(this); - System.out.println( - "[Monitor] Rejecting rocket EID=" + rocket.getEntityId() + - " for monitor " + pos + - " (no assembler claim; master-bound monitor)" - ); return false; } if (!isRocketAllowedForMaster(rocket)) { rocket.unlinkInfrastructure(this); - System.out.println( - "[Monitor] Rejecting rocket EID=" + rocket.getEntityId() + - " for monitor " + pos + - " (rocket type not allowed for this master)" - ); return false; } } @@ -377,7 +367,6 @@ public boolean linkRocket(EntityRocketBase rocket) { registeredBus = true; } - // --- debug: monitor <- rocket link (kept) -------------------------- if (!world.isRemote) { final int dim = rocket.world.provider.getDimension(); final int eid = rocket.getEntityId(); @@ -401,16 +390,6 @@ public boolean linkRocket(EntityRocketBase rocket) { } catch (Throwable t) { /* keep simple */ } } - System.out.println( - "[Monitor] Linked @ " + pos + - " -> Rocket EID=" + eid + - " dim=" + dim + - " pos=(" + String.format("%.1f, %.1f, %.1f", rx, ry, rz) + ")" + - " fuel=" + (ft == null ? "NONE" : ft.name()) + " " + fAmt + "/" + fCap + - (thrust >= 0 ? (" thrust=" + thrust) : "") + - (weight >= 0 ? (" weight=" + weight) : "") - ); - // Fresh snapshot + UI as before primeSnapshotsFromRocket(); @@ -427,8 +406,6 @@ public boolean linkRocket(EntityRocketBase rocket) { lastStatusTick = 0L; } } - // ------------------------------------------------------------------- - return true; } @@ -748,7 +725,6 @@ else if (id == TAB_SWITCH && !world.isRemote) { } if (id == 100) { if (linkedRocket != null) { - System.out.println("[MS] Launch clicked @ " + pos + ", linked? " + (linkedRocket!=null)); // always re-prime before launch to avoid stale weight/fuel decisions if (linkedRocket instanceof EntityRocket) { ((EntityRocket) linkedRocket).recalculateStats(); From a1225c9399a9de258bc2fa5c828c8cf3291e3b48 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 16 Nov 2025 16:07:45 +0100 Subject: [PATCH 217/274] Add newline at end of EntityStationDeployedRocket.java Fix missing newline at end of file. From 7fd017e88fdb445e8903ec514a5dad10edc45999 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 16 Nov 2025 16:08:25 +0100 Subject: [PATCH 218/274] Refactor comment for clarity in TileFuelingStation --- .../tile/infrastructure/TileFuelingStation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java index 2bc3aa5c1..8733f8fd5 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/infrastructure/TileFuelingStation.java @@ -62,7 +62,7 @@ public class TileFuelingStation extends TileInventoriedRFConsumerTank implements // Cache last emitted redstone to avoid duplicate updates private Boolean lastRs = null; - // Small perf win: cache resolved fluids from rocket stats + // Cache resolved fluids from rocket stats private String lastFuelStr = null, lastOxStr = null, lastWorkStr = null; private Fluid cachedFuelFluid = null, cachedOxFluid = null, cachedWorkFluid = null; From f6e64bd25461a4069d79bc4ede58abb3c66fe2db Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 16 Nov 2025 16:09:47 +0100 Subject: [PATCH 219/274] Fix missing newline at end of TooltipInjector.java From 13acc9b7364380c0c9b988441132728ccad9c21d Mon Sep 17 00:00:00 2001 From: kaduvill Date: Sun, 16 Nov 2025 16:10:16 +0100 Subject: [PATCH 220/274] Refactor language file for item and tile names Updated various item and tile names for clarity and consistency. Adjusted tooltips and descriptions for several components, including solar panels, weather controllers, and hovercraft. --- .../assets/advancedrocketry/lang/en_US.lang | 650 +++++++++++++++++- 1 file changed, 643 insertions(+), 7 deletions(-) diff --git a/src/main/resources/assets/advancedrocketry/lang/en_US.lang b/src/main/resources/assets/advancedrocketry/lang/en_US.lang index ca09d5df2..59217f53f 100644 --- a/src/main/resources/assets/advancedrocketry/lang/en_US.lang +++ b/src/main/resources/assets/advancedrocketry/lang/en_US.lang @@ -136,7 +136,7 @@ tile.precisionlaseretcher.name=Precision Laser Etcher tile.enrichedLavaBlock.name=Enriched Lava Block tile.basalt.name=Basalt tile.landingfloat.name=Landing Float -tile.solararray.name=Solar Array +tile.solararray.name=Solar Array Controller tile.solararraypanel.name=Solar Array Panel tile.serviceStation.name=Service Station @@ -187,12 +187,12 @@ item.itemUpgrade.4.name=Anti-Fog Visor item.itemUpgrade.5.name=Earthbright Visor item.atmAnalyser.name=Atmosphere Analyzer item.biomeChanger.name=Biome Changer Remote -item.weatherController.name=Weather Satellite Remote +item.weatherController.name=Weather Remote item.basicLaserGun.name=Basic Laser Gun item.beaconFinder.name=Beacon Finder item.thermite.name=Thermite item.hovercraft.name=Hovercraft -item.hovercraft.tooltip=Long lasting dilithium power source. It'll probably outlive you. +item.hovercraft.tooltip=Long lasting dilithium Power source. It'll probably outlive you. item.jetPack.name=Suit Jetpack item.pressureTank.0.name=Low Pressure Tank @@ -339,7 +339,7 @@ msg.monitoringStation.deorbiting=Returned from orbit! msg.monitoringStation.landed=Landed msg.monitoringStation.aborted=Aborted! msg.monitoringStation.returningToDock=Returning to dock - +msg.monitoringStation.noLinkedRocket=Not Linked to any Rocket! msg.guidanceComputerHatch.loadingState=Loading State: msg.guidanceComputerHatch.ejectonlanding=Auto Eject Upon Landing @@ -359,7 +359,7 @@ msg.rocketLoader.allowredstoneinput=Allow redstone input msg.rocketLoader.allowredstoneoutput=Allow redstone output msg.rocketLoader.none=None msg.rocketLoader.link=You program the linker with the rocket loader at: -msg.microwaverec.notgenerating=Generating 0 FE/t +msg.microwaverec.notgenerating=Generating 0 RF/t msg.microwaverec.generating=Generating msg.abdp.compositionresearch=Composition Research msg.abdp.distanceresearch=Distance Research @@ -521,11 +521,11 @@ msg.wirelessTransciever.type=Type: %s msg.wirelessTransciever.network=Network: msg.wirelessTransciever.network.unlinked=Unlinked -msg.powerunit.rfpertick=FE/t +msg.powerunit.rfpertick=RF/t msg.linker.error.firstMachine=This must be the first machine to link! msg.linker.program=Coordinates programmed into Linker msg.linker.success=Linked Sucessfully -msg.notenoughpower=Not Enough power! +msg.notenoughpower=Not Enough Power! msg.empty=Empty msg.yes=yes msg.no=no @@ -549,8 +549,644 @@ commands.weather.always_not_clear=This planet is always not clear... commands.weather.cannot_rain=Cannot start a rain here commands.weather.cannot_thunder=Cannot start a thunder here +# Jeistuff jei.sb.satellitepreview=Ready for orbit! jei.sb.copy.source=Source jei.sb.copy.output=New Copy jei.sb.assemblyhint=Atleast one solar panel jei.sb.copychiphint=Make backups! + +jei.ar.fuel.role.monopropellant=Monopropellant Fuel +jei.ar.fuel.role.biprop_fuel=Bipropellant Fuel +jei.ar.fuel.role.oxidizer=Oxidizer +jei.ar.fuel.role.working_fluid=Working Fluid +jei.ar.stationAssembler.newStationChipHint=§cThis Points to the new Station! + +# Generic hint +tooltip.advancedrocketry.hold_shift=Hold §eShift§7 for details +tooltip.advancedrocketry.hold_alt=Hold §eAlt§7 for advanced tips + +# Fuel Tank (monoprop) +tooltip.advancedrocketry.fueltank=§cPart of Rocket +tooltip.advancedrocketry.fueltank.shift.1=§fHolds: §b%s +tooltip.advancedrocketry.fueltank.alt.1=Lets Rockety Rockrock! + +# Bipropellant Fuel Tank +tooltip.advancedrocketry.bipropfueltank=§cPart of Rocket +tooltip.advancedrocketry.bipropfueltank.shift.1=§fHolds: §b%s +tooltip.advancedrocketry.bipropfueltank.alt.1=§fBipropellant Rocket requires §bBipropellant§f and §bOxidizer§f tanks + +# Oxidizer Fuel Tank +tooltip.advancedrocketry.oxidizerfueltank=§cPart of Rocket +tooltip.advancedrocketry.oxidizerfueltank.shift.1=§fHolds: §b%s +tooltip.advancedrocketry.oxidizerfueltank.alt.1=§fBipropellant Rocket requires §bBipropellant§f and §bOxidizer§f tanks + +# Nuclear Fuel Tank +tooltip.advancedrocketry.nuclearfueltank=§cPart of Rocket +tooltip.advancedrocketry.nuclearfueltank.shift.1=§fHolds: §b%s +tooltip.advancedrocketry.nuclearfueltank.alt.1=§fRequires §bNuclear Core§f and §bNuclear Engine + +# Monopropellant Engine +tooltip.advancedrocketry.monopropmotor=§cPart of Rocket +tooltip.advancedrocketry.monopropmotor.shift.1=Uses §bMonopropellant Fuel§7 +tooltip.advancedrocketry.monopropmotor.alt.1=Check Fueling Station JEI-page + +# Nuclear Core +tooltip.advancedrocketry.nuclearcore=§cPart of Rocket +tooltip.advancedrocketry.nuclearcore.shift.1=Needs to be directly on top of a +tooltip.advancedrocketry.nuclearcore.shift.2=Nuclear Engine or another Nuclear Core. +tooltip.advancedrocketry.nuclearcore.alt.1=Vertical placement rules doesn't apply +tooltip.advancedrocketry.nuclearcore.alt.2=for Unmanned Vehicles (Gas Mission rockets) + +# Nuclear rocketengine +tooltip.advancedrocketry.nuclearmotor=§cPart of Rocket §6Allows planetary travel! +tooltip.advancedrocketry.nuclearmotor.shift.1=Uses §bWorking fluid§7 +tooltip.advancedrocketry.nuclearmotor.shift.2=Needs Nuclear Core directly above. +tooltip.advancedrocketry.nuclearmotor.alt.1=Check Fueling Station JEI-page + +# Bipropellant Engine +tooltip.advancedrocketry.bipropmotor=§cPart of Rocket +tooltip.advancedrocketry.bipropmotor.shift.1=Uses §bBipropellant Fuel§7 and §bOxidizer§7 +tooltip.advancedrocketry.bipropmotor.alt.1=Check Fueling Station JEI-page + +# Drill +tooltip.advancedrocketry.drill=§cPart of Rocket +tooltip.advancedrocketry.drill.shift.1=Lowers duration of §6Mining Missions§7 +tooltip.advancedrocketry.drill.shift.2=§bEffect stacks +tooltip.advancedrocketry.drill.alt.1=This rocket is built with Rocket Assembling Machine +tooltip.advancedrocketry.drill.alt.2=Requires a programmed Asteroid Chip + +# Gas Intake +tooltip.advancedrocketry.intake=§cPart of Rocket +tooltip.advancedrocketry.intake.shift.1=Lowers duration of §6Gas Missions§7 +tooltip.advancedrocketry.intake.shift.2=§bEffect stacks +tooltip.advancedrocketry.intake.alt.1=This rocket is built with Unmanned Vehicle Assembler +tooltip.advancedrocketry.intake.alt.2=Launched from Space Station orbiting a Gas giant + +# Seat +tooltip.advancedrocketry.seat=§cPart of rocket +tooltip.advancedrocketry.seat.shift.1=Adds a passenger slot to the rocket + +# Guidance Computer +tooltip.advancedrocketry.guidancecomputer=§cPart of Rocket +tooltip.advancedrocketry.guidancecomputer.shift.1=Insert a §cChip§7 or programmed §cLinker§7 +tooltip.advancedrocketry.guidancecomputer.alt.1=Remember to tell rocket which planet to target +tooltip.advancedrocketry.guidancecomputer.alt.2=when deploying Satellites or Space Station into orbit + +# Service Monitor +tooltip.advancedrocketry.servicemonitor=§cPart of Rocket +tooltip.advancedrocketry.servicemonitor.shift.1=Enables damage view +tooltip.advancedrocketry.servicemonitor.shift.2=in rocket GUI +tooltip.advancedrocketry.servicemonitor.alt.1=WIP +tooltip.advancedrocketry.servicemonitor.alt.2= + +# Docking Pad (landingPad) +tooltip.advancedrocketry.landingpad=Replace the launchpad’s center block with this +tooltip.advancedrocketry.landingpad.shift.1=§cLinker§7 can store this block's exact position (dimension-aware). +tooltip.advancedrocketry.landingpad.shift.2=Insert in §4Guidance Computer§7 to land here. +tooltip.advancedrocketry.landingpad.alt.1=Place a programmed Linker in the Docking Pad. +tooltip.advancedrocketry.landingpad.alt.2=Rockets launched from this pad will fly to the Linker’s saved coordinates (used for automation). +tooltip.advancedrocketry.landingpad.alt.3=if there is nothing in the rocket's guidance computer. + +# Launch Pad +tooltip.advancedrocketry.launchpad=Base for Launch Pad platform. +tooltip.advancedrocketry.launchpad.shift.1=Place Launch Pad blocks in a flat square. +tooltip.advancedrocketry.launchpad.shift.2=3x3, 4x4, 5x5, .... +tooltip.advancedrocketry.launchpad.alt.1=§bAdd Structure Tower (minimum 4 high, starting at same y as Launch Pad) +tooltip.advancedrocketry.launchpad.alt.2=§fRocket/Station Assembler will connect automatically + +# Structure Tower +tooltip.advancedrocketry.structuretower=Vertical support for the Launch Pad platform. +tooltip.advancedrocketry.structuretower.shift.1=Tower must be minimum 4 blocks. +tooltip.advancedrocketry.structuretower.shift.2=Bottom block must touch the Launch Pad. +tooltip.advancedrocketry.structuretower.alt.1=Main block for Unmanned Vehicle Assembler structure +tooltip.advancedrocketry.structuretower.alt.2=Check wiki for more info. + +# Terraformer +tooltip.advancedrocketry.terraformer=Terraform +tooltip.advancedrocketry.terraformer.shift.1=Terraform stuff +tooltip.advancedrocketry.terraformer.shift.2= +tooltip.advancedrocketry.terraformer.alt.1=Terraform stuff +tooltip.advancedrocketry.terraformer.alt.2= + +# Rocket Monitoring Station +tooltip.advancedrocketry.monitoringstation=§cInfrastructure +tooltip.advancedrocketry.monitoringstation.shift.1=Launch with Redstone Signal! +tooltip.advancedrocketry.monitoringstation.shift.2=§fLink to §4Rocket Assembler/Dockingpad§f or §4Rocket +tooltip.advancedrocketry.monitoringstation.alt.1=§bMissions becomes active when orbit reached! + +# Satellite Terminal +tooltip.advancedrocketry.satellitemonitor=Communicates with Satellites +tooltip.advancedrocketry.satellitemonitor.shift.1=Insert Satellite Chip +tooltip.advancedrocketry.satellitemonitor.shift.2=Download Data +tooltip.advancedrocketry.satellitemonitor.alt.1=§fTransfer and Auto-Download Data with Wireless Tranciever or Data Unit + +# Satellite Builder +tooltip.advancedrocketry.satellitebuilder=Assembles Satellites +tooltip.advancedrocketry.satellitebuilder.shift.1=Also Copy Chips/Remotes. +tooltip.advancedrocketry.satellitebuilder.shift.2=§bMust be on top of a Power Plug! +tooltip.advancedrocketry.satellitebuilder.alt.1=Insert chassis, Chip/Remote +tooltip.advancedrocketry.satellitebuilder.alt.2=core component + other components + + +### Infrastructure +## BlockARHatch + +# TileDataBus +tooltip.advancedrocketry.hatch.databus=Capacity: §62000 §7Data +tooltip.advancedrocketry.hatch.databus.shift.1=§bCan only hold one type of Data + +# TileSatelliteHatch +tooltip.advancedrocketry.hatch.satellite=§cPart of Rocket +tooltip.advancedrocketry.hatch.satellite.shift.1=Used to put payloads in orbit +tooltip.advancedrocketry.hatch.satellite.shift.2=Remember to set target planet for orbit! +tooltip.advancedrocketry.hatch.satellite.alt.1=§fUsed in §4Station Assembler§f to pack and store the Station + +# TileRocketUnloader +tooltip.advancedrocketry.hatch.item_unloader=§cInfrastructure +tooltip.advancedrocketry.hatch.item_unloader.shift.1=Emits redstone when empty +tooltip.advancedrocketry.hatch.item_unloader.alt.1=§fLink to §4Rocket Assembler/Dockingpad§f or §4Rocket +tooltip.advancedrocketry.hatch.item_unloader.alt.2=§fRockets landing here will auto-link to this. + +# TileRocketLoader +tooltip.advancedrocketry.hatch.item_loader=§cInfrastructure +tooltip.advancedrocketry.hatch.item_loader.shift.1=Emits redstone when full +tooltip.advancedrocketry.hatch.item_loader.alt.1=§fLink to §4Rocket Assembler/Dockingpad§f or §4Rocket +tooltip.advancedrocketry.hatch.item_loader.alt.2=§fRockets landing here will auto-link to this. + +# TileRocketFluidUnloader +tooltip.advancedrocketry.hatch.fluid_unloader=§cInfrastructure +tooltip.advancedrocketry.hatch.fluid_unloader.shift.1=Emits redstone when empty +tooltip.advancedrocketry.hatch.fluid_unloader.alt.1=§fLink to §4Rocket Assembler/Dockingpad§f or §4Rocket +tooltip.advancedrocketry.hatch.fluid_unloader.alt.2=§fRockets landing here will auto-link to this. + +# TileRocketFluidLoader +tooltip.advancedrocketry.hatch.fluid_loader=§cInfrastructure +tooltip.advancedrocketry.hatch.fluid_loader.shift.1=Emits redstone when full +tooltip.advancedrocketry.hatch.fluid_loader.alt.1=§fLink to §4Rocket Assembler/Dockingpad§f or §4Rocket +tooltip.advancedrocketry.hatch.fluid_loader.alt.2=§fRockets landing here will auto-link to this. + +# Guidance Computer Access +tooltip.advancedrocketry.hatch.gca=§cInfrastructure +tooltip.advancedrocketry.hatch.gca.shift.1=Emits redstone when empty +tooltip.advancedrocketry.hatch.gca.alt.1=§fLink to §4Rocket Assembler/Dockingpad§f or §4Rocket +tooltip.advancedrocketry.hatch.gca.alt.2=§fRockets landing here will auto-link to this. + +## /BlockARHatch + +# Fueling Station +tooltip.advancedrocketry.fuelingstation=§cInfrastructure +tooltip.advancedrocketry.fuelingstation.shift.1=Emits redstone when full +tooltip.advancedrocketry.fuelingstation.shift.2=if station has same fueltype. +tooltip.advancedrocketry.fuelingstation.alt.1=§fLink to §4Rocket Assembler/Dockingpad§f or §4Rocket +tooltip.advancedrocketry.fuelingstation.alt.2=§fRockets landing here will auto-link to this. + +# Service Station +tooltip.advancedrocketry.servicestation=§cInfrastructure +tooltip.advancedrocketry.servicestation.shift.1=Repair rocket +tooltip.advancedrocketry.servicestation.shift.2=§o(WIP) +tooltip.advancedrocketry.fuelingstation.alt.1=§fLink to §4Rocket Assembler/Dockingpad§f or §4Rocket + +## // Infrastructure + +# Pressurized Fluid Tank +tooltip.advancedrocketry.fluidtank.shift.1=§cConnects to tanks above or below to make a bigger tank + +# Wireless Transciever +tooltip.advancedrocketry.transceiver=Transfers §6Data +tooltip.advancedrocketry.transceiver.shift.1=Use §cLinker§7 to create Networks +tooltip.advancedrocketry.transceiver.shift.2=Supports multiple Tranceivers +tooltip.advancedrocketry.transceiver.alt.1=§fExtractmode toggles autodownload from Terminal +tooltip.advancedrocketry.transceiver.alt.2=(reinsert chip if stale) + +# Atmosphere Detector +tooltip.advancedrocketry.atmosphereDetector=Emits redstone based on Atmosphere +tooltip.advancedrocketry.atmosphereDetector.shift.1=Select wanted Atmosphere +tooltip.advancedrocketry.atmosphereDetector.shift.2=emits if the condition is true +tooltip.advancedrocketry.atmosphereDetector.alt.1=Can detect: air, vacuum, +tooltip.advancedrocketry.atmosphereDetector.alt.2=low O₂, No O₂, very hot and more. + +# Station Light +tooltip.advancedrocketry.circlelight=Always on +tooltip.advancedrocketry.circlelight.shift.1=Does not require +tooltip.advancedrocketry.circlelight.shift.2=Power or Redstone + +# Gas Charge Pad +tooltip.advancedrocketry.oxygencharger=Charges Space Suit O₂ and H₂ +tooltip.advancedrocketry.oxygencharger.shift.1=Stand on pad to refill +tooltip.advancedrocketry.oxygencharger.alt.1=Does not require Power + +# Docking Port +tooltip.advancedrocketry.dockingport=Marks a station module docking point +tooltip.advancedrocketry.dockingport.shift.1=On the station: set a unique “My ID” +tooltip.advancedrocketry.dockingport.shift.2=On the new module: set “Target ID” +tooltip.advancedrocketry.dockingport.alt.1=Build new module in Station Builder +tooltip.advancedrocketry.dockingport.alt.2=clamp faces must face each other + +# Pipe Seal +tooltip.advancedrocketry.pipeseal=Airtight holes! +tooltip.advancedrocketry.pipeseal.shift.1=Seal a 1×1 gap by framing it with this +tooltip.advancedrocketry.pipeseal.shift.2=§bRequires 4 blocks per hole +tooltip.advancedrocketry.pipeseal.alt.1=Allows pipes through while keeping O₂ in +tooltip.advancedrocketry.pipeseal.alt.2=Entities can pass through the opening + +# Planet Selector (full-screen) +tooltip.advancedrocketry.planetselector=Browse Spacebodies +tooltip.advancedrocketry.planetselector.shift.1=Opens full-screen planet UI. +tooltip.advancedrocketry.planetselector.shift.2=Browse systems, planets and moons +tooltip.advancedrocketry.planetselector.alt.1=Allows you to remotely set a +tooltip.advancedrocketry.planetselector.alt.2=planet destination for warp controller. + +# Holographic Planet Selector +tooltip.advancedrocketry.planetholoselector=Holographic Spacebody Display +tooltip.advancedrocketry.planetholoselector.shift.1=Makes holographs in-world +tooltip.advancedrocketry.planetholoselector.alt.1="Functions the as planet selector +tooltip.advancedrocketry.planetholoselector.alt.2=but with a 3D holographic display" + +# Orientation Controller +tooltip.advancedrocketry.orientationctrl=§cSpace Station Controller +tooltip.advancedrocketry.orientationctrl.shift.1=Customize Angular Velocity +tooltip.advancedrocketry.orientationctrl.alt.1=§bCosmetic only§7 + +# Gravity Controller +tooltip.advancedrocketry.gravityctrl=§cSpace Station Controller +tooltip.advancedrocketry.gravityctrl.shift.1=Artificial gravity! +tooltip.advancedrocketry.gravityctrl.alt.1=§bCosmetic only§7 +tooltip.advancedrocketry.gravityctrl.alt.2=Redstone control + +# Altitude Controller +tooltip.advancedrocketry.altitudectrl=§cSpace Station Controller +tooltip.advancedrocketry.altitudectrl.shift.1=Customize orbital height +tooltip.advancedrocketry.altitudectrl.alt.1=§bCosmetic only§7 +tooltip.advancedrocketry.altitudectrl.alt.2=Redstone control + +# Co2Scrubber +tooltip.advancedrocketry.scrubber=Place next to Oxygen Vent +tooltip.advancedrocketry.scrubber.shift.1=Reduces Oxygen use (max 2) +tooltip.advancedrocketry.scrubber.alt.1=Each scrubber halves O₂ use, increases Power use. +tooltip.advancedrocketry.scrubber.alt.2=With 2 Scrubbers Oxygen Vent won't use Oxygen. + +# Oxygen Vent +tooltip.advancedrocketry.oxygenvent=Creates breathable air in sealed rooms. +tooltip.advancedrocketry.oxygenvent.shift.1=Requires Power and Oxygen. +tooltip.advancedrocketry.oxygenvent.shift.2=Place inside enclosed area. +tooltip.advancedrocketry.oxygenvent.alt.1=Use CO2 Scrubber instead of oxygen. +tooltip.advancedrocketry.oxygenvent.alt.2=Range: %s blocks radius. + +# Airlock Door +tooltip.advancedrocketry.smallairlock=Airtight door! +tooltip.advancedrocketry.smallairlock.shift.1=Not airtight, leaks when open +tooltip.advancedrocketry.smallairlock.alt.1=Build a proper airlock +tooltip.advancedrocketry.smallairlock.alt.2=using 2 doors + +# Warp Controller +tooltip.advancedrocketry.warpcontroller=Turns the station into a §6Starship +tooltip.advancedrocketry.warpcontroller.shift.1=Place §4Warp Controller§7 + §4Warp Core§7 on a space station +tooltip.advancedrocketry.warpcontroller.shift.2=Warp between planets and solar systems +tooltip.advancedrocketry.warpcontroller.alt.1=UI shows location, destinations, and warp fuel +tooltip.advancedrocketry.warpcontroller.alt.2=(You made it this far! check wiki bro) + +# CarbonScrubberCartridge +tooltip.advancedrocketry.scrubbercart=Used in CO₂ Scrubber +tooltip.advancedrocketry.scrubbercart.shift.1=Purifies air while at cost of durability. +tooltip.advancedrocketry.atmanalyzer.alt.1=Should last more than 24h + +# Seal Detector +tooltip.advancedrocketry.sealdetector=Detects if a block is airtight +tooltip.advancedrocketry.sealdetector.shift.1=§fRight Click on block to use + +# Lens +tooltip.advancedrocketry.lens=§cPart of Observatory +tooltip.advancedrocketry.lens.shift.1=§bUse Holo-Projector! + +## SPACE SUIT + COMPONENTS + +# Suit Working Station +tooltip.advancedrocketry.suitworkingstation=Install/remove §5Space Suit Components +tooltip.advancedrocketry.suitworkingstation.shift.1=Works with Space Suit armor +tooltip.advancedrocketry.suitworkingstation.shift.2=(Helmet/Chest/Legs/Boots) +tooltip.advancedrocketry.suitworkingstation.alt.1=Does not require Power + +# Jetpack +tooltip.advancedrocketry.jetpack=§5Space Suit Component +tooltip.advancedrocketry.jetpack.shift.1=§dSlot: Chest§7 + +# AtmosphereAnalyzer +tooltip.advancedrocketry.atmanalyzer=§5Space Suit ComponentRight Click to check atmosphere. +tooltip.advancedrocketry.atmanalyzer.shift.1=§fRight Click to check atmosphere. +tooltip.advancedrocketry.atmanalyzer.shift.2=§dSlot: Helmet§7 +tooltip.advancedrocketry.atmanalyzer.alt.1=Breathable? Depends on atmosphere +tooltip.advancedrocketry.atmanalyzer.alt.2=Shows type and pressure + +# BeaconFinder +tooltip.advancedrocketry.beaconfinder=§5Space Suit Component +tooltip.advancedrocketry.beaconfinder.shift.1=§fShows a HUD arrow toward AR beacons in this dimension +tooltip.advancedrocketry.beaconfinder.shift.2=§dSlot: Helmet§7 +tooltip.advancedrocketry.beaconfinder.alt.1=Arrow offset is relative to your facing +tooltip.advancedrocketry.beaconfinder.alt.2=Works only in AR dimensions that have registered beacons. + +# PressureTank +tooltip.advancedrocketry.pressuretank.shift.1=§dSlot: Chest§7 +tooltip.advancedrocketry.pressuretank.alt.1=§fStores Oxygen for suit +tooltip.advancedrocketry.pressuretank.alt.2=§fStores Hydrogen for Jetpack + +## Item Upgrade +# 0 = Hover +tooltip.advancedrocketry.itemupgrade.0=§5Space Suit Component +tooltip.advancedrocketry.itemupgrade.0.shift.1=§fEnables Jetpack hover mode +tooltip.advancedrocketry.itemupgrade.0.shift.2=§dSlot: Helmet§7 +tooltip.advancedrocketry.itemupgrade.0.alt.1=Requires a Jetpack installed in the chestplate. +tooltip.advancedrocketry.itemupgrade.0.alt.2=Stacking has no additional effect. + +# 1 = Flight Speed Control Upgrade +tooltip.advancedrocketry.itemupgrade.1=§5Space Suit Component +tooltip.advancedrocketry.itemupgrade.1.shift.1=§fBoosts Jetpack flight speed +tooltip.advancedrocketry.itemupgrade.1.shift.2=§dSlot: Helmet§7 +tooltip.advancedrocketry.itemupgrade.1.alt.1=Requires a Jetpack installed in the chestplate. +tooltip.advancedrocketry.itemupgrade.1.alt.2=§bEffect Stacks! + +# 2 = Bionic Leg Upgrade (speed) +tooltip.advancedrocketry.itemupgrade.2=§5Space Suit Component +tooltip.advancedrocketry.itemupgrade.2.shift.1=§fLeg upgrade: increases walk speed +tooltip.advancedrocketry.itemupgrade.2.shift.2=§dSlot: Legs§7 +tooltip.advancedrocketry.itemupgrade.2.alt.1=Sprint to activate +tooltip.advancedrocketry.itemupgrade.2.alt.2=Stacks with multiple modules. + +# 3 = Padded Landing Boots Upgrade (no fall damage; config-aware) +tooltip.advancedrocketry.itemupgrade.3=§5Space Suit Component +tooltip.advancedrocketry.itemupgrade.3.shift.1=§fEliminates fall damage +tooltip.advancedrocketry.itemupgrade.3.shift.2=§dSlot: Feet§7 +tooltip.advancedrocketry.itemupgrade.3.alt.1= +tooltip.advancedrocketry.itemupgrade.3.alt.2=Stacking has no additional effect. + +# 4 = Antifog Visor Upgrade +tooltip.advancedrocketry.itemupgrade.4=§5Space Suit Component +tooltip.advancedrocketry.itemupgrade.4.shift.1=WIP if u know what this does contact me +tooltip.advancedrocketry.itemupgrade.4.shift.2=§dSlot: Helmet§7 +tooltip.advancedrocketry.itemupgrade.4.alt.1=See through fog on high pressure planets +tooltip.advancedrocketry.itemupgrade.4.alt.2=Stacking has no additional effect. + +# 5 = Earthbright Visor +tooltip.advancedrocketry.itemupgrade.5=§5Space Suit Component +tooltip.advancedrocketry.itemupgrade.5.shift.1=WIP if u know what this does contact me +tooltip.advancedrocketry.itemupgrade.5.shift.2=§dSlot: Helmet§7 +tooltip.advancedrocketry.itemupgrade.5.alt.1= +tooltip.advancedrocketry.itemupgrade.5.alt.2=Stacking has no additional effect. + +## Satellite Components +# Primary Function payloads +tooltip.advancedrocketry.satfunc.optical=§5Satellite Core Component +tooltip.advancedrocketry.satfunc.optical.shift.1=§bCollects Distance Data§7 +tooltip.advancedrocketry.satfunc.optical.shift.2=§oDownload Data in Satellite Terminal +tooltip.advancedrocketry.satfunc.optical.alt.1=Combine with Satellite Chip +tooltip.advancedrocketry.satfunc.optical.alt.2=when assembling + +tooltip.advancedrocketry.satfunc.composition=§5Satellite Core Component +tooltip.advancedrocketry.satfunc.composition.shift.1=§bCollects Composition Data§7 +tooltip.advancedrocketry.satfunc.composition.shift.2=§oDownload data in Satellite Terminal +tooltip.advancedrocketry.satfunc.composition.alt.1=Combine with Satellite Chip +tooltip.advancedrocketry.satfunc.composition.alt.2=when assembling + +tooltip.advancedrocketry.satfunc.mass=§5Satellite Core Component +tooltip.advancedrocketry.satfunc.mass.shift.1=§bCollects Mass Data§7 +tooltip.advancedrocketry.satfunc.mass.shift.2=§oDownload data in Satellite Terminal +tooltip.advancedrocketry.satfunc.mass.alt.1=Combine with Satellite Chip +tooltip.advancedrocketry.satfunc.mass.alt.2=when assembling + +tooltip.advancedrocketry.satfunc.microwave=§5Satellite Core Component +tooltip.advancedrocketry.satfunc.microwave.shift.1=§bGenerates Power in Space§7 +tooltip.advancedrocketry.satfunc.microwave.shift.2=§oNeeds Microwave Receiver (5x5 Multiblock) +tooltip.advancedrocketry.satfunc.microwave.alt.1=Combine with Satellite Chip +tooltip.advancedrocketry.satfunc.microwave.alt.2=when assembling + +tooltip.advancedrocketry.satfunc.oremapping=§5Satellite Core Component +tooltip.advancedrocketry.satfunc.oremapping.shift.1=§bScans the planet for Ore§7 +tooltip.advancedrocketry.satfunc.oremapping.alt.1=Combine with Ore Scanner +tooltip.advancedrocketry.satfunc.oremapping.alt.2=when assembling + +tooltip.advancedrocketry.satfunc.biomechanger=§5Satellite Core Component +tooltip.advancedrocketry.satfunc.biomechanger.shift.1=§bAdjusts biomes§7 +tooltip.advancedrocketry.satfunc.biomechanger.alt.1=Combine with Biome Changer Remote +tooltip.advancedrocketry.satfunc.biomechanger.alt.2=when assembling + +tooltip.advancedrocketry.satfunc.weather=§5Satellite Core Component +tooltip.advancedrocketry.satfunc.weather.shift.1=§bDoes some weather stuff! +tooltip.advancedrocketry.satfunc.weather.alt.1=Combine with Weather Remote +tooltip.advancedrocketry.satfunc.weather.alt.2=when assembling + +# Power Sources +tooltip.advancedrocketry.satpower.0=§5Satellite Component +tooltip.advancedrocketry.satpower.0.shift.1=§fGenerates §c4 §fRF/t§7 +tooltip.advancedrocketry.satpower.0.shift.2=§oSatellites requires atleast 1 powergen + +tooltip.advancedrocketry.satpower.1=§5Satellite Component +tooltip.advancedrocketry.satpower.1.shift.1=§fGenerates §c40 §fRF/t§7 +tooltip.advancedrocketry.satpower.1.shift.2=§oSatellites requires atleast 1 powergen + +# LibVulpes Batteries +tooltip.libvulpes.battery.0=§5Satellite Component§7 +tooltip.libvulpes.battery.0.shift.1=Increases Powerstorage +tooltip.libvulpes.battery.0.shift.2=§fCapacity: §c10.000 §fRF§7 + +tooltip.libvulpes.battery.1=§5Satellite Component +tooltip.libvulpes.battery.1.shift.1=Increases Powerstorage +tooltip.libvulpes.battery.1.shift.2=§fCapacity: §c40.000 §fRF§7 + +# Data Unit +tooltip.advancedrocketry.itemdataunit.shift.1=§fIncrease Satellite Data Storage by 1000 +tooltip.advancedrocketry.itemdataunit.alt.1=§fWorks as Datastorage in inventory aswell + +## Chips / remotes +# Asteroid Chip +tooltip.advancedrocketry.asteroidchip.shift.1=§bUsed for Mining Missions§7 +tooltip.advancedrocketry.asteroidchip.shift.2=§fProgram in §cObservatory +tooltip.advancedrocketry.asteroidchip.alt.1=§4Insert programmed Chip in Guidance Computer§7 + +# Station Chip +tooltip.advancedrocketry.stationchip=§bMake Backups! +tooltip.advancedrocketry.stationchip.shift.1=§fProgram in Space Station Assembler +tooltip.advancedrocketry.stationchip.alt.1=§4Insert programmed Chip in Guidance Computer§7 + +# Planet Chip +tooltip.advancedrocketry.planetidchip.shift.1=§fInsert Chip in §4Guidance Computer§7 +tooltip.advancedrocketry.planetidchip.shift.2=§fSet destination in Rocket GUI to program it. +tooltip.advancedrocketry.planetidchip.alt.1=§4Doublecheck that this is programmed before Launch! + +# Satellite Chip +tooltip.advancedrocketry.satidchip=§bMake Backups! +tooltip.advancedrocketry.satidchip.shift.1=§fStores a satellite’s ID. +tooltip.advancedrocketry.satidchip.alt.1=§4Use in Satellite Monitor to link or in the Microwave Receiver Multiblock (Input hatch). §8 (Planet: resolves if put in Terminal) + +# Elevator Chip +tooltip.advancedrocketry.elevatorchip=Space Elevator Chip +tooltip.advancedrocketry.elevatorchip.shift.1=§fLinks an elevator pad/destination. + + +## Multiblocks + +# Black Hole Generator +tooltip.advancedrocketry.blackholegen=Generates Power from compressed mass +tooltip.advancedrocketry.blackholegen.shift.1=§bUse Holo-Projector! + +# Microwave Receiver +tooltip.advancedrocketry.microwavereceiver=Receives Power from Solar Satellites +tooltip.advancedrocketry.microwavereceiver.shift.1=5x5 Multiblock +tooltip.advancedrocketry.microwavereceiver.shift.2=§bUse Holo-Projector! +tooltip.advancedrocketry.microwavereceiver.alt.1=§fSolar Satellites are built with §bMicrowave Transmitter§f and §bSatellite Chip +tooltip.advancedrocketry.microwavereceiver.alt.2=§8RF/t = (sum Satellites RF/t) * (2 * AtmospheredensityFactor) + +# Solar Panel (part of Microwave Receiver) +tooltip.advancedrocketry.solarpanel=§cPart of Multiblock +tooltip.advancedrocketry.solarpanel.shift.1=5x5 Multiblock +tooltip.advancedrocketry.solarpanel.shift.2=§o§f(Microwave Receiver) +tooltip.advancedrocketry.solarpanel.shift.3=§bUse Holo-Projector! + +# Solar Array Controller +tooltip.advancedrocketry.solararray=Generates Power from sunlight +tooltip.advancedrocketry.solararray.shift.1=Requires 63x Solar Array Panels +tooltip.advancedrocketry.solararray.shift.2=§bUse Holo-Projector! +tooltip.advancedrocketry.solararray.alt.1= + +# Solar Array Panel +tooltip.advancedrocketry.solararraypanel=§cPart of Multiblock +tooltip.advancedrocketry.solararraypanel.shift.1=Requires 63x Solar Array Panels and Controller +tooltip.advancedrocketry.solararraypanel.shift.2=§bUse Holo-Projector! +tooltip.advancedrocketry.solararray.alt.1= + +# Solar Generator +tooltip.advancedrocketry.solargenerator=Basic Solar Panel +tooltip.advancedrocketry.solargenerator.shift.1=§fGenerates §c2 §fRF/t§7 + +# Arc Furnace +tooltip.advancedrocketry.arcfurnace=Smelts at extreme temperatures +tooltip.advancedrocketry.arcfurnace.shift.1=§bUse Holo-Projector! + +# Rolling Machine +tooltip.advancedrocketry.rollingmachine=Rolls plates and foils +tooltip.advancedrocketry.rollingmachine.shift.1=§bUse Holo-Projector! + +# Lathe +tooltip.advancedrocketry.lathe=Turns rods and shafts +tooltip.advancedrocketry.lathe.shift.1=§bUse Holo-Projector! + +# Crystallizer +tooltip.advancedrocketry.crystallizer=Grows high-purity crystals +tooltip.advancedrocketry.crystallizer.shift.1=§bUse Holo-Projector! + +# Cutting Machine +tooltip.advancedrocketry.cuttingmachine=Precision cutting of materials +tooltip.advancedrocketry.cuttingmachine.shift.1=§bUse Holo-Projector! + +# Precision Assembler +tooltip.advancedrocketry.precisionassembler=Automates complex assembly +tooltip.advancedrocketry.precisionassembler.shift.1=§bUse Holo-Projector! + +# Electrolyser +tooltip.advancedrocketry.electrolyser=Splits compounds via electrolysis +tooltip.advancedrocketry.electrolyser.shift.1=§bUse Holo-Projector! + +# Chemical Reactor +tooltip.advancedrocketry.chemreactor=Processes chemical reactions +tooltip.advancedrocketry.chemreactor.shift.1=§bUse Holo-Projector! + +# Precision Laser Etcher +tooltip.advancedrocketry.precisionlaseretcher=Laser-etches fine circuits +tooltip.advancedrocketry.precisionlaseretcher.shift.1=§bUse Holo-Projector! + +# Observatory +tooltip.advancedrocketry.observatory=Analyzes celestial bodies +tooltip.advancedrocketry.observatory.shift.1=§fUsed for §6Mining Missions +tooltip.advancedrocketry.observatory.shift.2=§bUse Holo-Projector! +tooltip.advancedrocketry.observatory.alt.1=§fInsert §cAsteroid Chip + + +# Planet Analyser +tooltip.advancedrocketry.planetanalyser=Processes planet scan data +tooltip.advancedrocketry.planetanalyser.shift.1=§bUse Holo-Projector! + +# Centrifuge +tooltip.advancedrocketry.centrifuge=Separates by density +tooltip.advancedrocketry.centrifuge.shift.1=§bUse Holo-Projector! + +# Warp Core +tooltip.advancedrocketry.warpcore=Core for §6Starship +tooltip.advancedrocketry.warpcore.shift.1=§bUse Holo-Projector! + +# Beacon +tooltip.advancedrocketry.beacon=Long-range signal beacon +tooltip.advancedrocketry.beacon.shift.1=§bUse Holo-Projector! + +# Biome Scanner +tooltip.advancedrocketry.biomescan=Scans planetary biomes +tooltip.advancedrocketry.biomescan.shift.1=§bUse Holo-Projector! + +# Railgun +tooltip.advancedrocketry.railgun=Shoots Items into space +tooltip.advancedrocketry.railgun.shift.1=§bUse Holo-Projector! +tooltip.advancedrocketry.railgun.alt.1="The railgun is not powerful enough to transport item stacks between planets and its range is limited to bodies within the same system" + +# Space Elevator Controller +tooltip.advancedrocketry.spaceelevatorctrl=Controls the Space Elevator +tooltip.advancedrocketry.spaceelevatorctrl.shift.1=§bUse Holo-Projector! + +# Atmosphere Terraformer +tooltip.advancedrocketry.atmosterraformer=Changes Atmospheric pressure on an entire planet planet +tooltip.advancedrocketry.atmosterraformer.shift.1=§bUse Holo-Projector! +tooltip.advancedrocketry.atmosterraformer.alt.1=Increase and decrease the atmosphere pressure by using connected §cBiome changing remote. + +# Area Gravity Controller +tooltip.advancedrocketry.gravitymachine=Manipulates Gravity +tooltip.advancedrocketry.gravitymachine.shift.1=§fCan also affect the direction of Gravity +tooltip.advancedrocketry.gravitymachine.shift.2=§bUse Holo-Projector! + +# Orbital Last Drill +tooltip.advancedrocketry.spacelaser=§cSpace Station Multiblock +tooltip.advancedrocketry.spacelaser.shift.1=§bUse Holo-Projector! + +# Force Field Projector +tooltip.advancedrocketry.forcefieldprojector=Projeccts up to 32 blocks away! +tooltip.advancedrocketry.forcefieldprojector.shift.1=Activate with Redstone + +# Vacuum Laser +tooltip.advancedrocketry.vacuumlaser=§cPart of Multiblock +tooltip.advancedrocketry.vacuumlaser.shift.1=§bUse Holo-Projector! + + +# Pump +tooltip.advancedrocketry.pump=Searches for fluid directly below +tooltip.advancedrocketry.pump.shift.1=§cPulls from the connected pool within 64 blocks. +tooltip.advancedrocketry.pump.alt.1=§fAutoejects to nearby tank +tooltip.advancedrocketry.pump.alt.2=Redstone turns it off + +# Parts for Multiblock +tooltip.advancedrocketry.concrete=§cPart of Multiblock +tooltip.advancedrocketry.concrete.shift.1=§bUse Holo-Projector! +tooltip.advancedrocketry.blastbrick=§cPart of Multiblock +tooltip.advancedrocketry.blastbrick.shift.1=§bUse Holo-Projector! +tooltip.advancedrocketry.qcrucible=§cPart of Multiblock +tooltip.advancedrocketry.qcrucible.shift.1=§bUse Holo-Projector! +tooltip.advancedrocketry.sawblade=§cPart of Multiblock +tooltip.advancedrocketry.sawblade.shift.1=§bUse Holo-Projector! + +## Assemblers +# Rocket Assembler +tooltip.advancedrocketry.rocketassembler=§cBuilds Rockets +tooltip.advancedrocketry.rocketassembler.shift.1=§bRequires Launch Pad + Structure Tower Structure +tooltip.advancedrocketry.rocketassembler.shift.2=§fConnecting all infrastructure to this lets them autoconnect to Rocket on Pad +tooltip.advancedrocketry.rocketassembler.alt.1=§fPlace this 1 block higher than Launch Pad, connecting lower corners and facing opposite of the Launch Pad square + +# Station Assembler +tooltip.advancedrocketry.stationassembler=§cPacks Space Stations down for Launch! +tooltip.advancedrocketry.stationassembler.shift.1=§bRequires Launch Pad + Structure Tower Structure +tooltip.advancedrocketry.stationassembler.alt.1=§fPlace this 1 block higher than Launch Pad, connecting lower corners and facing opposite of the Launch Pad square + +# Packet Station +tooltip.advancedrocketry.packedstructure=Insert in §cSatellite Bay§7 to put in Orbit! +tooltip.advancedrocketry.packedstructure.shift.1=§eRemember to tell Rocket what planet it should deplay payload into Orbit! + +# Deployable Rocket Assembler +tooltip.advancedrocketry.deployablerocketassembler=§cBuilds Rockets on Space Stations +tooltip.advancedrocketry.deployablerocketassembler.shift.1=§bRequires Structure Tower blocks +tooltip.advancedrocketry.deployablerocketassembler.shift.2=§fUsed for §6Gas Missions§7 +tooltip.advancedrocketry.deployablerocketassembler.alt.1=§fPlace this in the middle of upside down T facing outwards in space, then a horizontal support outwards from the top of tower. +tooltip.advancedrocketry.deployablerocketassembler.alt.2=Check wiki if unsure! From d7857cf27a9d85d6e7cfa5da5c3ccd81c615edad Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:27:47 +0100 Subject: [PATCH 221/274] Refactor item information display in ItemData --- .../java/zmaster587/advancedRocketry/item/ItemData.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemData.java b/src/main/java/zmaster587/advancedRocketry/item/ItemData.java index ccd62a615..4de0f0af9 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemData.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemData.java @@ -98,18 +98,17 @@ public void addInformation(@Nonnull ItemStack stack, @Nullable World world, List DataStorage data = getDataStorage(stack); - // 1) Type: + // Type: list.add(TextFormatting.DARK_PURPLE + "Space Suit Component"); String typeText = net.minecraft.client.resources.I18n.format(data.getDataType().toString()); list.add(net.minecraft.util.text.TextFormatting.WHITE + "Type: " + typeText); - - // 2) §fData stored: §6 §f/§6 + // Data: list.add(net.minecraft.util.text.TextFormatting.WHITE + "Data stored: " + net.minecraft.util.text.TextFormatting.GOLD + data.getData() + net.minecraft.util.text.TextFormatting.WHITE + " / " + net.minecraft.util.text.TextFormatting.GOLD + data.getMaxData()); - // 3) Hold Shift for more info + // Hold Shift for more info if (net.minecraft.client.gui.GuiScreen.isShiftKeyDown()) { list.add(net.minecraft.util.text.TextFormatting.GRAY + net.minecraft.client.resources.I18n.format("tooltip.advancedrocketry.itemdataunit.shift.1")); @@ -119,5 +118,4 @@ public void addInformation(@Nonnull ItemStack stack, @Nullable World world, List net.minecraft.client.resources.I18n.format("tooltip.advancedrocketry.hold_shift")); } } - } From fef59f59e2dc332901e5151e7ea33b49a48e836b Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:28:49 +0100 Subject: [PATCH 222/274] Clean up renderScreen method in ItemPressureTank --- .../advancedRocketry/item/components/ItemPressureTank.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/components/ItemPressureTank.java b/src/main/java/zmaster587/advancedRocketry/item/components/ItemPressureTank.java index 39007f1b0..163ace625 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/components/ItemPressureTank.java +++ b/src/main/java/zmaster587/advancedRocketry/item/components/ItemPressureTank.java @@ -117,14 +117,11 @@ public boolean isAllowedInSlot(@Nonnull ItemStack stack, EntityEquipmentSlot slo @SideOnly(Side.CLIENT) public void renderScreen(@Nonnull ItemStack componentStack, List modules, RenderGameOverlayEvent event, Gui gui) { // TODO Auto-generated method stub - } - - + @Override public ICapabilityProvider initCapabilities(@Nonnull ItemStack stack, NBTTagCompound nbt) { return new TankCapabilityItemStack(stack, getCapacity(stack)); } - } From a1df6d81494128859bc77ecdc54b37f52c66f4d6 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:30:36 +0100 Subject: [PATCH 223/274] Reorganize imports and clean up BlockTransciever --- .../advancedRocketry/block/BlockTransciever.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java b/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java index a7a966723..9eb0d0f61 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockTransciever.java @@ -1,7 +1,5 @@ package zmaster587.advancedRocketry.block; -import javax.annotation.Nonnull; - import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.IBlockState; import net.minecraft.client.util.ITooltipFlag; @@ -21,13 +19,10 @@ import zmaster587.libVulpes.block.BlockTile; import zmaster587.advancedRocketry.client.TooltipInjector; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; - - - - public class BlockTransciever extends BlockTile { public static final PropertyDirection FACING = PropertyDirection.create("facing"); @@ -75,8 +70,6 @@ public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, Bloc public BlockRenderLayer getBlockLayer() { return BlockRenderLayer.CUTOUT_MIPPED; } - // If this still errors in your mappings, rename the method to: - // public BlockRenderLayer getRenderLayer() { return BlockRenderLayer.CUTOUT_MIPPED; } @Override protected BlockStateContainer createBlockState() { From 9a91ffe48312fc1ed19094d7a74fe175cf1f49bc Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:32:14 +0100 Subject: [PATCH 224/274] Refactor ItemBlockFluidTank by removing imports Removed unused imports and cleaned up comments. --- .../advancedRocketry/item/ItemBlockFluidTank.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java b/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java index 4b19ff280..2f05015fd 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemBlockFluidTank.java @@ -24,15 +24,9 @@ import zmaster587.advancedRocketry.api.ARConfiguration; import zmaster587.advancedRocketry.tile.TileFluidTank; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; - import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; - -import org.lwjgl.input.Keyboard; - import java.util.List; public class ItemBlockFluidTank extends ItemBlock { @@ -64,7 +58,7 @@ public void addInformation(@Nonnull ItemStack stack, @Nullable World world, List list.add("Fluid: " + fluidName); list.add("Level: " + amount + "/" + capMb + " mB"); - // --- SHIFT for more info (adds two short lines) --- + // --- SHIFT for more info --- if (GuiScreen.isShiftKeyDown()) { list.add(TextFormatting.GRAY + I18n.format("tooltip.advancedrocketry.fluidtank.shift.1")); } else if (I18n.hasKey("tooltip.advancedrocketry.hold_shift")) { @@ -95,7 +89,6 @@ public boolean placeBlockAt(@Nonnull ItemStack stack, EntityPlayer player, World return true; } - public void fill(@Nonnull ItemStack stack, FluidStack fluid) { NBTTagCompound nbt; FluidTank tank = new FluidTank(getCapMb()); From 62c87d41d597b49accbed701ce01a3b9774313ea Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:39:04 +0100 Subject: [PATCH 225/274] Remove unnecessary blank lines in BlockForceFieldProjector --- .../advancedRocketry/block/BlockForceFieldProjector.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockForceFieldProjector.java b/src/main/java/zmaster587/advancedRocketry/block/BlockForceFieldProjector.java index 513c5e741..19405aa88 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockForceFieldProjector.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockForceFieldProjector.java @@ -1,7 +1,6 @@ package zmaster587.advancedRocketry.block; import java.util.List; - import javax.annotation.Nullable; import net.minecraft.block.material.Material; @@ -48,5 +47,4 @@ public void addInformation(ItemStack stack, @Nullable World world, List int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.forcefieldprojector", insertAt); } - } From f0344b9e2d6804c0ec579fb50902ace8fe0af47b Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:40:16 +0100 Subject: [PATCH 226/274] Fix formatting in BlockSolarGenerator.java From 8e4dd413e458080adcb4b9346e586cac9161c7de Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:42:02 +0100 Subject: [PATCH 227/274] Fix formatting in BlockNuclearCore.java From 17a38342c21483e5191c7b7d34652b68b114e362 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:43:06 +0100 Subject: [PATCH 228/274] Refactor comment for visual tag generation --- .../java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java b/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java index d2fbad2d1..2c2ee55ac 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemAsteroidChip.java @@ -113,7 +113,7 @@ public void addInformation(@Nonnull ItemStack stack, World world, List l final long disp = makeDisplayId(id, type); final String hex = Long.toUnsignedString(disp, 16).toUpperCase(); - // Fixed-length visual tag (avoid lookalikes by using N=6 chars) + // Fixed-length visual tag final int N = 6; final String shortHex = (hex.length() > N) ? hex.substring(hex.length() - N) : hex; From 9fc62c3b9009109bef298240f76009a448068dc9 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:43:53 +0100 Subject: [PATCH 229/274] Fix missing newline at end of ItemPlanetIdentificationChip.java From 16dae64ae805795275e95eda41968aaec84f780f Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:44:32 +0100 Subject: [PATCH 230/274] Fix formatting issue in BlockRocketMotor.java From 546755d87c412652f1fea449cdde498b5a11408e Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:45:16 +0100 Subject: [PATCH 231/274] Add newline at end of BlockBipropellantRocketMotor.java Fix missing newline at end of file. From 3801a2395b57b20c1e2b3170dca865a8a55f1b0a Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:46:17 +0100 Subject: [PATCH 232/274] Add newline at end of Co2ScrubberWrapper.java Added a newline at the end of the file for consistency. From 5c73fb7502cc9b5d216ec04ec4ea0263d7d99379 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:46:39 +0100 Subject: [PATCH 233/274] Fix missing newline at end of Co2ScrubberRecipeMaker.java Added a newline at the end of the file. From dcc99e3a78a616be94b2aacf228e85ed3d0dee98 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:47:08 +0100 Subject: [PATCH 234/274] Fix recipe validation logic in Co2ScrubberRecipeHandler From 0db3f06d946771aa15bb44713393bb80b6895806 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:47:37 +0100 Subject: [PATCH 235/274] Remove commented code and clean up formatting --- .../integration/jei/co2scrubber/Co2ScrubberCategory.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberCategory.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberCategory.java index 6aac19c5c..298b201bc 100644 --- a/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberCategory.java +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/co2scrubber/Co2ScrubberCategory.java @@ -17,7 +17,6 @@ public class Co2ScrubberCategory implements IRecipeCategory private final IDrawable icon; private final IDrawable slot; - // Compact like your fueling station: 150x40 public Co2ScrubberCategory(IGuiHelper gui) { this.bg = gui.createBlankDrawable(150, 40); this.icon = gui.createDrawableIngredient(new ItemStack(AdvancedRocketryBlocks.blockCO2Scrubber)); @@ -43,7 +42,6 @@ public void setRecipe(IRecipeLayout layout, Co2ScrubberWrapper wrapper, IIngredi items.set(1, new ItemStack(AdvancedRocketryBlocks.blockOxygenVent)); } - @Override public void drawExtras(Minecraft mc) { // Draw the slot frame behind the cartridge From d5b68fb13043a16e8cae12faae34fa78f760b880 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:48:35 +0100 Subject: [PATCH 236/274] Add newline at end of BlockPressurizedFluidTank.java Fix formatting by adding a newline at the end of the file. From 40fe80340951f468158ac54b567c8fc197ff6a44 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:49:35 +0100 Subject: [PATCH 237/274] Add newline at end of BlockTileRedstoneEmitter.java Fix formatting by adding a newline at the end of the file. From ab92fedc20c5a1e50ca6f77b04fd4e50c4a1bb85 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:50:30 +0100 Subject: [PATCH 238/274] Define supported data types in MultiData Add supported data types for MultiData class --- .../advancedRocketry/world/util/MultiData.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/world/util/MultiData.java b/src/main/java/zmaster587/advancedRocketry/world/util/MultiData.java index f523f032d..27b4178d5 100644 --- a/src/main/java/zmaster587/advancedRocketry/world/util/MultiData.java +++ b/src/main/java/zmaster587/advancedRocketry/world/util/MultiData.java @@ -19,6 +19,14 @@ public MultiData() { reset(); } + private static final java.util.EnumSet SUPPORTED_TYPES = + java.util.EnumSet.of( + DataStorage.DataType.COMPOSITION, + DataStorage.DataType.MASS, + DataStorage.DataType.DISTANCE + ); + + public void reset() { for (DataStorage.DataType type : DataStorage.DataType.values()) { if (type != DataStorage.DataType.UNDEFINED) @@ -91,4 +99,4 @@ public void readFromNBT(NBTTagCompound nbt) { } } } -} \ No newline at end of file +} From 1ff2944a528d3b068ec395131942834273901c06 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:51:49 +0100 Subject: [PATCH 239/274] Clean up BlockLinkedHorizontalTexture.java Remove unnecessary blank lines and fix formatting. --- .../advancedRocketry/block/BlockLinkedHorizontalTexture.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockLinkedHorizontalTexture.java b/src/main/java/zmaster587/advancedRocketry/block/BlockLinkedHorizontalTexture.java index 5c5e574ba..aee2caf69 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockLinkedHorizontalTexture.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockLinkedHorizontalTexture.java @@ -135,5 +135,4 @@ private static boolean isAltDown() { return false; } } - } From d9c8bbe3f0bf8b014aa30fd0e27b455ee09bbe32 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:52:42 +0100 Subject: [PATCH 240/274] Remove unnecessary comment in FuelingStationWrapper --- .../integration/jei/fuelingStation/FuelingStationWrapper.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationWrapper.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationWrapper.java index 2f0af02ef..2c5811be2 100644 --- a/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationWrapper.java +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationWrapper.java @@ -84,7 +84,6 @@ public ItemStack getRoleTankStack() { } } - // keep this helper; category uses it conditionally public ItemStack getFilledContainer() { ItemStack is = net.minecraftforge.fluids.FluidUtil.getFilledBucket(fluid); return is == null ? ItemStack.EMPTY : is; From 6fedd10b235ae8be274853e154a826537d4a36de Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:53:10 +0100 Subject: [PATCH 241/274] Remove commented code in FuelingStationRecipeMaker --- .../jei/fuelingStation/FuelingStationRecipeMaker.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationRecipeMaker.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationRecipeMaker.java index 76bc797ec..ab6af1c14 100644 --- a/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationRecipeMaker.java +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationRecipeMaker.java @@ -35,7 +35,6 @@ private static void add(List list, } } - // Optional: keep this to match your existing makers public static List getMachineRecipes(IJeiHelpers helpers, Class ignored) { return getRecipes(helpers); } From 24304a8ea87bbe18d703358f7a6198b71188111b Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:53:28 +0100 Subject: [PATCH 242/274] Add newline at end of FuelingStationRecipeHandler.java Fix formatting by adding a newline at the end of the file. From 6f4c16c2567fd92d1d0752f28f93679a34b489e0 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:54:06 +0100 Subject: [PATCH 243/274] Remove commented-out code in drawExtras method --- .../jei/fuelingStation/FuelingStationCategory.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationCategory.java b/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationCategory.java index 1124851b1..240586afe 100644 --- a/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationCategory.java +++ b/src/main/java/zmaster587/advancedRocketry/integration/jei/fuelingStation/FuelingStationCategory.java @@ -90,9 +90,8 @@ public void setRecipe(IRecipeLayout layout, FuelingStationWrapper wrapper, IIngr @Override public void drawExtras(Minecraft mc) { - // Draw tank bezel and slot frames so it looks like the real GUI - tankFrame.draw(mc, 27, 2); // 14x54 bezel - slotFrame.draw(mc, 45, 6); // bucket slot + tankFrame.draw(mc, 27, 2); + slotFrame.draw(mc, 45, 6); } } From f5e1a476bf595cfa2a53cd58788c30b90e0be1ad Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:54:52 +0100 Subject: [PATCH 244/274] Add newline at end of BlockLandingPad.java Fix missing newline at end of file in BlockLandingPad.java From 75f362129dd30e8b820bba88262ccd47992b1dc4 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:55:25 +0100 Subject: [PATCH 245/274] Fix formatting and add newline at end of file From 8c41706f08b218937460f98f30877a0228a72913 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:55:55 +0100 Subject: [PATCH 246/274] Fix formatting issue in ItemSealDetector.java From dc592bbea6a8281cd797549f1cb0138c3004d039 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:57:31 +0100 Subject: [PATCH 247/274] Add tooltip support to BlockDoor2 --- .../java/zmaster587/advancedRocketry/block/BlockDoor2.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockDoor2.java b/src/main/java/zmaster587/advancedRocketry/block/BlockDoor2.java index e6012eb75..f02831f46 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockDoor2.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockDoor2.java @@ -3,6 +3,7 @@ import net.minecraft.block.BlockDoor; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; import net.minecraft.item.Item; @@ -14,9 +15,13 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.advancedRocketry.api.AdvancedRocketryItems; +import zmaster587.advancedRocketry.client.TooltipInjector; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import javax.annotation.ParametersAreNullableByDefault; + +import java.util.List; import java.util.Random; public class BlockDoor2 extends BlockDoor { @@ -45,5 +50,5 @@ public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ) { return false; - } + } } From c31bb9ba76a1360a780a9be2dbe39f7855bb3c1c Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:57:59 +0100 Subject: [PATCH 248/274] Fix formatting and remove unnecessary line --- src/main/java/zmaster587/advancedRocketry/block/BlockDoor2.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockDoor2.java b/src/main/java/zmaster587/advancedRocketry/block/BlockDoor2.java index f02831f46..cd569c4cf 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockDoor2.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockDoor2.java @@ -37,7 +37,6 @@ public ItemStack getItem(World worldIn, BlockPos pos, IBlockState state) { return new ItemStack(AdvancedRocketryItems.itemSmallAirlockDoor); } - @Override @Nonnull public Item getItemDropped(IBlockState state, Random rand, int fortune) { From fe1d65223a95d59cb7afb6fee9828c90434209a0 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:58:49 +0100 Subject: [PATCH 249/274] Fix formatting and remove unnecessary newline --- .../zmaster587/advancedRocketry/block/BlockWarpController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockWarpController.java b/src/main/java/zmaster587/advancedRocketry/block/BlockWarpController.java index 227058aa7..016e09722 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockWarpController.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockWarpController.java @@ -16,7 +16,6 @@ import zmaster587.libVulpes.block.BlockTile; import java.util.List; - import javax.annotation.Nonnull; import javax.annotation.Nullable; From 71513392f52e4efbcfade5f1db7a9bbdb66098b3 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 08:59:41 +0100 Subject: [PATCH 250/274] Fix formatting and remove unnecessary whitespace --- .../zmaster587/advancedRocketry/block/BlockTileTerraformer.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockTileTerraformer.java b/src/main/java/zmaster587/advancedRocketry/block/BlockTileTerraformer.java index 55f038c9a..e4967cba4 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockTileTerraformer.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockTileTerraformer.java @@ -37,7 +37,6 @@ import zmaster587.libVulpes.util.IAdjBlockUpdate; import java.util.List; - import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -177,5 +176,4 @@ public void addInformation(ItemStack stack, @Nullable World world, List int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.terraformer", insertAt); } - } From e5cd6910d555992e66cf5fee5c154ed18734b592 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:00:21 +0100 Subject: [PATCH 251/274] Remove extra newline in BlockSeal.java --- src/main/java/zmaster587/advancedRocketry/block/BlockSeal.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockSeal.java b/src/main/java/zmaster587/advancedRocketry/block/BlockSeal.java index f19828940..a34786b89 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockSeal.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockSeal.java @@ -209,5 +209,4 @@ public void addInformation(ItemStack stack, @Nullable World world, List int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.pipeseal", insertAt); } - } From ca13e7e8eb9657b33e1c23adfdc4af8ae301e5bd Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:01:22 +0100 Subject: [PATCH 252/274] Fix missing newline at end of ItemBiomeChanger.java From be0e7e72f470535be4580b00d78efb6035e4cf85 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:02:13 +0100 Subject: [PATCH 253/274] Remove unnecessary newline at end of BlockSuitWorkstation.java --- .../zmaster587/advancedRocketry/block/BlockSuitWorkstation.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockSuitWorkstation.java b/src/main/java/zmaster587/advancedRocketry/block/BlockSuitWorkstation.java index 84cca8f0e..cea44cc89 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockSuitWorkstation.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockSuitWorkstation.java @@ -69,5 +69,4 @@ public void addInformation(ItemStack stack, @Nullable World world, List int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.suitworkingstation", insertAt); } - } From c7ed0e5b5e7f6f1b51eff419bddd825c9e43197f Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:02:49 +0100 Subject: [PATCH 254/274] Fix formatting by removing extra newlines --- .../zmaster587/advancedRocketry/block/BlockRedstoneEmitter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockRedstoneEmitter.java b/src/main/java/zmaster587/advancedRocketry/block/BlockRedstoneEmitter.java index 94131b83a..dc4a78830 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockRedstoneEmitter.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockRedstoneEmitter.java @@ -105,5 +105,4 @@ public void addInformation(ItemStack stack, @Nullable World world, List public boolean canProvidePower(IBlockState state) { return true; } - } From e9e3e4ba6fd3651a1fca8d79b9d2d427b7d6641c Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:03:27 +0100 Subject: [PATCH 255/274] Add newline at end of TileAtmosphereDetector.java Fix missing newline at end of file. From 50a7256bba9c9b20256cea487cf91ba136835803 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:05:48 +0100 Subject: [PATCH 256/274] Fix formatting in BlockLens.java From 808653c000898f7a2ebaa831d3c0f9d6cb900a6f Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:06:15 +0100 Subject: [PATCH 257/274] Fix formatting and add tooltip information for BlockSeat --- src/main/java/zmaster587/advancedRocketry/block/BlockSeat.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockSeat.java b/src/main/java/zmaster587/advancedRocketry/block/BlockSeat.java index 0e3a63004..71d3d565c 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockSeat.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockSeat.java @@ -119,5 +119,4 @@ public void addInformation(ItemStack stack, @Nullable World world, List int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.seat", insertAt); } - } From b6defb33b1c112f9c51ed424581d175265fe72d4 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:06:48 +0100 Subject: [PATCH 258/274] Fix formatting by removing extra newlines --- src/main/java/zmaster587/advancedRocketry/block/BlockIntake.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockIntake.java b/src/main/java/zmaster587/advancedRocketry/block/BlockIntake.java index 652466352..af0b222e0 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockIntake.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockIntake.java @@ -32,5 +32,4 @@ public void addInformation(ItemStack stack, @Nullable World world, List public int getIntakeAmt(IBlockState state) { return 1; } - } From 20f6cfbbccdff2b95113d72b98bf1ae5d483c814 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:07:18 +0100 Subject: [PATCH 259/274] Remove unnecessary newline and fix formatting --- .../java/zmaster587/advancedRocketry/block/BlockMiningDrill.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockMiningDrill.java b/src/main/java/zmaster587/advancedRocketry/block/BlockMiningDrill.java index db5141062..13b4fc1db 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockMiningDrill.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockMiningDrill.java @@ -44,5 +44,4 @@ public void addInformation(ItemStack stack, @Nullable World world, List public int powerConsumption() { return 0; } - } From acdee5bc680e5cac7027d78208edf61a07c2c8a1 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:07:58 +0100 Subject: [PATCH 260/274] Remove unnecessary newline and clean up code --- .../zmaster587/advancedRocketry/item/ItemAtmosphereAnalzer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemAtmosphereAnalzer.java b/src/main/java/zmaster587/advancedRocketry/item/ItemAtmosphereAnalzer.java index eec4f7ef9..06f01c537 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemAtmosphereAnalzer.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemAtmosphereAnalzer.java @@ -159,5 +159,4 @@ public void renderScreen(@Nonnull ItemStack componentStack, List modu public ResourceIcon getComponentIcon(@Nonnull ItemStack armorStack) { return null; } - } From 510571ab3c603e6f2a7982d0ec8e6712d83a6c78 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:09:12 +0100 Subject: [PATCH 261/274] Fix formatting by removing trailing newline Removed unnecessary newline at the end of the file. --- .../advancedRocketry/mission/MissionResourceCollection.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/mission/MissionResourceCollection.java b/src/main/java/zmaster587/advancedRocketry/mission/MissionResourceCollection.java index 6b4e20c68..8126abccf 100644 --- a/src/main/java/zmaster587/advancedRocketry/mission/MissionResourceCollection.java +++ b/src/main/java/zmaster587/advancedRocketry/mission/MissionResourceCollection.java @@ -198,5 +198,4 @@ public void unlinkInfrastructure(IInfrastructure tile) { HashedBlockPosition pos = new HashedBlockPosition(((TileEntity) tile).getPos()); infrastructureCoords.remove(pos); } - } From c02861788f6de64c36a95a88f30efd4ed87cf877 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:10:04 +0100 Subject: [PATCH 262/274] Add newline at end of EntityStationDeployedRocket.java Fix missing newline at end of file. From 7d7a59f5d12c5e52e9ae881b6d5882a095b117be Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:11:56 +0100 Subject: [PATCH 263/274] Add newline at end of TileUnmannedVehicleAssembler.java Fix missing newline at end of file From c2e1c89b08d286a1e6aa82be2d5bc2a75a99f226 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:12:24 +0100 Subject: [PATCH 264/274] Fix missing newline at end of TileSatelliteTerminal.java From 36e526dc20a1092eac15f5790c0046dabb7c054a Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:13:34 +0100 Subject: [PATCH 265/274] Refactor TileWirelessTransciever code structure --- .../tile/cables/TileWirelessTransciever.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java b/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java index b44255465..69a3c44ba 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/cables/TileWirelessTransciever.java @@ -33,8 +33,6 @@ import zmaster587.libVulpes.network.PacketMachine; import zmaster587.libVulpes.util.INetworkMachine; - - import javax.annotation.Nonnull; import java.util.LinkedList; import java.util.List; @@ -277,7 +275,7 @@ public List getModules(int id, EntityPlayer player) { list.add(toggleSwitch); list.add(netIdLabel); - // Bar-only UI (no buttons/slots). Place it where you want it. + // Bar-only UI list.add(new ModuleWirelessBufferBar(14, 22, uiBuffer)); return list; @@ -461,7 +459,7 @@ public void update() { // Resolve front for either 6-way or legacy block EnumFacing front = resolveFront(state); - EnumFacing facing = front.getOpposite(); // keep existing IO semantics + EnumFacing facing = front.getOpposite(); TileEntity neighbor = world.getTileEntity(getPos().offset(facing)); if (neighbor == null || neighbor instanceof TileWirelessTransciever) return; if (!(neighbor instanceof IDataHandler)) return; @@ -537,6 +535,4 @@ public void invalidate() { super.invalidate(); } - - } From c4cd7c78a10a850893f15b7c3bb8066d97543854 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:14:31 +0100 Subject: [PATCH 266/274] Fix missing newline at end of StatsRocket.java Add missing newline at the end of the file From 4b8f6dc5f6841d3f3778db311eb92a55cda8a5b2 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:19:40 +0100 Subject: [PATCH 267/274] Add newline at end of WeightEngine.java Fix formatting issue by adding a newline at the end of the file. From d56faae3c51f446130efc09437083c735ea2bcfc Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:20:55 +0100 Subject: [PATCH 268/274] Update TileFluidTank.java --- .../java/zmaster587/advancedRocketry/tile/TileFluidTank.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/zmaster587/advancedRocketry/tile/TileFluidTank.java b/src/main/java/zmaster587/advancedRocketry/tile/TileFluidTank.java index 8cde1f94f..c0843e49f 100644 --- a/src/main/java/zmaster587/advancedRocketry/tile/TileFluidTank.java +++ b/src/main/java/zmaster587/advancedRocketry/tile/TileFluidTank.java @@ -366,8 +366,4 @@ else if (dir == EnumFacing.UP) { exitColumnOp(); } } - - - - } From 46b3ee077b2237f409c0dc37dc02184d9f6a5662 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:22:28 +0100 Subject: [PATCH 269/274] Refactor DataStorage.java formatting Removed an empty line and fixed the closing brace formatting. --- src/main/java/zmaster587/advancedRocketry/api/DataStorage.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/api/DataStorage.java b/src/main/java/zmaster587/advancedRocketry/api/DataStorage.java index ac53852fc..c99849801 100644 --- a/src/main/java/zmaster587/advancedRocketry/api/DataStorage.java +++ b/src/main/java/zmaster587/advancedRocketry/api/DataStorage.java @@ -168,7 +168,6 @@ public void readFromNBT(NBTTagCompound nbt) { } } - public enum DataType { UNDEFINED, DISTANCE, From dbf0fe2fbaf1cb86845b7229b45845f4fc436716 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:23:07 +0100 Subject: [PATCH 270/274] Fix missing newline at end of ItemSatellite.java Added a newline at the end of the file. From bc25c2366c6f4198676b7cac23c534d2ea508110 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Mon, 17 Nov 2025 09:23:34 +0100 Subject: [PATCH 271/274] Fix missing newline in ItemSatelliteIdentificationChip.java Add missing newline at end of file From 255e9a45fbad077ff8d38d334601c6ccaaef2ae4 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 20 Nov 2025 19:39:19 +0100 Subject: [PATCH 272/274] Implement tooltip for ItemJackHammer Added tooltip information for ItemJackHammer. --- .../advancedRocketry/item/ItemJackHammer.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemJackHammer.java b/src/main/java/zmaster587/advancedRocketry/item/ItemJackHammer.java index 6aa3551b3..560f3554d 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemJackHammer.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemJackHammer.java @@ -4,14 +4,22 @@ import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemTool; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.oredict.OreDictionary; import zmaster587.advancedRocketry.api.MaterialGeode; +import zmaster587.advancedRocketry.client.TooltipInjector; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; + +import java.util.List; import java.util.Set; public class ItemJackHammer extends ItemTool { @@ -40,4 +48,12 @@ public float getDestroySpeed(@Nonnull ItemStack stack, IBlockState state) { public boolean canHarvestBlock(IBlockState blockIn) { return true; } + + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.jackhammer", insertAt); + } + } From 1d07d610245359a4a431260620aa704c6197aa70 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 20 Nov 2025 19:39:42 +0100 Subject: [PATCH 273/274] Add tooltip support to BlockThermiteTorch Implement tooltip information for Thermite Torch. --- .../block/BlockThermiteTorch.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/zmaster587/advancedRocketry/block/BlockThermiteTorch.java b/src/main/java/zmaster587/advancedRocketry/block/BlockThermiteTorch.java index 3c5aedd3a..266895ca5 100644 --- a/src/main/java/zmaster587/advancedRocketry/block/BlockThermiteTorch.java +++ b/src/main/java/zmaster587/advancedRocketry/block/BlockThermiteTorch.java @@ -1,7 +1,23 @@ package zmaster587.advancedRocketry.block; +import java.util.List; + +import javax.annotation.Nullable; + import net.minecraft.block.BlockTorch; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import zmaster587.advancedRocketry.client.TooltipInjector; public class BlockThermiteTorch extends BlockTorch { + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.thermitetorch", insertAt); + } } From 4fa3b38453bc98901880bacc5291b630192a9b26 Mon Sep 17 00:00:00 2001 From: kaduvill Date: Thu, 20 Nov 2025 19:40:15 +0100 Subject: [PATCH 274/274] Add tooltip information to ItemThermite --- .../advancedRocketry/item/ItemThermite.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/zmaster587/advancedRocketry/item/ItemThermite.java b/src/main/java/zmaster587/advancedRocketry/item/ItemThermite.java index a17a52453..9b0368631 100644 --- a/src/main/java/zmaster587/advancedRocketry/item/ItemThermite.java +++ b/src/main/java/zmaster587/advancedRocketry/item/ItemThermite.java @@ -1,9 +1,17 @@ package zmaster587.advancedRocketry.item; +import net.minecraft.client.util.ITooltipFlag; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import zmaster587.advancedRocketry.client.TooltipInjector; + +import java.util.List; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class ItemThermite extends Item { @@ -11,5 +19,11 @@ public class ItemThermite extends Item { public int getItemBurnTime(@Nonnull ItemStack itemStack) { return 6000; } - + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack stack, @Nullable World world, List tooltip, ITooltipFlag flag) { + int insertAt = TooltipInjector.computeInsertIndex(tooltip, flag.isAdvanced()); + TooltipInjector.renderShiftAlt(stack, tooltip, "tooltip.advancedrocketry.thermite", insertAt); + } + }