From c38784b12e0f987fd1dece29e05d356a9ad541a4 Mon Sep 17 00:00:00 2001 From: Pilzinsel64 Date: Mon, 26 Feb 2024 15:56:53 +0100 Subject: [PATCH] update bs & deps --- .editorconfig | 22 + .gitattributes | 44 + .github/workflows/build-and-test.yml | 13 + .github/workflows/release-tags.yml | 14 + .gitignore | 63 +- BeefCore | 1 - CODEOWNERS | 3 + LICENSE-template | 21 + build.gradle | 95 +- dependencies.gradle | 40 + gradle.properties | 183 ++ gradle/wrapper/gradle-wrapper.jar | Bin 51017 -> 43462 bytes gradle/wrapper/gradle-wrapper.properties | 5 +- gradlew | 311 +- gradlew.bat | 86 +- jitpack.yml | 2 + repositories.gradle | 5 + settings.gradle | 21 + .../computercraft/api/ComputerCraftAPI.java | 380 +-- .../computercraft/api/filesystem/IMount.java | 84 +- .../api/filesystem/IWritableMount.java | 82 +- .../computercraft/api/lua/ILuaContext.java | 72 +- .../computercraft/api/lua/ILuaObject.java | 28 +- .../computercraft/api/lua/LuaException.java | 17 +- .../computercraft/api/media/IMedia.java | 95 +- .../api/media/IMediaProvider.java | 8 +- .../api/peripheral/IComputerAccess.java | 161 +- .../api/peripheral/IPeripheral.java | 162 +- .../api/peripheral/IPeripheralProvider.java | 8 +- .../redstone/IBundledRedstoneProvider.java | 11 +- .../api/turtle/ITurtleAccess.java | 139 +- .../api/turtle/ITurtleCommand.java | 22 +- .../api/turtle/ITurtleUpgrade.java | 142 +- .../api/turtle/TurtleAnimation.java | 3 +- .../api/turtle/TurtleCommandResult.java | 37 +- .../computercraft/api/turtle/TurtleSide.java | 19 +- .../api/turtle/TurtleUpgradeType.java | 26 +- .../computercraft/api/turtle/TurtleVerb.java | 22 +- .../api/FactoryRegistry.java | 202 +- .../api/FertilizerType.java | 42 +- .../minefactoryreloaded/api/HarvestType.java | 73 +- .../api/IDeepStorageUnit.java | 48 +- .../api/IFactoryFertilizable.java | 60 +- .../api/IFactoryFertilizer.java | 39 +- .../api/IFactoryFruit.java | 126 +- .../api/IFactoryGrindable.java | 41 +- .../api/IFactoryHarvestable.java | 117 +- .../api/IFactoryLaserTarget.java | 32 +- .../api/IFactoryPlantable.java | 108 +- .../api/IFactoryRanchable.java | 31 +- .../api/ILiquidDrinkHandler.java | 6 +- .../minefactoryreloaded/api/IMFRHammer.java | 6 +- .../api/IMobEggHandler.java | 17 +- .../api/IMobSpawnHandler.java | 34 +- .../minefactoryreloaded/api/INeedleAmmo.java | 13 +- .../api/IRandomMobProvider.java | 7 +- .../api/ISafariNetHandler.java | 31 +- .../minefactoryreloaded/api/ISyringe.java | 74 +- .../minefactoryreloaded/api/MobDrop.java | 28 +- .../minefactoryreloaded/api/RanchedItem.java | 99 +- .../minefactoryreloaded/api/RandomMob.java | 41 +- .../api/ReplacementBlock.java | 239 +- .../minefactoryreloaded/api/ValuedItem.java | 127 +- .../api/rednet/IRedNetInfo.java | 33 +- .../api/rednet/IRedNetInputNode.java | 60 +- .../api/rednet/IRedNetLogicCircuit.java | 31 +- .../api/rednet/IRedNetLogicPoint.java | 52 +- .../api/rednet/IRedNetNetworkContainer.java | 45 +- .../api/rednet/IRedNetOmniNode.java | 5 +- .../api/rednet/IRedNetOutputNode.java | 56 +- .../connectivity/IRedNetConnection.java | 34 +- .../connectivity/IRedNetDecorative.java | 3 +- .../connectivity/IRedNetNoConnection.java | 5 +- .../connectivity/RedNetConnectionType.java | 123 +- .../bigreactors/api/IHeatEntity.java | 63 +- .../bigreactors/api/IRadiationModerator.java | 3 +- .../bigreactors/api/IReactorFuel.java | 105 +- .../bigreactors/api/IReactorSolid.java | 52 +- .../bigreactors/api/data/CoilPartData.java | 18 +- .../api/data/FluidToReactantMapping.java | 79 +- .../api/data/OreDictToReactantMapping.java | 28 +- .../bigreactors/api/data/ReactantData.java | 115 +- .../api/data/ReactantToFluidMapping.java | 79 +- .../api/data/ReactorInteriorData.java | 29 +- .../bigreactors/api/data/ReactorReaction.java | 78 +- .../api/data/SourceProductMapping.java | 132 +- .../bigreactors/api/imc/MessageRouter.java | 65 +- .../bigreactors/api/registry/Reactants.java | 654 +++-- .../api/registry/ReactorConversions.java | 58 +- .../api/registry/ReactorInterior.java | 95 +- .../bigreactors/api/registry/TurbineCoil.java | 50 +- .../client/BRRenderTickHandler.java | 3 +- .../bigreactors/client/BeefIconManager.java | 91 +- .../bigreactors/client/ClientProxy.java | 134 +- .../client/CommonBlockIconManager.java | 38 +- .../bigreactors/client/gui/BeefGuiBase.java | 256 +- .../client/gui/BeefGuiDeviceBase.java | 144 +- .../client/gui/GuiCyaniteReprocessor.java | 119 +- .../client/gui/GuiReactorAccessPort.java | 187 +- .../client/gui/GuiReactorControlRod.java | 334 ++- .../client/gui/GuiReactorRedNetPort.java | 699 +++-- .../client/gui/GuiReactorRedstonePort.java | 1194 ++++---- .../client/gui/GuiReactorStatus.java | 634 ++-- .../client/gui/GuiTurbineController.java | 678 +++-- .../client/renderer/RotorSimpleRenderer.java | 714 ++--- .../client/renderer/RotorSpecialRenderer.java | 244 +- .../renderer/SimpleRendererFuelRod.java | 330 +-- .../bigreactors/common/BRConfig.java | 49 +- .../bigreactors/common/BREventHandler.java | 62 +- .../bigreactors/common/BRLoader.java | 150 +- .../bigreactors/common/BRLog.java | 29 +- .../bigreactors/common/BigReactors.java | 2147 ++++++++------ .../common/BigReactorsTickHandler.java | 66 +- .../bigreactors/common/CommonProxy.java | 277 +- .../bigreactors/common/CreativeTabBR.java | 14 +- .../common/block/BlockBRDevice.java | 414 ++- .../common/block/BlockBRGenericFluid.java | 49 +- .../common/block/BlockBRMetal.java | 148 +- .../bigreactors/common/block/BlockBROre.java | 65 +- .../common/data/RadiationData.java | 36 +- .../common/data/RadiationPacket.java | 5 +- .../common/data/ReactantStack.java | 183 +- .../bigreactors/common/data/ReactorFuel.java | 114 +- .../common/data/ReactorSolidMapping.java | 83 +- .../common/data/StandardReactants.java | 34 +- .../interfaces/IBeefDebuggableTile.java | 6 +- .../interfaces/IBeefReconfigurableSides.java | 13 +- .../interfaces/IMultipleFluidHandler.java | 4 +- .../common/interfaces/IReactorFuelInfo.java | 38 +- .../common/interfaces/IWrenchable.java | 18 +- .../bigreactors/common/item/ItemBRBucket.java | 65 +- .../bigreactors/common/item/ItemBase.java | 97 +- .../common/item/ItemBeefDebugTool.java | 157 +- .../common/item/ItemBlockBigReactors.java | 10 +- .../bigreactors/common/item/ItemIngot.java | 146 +- .../common/multiblock/MultiblockReactor.java | 2615 +++++++++-------- .../common/multiblock/MultiblockTurbine.java | 2430 +++++++-------- .../common/multiblock/block/BlockFuelRod.java | 169 +- .../multiblock/block/BlockMBCreativePart.java | 266 +- .../block/BlockMultiblockGlass.java | 301 +- .../multiblock/block/BlockReactorPart.java | 1228 ++++---- .../block/BlockReactorRedstonePort.java | 367 +-- .../multiblock/block/BlockTurbinePart.java | 917 +++--- .../block/BlockTurbineRotorPart.java | 234 +- .../multiblock/helpers/CoolantContainer.java | 388 +-- .../helpers/FloatUpdateTracker.java | 104 +- .../multiblock/helpers/FluidHelper.java | 800 ++--- .../multiblock/helpers/FuelContainer.java | 368 +-- .../multiblock/helpers/RadiationHelper.java | 436 +-- .../multiblock/helpers/ReactantContainer.java | 669 ++--- .../common/multiblock/helpers/RotorInfo.java | 23 +- .../multiblock/interfaces/IActivateable.java | 33 +- .../interfaces/IConditionalUpdater.java | 13 +- .../interfaces/IMultiblockGuiHandler.java | 29 +- .../interfaces/INeighborUpdatableEntity.java | 47 +- .../interfaces/ITickableMultiblockPart.java | 9 +- .../TileEntityReactorAccessPort.java | 880 +++--- .../TileEntityReactorComputerPort.java | 709 ++--- .../TileEntityReactorControlRod.java | 338 ++- .../TileEntityReactorCoolantPort.java | 419 +-- .../tileentity/TileEntityReactorFuelRod.java | 395 +-- .../tileentity/TileEntityReactorGlass.java | 63 +- .../tileentity/TileEntityReactorPart.java | 205 +- .../tileentity/TileEntityReactorPartBase.java | 245 +- .../tileentity/TileEntityReactorPowerTap.java | 269 +- .../TileEntityReactorRedNetPort.java | 931 +++--- .../TileEntityReactorRedstonePort.java | 842 +++--- .../TileEntityTurbineComputerPort.java | 484 ++- .../TileEntityTurbineFluidPort.java | 389 +-- .../tileentity/TileEntityTurbinePartBase.java | 214 +- .../TileEntityTurbinePartGlass.java | 47 +- .../TileEntityTurbinePartStandard.java | 150 +- .../tileentity/TileEntityTurbinePowerTap.java | 269 +- .../TileEntityTurbineRotorBearing.java | 210 +- .../TileEntityTurbineRotorPart.java | 66 +- .../TileEntityReactorCreativeCoolantPort.java | 67 +- ...leEntityTurbineCreativeSteamGenerator.java | 27 +- .../TileEntityCyaniteReprocessor.java | 392 +-- .../tileentity/base/TileEntityBeefBase.java | 538 ++-- .../tileentity/base/TileEntityInventory.java | 526 ++-- .../base/TileEntityPoweredInventory.java | 361 +-- .../base/TileEntityPoweredInventoryFluid.java | 499 ++-- .../bigreactors/gui/BeefGuiControlBase.java | 209 +- .../bigreactors/gui/BeefGuiIconManager.java | 133 +- .../gui/BigReactorsGUIHandler.java | 68 +- .../bigreactors/gui/IBeefGuiControl.java | 44 +- .../bigreactors/gui/IBeefGuiEntity.java | 55 +- .../bigreactors/gui/IBeefListBoxEntry.java | 8 +- .../bigreactors/gui/IBeefTooltipControl.java | 11 +- .../gui/container/ContainerBasic.java | 16 +- .../ContainerCyaniteReprocessor.java | 351 +-- .../container/ContainerReactorAccessPort.java | 331 +-- .../container/ContainerReactorController.java | 50 +- .../gui/container/ContainerSlotless.java | 40 +- .../gui/container/ISlotlessUpdater.java | 36 +- .../gui/controls/BeefGuiFluidBar.java | 134 +- .../gui/controls/BeefGuiFuelMixBar.java | 238 +- .../gui/controls/BeefGuiHeatBar.java | 88 +- .../bigreactors/gui/controls/BeefGuiIcon.java | 81 +- .../gui/controls/BeefGuiIconProgressBar.java | 71 +- .../controls/BeefGuiInsertionProgressBar.java | 145 +- .../gui/controls/BeefGuiLabel.java | 167 +- .../gui/controls/BeefGuiListBox.java | 197 +- .../gui/controls/BeefGuiPowerBar.java | 63 +- .../gui/controls/BeefGuiProgressArrow.java | 48 +- .../BeefGuiRedNetChannelSelector.java | 181 +- .../gui/controls/BeefGuiRpmBar.java | 96 +- .../controls/BeefGuiTextureProgressBar.java | 114 +- .../controls/BeefGuiVerticalProgressBar.java | 189 +- .../gui/controls/GuiIconButton.java | 125 +- .../gui/controls/GuiSelectableButton.java | 128 +- .../gui/controls/grab/BeefGuiGrabSource.java | 103 +- .../gui/controls/grab/BeefGuiGrabTarget.java | 172 +- .../gui/controls/grab/IBeefGuiGrabbable.java | 5 +- .../controls/grab/RedNetConfigGrabTarget.java | 103 +- .../controls/grab/RedNetConfigGrabbable.java | 61 +- .../gui/slot/SlotReactorInput.java | 37 +- .../bigreactors/gui/slot/SlotRemoveOnly.java | 17 +- .../gui/slot/SlotRestrictedOreTypes.java | 53 +- .../bigreactors/net/CommonPacketHandler.java | 122 +- .../bigreactors/net/helpers/RedNetChange.java | 122 +- .../ControlRodChangeInsertionMessage.java | 92 +- .../message/ControlRodChangeNameMessage.java | 32 +- .../net/message/ControlRodUpdateMessage.java | 25 +- .../message/DeviceChangeExposureMessage.java | 94 +- .../message/DeviceUpdateExposureMessage.java | 101 +- .../net/message/DeviceUpdateMessage.java | 22 +- .../message/DeviceUpdateRotationMessage.java | 22 +- .../MachineCommandActivateMessage.java | 90 +- ...actorAccessPortChangeDirectionMessage.java | 81 +- .../ReactorRedNetPortChangeMessage.java | 72 +- .../ReactorRedstonePortChangeMessage.java | 34 +- .../message/base/ReactorMessageClient.java | 76 +- .../message/base/ReactorMessageServer.java | 76 +- .../net/message/base/TileMessageClient.java | 55 +- .../net/message/base/TileMessageServer.java | 54 +- .../message/base/TurbineMessageClient.java | 76 +- .../message/base/TurbineMessageServer.java | 76 +- .../net/message/base/WorldMessage.java | 90 +- .../net/message/base/WorldMessageClient.java | 30 +- .../net/message/base/WorldMessageServer.java | 25 +- .../ReactorChangeWasteEjectionMessage.java | 65 +- .../ReactorCommandEjectMessage.java | 84 +- .../ReactorCommandEjectToPortMessage.java | 111 +- .../multiblock/ReactorUpdateMessage.java | 60 +- .../ReactorUpdateWasteEjectionMessage.java | 27 +- .../TurbineChangeInductorMessage.java | 63 +- .../TurbineChangeMaxIntakeMessage.java | 63 +- .../multiblock/TurbineChangeVentMessage.java | 63 +- .../multiblock/TurbineUpdateMessage.java | 62 +- .../utils/AdjacentInventoryHelper.java | 221 +- .../bigreactors/utils/FloatAverager.java | 81 +- .../bigreactors/utils/InventoryHelper.java | 148 +- .../utils/SidedInventoryHelper.java | 47 +- .../bigreactors/utils/StaticUtils.java | 674 ++--- .../bigreactors/utils/intermod/IMCHelper.java | 75 +- .../utils/intermod/ModHelperBase.java | 26 +- .../intermod/ModHelperComputerCraft.java | 12 +- .../utils/intermod/ModHelperMekanism.java | 177 +- .../world/BRSimpleOreGenerator.java | 199 +- .../bigreactors/world/BRWorldGenerator.java | 65 +- .../core/common/BeefCoreLog.java | 38 + .../core/common/CoordTriplet.java | 163 + .../core/multiblock/BlockMultiblockBase.java | 15 + .../core/multiblock/IMultiblockPart.java | 205 ++ .../MultiblockClientTickHandler.java | 16 + .../multiblock/MultiblockControllerBase.java | 1037 +++++++ .../multiblock/MultiblockEventHandler.java | 31 + .../core/multiblock/MultiblockRegistry.java | 146 + .../MultiblockServerTickHandler.java | 23 + .../multiblock/MultiblockTileEntityBase.java | 370 +++ .../MultiblockValidationException.java | 14 + .../multiblock/MultiblockWorldRegistry.java | 426 +++ .../multiblock/rectangular/PartPosition.java | 29 + .../RectangularMultiblockControllerBase.java | 155 + .../RectangularMultiblockTileEntityBase.java | 109 + src/main/resources/mcmod.info | 35 +- 277 files changed, 26750 insertions(+), 21317 deletions(-) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .github/workflows/build-and-test.yml create mode 100644 .github/workflows/release-tags.yml delete mode 160000 BeefCore create mode 100644 CODEOWNERS create mode 100644 LICENSE-template create mode 100644 dependencies.gradle create mode 100644 gradle.properties create mode 100644 jitpack.yml create mode 100644 repositories.gradle create mode 100644 settings.gradle create mode 100644 src/main/java/erogenousbeef/core/common/BeefCoreLog.java create mode 100644 src/main/java/erogenousbeef/core/common/CoordTriplet.java create mode 100644 src/main/java/erogenousbeef/core/multiblock/BlockMultiblockBase.java create mode 100644 src/main/java/erogenousbeef/core/multiblock/IMultiblockPart.java create mode 100644 src/main/java/erogenousbeef/core/multiblock/MultiblockClientTickHandler.java create mode 100644 src/main/java/erogenousbeef/core/multiblock/MultiblockControllerBase.java create mode 100644 src/main/java/erogenousbeef/core/multiblock/MultiblockEventHandler.java create mode 100644 src/main/java/erogenousbeef/core/multiblock/MultiblockRegistry.java create mode 100644 src/main/java/erogenousbeef/core/multiblock/MultiblockServerTickHandler.java create mode 100644 src/main/java/erogenousbeef/core/multiblock/MultiblockTileEntityBase.java create mode 100644 src/main/java/erogenousbeef/core/multiblock/MultiblockValidationException.java create mode 100644 src/main/java/erogenousbeef/core/multiblock/MultiblockWorldRegistry.java create mode 100644 src/main/java/erogenousbeef/core/multiblock/rectangular/PartPosition.java create mode 100644 src/main/java/erogenousbeef/core/multiblock/rectangular/RectangularMultiblockControllerBase.java create mode 100644 src/main/java/erogenousbeef/core/multiblock/rectangular/RectangularMultiblockTileEntityBase.java diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..4ffbd908 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,22 @@ +# This is the universal Text Editor Configuration +# for all GTNewHorizons projects +# See: https://editorconfig.org/ + +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{bat,ini}] +end_of_line = crlf + +[*.{dtd,json,info,mcmeta,md,sh,svg,xml,xsd,xsl,yaml,yml}] +indent_size = 2 + +[*.lang] +trim_trailing_whitespace = false diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..fd2792b6 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,44 @@ +* text eol=lf + +*.[jJ][aA][rR] binary + +*.[pP][nN][gG] binary +*.[jJ][pP][gG] binary +*.[jJ][pP][eE][gG] binary +*.[gG][iI][fF] binary +*.[tT][iI][fF] binary +*.[tT][iI][fF][fF] binary +*.[iI][cC][oO] binary +*.[sS][vV][gG] text +*.[eE][pP][sS] binary +*.[xX][cC][fF] binary + +*.[kK][aA][rR] binary +*.[mM]4[aA] binary +*.[mM][iI][dD] binary +*.[mM][iI][dD][iI] binary +*.[mM][pP]3 binary +*.[oO][gG][gG] binary +*.[rR][aA] binary + +*.7[zZ] binary +*.[gG][zZ] binary +*.[tT][aA][rR] binary +*.[tT][gG][zZ] binary +*.[zZ][iI][pP] binary + +*.[tT][cC][nN] binary +*.[sS][oO] binary +*.[dD][lL][lL] binary +*.[dD][yY][lL][iI][bB] binary +*.[pP][sS][dD] binary +*.[tT][tT][fF] binary +*.[oO][tT][fF] binary + +*.[pP][aA][tT][cC][hH] -text + +*.[bB][aA][tT] text eol=crlf +*.[cC][mM][dD] text eol=crlf +*.[pP][sS]1 text eol=crlf + +*[aA][uU][tT][oO][gG][eE][nN][eE][rR][aA][tT][eE][dD]* binary diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml new file mode 100644 index 00000000..3ee2f686 --- /dev/null +++ b/.github/workflows/build-and-test.yml @@ -0,0 +1,13 @@ + +name: Build and test + +on: + pull_request: + branches: [ master, main ] + push: + branches: [ master, main ] + +jobs: + build-and-test: + uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/build-and-test.yml@master + secrets: inherit diff --git a/.github/workflows/release-tags.yml b/.github/workflows/release-tags.yml new file mode 100644 index 00000000..e4c0be6b --- /dev/null +++ b/.github/workflows/release-tags.yml @@ -0,0 +1,14 @@ + +name: Release tagged build + +on: + push: + tags: [ '*' ] + +permissions: + contents: write + +jobs: + release-tags: + uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/release-tags.yml@master + secrets: inherit diff --git a/.gitignore b/.gitignore index d923ac90..5e80e0ae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,35 +1,38 @@ -# ForgeGradle -/.gradle -/build -/run - -# Minecraft runtime files and config files -/logs -/config -options.txt -/saves -usernamecache.json - -# Eclipse +.gradle +.settings +/.idea/ +/.vscode/ +/run/ +/build/ +/eclipse/ .classpath .project -/.settings -/bin -/eclipse - -# IntelliJ -/.idea +/bin/ +/config/ +/crash-reports/ +/logs/ +options.txt +/saves/ +usernamecache.json +banned-ips.json +banned-players.json +eula.txt +ops.json +server.properties +servers.dat +usercache.json +whitelist.json +/out/ *.iml *.ipr *.iws -/out - -# Mac Stuff -.DS_Store -*.command - -# External APIs -/lib - -# BeefCore, when it's copied into the source tree -/src/main/java/erogenousbeef/core +src/main/resources/mixins.*([!.]).json +*.bat +*.DS_Store +!gradlew.bat +.factorypath +addon.local.gradle +addon.local.gradle.kts +addon.late.local.gradle +addon.late.local.gradle.kts +layout.json diff --git a/BeefCore b/BeefCore deleted file mode 160000 index dc07c85b..00000000 --- a/BeefCore +++ /dev/null @@ -1 +0,0 @@ -Subproject commit dc07c85b37055785eb718d82abafb92f1dab65d9 diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 00000000..a6b5f68c --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,3 @@ +# Any Github changes require admin approval +/.github/** @GTNewHorizons/admin + diff --git a/LICENSE-template b/LICENSE-template new file mode 100644 index 00000000..242da623 --- /dev/null +++ b/LICENSE-template @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/build.gradle b/build.gradle index 16b5197e..e57a16f9 100644 --- a/build.gradle +++ b/build.gradle @@ -1,94 +1,5 @@ -buildscript { - repositories { - mavenCentral() - maven { - name = "forge" - url = "http://files.minecraftforge.net/maven" - } - maven { - name = "sonatype" - url = "https://oss.sonatype.org/content/repositories/snapshots/" - } - } - dependencies { - classpath 'net.minecraftforge.gradle:ForgeGradle:1.2-SNAPSHOT' - } -} - -apply plugin: 'forge' - -sourceSets.main.java.srcDirs += 'BeefCore/src/main/java' - -ant.loadproperties(srcFile: "version.properties") -version = ant.properties['vMajor'] + "." + ant.properties['vMinor'] + "." + ant.properties['vPatch'] + ant.properties['vSuffix'] - -group = "erogenousbeef" // http://maven.apache.org/guides/mini/guide-naming-conventions.html -archivesBaseName = "BigReactors" - -minecraft { - version = "1.7.10-10.13.2.1291" - runDir = "run" - - replaceIn "BRConfig.java" - replace "@VERSION@", project.version -} - -repositories { - maven { - name = "OpenComputers" - url = "http://maven.cil.li/" - } - maven { - name = "codechicken" - url = "http://chickenbones.net/maven" - } - ivy { - name "CoFHCore" - artifactPattern "http://addons-origin.cursecdn.com/files/2230/211/[module]-[revision].[ext]" - } -} - -dependencies { - //compile 'codechicken:CodeChickenCore:1.7.10-1.0.4.29:dev' - //compile 'codechicken:NotEnoughItems:1.7.10-1.0.3.67:dev' - compile 'com.mod-buildcraft:buildcraft:6.0.18:dev' - compile 'li.cil.oc:OpenComputers:MC1.7.10-1.4.0.+:api' - compile name: 'CoFHCore', version: '[1.7.10]3.0.0RC7-211-dev', ext: 'jar' -} - -processResources -{ - // this will ensure that this task is redone when the versions change. - inputs.property "version", project.version - inputs.property "mcversion", project.minecraft.version - - // replace stuff in mcmod.info, nothing else - from(sourceSets.main.resources.srcDirs) { - include 'mcmod.info' - - // replace version and mcversion - expand 'version':project.version, 'mcversion':project.minecraft.version - } - - // copy everything else, thats not the mcmod.info - from(sourceSets.main.resources.srcDirs) { - exclude 'mcmod.info' - } -} - -// NOTE: When using the addVersion task, it MUST be run in a separate gradle run -// from build, or else the mod will have a mismatched version number. -// This is because the minecraft project's replaceIn system runs at -// configuration time, and you cannot specify which tasks run -// during configuration time. This blows, but it works for now. - -task addVersion { - inputs.property "version", project.version - outputs.file "version.properties" -} +//version: 1707058017 -addVersion << { - ant.propertyfile(file: "version.properties") { - entry( key: "vPatch", type: int, value: 1, operation: "+" ) - } +plugins { + id 'com.gtnewhorizons.gtnhconvention' } diff --git a/dependencies.gradle b/dependencies.gradle new file mode 100644 index 00000000..bedbcb50 --- /dev/null +++ b/dependencies.gradle @@ -0,0 +1,40 @@ +/* + * Add your dependencies here. Supported configurations: + * - api("group:name:version:classifier"): if you use the types from this dependency in the public API of this mod + * Available at runtime and compiletime for mods depending on this mod + * - implementation("g:n:v:c"): if you need this for internal implementation details of the mod, but none of it is visible via the public API + * Available at runtime but not compiletime for mods depending on this mod + * - compileOnly("g:n:v:c"): if the mod you're building doesn't need this dependency during runtime at all, e.g. for optional mods + * Not available at all for mods depending on this mod, only visible at compiletime for this mod + * - compileOnlyApi("g:n:v:c"): like compileOnly, but also visible at compiletime for mods depending on this mod + * Available at compiletime but not runtime for mods depending on this mod + * - runtimeOnlyNonPublishable("g:n:v:c"): if you want to include a mod in this mod's runClient/runServer runs, but not publish it as a dependency + * Not available at all for mods depending on this mod, only visible at runtime for this mod + * - devOnlyNonPublishable("g:n:v:c"): a combination of runtimeOnlyNonPublishable and compileOnly for dependencies present at both compiletime and runtime, + * but not published as Maven dependencies - useful for RFG-deobfuscated dependencies or local testing + * - runtimeOnly("g:n:v:c"): if you don't need this at compile time, but want it to be present at runtime + * Available at runtime for mods depending on this mod + * - annotationProcessor("g:n:v:c"): mostly for java compiler plugins, if you know you need this, use it, otherwise don't worry + * - testCONFIG("g:n:v:c") - replace CONFIG by one of the above (except api), same as above but for the test sources instead of main + * + * - shadowImplementation("g:n:v:c"): effectively the same as API, but the dependency is included in your jar under a renamed package name + * Requires you to enable usesShadowedDependencies in gradle.properties + * + * - compile("g:n:v:c"): deprecated, replace with "api" (works like the old "compile") or "implementation" (can be more efficient) + * + * You can exclude transitive dependencies (dependencies of the chosen dependency) by appending { transitive = false } if needed, + * but use this sparingly as it can break using your mod as another mod's dependency if you're not careful. + * + * To depend on obfuscated jars you can use `devOnlyNonPublishable(rfg.deobf("dep:spec:1.2.3"))` to fetch an obfuscated jar from maven, + * or `devOnlyNonPublishable(rfg.deobf(project.files("libs/my-mod-jar.jar")))` to use a file. + * + * Gradle names for some of the configuration can be misleading, compileOnlyApi and runtimeOnly both get published as dependencies in Maven, but compileOnly does not. + * The buildscript adds runtimeOnlyNonPublishable to also have a runtime dependency that's not published. + * + * For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph + */ +dependencies { + api("curse.maven:cofh-core-69162:2388751") { transitive = false } + compileOnly("com.github.GTNewHorizons:BuildCraft:7.1.39:dev") { transitive = false } + compileOnly('com.github.GTNewHorizons:OpenComputers:1.10.6-GTNH:api') { transitive = false } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000..2a210ef3 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,183 @@ +# ExampleMod tag to use as Blowdryer (Spotless, etc.) settings version, leave empty to disable. +# LOCAL to test local config updates. +gtnh.settings.blowdryerTag = 0.2.2 + +# Human-readable mod name, available for mcmod.info population. +modName = Big Reactors + +# Case-sensitive identifier string, available for mcmod.info population and used for automatic mixin JSON generation. +# Conventionally lowercase. +modId = BigReactors + +# Root package of the mod, used to find various classes in other properties, +# mcmod.info substitution, enabling assertions in run tasks, etc. +modGroup = erogenousbeef.bigreactors + +# Whether to use modGroup as the maven publishing group. +# Due to a history of using JitPack, the default is com.github.GTNewHorizons for all mods. +useModGroupForPublishing = false + +# Updates your build.gradle and settings.gradle automatically whenever an update is available. +autoUpdateBuildScript = false + +# Version of Minecraft to target +minecraftVersion = 1.7.10 + +# Version of Minecraft Forge to target +forgeVersion = 10.13.4.1614 + +# Specify an MCP channel for dependency deobfuscation and the deobfParams task. +channel = stable + +# Specify an MCP mappings version for dependency deobfuscation and the deobfParams task. +mappingsVersion = 12 + +# Defines other MCP mappings for dependency deobfuscation. +remoteMappings = https\://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/conf/ + +# Select a default username for testing your mod. You can always override this per-run by running +# `./gradlew runClient --username=AnotherPlayer`, or configuring this command in your IDE. +developmentEnvironmentUserName = Developer + +# Enables using modern Java syntax (up to version 17) via Jabel, while still targeting JVM 8. +# See https://github.com/bsideup/jabel for details on how this works. +enableModernJavaSyntax = true + +# Enables injecting missing generics into the decompiled source code for a better coding experience. +# Turns most publicly visible List, Map, etc. into proper List, Map types. +enableGenericInjection = true + +# Generate a class with a String field for the mod version named as defined below. +# If generateGradleTokenClass is empty or not missing, no such class will be generated. +# If gradleTokenVersion is empty or missing, the field will not be present in the class. +generateGradleTokenClass = erogenousbeef.bigreactors.Tags + +# Name of the token containing the project's current version to generate/replace. +gradleTokenVersion = VERSION + +# [DEPRECATED] +# Multiple source files can be defined here by providing a comma-separated list: Class1.java,Class2.java,Class3.java +# public static final String VERSION = "GRADLETOKEN_VERSION"; +# The string's content will be replaced with your mod's version when compiled. You should use this to specify your mod's +# version in @Mod([...], version = VERSION, [...]). +# Leave these properties empty to skip individual token replacements. +replaceGradleTokenInFile = + +# In case your mod provides an API for other mods to implement you may declare its package here. Otherwise, you can +# leave this property empty. +# Example value: (apiPackage = api) + (modGroup = com.myname.mymodid) -> com.myname.mymodid.api +apiPackage = api + +# Specify the configuration file for Forge's access transformers here. It must be placed into /src/main/resources/META-INF/ +# There can be multiple files in a space-separated list. +# Example value: mymodid_at.cfg nei_at.cfg +accessTransformersFile = + +# Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled! +usesMixins = false + +# Adds some debug arguments like verbose output and class export. +usesMixinDebug = false + +# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise. +mixinPlugin = + +# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail! +mixinsPackage = + +# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin! +# This parameter is for legacy compatibility only +# Example value: (coreModClass = asm.FMLPlugin) + (modGroup = com.myname.mymodid) -> com.myname.mymodid.asm.FMLPlugin +coreModClass = + +# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod ( = some class +# that is annotated with @Mod) you want this to be true. When in doubt: leave it on false! +containsMixinsAndOrCoreModOnly = false + +# Enables Mixins even if this mod doesn't use them, useful if one of the dependencies uses mixins. +forceEnableMixins = false + +# If enabled, you may use 'shadowCompile' for dependencies. They will be integrated into your jar. It is your +# responsibility to check the license and request permission for distribution if required. +usesShadowedDependencies = false + +# If disabled, won't remove unused classes from shadowed dependencies. Some libraries use reflection to access +# their own classes, making the minimization unreliable. +minimizeShadowedDependencies = true + +# If disabled, won't rename the shadowed classes. +relocateShadowedDependencies = true + +# Adds the GTNH maven, CurseMaven, IC2/Player maven, and some more well-known 1.7.10 repositories. +includeWellKnownRepositories = true + +# Change these to your Maven coordinates if you want to publish to a custom Maven repository instead of the default GTNH Maven. +# Authenticate with the MAVEN_USER and MAVEN_PASSWORD environment variables. +# If you need a more complex setup disable maven publishing here and add a publishing repository to addon.gradle. +usesMavenPublishing = true + +# Maven repository to publish the mod to. +# mavenPublishUrl = https\://nexus.gtnewhorizons.com/repository/releases/ + +# Publishing to Modrinth requires you to set the MODRINTH_TOKEN environment variable to your current Modrinth API token. +# +# The project's ID on Modrinth. Can be either the slug or the ID. +# Leave this empty if you don't want to publish to Modrinth. +modrinthProjectId = + +# The project's relations on Modrinth. You can use this to refer to other projects on Modrinth. +# Syntax: scope1-type1:name1;scope2-type2:name2;... +# Where scope can be one of [required, optional, incompatible, embedded], +# type can be one of [project, version], +# and the name is the Modrinth project or version slug/id of the other mod. +# Example: required-project:fplib;optional-project:gasstation;incompatible-project:gregtech +# Note: GTNH Mixins is automatically set as a required dependency if usesMixins = true +modrinthRelations = + +# Publishing to CurseForge requires you to set the CURSEFORGE_TOKEN environment variable to one of your CurseForge API tokens. +# +# The project's numeric ID on CurseForge. You can find this in the About Project box. +# Leave this empty if you don't want to publish on CurseForge. +curseForgeProjectId = + +# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge. +# Syntax: type1:name1;type2:name2;... +# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible], +# and the name is the CurseForge project slug of the other mod. +# Example: requiredDependency:railcraft;embeddedLibrary:cofhlib;incompatible:buildcraft +# Note: UniMixins is automatically set as a required dependency if usesMixins = true. +curseForgeRelations = + +# Optional parameter to customize the produced artifacts. Use this to preserve artifact naming when migrating older +# projects. New projects should not use this parameter. +# customArchiveBaseName = + +# Optional parameter to have the build automatically fail if an illegal version is used. +# This can be useful if you e.g. only want to allow versions in the form of '1.1.xxx'. +# The check is ONLY performed if the version is a git tag. +# Note: the specified string must be escaped, so e.g. 1\\.1\\.\\d+ instead of 1\.1\.\d+ +# versionPattern = + +# Uncomment to prevent the source code from being published. +# noPublishedSources = true + +# Uncomment this to disable Spotless checks. +# This should only be uncommented to keep it easier to sync with upstream/other forks. +# That is, if there is no other active fork/upstream, NEVER change this. +# disableSpotless = true + +# Uncomment this to disable Checkstyle checks (currently wildcard import check). +# disableCheckstyle = true + +# Override the IDEA build type. Valid values are: "" (leave blank, do not override), "idea" (force use native IDEA build), "gradle" +# (force use delegated build). +# This is meant to be set in $HOME/.gradle/gradle.properties. +# e.g. add "systemProp.org.gradle.project.ideaOverrideBuildType=idea" will override the build type to be native build. +# WARNING: If you do use this option, it will overwrite whatever you have in your existing projects. This might not be what you want! +# Usually there is no need to uncomment this here as other developers do not necessarily use the same build type as you. +# ideaOverrideBuildType = idea + +# Whether IDEA should run spotless checks when pressing the Build button. +# This is meant to be set in $HOME/.gradle/gradle.properties. +# ideaCheckSpotlessOnBuild = true + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index b7612167031001b7b84baf2a959e8ea8ad03c011..d64cd4917707c1f8861d8cb53dd15194d4248596 100644 GIT binary patch literal 43462 zcma&NWl&^owk(X(xVyW%ySuwf;qI=D6|RlDJ2cR^yEKh!@I- zp9QeisK*rlxC>+~7Dk4IxIRsKBHqdR9b3+fyL=ynHmIDe&|>O*VlvO+%z5;9Z$|DJ zb4dO}-R=MKr^6EKJiOrJdLnCJn>np?~vU-1sSFgPu;pthGwf}bG z(1db%xwr#x)r+`4AGu$j7~u2MpVs3VpLp|mx&;>`0p0vH6kF+D2CY0fVdQOZ@h;A` z{infNyvmFUiu*XG}RNMNwXrbec_*a3N=2zJ|Wh5z* z5rAX$JJR{#zP>KY**>xHTuw?|-Rg|o24V)74HcfVT;WtQHXlE+_4iPE8QE#DUm%x0 zEKr75ur~W%w#-My3Tj`hH6EuEW+8K-^5P62$7Sc5OK+22qj&Pd1;)1#4tKihi=~8C zHiQSst0cpri6%OeaR`PY>HH_;CPaRNty%WTm4{wDK8V6gCZlG@U3$~JQZ;HPvDJcT1V{ z?>H@13MJcCNe#5z+MecYNi@VT5|&UiN1D4ATT+%M+h4c$t;C#UAs3O_q=GxK0}8%8 z8J(_M9bayxN}69ex4dzM_P3oh@ZGREjVvn%%r7=xjkqxJP4kj}5tlf;QosR=%4L5y zWhgejO=vao5oX%mOHbhJ8V+SG&K5dABn6!WiKl{|oPkq(9z8l&Mm%(=qGcFzI=eLu zWc_oCLyf;hVlB@dnwY98?75B20=n$>u3b|NB28H0u-6Rpl((%KWEBOfElVWJx+5yg z#SGqwza7f}$z;n~g%4HDU{;V{gXIhft*q2=4zSezGK~nBgu9-Q*rZ#2f=Q}i2|qOp z!!y4p)4o=LVUNhlkp#JL{tfkhXNbB=Ox>M=n6soptJw-IDI|_$is2w}(XY>a=H52d z3zE$tjPUhWWS+5h=KVH&uqQS=$v3nRs&p$%11b%5qtF}S2#Pc`IiyBIF4%A!;AVoI zXU8-Rpv!DQNcF~(qQnyyMy=-AN~U>#&X1j5BLDP{?K!%h!;hfJI>$mdLSvktEr*89 zdJHvby^$xEX0^l9g$xW-d?J;L0#(`UT~zpL&*cEh$L|HPAu=P8`OQZV!-}l`noSp_ zQ-1$q$R-gDL)?6YaM!=8H=QGW$NT2SeZlb8PKJdc=F-cT@j7Xags+Pr*jPtlHFnf- zh?q<6;)27IdPc^Wdy-mX%2s84C1xZq9Xms+==F4);O`VUASmu3(RlgE#0+#giLh-& zcxm3_e}n4{%|X zJp{G_j+%`j_q5}k{eW&TlP}J2wtZ2^<^E(O)4OQX8FDp6RJq!F{(6eHWSD3=f~(h} zJXCf7=r<16X{pHkm%yzYI_=VDP&9bmI1*)YXZeB}F? z(%QsB5fo*FUZxK$oX~X^69;x~j7ms8xlzpt-T15e9}$4T-pC z6PFg@;B-j|Ywajpe4~bk#S6(fO^|mm1hKOPfA%8-_iGCfICE|=P_~e;Wz6my&)h_~ zkv&_xSAw7AZ%ThYF(4jADW4vg=oEdJGVOs>FqamoL3Np8>?!W#!R-0%2Bg4h?kz5I zKV-rKN2n(vUL%D<4oj@|`eJ>0i#TmYBtYmfla;c!ATW%;xGQ0*TW@PTlGG><@dxUI zg>+3SiGdZ%?5N=8uoLA|$4isK$aJ%i{hECP$bK{J#0W2gQ3YEa zZQ50Stn6hqdfxJ*9#NuSLwKFCUGk@c=(igyVL;;2^wi4o30YXSIb2g_ud$ zgpCr@H0qWtk2hK8Q|&wx)}4+hTYlf;$a4#oUM=V@Cw#!$(nOFFpZ;0lc!qd=c$S}Z zGGI-0jg~S~cgVT=4Vo)b)|4phjStD49*EqC)IPwyeKBLcN;Wu@Aeph;emROAwJ-0< z_#>wVm$)ygH|qyxZaet&(Vf%pVdnvKWJn9`%DAxj3ot;v>S$I}jJ$FLBF*~iZ!ZXE zkvui&p}fI0Y=IDX)mm0@tAd|fEHl~J&K}ZX(Mm3cm1UAuwJ42+AO5@HwYfDH7ipIc zmI;1J;J@+aCNG1M`Btf>YT>~c&3j~Qi@Py5JT6;zjx$cvOQW@3oQ>|}GH?TW-E z1R;q^QFjm5W~7f}c3Ww|awg1BAJ^slEV~Pk`Kd`PS$7;SqJZNj->it4DW2l15}xP6 zoCl$kyEF%yJni0(L!Z&14m!1urXh6Btj_5JYt1{#+H8w?5QI%% zo-$KYWNMJVH?Hh@1n7OSu~QhSswL8x0=$<8QG_zepi_`y_79=nK=_ZP_`Em2UI*tyQoB+r{1QYZCpb?2OrgUw#oRH$?^Tj!Req>XiE#~B|~ z+%HB;=ic+R@px4Ld8mwpY;W^A%8%l8$@B@1m5n`TlKI6bz2mp*^^^1mK$COW$HOfp zUGTz-cN9?BGEp}5A!mDFjaiWa2_J2Iq8qj0mXzk; z66JBKRP{p%wN7XobR0YjhAuW9T1Gw3FDvR5dWJ8ElNYF94eF3ebu+QwKjtvVu4L zI9ip#mQ@4uqVdkl-TUQMb^XBJVLW(-$s;Nq;@5gr4`UfLgF$adIhd?rHOa%D);whv z=;krPp~@I+-Z|r#s3yCH+c1US?dnm+C*)r{m+86sTJusLdNu^sqLrfWed^ndHXH`m zd3#cOe3>w-ga(Dus_^ppG9AC>Iq{y%%CK+Cro_sqLCs{VLuK=dev>OL1dis4(PQ5R zcz)>DjEkfV+MO;~>VUlYF00SgfUo~@(&9$Iy2|G0T9BSP?&T22>K46D zL*~j#yJ?)^*%J3!16f)@Y2Z^kS*BzwfAQ7K96rFRIh>#$*$_Io;z>ux@}G98!fWR@ zGTFxv4r~v)Gsd|pF91*-eaZ3Qw1MH$K^7JhWIdX%o$2kCbvGDXy)a?@8T&1dY4`;L z4Kn+f%SSFWE_rpEpL9bnlmYq`D!6F%di<&Hh=+!VI~j)2mfil03T#jJ_s?}VV0_hp z7T9bWxc>Jm2Z0WMU?`Z$xE74Gu~%s{mW!d4uvKCx@WD+gPUQ zV0vQS(Ig++z=EHN)BR44*EDSWIyT~R4$FcF*VEY*8@l=218Q05D2$|fXKFhRgBIEE zdDFB}1dKkoO^7}{5crKX!p?dZWNz$m>1icsXG2N+((x0OIST9Zo^DW_tytvlwXGpn zs8?pJXjEG;T@qrZi%#h93?FP$!&P4JA(&H61tqQi=opRzNpm zkrG}$^t9&XduK*Qa1?355wd8G2CI6QEh@Ua>AsD;7oRUNLPb76m4HG3K?)wF~IyS3`fXuNM>${?wmB zpVz;?6_(Fiadfd{vUCBM*_kt$+F3J+IojI;9L(gc9n3{sEZyzR9o!_mOwFC#tQ{Q~ zP3-`#uK#tP3Q7~Q;4H|wjZHO8h7e4IuBxl&vz2w~D8)w=Wtg31zpZhz%+kzSzL*dV zwp@{WU4i;hJ7c2f1O;7Mz6qRKeASoIv0_bV=i@NMG*l<#+;INk-^`5w@}Dj~;k=|}qM1vq_P z|GpBGe_IKq|LNy9SJhKOQ$c=5L{Dv|Q_lZl=-ky*BFBJLW9&y_C|!vyM~rQx=!vun z?rZJQB5t}Dctmui5i31C_;_}CEn}_W%>oSXtt>@kE1=JW*4*v4tPp;O6 zmAk{)m!)}34pTWg8{i>($%NQ(Tl;QC@J@FfBoc%Gr&m560^kgSfodAFrIjF}aIw)X zoXZ`@IsMkc8_=w%-7`D6Y4e*CG8k%Ud=GXhsTR50jUnm+R*0A(O3UKFg0`K;qp1bl z7``HN=?39ic_kR|^R^~w-*pa?Vj#7|e9F1iRx{GN2?wK!xR1GW!qa=~pjJb-#u1K8 zeR?Y2i-pt}yJq;SCiVHODIvQJX|ZJaT8nO+(?HXbLefulKKgM^B(UIO1r+S=7;kLJ zcH}1J=Px2jsh3Tec&v8Jcbng8;V-`#*UHt?hB(pmOipKwf3Lz8rG$heEB30Sg*2rx zV<|KN86$soN(I!BwO`1n^^uF2*x&vJ$2d$>+`(romzHP|)K_KkO6Hc>_dwMW-M(#S zK(~SiXT1@fvc#U+?|?PniDRm01)f^#55;nhM|wi?oG>yBsa?~?^xTU|fX-R(sTA+5 zaq}-8Tx7zrOy#3*JLIIVsBmHYLdD}!0NP!+ITW+Thn0)8SS!$@)HXwB3tY!fMxc#1 zMp3H?q3eD?u&Njx4;KQ5G>32+GRp1Ee5qMO0lZjaRRu&{W<&~DoJNGkcYF<5(Ab+J zgO>VhBl{okDPn78<%&e2mR{jwVCz5Og;*Z;;3%VvoGo_;HaGLWYF7q#jDX=Z#Ml`H z858YVV$%J|e<1n`%6Vsvq7GmnAV0wW4$5qQ3uR@1i>tW{xrl|ExywIc?fNgYlA?C5 zh$ezAFb5{rQu6i7BSS5*J-|9DQ{6^BVQ{b*lq`xS@RyrsJN?-t=MTMPY;WYeKBCNg z^2|pN!Q^WPJuuO4!|P@jzt&tY1Y8d%FNK5xK(!@`jO2aEA*4 zkO6b|UVBipci?){-Ke=+1;mGlND8)6+P;8sq}UXw2hn;fc7nM>g}GSMWu&v&fqh

iViYT=fZ(|3Ox^$aWPp4a8h24tD<|8-!aK0lHgL$N7Efw}J zVIB!7=T$U`ao1?upi5V4Et*-lTG0XvExbf!ya{cua==$WJyVG(CmA6Of*8E@DSE%L z`V^$qz&RU$7G5mg;8;=#`@rRG`-uS18$0WPN@!v2d{H2sOqP|!(cQ@ zUHo!d>>yFArLPf1q`uBvY32miqShLT1B@gDL4XoVTK&@owOoD)OIHXrYK-a1d$B{v zF^}8D3Y^g%^cnvScOSJR5QNH+BI%d|;J;wWM3~l>${fb8DNPg)wrf|GBP8p%LNGN# z3EaIiItgwtGgT&iYCFy9-LG}bMI|4LdmmJt@V@% zb6B)1kc=T)(|L@0;wr<>=?r04N;E&ef+7C^`wPWtyQe(*pD1pI_&XHy|0gIGHMekd zF_*M4yi6J&Z4LQj65)S zXwdM{SwUo%3SbPwFsHgqF@V|6afT|R6?&S;lw=8% z3}@9B=#JI3@B*#4s!O))~z zc>2_4Q_#&+5V`GFd?88^;c1i7;Vv_I*qt!_Yx*n=;rj!82rrR2rQ8u5(Ejlo{15P% zs~!{%XJ>FmJ})H^I9bn^Re&38H{xA!0l3^89k(oU;bZWXM@kn$#aoS&Y4l^-WEn-fH39Jb9lA%s*WsKJQl?n9B7_~P z-XM&WL7Z!PcoF6_D>V@$CvUIEy=+Z&0kt{szMk=f1|M+r*a43^$$B^MidrT0J;RI` z(?f!O<8UZkm$_Ny$Hth1J#^4ni+im8M9mr&k|3cIgwvjAgjH z8`N&h25xV#v*d$qBX5jkI|xOhQn!>IYZK7l5#^P4M&twe9&Ey@@GxYMxBZq2e7?`q z$~Szs0!g{2fGcp9PZEt|rdQ6bhAgpcLHPz?f-vB?$dc*!9OL?Q8mn7->bFD2Si60* z!O%y)fCdMSV|lkF9w%x~J*A&srMyYY3{=&$}H zGQ4VG_?$2X(0|vT0{=;W$~icCI{b6W{B!Q8xdGhF|D{25G_5_+%s(46lhvNLkik~R z>nr(&C#5wwOzJZQo9m|U<;&Wk!_#q|V>fsmj1g<6%hB{jGoNUPjgJslld>xmODzGjYc?7JSuA?A_QzjDw5AsRgi@Y|Z0{F{!1=!NES-#*f^s4l0Hu zz468))2IY5dmD9pa*(yT5{EyP^G>@ZWumealS-*WeRcZ}B%gxq{MiJ|RyX-^C1V=0 z@iKdrGi1jTe8Ya^x7yyH$kBNvM4R~`fbPq$BzHum-3Zo8C6=KW@||>zsA8-Y9uV5V z#oq-f5L5}V<&wF4@X@<3^C%ptp6+Ce)~hGl`kwj)bsAjmo_GU^r940Z-|`<)oGnh7 zFF0Tde3>ui?8Yj{sF-Z@)yQd~CGZ*w-6p2U<8}JO-sRsVI5dBji`01W8A&3$?}lxBaC&vn0E$c5tW* zX>5(zzZ=qn&!J~KdsPl;P@bmA-Pr8T*)eh_+Dv5=Ma|XSle6t(k8qcgNyar{*ReQ8 zTXwi=8vr>!3Ywr+BhggHDw8ke==NTQVMCK`$69fhzEFB*4+H9LIvdt-#IbhZvpS}} zO3lz;P?zr0*0$%-Rq_y^k(?I{Mk}h@w}cZpMUp|ucs55bcloL2)($u%mXQw({Wzc~ z;6nu5MkjP)0C(@%6Q_I_vsWrfhl7Zpoxw#WoE~r&GOSCz;_ro6i(^hM>I$8y>`!wW z*U^@?B!MMmb89I}2(hcE4zN2G^kwyWCZp5JG>$Ez7zP~D=J^LMjSM)27_0B_X^C(M z`fFT+%DcKlu?^)FCK>QzSnV%IsXVcUFhFdBP!6~se&xxrIxsvySAWu++IrH;FbcY$ z2DWTvSBRfLwdhr0nMx+URA$j3i7_*6BWv#DXfym?ZRDcX9C?cY9sD3q)uBDR3uWg= z(lUIzB)G$Hr!){>E{s4Dew+tb9kvToZp-1&c?y2wn@Z~(VBhqz`cB;{E4(P3N2*nJ z_>~g@;UF2iG{Kt(<1PyePTKahF8<)pozZ*xH~U-kfoAayCwJViIrnqwqO}7{0pHw$ zs2Kx?s#vQr7XZ264>5RNKSL8|Ty^=PsIx^}QqOOcfpGUU4tRkUc|kc7-!Ae6!+B{o~7nFpm3|G5^=0#Bnm6`V}oSQlrX(u%OWnC zoLPy&Q;1Jui&7ST0~#+}I^&?vcE*t47~Xq#YwvA^6^} z`WkC)$AkNub|t@S!$8CBlwbV~?yp&@9h{D|3z-vJXgzRC5^nYm+PyPcgRzAnEi6Q^gslXYRv4nycsy-SJu?lMps-? zV`U*#WnFsdPLL)Q$AmD|0`UaC4ND07+&UmOu!eHruzV|OUox<+Jl|Mr@6~C`T@P%s zW7sgXLF2SSe9Fl^O(I*{9wsFSYb2l%-;&Pi^dpv!{)C3d0AlNY6!4fgmSgj_wQ*7Am7&$z;Jg&wgR-Ih;lUvWS|KTSg!&s_E9_bXBkZvGiC6bFKDWZxsD$*NZ#_8bl zG1P-#@?OQzED7@jlMJTH@V!6k;W>auvft)}g zhoV{7$q=*;=l{O>Q4a@ ziMjf_u*o^PsO)#BjC%0^h>Xp@;5$p{JSYDt)zbb}s{Kbt!T*I@Pk@X0zds6wsefuU zW$XY%yyRGC94=6mf?x+bbA5CDQ2AgW1T-jVAJbm7K(gp+;v6E0WI#kuACgV$r}6L? zd|Tj?^%^*N&b>Dd{Wr$FS2qI#Ucs1yd4N+RBUQiSZGujH`#I)mG&VKoDh=KKFl4=G z&MagXl6*<)$6P}*Tiebpz5L=oMaPrN+caUXRJ`D?=K9!e0f{@D&cZLKN?iNP@X0aF zE(^pl+;*T5qt?1jRC=5PMgV!XNITRLS_=9{CJExaQj;lt!&pdzpK?8p>%Mb+D z?yO*uSung=-`QQ@yX@Hyd4@CI^r{2oiu`%^bNkz+Nkk!IunjwNC|WcqvX~k=><-I3 zDQdbdb|!v+Iz01$w@aMl!R)koD77Xp;eZwzSl-AT zr@Vu{=xvgfq9akRrrM)}=!=xcs+U1JO}{t(avgz`6RqiiX<|hGG1pmop8k6Q+G_mv zJv|RfDheUp2L3=^C=4aCBMBn0aRCU(DQwX-W(RkRwmLeuJYF<0urcaf(=7)JPg<3P zQs!~G)9CT18o!J4{zX{_e}4eS)U-E)0FAt}wEI(c0%HkxgggW;(1E=>J17_hsH^sP z%lT0LGgbUXHx-K*CI-MCrP66UP0PvGqM$MkeLyqHdbgP|_Cm!7te~b8p+e6sQ_3k| zVcwTh6d83ltdnR>D^)BYQpDKlLk3g0Hdcgz2}%qUs9~~Rie)A-BV1mS&naYai#xcZ z(d{8=-LVpTp}2*y)|gR~;qc7fp26}lPcLZ#=JpYcn3AT9(UIdOyg+d(P5T7D&*P}# zQCYplZO5|7+r19%9e`v^vfSS1sbX1c%=w1;oyruXB%Kl$ACgKQ6=qNWLsc=28xJjg zwvsI5-%SGU|3p>&zXVl^vVtQT3o-#$UT9LI@Npz~6=4!>mc431VRNN8od&Ul^+G_kHC`G=6WVWM z%9eWNyy(FTO|A+@x}Ou3CH)oi;t#7rAxdIXfNFwOj_@Y&TGz6P_sqiB`Q6Lxy|Q{`|fgmRG(k+!#b*M+Z9zFce)f-7;?Km5O=LHV9f9_87; zF7%R2B+$?@sH&&-$@tzaPYkw0;=i|;vWdI|Wl3q_Zu>l;XdIw2FjV=;Mq5t1Q0|f< zs08j54Bp`3RzqE=2enlkZxmX6OF+@|2<)A^RNQpBd6o@OXl+i)zO%D4iGiQNuXd+zIR{_lb96{lc~bxsBveIw6umhShTX+3@ZJ=YHh@ zWY3(d0azg;7oHn>H<>?4@*RQbi>SmM=JrHvIG(~BrvI)#W(EAeO6fS+}mxxcc+X~W6&YVl86W9WFSS}Vz-f9vS?XUDBk)3TcF z8V?$4Q)`uKFq>xT=)Y9mMFVTUk*NIA!0$?RP6Ig0TBmUFrq*Q-Agq~DzxjStQyJ({ zBeZ;o5qUUKg=4Hypm|}>>L=XKsZ!F$yNTDO)jt4H0gdQ5$f|d&bnVCMMXhNh)~mN z@_UV6D7MVlsWz+zM+inZZp&P4fj=tm6fX)SG5H>OsQf_I8c~uGCig$GzuwViK54bcgL;VN|FnyQl>Ed7(@>=8$a_UKIz|V6CeVSd2(P z0Uu>A8A+muM%HLFJQ9UZ5c)BSAv_zH#1f02x?h9C}@pN@6{>UiAp>({Fn(T9Q8B z^`zB;kJ5b`>%dLm+Ol}ty!3;8f1XDSVX0AUe5P#@I+FQ-`$(a;zNgz)4x5hz$Hfbg z!Q(z26wHLXko(1`;(BAOg_wShpX0ixfWq3ponndY+u%1gyX)_h=v1zR#V}#q{au6; z!3K=7fQwnRfg6FXtNQmP>`<;!N137paFS%y?;lb1@BEdbvQHYC{976l`cLqn;b8lp zIDY>~m{gDj(wfnK!lpW6pli)HyLEiUrNc%eXTil|F2s(AY+LW5hkKb>TQ3|Q4S9rr zpDs4uK_co6XPsn_z$LeS{K4jFF`2>U`tbgKdyDne`xmR<@6AA+_hPNKCOR-Zqv;xk zu5!HsBUb^!4uJ7v0RuH-7?l?}b=w5lzzXJ~gZcxRKOovSk@|#V+MuX%Y+=;14i*%{)_gSW9(#4%)AV#3__kac1|qUy!uyP{>?U#5wYNq}y$S9pCc zFc~4mgSC*G~j0u#qqp9 z${>3HV~@->GqEhr_Xwoxq?Hjn#=s2;i~g^&Hn|aDKpA>Oc%HlW(KA1?BXqpxB;Ydx)w;2z^MpjJ(Qi(X!$5RC z*P{~%JGDQqojV>2JbEeCE*OEu!$XJ>bWA9Oa_Hd;y)F%MhBRi*LPcdqR8X`NQ&1L# z5#9L*@qxrx8n}LfeB^J{%-?SU{FCwiWyHp682F+|pa+CQa3ZLzBqN1{)h4d6+vBbV zC#NEbQLC;}me3eeYnOG*nXOJZEU$xLZ1<1Y=7r0(-U0P6-AqwMAM`a(Ed#7vJkn6plb4eI4?2y3yOTGmmDQ!z9`wzbf z_OY#0@5=bnep;MV0X_;;SJJWEf^E6Bd^tVJ9znWx&Ks8t*B>AM@?;D4oWUGc z!H*`6d7Cxo6VuyS4Eye&L1ZRhrRmN6Lr`{NL(wDbif|y&z)JN>Fl5#Wi&mMIr5i;x zBx}3YfF>>8EC(fYnmpu~)CYHuHCyr5*`ECap%t@y=jD>!_%3iiE|LN$mK9>- zHdtpy8fGZtkZF?%TW~29JIAfi2jZT8>OA7=h;8T{{k?c2`nCEx9$r zS+*&vt~2o^^J+}RDG@+9&M^K*z4p{5#IEVbz`1%`m5c2};aGt=V?~vIM}ZdPECDI)47|CWBCfDWUbxBCnmYivQ*0Nu_xb*C>~C9(VjHM zxe<*D<#dQ8TlpMX2c@M<9$w!RP$hpG4cs%AI){jp*Sj|*`m)5(Bw*A0$*i-(CA5#%>a)$+jI2C9r6|(>J8InryENI z$NohnxDUB;wAYDwrb*!N3noBTKPpPN}~09SEL18tkG zxgz(RYU_;DPT{l?Q$+eaZaxnsWCA^ds^0PVRkIM%bOd|G2IEBBiz{&^JtNsODs;5z zICt_Zj8wo^KT$7Bg4H+y!Df#3mbl%%?|EXe!&(Vmac1DJ*y~3+kRKAD=Ovde4^^%~ zw<9av18HLyrf*_>Slp;^i`Uy~`mvBjZ|?Ad63yQa#YK`4+c6;pW4?XIY9G1(Xh9WO8{F-Aju+nS9Vmv=$Ac0ienZ+p9*O%NG zMZKy5?%Z6TAJTE?o5vEr0r>f>hb#2w2U3DL64*au_@P!J!TL`oH2r*{>ffu6|A7tv zL4juf$DZ1MW5ZPsG!5)`k8d8c$J$o;%EIL0va9&GzWvkS%ZsGb#S(?{!UFOZ9<$a| zY|a+5kmD5N&{vRqkgY>aHsBT&`rg|&kezoD)gP0fsNYHsO#TRc_$n6Lf1Z{?+DLziXlHrq4sf(!>O{?Tj;Eh@%)+nRE_2VxbN&&%%caU#JDU%vL3}Cb zsb4AazPI{>8H&d=jUaZDS$-0^AxE@utGs;-Ez_F(qC9T=UZX=>ok2k2 ziTn{K?y~a5reD2A)P${NoI^>JXn>`IeArow(41c-Wm~)wiryEP(OS{YXWi7;%dG9v zI?mwu1MxD{yp_rrk!j^cKM)dc4@p4Ezyo%lRN|XyD}}>v=Xoib0gOcdXrQ^*61HNj z=NP|pd>@yfvr-=m{8$3A8TQGMTE7g=z!%yt`8`Bk-0MMwW~h^++;qyUP!J~ykh1GO z(FZ59xuFR$(WE;F@UUyE@Sp>`aVNjyj=Ty>_Vo}xf`e7`F;j-IgL5`1~-#70$9_=uBMq!2&1l zomRgpD58@)YYfvLtPW}{C5B35R;ZVvB<<#)x%srmc_S=A7F@DW8>QOEGwD6suhwCg z>Pa+YyULhmw%BA*4yjDp|2{!T98~<6Yfd(wo1mQ!KWwq0eg+6)o1>W~f~kL<-S+P@$wx*zeI|1t7z#Sxr5 zt6w+;YblPQNplq4Z#T$GLX#j6yldXAqj>4gAnnWtBICUnA&-dtnlh=t0Ho_vEKwV` z)DlJi#!@nkYV#$!)@>udAU*hF?V`2$Hf=V&6PP_|r#Iv*J$9)pF@X3`k;5})9^o4y z&)~?EjX5yX12O(BsFy-l6}nYeuKkiq`u9145&3Ssg^y{5G3Pse z9w(YVa0)N-fLaBq1`P!_#>SS(8fh_5!f{UrgZ~uEdeMJIz7DzI5!NHHqQtm~#CPij z?=N|J>nPR6_sL7!f4hD_|KH`vf8(Wpnj-(gPWH+ZvID}%?~68SwhPTC3u1_cB`otq z)U?6qo!ZLi5b>*KnYHWW=3F!p%h1;h{L&(Q&{qY6)_qxNfbP6E3yYpW!EO+IW3?@J z);4>g4gnl^8klu7uA>eGF6rIGSynacogr)KUwE_R4E5Xzi*Qir@b-jy55-JPC8c~( zo!W8y9OGZ&`xmc8;=4-U9=h{vCqfCNzYirONmGbRQlR`WWlgnY+1wCXbMz&NT~9*| z6@FrzP!LX&{no2!Ln_3|I==_4`@}V?4a;YZKTdw;vT<+K+z=uWbW(&bXEaWJ^W8Td z-3&1bY^Z*oM<=M}LVt>_j+p=2Iu7pZmbXrhQ_k)ysE9yXKygFNw$5hwDn(M>H+e1&9BM5!|81vd%r%vEm zqxY3?F@fb6O#5UunwgAHR9jp_W2zZ}NGp2%mTW@(hz7$^+a`A?mb8|_G*GNMJ) zjqegXQio=i@AINre&%ofexAr95aop5C+0MZ0m-l=MeO8m3epm7U%vZB8+I+C*iNFM z#T3l`gknX;D$-`2XT^Cg*vrv=RH+P;_dfF++cP?B_msQI4j+lt&rX2)3GaJx%W*Nn zkML%D{z5tpHH=dksQ*gzc|}gzW;lwAbxoR07VNgS*-c3d&8J|;@3t^ zVUz*J*&r7DFRuFVDCJDK8V9NN5hvpgGjwx+5n)qa;YCKe8TKtdnh{I7NU9BCN!0dq zczrBk8pE{{@vJa9ywR@mq*J=v+PG;?fwqlJVhijG!3VmIKs>9T6r7MJpC)m!Tc#>g zMtVsU>wbwFJEfwZ{vB|ZlttNe83)$iz`~#8UJ^r)lJ@HA&G#}W&ZH*;k{=TavpjWE z7hdyLZPf*X%Gm}i`Y{OGeeu^~nB8=`{r#TUrM-`;1cBvEd#d!kPqIgYySYhN-*1;L z^byj%Yi}Gx)Wnkosi337BKs}+5H5dth1JA{Ir-JKN$7zC)*}hqeoD(WfaUDPT>0`- z(6sa0AoIqASwF`>hP}^|)a_j2s^PQn*qVC{Q}htR z5-)duBFXT_V56-+UohKXlq~^6uf!6sA#ttk1o~*QEy_Y-S$gAvq47J9Vtk$5oA$Ct zYhYJ@8{hsC^98${!#Ho?4y5MCa7iGnfz}b9jE~h%EAAv~Qxu)_rAV;^cygV~5r_~?l=B`zObj7S=H=~$W zPtI_m%g$`kL_fVUk9J@>EiBH zOO&jtn~&`hIFMS5S`g8w94R4H40mdNUH4W@@XQk1sr17b{@y|JB*G9z1|CrQjd+GX z6+KyURG3;!*BQrentw{B2R&@2&`2}n(z-2&X7#r!{yg@Soy}cRD~j zj9@UBW+N|4HW4AWapy4wfUI- zZ`gSL6DUlgj*f1hSOGXG0IVH8HxK?o2|3HZ;KW{K+yPAlxtb)NV_2AwJm|E)FRs&& z=c^e7bvUsztY|+f^k7NXs$o1EUq>cR7C0$UKi6IooHWlK_#?IWDkvywnzg&ThWo^? z2O_N{5X39#?eV9l)xI(>@!vSB{DLt*oY!K1R8}_?%+0^C{d9a%N4 zoxHVT1&Lm|uDX%$QrBun5e-F`HJ^T$ zmzv)p@4ZHd_w9!%Hf9UYNvGCw2TTTbrj9pl+T9%-_-}L(tES>Or-}Z4F*{##n3~L~TuxjirGuIY#H7{%$E${?p{Q01 zi6T`n;rbK1yIB9jmQNycD~yZq&mbIsFWHo|ZAChSFPQa<(%d8mGw*V3fh|yFoxOOiWJd(qvVb!Z$b88cg->N=qO*4k~6;R==|9ihg&riu#P~s4Oap9O7f%crSr^rljeIfXDEg>wi)&v*a%7zpz<9w z*r!3q9J|390x`Zk;g$&OeN&ctp)VKRpDSV@kU2Q>jtok($Y-*x8_$2piTxun81@vt z!Vj?COa0fg2RPXMSIo26T=~0d`{oGP*eV+$!0I<(4azk&Vj3SiG=Q!6mX0p$z7I}; z9BJUFgT-K9MQQ-0@Z=^7R<{bn2Fm48endsSs`V7_@%8?Bxkqv>BDoVcj?K#dV#uUP zL1ND~?D-|VGKe3Rw_7-Idpht>H6XRLh*U7epS6byiGvJpr%d}XwfusjH9g;Z98H`x zyde%%5mhGOiL4wljCaWCk-&uE4_OOccb9c!ZaWt4B(wYl!?vyzl%7n~QepN&eFUrw zFIOl9c({``6~QD+43*_tzP{f2x41h(?b43^y6=iwyB)2os5hBE!@YUS5?N_tXd=h( z)WE286Fbd>R4M^P{!G)f;h<3Q>Fipuy+d2q-)!RyTgt;wr$(?9ox3;q+{E*ZQHhOn;lM`cjnu9 zXa48ks-v(~b*;MAI<>YZH(^NV8vjb34beE<_cwKlJoR;k6lJNSP6v}uiyRD?|0w+X@o1ONrH8a$fCxXpf? z?$DL0)7|X}Oc%h^zrMKWc-NS9I0Utu@>*j}b@tJ=ixQSJ={4@854wzW@E>VSL+Y{i z#0b=WpbCZS>kUCO_iQz)LoE>P5LIG-hv9E+oG}DtlIDF>$tJ1aw9^LuhLEHt?BCj& z(O4I8v1s#HUi5A>nIS-JK{v!7dJx)^Yg%XjNmlkWAq2*cv#tHgz`Y(bETc6CuO1VkN^L-L3j_x<4NqYb5rzrLC-7uOv z!5e`GZt%B782C5-fGnn*GhDF$%(qP<74Z}3xx+{$4cYKy2ikxI7B2N+2r07DN;|-T->nU&!=Cm#rZt%O_5c&1Z%nlWq3TKAW0w zQqemZw_ue--2uKQsx+niCUou?HjD`xhEjjQd3%rrBi82crq*~#uA4+>vR<_S{~5ce z-2EIl?~s z1=GVL{NxP1N3%=AOaC}j_Fv=ur&THz zyO!d9kHq|c73kpq`$+t+8Bw7MgeR5~`d7ChYyGCBWSteTB>8WAU(NPYt2Dk`@#+}= zI4SvLlyk#pBgVigEe`?NG*vl7V6m+<}%FwPV=~PvvA)=#ths==DRTDEYh4V5}Cf$z@#;< zyWfLY_5sP$gc3LLl2x+Ii)#b2nhNXJ{R~vk`s5U7Nyu^3yFg&D%Txwj6QezMX`V(x z=C`{76*mNb!qHHs)#GgGZ_7|vkt9izl_&PBrsu@}L`X{95-2jf99K)0=*N)VxBX2q z((vkpP2RneSIiIUEnGb?VqbMb=Zia+rF~+iqslydE34cSLJ&BJW^3knX@M;t*b=EA zNvGzv41Ld_T+WT#XjDB840vovUU^FtN_)G}7v)1lPetgpEK9YS^OWFkPoE{ovj^=@ zO9N$S=G$1ecndT_=5ehth2Lmd1II-PuT~C9`XVePw$y8J#dpZ?Tss<6wtVglm(Ok7 z3?^oi@pPio6l&!z8JY(pJvG=*pI?GIOu}e^EB6QYk$#FJQ%^AIK$I4epJ+9t?KjqA+bkj&PQ*|vLttme+`9G=L% ziadyMw_7-M)hS(3E$QGNCu|o23|%O+VN7;Qggp?PB3K-iSeBa2b}V4_wY`G1Jsfz4 z9|SdB^;|I8E8gWqHKx!vj_@SMY^hLEIbSMCuE?WKq=c2mJK z8LoG-pnY!uhqFv&L?yEuxo{dpMTsmCn)95xanqBrNPTgXP((H$9N${Ow~Is-FBg%h z53;|Y5$MUN)9W2HBe2TD`ct^LHI<(xWrw}$qSoei?}s)&w$;&!14w6B6>Yr6Y8b)S z0r71`WmAvJJ`1h&poLftLUS6Ir zC$bG9!Im_4Zjse)#K=oJM9mHW1{%l8sz$1o?ltdKlLTxWWPB>Vk22czVt|1%^wnN@*!l)}?EgtvhC>vlHm^t+ogpgHI1_$1ox9e;>0!+b(tBrmXRB`PY1vp-R**8N7 zGP|QqI$m(Rdu#=(?!(N}G9QhQ%o!aXE=aN{&wtGP8|_qh+7a_j_sU5|J^)vxq;# zjvzLn%_QPHZZIWu1&mRAj;Sa_97p_lLq_{~j!M9N^1yp3U_SxRqK&JnR%6VI#^E12 z>CdOVI^_9aPK2eZ4h&^{pQs}xsijXgFYRIxJ~N7&BB9jUR1fm!(xl)mvy|3e6-B3j zJn#ajL;bFTYJ2+Q)tDjx=3IklO@Q+FFM}6UJr6km7hj7th9n_&JR7fnqC!hTZoM~T zBeaVFp%)0cbPhejX<8pf5HyRUj2>aXnXBqDJe73~J%P(2C?-RT{c3NjE`)om! zl$uewSgWkE66$Kb34+QZZvRn`fob~Cl9=cRk@Es}KQm=?E~CE%spXaMO6YmrMl%9Q zlA3Q$3|L1QJ4?->UjT&CBd!~ru{Ih^in&JXO=|<6J!&qp zRe*OZ*cj5bHYlz!!~iEKcuE|;U4vN1rk$xq6>bUWD*u(V@8sG^7>kVuo(QL@Ki;yL zWC!FT(q{E8#on>%1iAS0HMZDJg{Z{^!De(vSIq&;1$+b)oRMwA3nc3mdTSG#3uYO_ z>+x;7p4I;uHz?ZB>dA-BKl+t-3IB!jBRgdvAbW!aJ(Q{aT>+iz?91`C-xbe)IBoND z9_Xth{6?(y3rddwY$GD65IT#f3<(0o#`di{sh2gm{dw*#-Vnc3r=4==&PU^hCv$qd zjw;>i&?L*Wq#TxG$mFIUf>eK+170KG;~+o&1;Tom9}}mKo23KwdEM6UonXgc z!6N(@k8q@HPw{O8O!lAyi{rZv|DpgfU{py+j(X_cwpKqcalcqKIr0kM^%Br3SdeD> zHSKV94Yxw;pjzDHo!Q?8^0bb%L|wC;4U^9I#pd5O&eexX+Im{ z?jKnCcsE|H?{uGMqVie_C~w7GX)kYGWAg%-?8|N_1#W-|4F)3YTDC+QSq1s!DnOML3@d`mG%o2YbYd#jww|jD$gotpa)kntakp#K;+yo-_ZF9qrNZw<%#C zuPE@#3RocLgPyiBZ+R_-FJ_$xP!RzWm|aN)S+{$LY9vvN+IW~Kf3TsEIvP+B9Mtm! zpfNNxObWQpLoaO&cJh5>%slZnHl_Q~(-Tfh!DMz(dTWld@LG1VRF`9`DYKhyNv z2pU|UZ$#_yUx_B_|MxUq^glT}O5Xt(Vm4Mr02><%C)@v;vPb@pT$*yzJ4aPc_FZ3z z3}PLoMBIM>q_9U2rl^sGhk1VUJ89=*?7|v`{!Z{6bqFMq(mYiA?%KbsI~JwuqVA9$H5vDE+VocjX+G^%bieqx->s;XWlKcuv(s%y%D5Xbc9+ zc(_2nYS1&^yL*ey664&4`IoOeDIig}y-E~_GS?m;D!xv5-xwz+G`5l6V+}CpeJDi^ z%4ed$qowm88=iYG+(`ld5Uh&>Dgs4uPHSJ^TngXP_V6fPyl~>2bhi20QB%lSd#yYn zO05?KT1z@?^-bqO8Cg`;ft>ilejsw@2%RR7;`$Vs;FmO(Yr3Fp`pHGr@P2hC%QcA|X&N2Dn zYf`MqXdHi%cGR@%y7Rg7?d3?an){s$zA{!H;Ie5exE#c~@NhQUFG8V=SQh%UxUeiV zd7#UcYqD=lk-}sEwlpu&H^T_V0{#G?lZMxL7ih_&{(g)MWBnCZxtXg znr#}>U^6!jA%e}@Gj49LWG@*&t0V>Cxc3?oO7LSG%~)Y5}f7vqUUnQ;STjdDU}P9IF9d9<$;=QaXc zL1^X7>fa^jHBu_}9}J~#-oz3Oq^JmGR#?GO7b9a(=R@fw@}Q{{@`Wy1vIQ#Bw?>@X z-_RGG@wt|%u`XUc%W{J z>iSeiz8C3H7@St3mOr_mU+&bL#Uif;+Xw-aZdNYUpdf>Rvu0i0t6k*}vwU`XNO2he z%miH|1tQ8~ZK!zmL&wa3E;l?!!XzgV#%PMVU!0xrDsNNZUWKlbiOjzH-1Uoxm8E#r`#2Sz;-o&qcqB zC-O_R{QGuynW14@)7&@yw1U}uP(1cov)twxeLus0s|7ayrtT8c#`&2~Fiu2=R;1_4bCaD=*E@cYI>7YSnt)nQc zohw5CsK%m?8Ack)qNx`W0_v$5S}nO|(V|RZKBD+btO?JXe|~^Qqur%@eO~<8-L^9d z=GA3-V14ng9L29~XJ>a5k~xT2152zLhM*@zlp2P5Eu}bywkcqR;ISbas&#T#;HZSf z2m69qTV(V@EkY(1Dk3`}j)JMo%ZVJ*5eB zYOjIisi+igK0#yW*gBGj?@I{~mUOvRFQR^pJbEbzFxTubnrw(Muk%}jI+vXmJ;{Q6 zrSobKD>T%}jV4Ub?L1+MGOD~0Ir%-`iTnWZN^~YPrcP5y3VMAzQ+&en^VzKEb$K!Q z<7Dbg&DNXuow*eD5yMr+#08nF!;%4vGrJI++5HdCFcGLfMW!KS*Oi@=7hFwDG!h2< zPunUEAF+HncQkbfFj&pbzp|MU*~60Z(|Ik%Tn{BXMN!hZOosNIseT?R;A`W?=d?5X zK(FB=9mZusYahp|K-wyb={rOpdn=@;4YI2W0EcbMKyo~-#^?h`BA9~o285%oY zfifCh5Lk$SY@|2A@a!T2V+{^!psQkx4?x0HSV`(w9{l75QxMk!)U52Lbhn{8ol?S) zCKo*7R(z!uk<6*qO=wh!Pul{(qq6g6xW;X68GI_CXp`XwO zxuSgPRAtM8K7}5E#-GM!*ydOOG_{A{)hkCII<|2=ma*71ci_-}VPARm3crFQjLYV! z9zbz82$|l01mv`$WahE2$=fAGWkd^X2kY(J7iz}WGS z@%MyBEO=A?HB9=^?nX`@nh;7;laAjs+fbo!|K^mE!tOB>$2a_O0y-*uaIn8k^6Y zSbuv;5~##*4Y~+y7Z5O*3w4qgI5V^17u*ZeupVGH^nM&$qmAk|anf*>r zWc5CV;-JY-Z@Uq1Irpb^O`L_7AGiqd*YpGUShb==os$uN3yYvb`wm6d=?T*it&pDk zo`vhw)RZX|91^^Wa_ti2zBFyWy4cJu#g)_S6~jT}CC{DJ_kKpT`$oAL%b^!2M;JgT zM3ZNbUB?}kP(*YYvXDIH8^7LUxz5oE%kMhF!rnPqv!GiY0o}NR$OD=ITDo9r%4E>E0Y^R(rS^~XjWyVI6 zMOR5rPXhTp*G*M&X#NTL`Hu*R+u*QNoiOKg4CtNPrjgH>c?Hi4MUG#I917fx**+pJfOo!zFM&*da&G_x)L(`k&TPI*t3e^{crd zX<4I$5nBQ8Ax_lmNRa~E*zS-R0sxkz`|>7q_?*e%7bxqNm3_eRG#1ae3gtV9!fQpY z+!^a38o4ZGy9!J5sylDxZTx$JmG!wg7;>&5H1)>f4dXj;B+@6tMlL=)cLl={jLMxY zbbf1ax3S4>bwB9-$;SN2?+GULu;UA-35;VY*^9Blx)Jwyb$=U!D>HhB&=jSsd^6yw zL)?a|>GxU!W}ocTC(?-%z3!IUhw^uzc`Vz_g>-tv)(XA#JK^)ZnC|l1`@CdX1@|!| z_9gQ)7uOf?cR@KDp97*>6X|;t@Y`k_N@)aH7gY27)COv^P3ya9I{4z~vUjLR9~z1Z z5=G{mVtKH*&$*t0@}-i_v|3B$AHHYale7>E+jP`ClqG%L{u;*ff_h@)al?RuL7tOO z->;I}>%WI{;vbLP3VIQ^iA$4wl6@0sDj|~112Y4OFjMs`13!$JGkp%b&E8QzJw_L5 zOnw9joc0^;O%OpF$Qp)W1HI!$4BaXX84`%@#^dk^hFp^pQ@rx4g(8Xjy#!X%+X5Jd@fs3amGT`}mhq#L97R>OwT5-m|h#yT_-v@(k$q7P*9X~T*3)LTdzP!*B} z+SldbVWrrwQo9wX*%FyK+sRXTa@O?WM^FGWOE?S`R(0P{<6p#f?0NJvnBia?k^fX2 zNQs7K-?EijgHJY}&zsr;qJ<*PCZUd*x|dD=IQPUK_nn)@X4KWtqoJNHkT?ZWL_hF? zS8lp2(q>;RXR|F;1O}EE#}gCrY~#n^O`_I&?&z5~7N;zL0)3Tup`%)oHMK-^r$NT% zbFg|o?b9w(q@)6w5V%si<$!U<#}s#x@0aX-hP>zwS#9*75VXA4K*%gUc>+yzupTDBOKH8WR4V0pM(HrfbQ&eJ79>HdCvE=F z|J>s;;iDLB^3(9}?biKbxf1$lI!*Z%*0&8UUq}wMyPs_hclyQQi4;NUY+x2qy|0J; zhn8;5)4ED1oHwg+VZF|80<4MrL97tGGXc5Sw$wAI#|2*cvQ=jB5+{AjMiDHmhUC*a zlmiZ`LAuAn_}hftXh;`Kq0zblDk8?O-`tnilIh|;3lZp@F_osJUV9`*R29M?7H{Fy z`nfVEIDIWXmU&YW;NjU8)EJpXhxe5t+scf|VXM!^bBlwNh)~7|3?fWwo_~ZFk(22% zTMesYw+LNx3J-_|DM~`v93yXe=jPD{q;li;5PD?Dyk+b? zo21|XpT@)$BM$%F=P9J19Vi&1#{jM3!^Y&fr&_`toi`XB1!n>sbL%U9I5<7!@?t)~ z;&H%z>bAaQ4f$wIzkjH70;<8tpUoxzKrPhn#IQfS%9l5=Iu))^XC<58D!-O z{B+o5R^Z21H0T9JQ5gNJnqh#qH^na|z92=hONIM~@_iuOi|F>jBh-?aA20}Qx~EpDGElELNn~|7WRXRFnw+Wdo`|# zBpU=Cz3z%cUJ0mx_1($X<40XEIYz(`noWeO+x#yb_pwj6)R(__%@_Cf>txOQ74wSJ z0#F3(zWWaR-jMEY$7C*3HJrohc79>MCUu26mfYN)f4M~4gD`}EX4e}A!U}QV8!S47 z6y-U-%+h`1n`*pQuKE%Av0@)+wBZr9mH}@vH@i{v(m-6QK7Ncf17x_D=)32`FOjjo zg|^VPf5c6-!FxN{25dvVh#fog=NNpXz zfB$o+0jbRkHH{!TKhE709f+jI^$3#v1Nmf80w`@7-5$1Iv_`)W^px8P-({xwb;D0y z7LKDAHgX<84?l!I*Dvi2#D@oAE^J|g$3!)x1Ua;_;<@#l1fD}lqU2_tS^6Ht$1Wl} zBESo7o^)9-Tjuz$8YQSGhfs{BQV6zW7dA?0b(Dbt=UnQs&4zHfe_sj{RJ4uS-vQpC zX;Bbsuju4%!o8?&m4UZU@~ZZjeFF6ex2ss5_60_JS_|iNc+R0GIjH1@Z z=rLT9%B|WWgOrR7IiIwr2=T;Ne?30M!@{%Qf8o`!>=s<2CBpCK_TWc(DX51>e^xh8 z&@$^b6CgOd7KXQV&Y4%}_#uN*mbanXq(2=Nj`L7H7*k(6F8s6{FOw@(DzU`4-*77{ zF+dxpv}%mFpYK?>N_2*#Y?oB*qEKB}VoQ@bzm>ptmVS_EC(#}Lxxx730trt0G)#$b zE=wVvtqOct1%*9}U{q<)2?{+0TzZzP0jgf9*)arV)*e!f`|jgT{7_9iS@e)recI#z zbzolURQ+TOzE!ymqvBY7+5NnAbWxvMLsLTwEbFqW=CPyCsmJ}P1^V30|D5E|p3BC5 z)3|qgw@ra7aXb-wsa|l^in~1_fm{7bS9jhVRkYVO#U{qMp z)Wce+|DJ}4<2gp8r0_xfZpMo#{Hl2MfjLcZdRB9(B(A(f;+4s*FxV{1F|4d`*sRNd zp4#@sEY|?^FIJ;tmH{@keZ$P(sLh5IdOk@k^0uB^BWr@pk6mHy$qf&~rI>P*a;h0C{%oA*i!VjWn&D~O#MxN&f@1Po# zKN+ zrGrkSjcr?^R#nGl<#Q722^wbYcgW@{+6CBS<1@%dPA8HC!~a`jTz<`g_l5N1M@9wn9GOAZ>nqNgq!yOCbZ@1z`U_N`Z>}+1HIZxk*5RDc&rd5{3qjRh8QmT$VyS;jK z;AF+r6XnnCp=wQYoG|rT2@8&IvKq*IB_WvS%nt%e{MCFm`&W*#LXc|HrD?nVBo=(8*=Aq?u$sDA_sC_RPDUiQ+wnIJET8vx$&fxkW~kP9qXKt zozR)@xGC!P)CTkjeWvXW5&@2?)qt)jiYWWBU?AUtzAN}{JE1I)dfz~7$;}~BmQF`k zpn11qmObXwRB8&rnEG*#4Xax3XBkKlw(;tb?Np^i+H8m(Wyz9k{~ogba@laiEk;2! zV*QV^6g6(QG%vX5Um#^sT&_e`B1pBW5yVth~xUs#0}nv?~C#l?W+9Lsb_5)!71rirGvY zTIJ$OPOY516Y|_014sNv+Z8cc5t_V=i>lWV=vNu#!58y9Zl&GsMEW#pPYPYGHQ|;vFvd*9eM==$_=vc7xnyz0~ zY}r??$<`wAO?JQk@?RGvkWVJlq2dk9vB(yV^vm{=NVI8dhsX<)O(#nr9YD?I?(VmQ z^r7VfUBn<~p3()8yOBjm$#KWx!5hRW)5Jl7wY@ky9lNM^jaT##8QGVsYeaVywmpv>X|Xj7gWE1Ezai&wVLt3p)k4w~yrskT-!PR!kiyQlaxl(( zXhF%Q9x}1TMt3~u@|#wWm-Vq?ZerK={8@~&@9r5JW}r#45#rWii};t`{5#&3$W)|@ zbAf2yDNe0q}NEUvq_Quq3cTjcw z@H_;$hu&xllCI9CFDLuScEMg|x{S7GdV8<&Mq=ezDnRZAyX-8gv97YTm0bg=d)(>N z+B2FcqvI9>jGtnK%eO%y zoBPkJTk%y`8TLf4)IXPBn`U|9>O~WL2C~C$z~9|0m*YH<-vg2CD^SX#&)B4ngOSG$ zV^wmy_iQk>dfN@Pv(ckfy&#ak@MLC7&Q6Ro#!ezM*VEh`+b3Jt%m(^T&p&WJ2Oqvj zs-4nq0TW6cv~(YI$n0UkfwN}kg3_fp?(ijSV#tR9L0}l2qjc7W?i*q01=St0eZ=4h zyGQbEw`9OEH>NMuIe)hVwYHsGERWOD;JxEiO7cQv%pFCeR+IyhwQ|y@&^24k+|8fD zLiOWFNJ2&vu2&`Jv96_z-Cd5RLgmeY3*4rDOQo?Jm`;I_(+ejsPM03!ly!*Cu}Cco zrQSrEDHNyzT(D5s1rZq!8#?f6@v6dB7a-aWs(Qk>N?UGAo{gytlh$%_IhyL7h?DLXDGx zgxGEBQoCAWo-$LRvM=F5MTle`M})t3vVv;2j0HZY&G z22^iGhV@uaJh(XyyY%} zd4iH_UfdV#T=3n}(Lj^|n;O4|$;xhu*8T3hR1mc_A}fK}jfZ7LX~*n5+`8N2q#rI$ z@<_2VANlYF$vIH$ zl<)+*tIWW78IIINA7Rr7i{<;#^yzxoLNkXL)eSs=%|P>$YQIh+ea_3k z_s7r4%j7%&*NHSl?R4k%1>Z=M9o#zxY!n8sL5>BO-ZP;T3Gut>iLS@U%IBrX6BA3k z)&@q}V8a{X<5B}K5s(c(LQ=%v1ocr`t$EqqY0EqVjr65usa=0bkf|O#ky{j3)WBR(((L^wmyHRzoWuL2~WTC=`yZ zn%VX`L=|Ok0v7?s>IHg?yArBcync5rG#^+u)>a%qjES%dRZoIyA8gQ;StH z1Ao7{<&}6U=5}4v<)1T7t!J_CL%U}CKNs-0xWoTTeqj{5{?Be$L0_tk>M9o8 zo371}S#30rKZFM{`H_(L`EM9DGp+Mifk&IP|C2Zu_)Ghr4Qtpmkm1osCf@%Z$%t+7 zYH$Cr)Ro@3-QDeQJ8m+x6%;?YYT;k6Z0E-?kr>x33`H%*ueBD7Zx~3&HtWn0?2Wt} zTG}*|v?{$ajzt}xPzV%lL1t-URi8*Zn)YljXNGDb>;!905Td|mpa@mHjIH%VIiGx- zd@MqhpYFu4_?y5N4xiHn3vX&|e6r~Xt> zZG`aGq|yTNjv;9E+Txuoa@A(9V7g?1_T5FzRI;!=NP1Kqou1z5?%X~Wwb{trRfd>i z8&y^H)8YnKyA_Fyx>}RNmQIczT?w2J4SNvI{5J&}Wto|8FR(W;Qw#b1G<1%#tmYzQ zQ2mZA-PAdi%RQOhkHy9Ea#TPSw?WxwL@H@cbkZwIq0B!@ns}niALidmn&W?!Vd4Gj zO7FiuV4*6Mr^2xlFSvM;Cp_#r8UaqIzHJQg_z^rEJw&OMm_8NGAY2)rKvki|o1bH~ z$2IbfVeY2L(^*rMRU1lM5Y_sgrDS`Z??nR2lX;zyR=c%UyGb*%TC-Dil?SihkjrQy~TMv6;BMs7P8il`H7DmpVm@rJ;b)hW)BL)GjS154b*xq-NXq2cwE z^;VP7ua2pxvCmxrnqUYQMH%a%nHmwmI33nJM(>4LznvY*k&C0{8f*%?zggpDgkuz&JBx{9mfb@wegEl2v!=}Sq2Gaty0<)UrOT0{MZtZ~j5y&w zXlYa_jY)I_+VA-^#mEox#+G>UgvM!Ac8zI<%JRXM_73Q!#i3O|)lOP*qBeJG#BST0 zqohi)O!|$|2SeJQo(w6w7%*92S})XfnhrH_Z8qe!G5>CglP=nI7JAOW?(Z29;pXJ9 zR9`KzQ=WEhy*)WH>$;7Cdz|>*i>=##0bB)oU0OR>>N<21e4rMCHDemNi2LD>Nc$;& zQRFthpWniC1J6@Zh~iJCoLOxN`oCKD5Q4r%ynwgUKPlIEd#?QViIqovY|czyK8>6B zSP%{2-<;%;1`#0mG^B(8KbtXF;Nf>K#Di72UWE4gQ%(_26Koiad)q$xRL~?pN71ZZ zujaaCx~jXjygw;rI!WB=xrOJO6HJ!!w}7eiivtCg5K|F6$EXa)=xUC za^JXSX98W`7g-tm@uo|BKj39Dl;sg5ta;4qjo^pCh~{-HdLl6qI9Ix6f$+qiZ$}s= zNguKrU;u+T@ko(Vr1>)Q%h$?UKXCY>3se%&;h2osl2D zE4A9bd7_|^njDd)6cI*FupHpE3){4NQ*$k*cOWZ_?CZ>Z4_fl@n(mMnYK62Q1d@+I zr&O))G4hMihgBqRIAJkLdk(p(D~X{-oBUA+If@B}j& zsHbeJ3RzTq96lB7d($h$xTeZ^gP0c{t!Y0c)aQE;$FY2!mACg!GDEMKXFOPI^)nHZ z`aSPJpvV0|bbrzhWWkuPURlDeN%VT8tndV8?d)eN*i4I@u zVKl^6{?}A?P)Fsy?3oi#clf}L18t;TjNI2>eI&(ezDK7RyqFxcv%>?oxUlonv(px) z$vnPzRH`y5A(x!yOIfL0bmgeMQB$H5wenx~!ujQK*nUBW;@Em&6Xv2%s(~H5WcU2R z;%Nw<$tI)a`Ve!>x+qegJnQsN2N7HaKzrFqM>`6R*gvh%O*-%THt zrB$Nk;lE;z{s{r^PPm5qz(&lM{sO*g+W{sK+m3M_z=4=&CC>T`{X}1Vg2PEfSj2x_ zmT*(x;ov%3F?qoEeeM>dUn$a*?SIGyO8m806J1W1o+4HRhc2`9$s6hM#qAm zChQ87b~GEw{ADfs+5}FJ8+|bIlIv(jT$Ap#hSHoXdd9#w<#cA<1Rkq^*EEkknUd4& zoIWIY)sAswy6fSERVm&!SO~#iN$OgOX*{9@_BWFyJTvC%S++ilSfCrO(?u=Dc?CXZ zzCG&0yVR{Z`|ZF0eEApWEo#s9osV>F{uK{QA@BES#&;#KsScf>y zvs?vIbI>VrT<*!;XmQS=bhq%46-aambZ(8KU-wOO2=en~D}MCToB_u;Yz{)1ySrPZ z@=$}EvjTdzTWU7c0ZI6L8=yP+YRD_eMMos}b5vY^S*~VZysrkq<`cK3>>v%uy7jgq z0ilW9KjVDHLv0b<1K_`1IkbTOINs0=m-22c%M~l=^S}%hbli-3?BnNq?b`hx^HX2J zIe6ECljRL0uBWb`%{EA=%!i^4sMcj+U_TaTZRb+~GOk z^ZW!nky0n*Wb*r+Q|9H@ml@Z5gU&W`(z4-j!OzC1wOke`TRAYGZVl$PmQ16{3196( zO*?`--I}Qf(2HIwb2&1FB^!faPA2=sLg(@6P4mN)>Dc3i(B0;@O-y2;lM4akD>@^v z=u>*|!s&9zem70g7zfw9FXl1bpJW(C#5w#uy5!V?Q(U35A~$dR%LDVnq@}kQm13{} zd53q3N(s$Eu{R}k2esbftfjfOITCL;jWa$}(mmm}d(&7JZ6d3%IABCapFFYjdEjdK z&4Edqf$G^MNAtL=uCDRs&Fu@FXRgX{*0<(@c3|PNHa>L%zvxWS={L8%qw`STm+=Rd zA}FLspESSIpE_^41~#5yI2bJ=9`oc;GIL!JuW&7YetZ?0H}$$%8rW@*J37L-~Rsx!)8($nI4 zZhcZ2^=Y+p4YPl%j!nFJA|*M^gc(0o$i3nlphe+~-_m}jVkRN{spFs(o0ajW@f3K{ zDV!#BwL322CET$}Y}^0ixYj2w>&Xh12|R8&yEw|wLDvF!lZ#dOTHM9pK6@Nm-@9Lnng4ZHBgBSrr7KI8YCC9DX5Kg|`HsiwJHg2(7#nS;A{b3tVO?Z% za{m5b3rFV6EpX;=;n#wltDv1LE*|g5pQ+OY&*6qCJZc5oDS6Z6JD#6F)bWxZSF@q% z+1WV;m!lRB!n^PC>RgQCI#D1br_o^#iPk>;K2hB~0^<~)?p}LG%kigm@moD#q3PE+ zA^Qca)(xnqw6x>XFhV6ku9r$E>bWNrVH9fum0?4s?Rn2LG{Vm_+QJHse6xa%nzQ?k zKug4PW~#Gtb;#5+9!QBgyB@q=sk9=$S{4T>wjFICStOM?__fr+Kei1 z3j~xPqW;W@YkiUM;HngG!;>@AITg}vAE`M2Pj9Irl4w1fo4w<|Bu!%rh%a(Ai^Zhi zs92>v5;@Y(Zi#RI*ua*h`d_7;byQSa*v9E{2x$<-_=5Z<7{%)}4XExANcz@rK69T0x3%H<@frW>RA8^swA+^a(FxK| zFl3LD*ImHN=XDUkrRhp6RY5$rQ{bRgSO*(vEHYV)3Mo6Jy3puiLmU&g82p{qr0F?ohmbz)f2r{X2|T2 z$4fdQ=>0BeKbiVM!e-lIIs8wVTuC_m7}y4A_%ikI;Wm5$9j(^Y z(cD%U%k)X>_>9~t8;pGzL6L-fmQO@K; zo&vQzMlgY95;1BSkngY)e{`n0!NfVgf}2mB3t}D9@*N;FQ{HZ3Pb%BK6;5#-O|WI( zb6h@qTLU~AbVW#_6?c!?Dj65Now7*pU{h!1+eCV^KCuPAGs28~3k@ueL5+u|Z-7}t z9|lskE`4B7W8wMs@xJa{#bsCGDFoRSNSnmNYB&U7 zVGKWe%+kFB6kb)e;TyHfqtU6~fRg)f|>=5(N36)0+C z`hv65J<$B}WUc!wFAb^QtY31yNleq4dzmG`1wHTj=c*=hay9iD071Hc?oYoUk|M*_ zU1GihAMBsM@5rUJ(qS?9ZYJ6@{bNqJ`2Mr+5#hKf?doa?F|+^IR!8lq9)wS3tF_9n zW_?hm)G(M+MYb?V9YoX^_mu5h-LP^TL^!Q9Z7|@sO(rg_4+@=PdI)WL(B7`!K^ND- z-uIuVDCVEdH_C@c71YGYT^_Scf_dhB8Z2Xy6vGtBSlYud9vggOqv^L~F{BraSE_t} zIkP+Hp2&nH^-MNEs}^`oMLy11`PQW$T|K(`Bu*(f@)mv1-qY(_YG&J2M2<7k;;RK~ zL{Fqj9yCz8(S{}@c)S!65aF<=&eLI{hAMErCx&>i7OeDN>okvegO87OaG{Jmi<|}D zaT@b|0X{d@OIJ7zvT>r+eTzgLq~|Dpu)Z&db-P4z*`M$UL51lf>FLlq6rfG)%doyp z)3kk_YIM!03eQ8Vu_2fg{+osaEJPtJ-s36R+5_AEG12`NG)IQ#TF9c@$99%0iye+ zUzZ57=m2)$D(5Nx!n)=5Au&O0BBgwxIBaeI(mro$#&UGCr<;C{UjJVAbVi%|+WP(a zL$U@TYCxJ=1{Z~}rnW;7UVb7+ZnzgmrogDxhjLGo>c~MiJAWs&&;AGg@%U?Y^0JhL ze(x6Z74JG6FlOFK(T}SXQfhr}RIFl@QXKnIcXYF)5|V~e-}suHILKT-k|<*~Ij|VF zC;t@=uj=hot~*!C68G8hTA%8SzOfETOXQ|3FSaIEjvBJp(A)7SWUi5!Eu#yWgY+;n zlm<$+UDou*V+246_o#V4kMdto8hF%%Lki#zPh}KYXmMf?hrN0;>Mv%`@{0Qn`Ujp) z=lZe+13>^Q!9zT);H<(#bIeRWz%#*}sgUX9P|9($kexOyKIOc`dLux}c$7It4u|Rl z6SSkY*V~g_B-hMPo_ak>>z@AVQ(_N)VY2kB3IZ0G(iDUYw+2d7W^~(Jq}KY=JnWS( z#rzEa&0uNhJ>QE8iiyz;n2H|SV#Og+wEZv=f2%1ELX!SX-(d3tEj$5$1}70Mp<&eI zCkfbByL7af=qQE@5vDVxx1}FSGt_a1DoE3SDI+G)mBAna)KBG4p8Epxl9QZ4BfdAN zFnF|Y(umr;gRgG6NLQ$?ZWgllEeeq~z^ZS7L?<(~O&$5|y)Al^iMKy}&W+eMm1W z7EMU)u^ke(A1#XCV>CZ71}P}0x)4wtHO8#JRG3MA-6g=`ZM!FcICCZ{IEw8Dm2&LQ z1|r)BUG^0GzI6f946RrBlfB1Vs)~8toZf~7)+G;pv&XiUO(%5bm)pl=p>nV^o*;&T z;}@oZSibzto$arQgfkp|z4Z($P>dTXE{4O=vY0!)kDO* zGF8a4wq#VaFpLfK!iELy@?-SeRrdz%F*}hjKcA*y@mj~VD3!it9lhRhX}5YOaR9$} z3mS%$2Be7{l(+MVx3 z(4?h;P!jnRmX9J9sYN#7i=iyj_5q7n#X(!cdqI2lnr8T$IfOW<_v`eB!d9xY1P=2q&WtOXY=D9QYteP)De?S4}FK6#6Ma z=E*V+#s8>L;8aVroK^6iKo=MH{4yEZ_>N-N z`(|;aOATba1^asjxlILk<4}f~`39dBFlxj>Dw(hMYKPO3EEt1@S`1lxFNM+J@uB7T zZ8WKjz7HF1-5&2=l=fqF-*@>n5J}jIxdDwpT?oKM3s8Nr`x8JnN-kCE?~aM1H!hAE z%%w(3kHfGwMnMmNj(SU(w42OrC-euI>Dsjk&jz3ts}WHqmMpzQ3vZrsXrZ|}+MHA7 z068obeXZTsO*6RS@o3x80E4ok``rV^Y3hr&C1;|ZZ0|*EKO`$lECUYG2gVFtUTw)R z4Um<0ZzlON`zTdvVdL#KFoMFQX*a5wM0Czp%wTtfK4Sjs)P**RW&?lP$(<}q%r68Z zS53Y!d@&~ne9O)A^tNrXHhXBkj~$8j%pT1%%mypa9AW5E&s9)rjF4@O3ytH{0z6riz|@< zB~UPh*wRFg2^7EbQrHf0y?E~dHlkOxof_a?M{LqQ^C!i2dawHTPYUE=X@2(3<=OOxs8qn_(y>pU>u^}3y&df{JarR0@VJn0f+U%UiF=$Wyq zQvnVHESil@d|8&R<%}uidGh7@u^(%?$#|&J$pvFC-n8&A>utA=n3#)yMkz+qnG3wd zP7xCnF|$9Dif@N~L)Vde3hW8W!UY0BgT2v(wzp;tlLmyk2%N|0jfG$%<;A&IVrOI< z!L)o>j>;dFaqA3pL}b-Je(bB@VJ4%!JeX@3x!i{yIeIso^=n?fDX`3bU=eG7sTc%g%ye8$v8P@yKE^XD=NYxTb zbf!Mk=h|otpqjFaA-vs5YOF-*GwWPc7VbaOW&stlANnCN8iftFMMrUdYNJ_Bnn5Vt zxfz@Ah|+4&P;reZxp;MmEI7C|FOv8NKUm8njF7Wb6Gi7DeODLl&G~}G4be&*Hi0Qw z5}77vL0P+7-B%UL@3n1&JPxW^d@vVwp?u#gVcJqY9#@-3X{ok#UfW3<1fb%FT`|)V~ggq z(3AUoUS-;7)^hCjdT0Kf{i}h)mBg4qhtHHBti=~h^n^OTH5U*XMgDLIR@sre`AaB$ zg)IGBET_4??m@cx&c~bA80O7B8CHR7(LX7%HThkeC*@vi{-pL%e)yXp!B2InafbDF zjPXf1mko3h59{lT6EEbxKO1Z5GF71)WwowO6kY|6tjSVSWdQ}NsK2x{>i|MKZK8%Q zfu&_0D;CO-Jg0#YmyfctyJ!mRJp)e#@O0mYdp|8x;G1%OZQ3Q847YWTyy|%^cpA;m zze0(5p{tMu^lDkpe?HynyO?a1$_LJl2L&mpeKu%8YvgRNr=%2z${%WThHG=vrWY@4 zsA`OP#O&)TetZ>s%h!=+CE15lOOls&nvC~$Qz0Ph7tHiP;O$i|eDwpT{cp>+)0-|; zY$|bB+Gbel>5aRN3>c0x)4U=|X+z+{ zn*_p*EQoquRL+=+p;=lm`d71&1NqBz&_ph)MXu(Nv6&XE7(RsS)^MGj5Q?Fwude-(sq zjJ>aOq!7!EN>@(fK7EE#;i_BGvli`5U;r!YA{JRodLBc6-`n8K+Fjgwb%sX;j=qHQ z7&Tr!)!{HXoO<2BQrV9Sw?JRaLXV8HrsNevvnf>Y-6|{T!pYLl7jp$-nEE z#X!4G4L#K0qG_4Z;Cj6=;b|Be$hi4JvMH!-voxqx^@8cXp`B??eFBz2lLD8RRaRGh zn7kUfy!YV~p(R|p7iC1Rdgt$_24i0cd-S8HpG|`@my70g^y`gu%#Tf_L21-k?sRRZHK&at(*ED0P8iw{7?R$9~OF$Ko;Iu5)ur5<->x!m93Eb zFYpIx60s=Wxxw=`$aS-O&dCO_9?b1yKiPCQmSQb>T)963`*U+Ydj5kI(B(B?HNP8r z*bfSBpSu)w(Z3j7HQoRjUG(+d=IaE~tv}y14zHHs|0UcN52fT8V_<@2ep_ee{QgZG zmgp8iv4V{k;~8@I%M3<#B;2R>Ef(Gg_cQM7%}0s*^)SK6!Ym+~P^58*wnwV1BW@eG z4sZLqsUvBbFsr#8u7S1r4teQ;t)Y@jnn_m5jS$CsW1um!p&PqAcc8!zyiXHVta9QC zY~wCwCF0U%xiQPD_INKtTb;A|Zf29(mu9NI;E zc-e>*1%(LSXB`g}kd`#}O;veb<(sk~RWL|f3ljxCnEZDdNSTDV6#Td({6l&y4IjKF z^}lIUq*ZUqgTPumD)RrCN{M^jhY>E~1pn|KOZ5((%F)G|*ZQ|r4zIbrEiV%42hJV8 z3xS)=!X1+=olbdGJ=yZil?oXLct8FM{(6ikLL3E%=q#O6(H$p~gQu6T8N!plf!96| z&Q3=`L~>U0zZh;z(pGR2^S^{#PrPxTRHD1RQOON&f)Siaf`GLj#UOk&(|@0?zm;Sx ztsGt8=29-MZs5CSf1l1jNFtNt5rFNZxJPvkNu~2}7*9468TWm>nN9TP&^!;J{-h)_ z7WsHH9|F%I`Pb!>KAS3jQWKfGivTVkMJLO-HUGM_a4UQ_%RgL6WZvrW+Z4ujZn;y@ zz9$=oO!7qVTaQAA^BhX&ZxS*|5dj803M=k&2%QrXda`-Q#IoZL6E(g+tN!6CA!CP* zCpWtCujIea)ENl0liwVfj)Nc<9mV%+e@=d`haoZ*`B7+PNjEbXBkv=B+Pi^~L#EO$D$ZqTiD8f<5$eyb54-(=3 zh)6i8i|jp(@OnRrY5B8t|LFXFQVQ895n*P16cEKTrT*~yLH6Z4e*bZ5otpRDri&+A zfNbK1D5@O=sm`fN=WzWyse!za5n%^+6dHPGX#8DyIK>?9qyX}2XvBWVqbP%%D)7$= z=#$WulZlZR<{m#gU7lwqK4WS1Ne$#_P{b17qe$~UOXCl>5b|6WVh;5vVnR<%d+Lnp z$uEmML38}U4vaW8>shm6CzB(Wei3s#NAWE3)a2)z@i{4jTn;;aQS)O@l{rUM`J@K& l00vQ5JBs~;vo!vr%%-k{2_Fq1Mn4QF81S)AQ99zk{{c4yR+0b! literal 51017 zcmaI7W0WY(vMt)SZQHhOcduS;+qP}nwr$(CZEH2&I&bfL-u=$q_vNUpQ9mL_Wky9t z&WM<$APo!x1poj60q`KZF9Ptl0sYtQZ-e~XWkpp4X(i>v=z#$g{vp^9t%kz;S3u=& zNBQ3cWd-FV#YB}==w!tnWv3=(q-p8qVWnxQW~OEvl^B+o_l_T?XvZX{Wv8hnX#k-v zLX1+5iZm$O&`C>N`ww7dj2*6IL-PlpPVEyN>#oD(JjuU9F4&>RtrkQfFSerWU{tTQdH z_y5pxtmab;+TYJ__gBULWeWeL<$r7Nf2rla*Qo67=wxiI;9&b#Sx)B0j(?xr+y$MT z%#3ZE%nkLOY#sikgkoiDTO>gQA2f>4(fNaNz3SwR6%Uo;2-|r*EXa|epfs{&vJiL^ zXlxG0Zeq{KB;R6PtHN;pK78XW&e%#C?G;h zzE~o`tkY+OmhF}!THQA9@lFwE-Jq{Ncy~)jpMI!82hB2Gs#SPnOQ6RAKm9?<75=-} zE!ZFjQ*u?9En|Rj*O_IdnzR0)7*`A^M!cxpm6N=G;gRhZ?_!5zYQ&x@`*7`&>suh8(vV55ruH`4wv-#{>(SUWrEQWJ zRtmaNweT0zLf_f#(yL^3utc>2!Yhs9Wxs&_=}bl-oLC$ zG`j!q)`AK7nL0l~LF|Ikc{aH3s)Pa-RCv;9Wnz=!zHs8p1jp|SMdD7zgcwi#e1G)X z#s@$<^E~r_fbc1xCS{d}NIWMy{WX(Bv96CEtUJM?X{r>|NKB}{ZJ?Nxu4W3)JL&1o zSYP%UB-r%%d-_s%Ks__5ID}lOZsM*0A%qoc;Leb~U26R$DYA_u>bvknIaI(-0lYm3 zO>5Fx+WC6z$?CSx7xqf>-(vCFE6++*6wNIbnjo6%8rQ0eLz5NZDi8#a@$!Dp8LGc8<4CyY@JqOikVL^ZNj)4^#vwPK~=2>`~@OhEYQ3>4<5)g(Ha7 z5$v}I!~t|8cqob~naK`FLrTLWYJR+Y2vX^8jMvx}KP?E#&8E04<~oJgU954ivP{-h zYRovwc6LlKY)4ZYH=IZ1OruMCdc^CSE!Jb_=zD?=S~wi^2Cu$C^Rcv-8o@>b4no zqbJC=k2`DgmI^VOu3@0r32)#9uouWV48^z^^;{aE+5S-U!2Jq~Fi$`o#xNg9+!psm zIb{DNAWY{FPDn(VmtbB1hDO)Z)r_MU*Q4f$0Vh$#_oL(?!5v`1YfhBcFnVGc^iDma zzxfLA2o{Jh1M3M2OpW6b9(V)$owgcGBmzUE7UlvID>*|D(tbIBghoO3Lb`a-Ta!wu z>81P&0+l{52)z88bLkEt+!4k%l;&l?=89Cvp+wc?h5nyrigTd7ISdK_@bMQJF#l&W z6?HSTa&|O#F%~noG8Qy6Gy;NLe#5)5wD@21RWhXVdQ3j?R>o_9o!F_~U$cmR-n1Osft)f+;RO8pw6%e?Ksc zNuPs3k2kd2nwipr3-^xqb9(#p!N&jnXBid%{xFfCCBG2}v1n-FSlkss2j}%r1cA>f zVp7un0y6K{mAN1%X-W@)T;Xo4Kfnx#B5@ci2lf!N8=HjkET}!)?4NuP1_~5rK%?Lc zED_oes`x=W1gx1~1|S{yg+3TQX-F$YG2~pc&Lqm$rylaoP9%RwgOpB_8A(g1#pqTn zH8bKZ;}wz_q64ZiTyhK0RUuJZ*eWtaJ1YqUrKHMcGCOiutd_BqodlnnEkaE2Qxx!I z$*@02+>lLDB3LP>6*?me11pl%z?@azn3*GXO4T#kQp0pS)eDo=Cz>4Uvx<$JS=nqT z-@7b^H|UL?3A-Sq&G{atSqEGN&mww<0AOZJhSsO-_qN+GAz%CQmX4kKO4RWPcJEVOGt_V+WVqph)&sQG94AW^W-CD?wrkXt8c`pw;FZ8JnY$zHV zD9E0f2=e}3QqjyMc=KGr3DJ~p$&BTY@i!RcfpC;CuO?!qrq|zQ62nlh{oTY=%(POw zU5JmC8gf}3E*;%I?z{4+vN#B=HXMb;mOKIVu)@+2LH%Va-bzT2!Hfjt5J&1yC zEUhonr;Fs!xQj@CQA#v*uYSZ>YpBvkE8!kXCpErL*{6%}P*$cv_vZbE63f8rw1F_6 z={m-72qyvp$JYLdD5b(EWZB9{Yu?Hr8YW%MsHUCxCQH?l|mH(#_E>y1d=QDmSJ=ZBwQ}8gypIL;P0t`G7oa77Osg9 zdf7kugeOcsYq+tqO8+vf7I$^yf$}%#lb7YlZvjq zN~+7tXguWjWzob+E2*RJaC`t;%~qc2qP|60J|bPJP<@AWZ9>27%t*M2AAx1)<@QUOvYQ5 zSfzxlHtkUIhTE!1+V)AV+!i`Dn{77Yps>Fd@9>m}YOpfu(Cy>~qK~qIh~Z}$uL@DN z-7enpQvt`Bfp7b6D3fOU*co8?WBn;rf&#Qk6gXkqJHxjqRkBkKbSQOvV3())DDfb` zd&I%%n|ns+_tRDQzF?-A%P`HLs?$d{+SsqMg(!6JN-ns>KW=9AscPXp+ZBqf9DXpM_-N_238}(YYwj6Ptkq%Jx3$`vWNXSOX_O~4oYTk(O zv~mJCM-#JU{Bhx#AceB0meFkt(zgrtqIn#T?JZd`AUMU>c`efLZ8X&>b z?gM#>-`K11|Ge8?Ai~6R1&qdtGw%)swgsul93b#E&;J6_EyUf;1KvHL@abE8S`F7V z+edS69sd*9#XtThvWxrZOE{;@0UoHyD=_D!F#w!VST{CdL~2GYrxf^!hO^XU!Y%BL z4UfD!im8_{25qDZz87hcFzJvX`H1tKoZ^RsQb*|`TLa{I99%(cv- z>+gZ06~gWuY(x)QS$5K5K^qNBE_qGb9h=3n*}Mx`l)|*UwTW4_StO20#Yk}8#`A*z z&r`v$*1tpVFL*%!`@e#hU;m1pgl%n1%uSsg^qtIYZT<~j5;koX1rS0^6FKB?*=O=; zX-@_6V>BJ45hCt!_gb7Vn4teWGq^Y$|mh{{Wcs2DeSlh$DVnC zf=|+)$C-G!ncy{Ra}X%xcK92GG6gtm&NXukTkdBZ-#S{=oTLQ458wkGfi*=a6Vzj2%6=&8;ZS(BOvnj>_r^|x$1aFZ2O zy2^eusV#7CBW@8*QLDW9b*hl$@D4JIXtH>kzVzpsb32_PsS8xCmFQ3>6#8Mi&8~0Q zvB^WP#V(JI`!7SF9u)`}_;*;pmhz#nP*fjO#z6$I<8M z_6Y>^!H7ZW^e>I0)b0RrX0Y^KFnMoa=*Wd-o}T2GdW3H--5Y77b+QqpPYDWE2IL}Zhl)gvks;8-RaYe3>_pam9q#wrkwz+w>mirf)!S(`Blo&x9k zRSCm}0<9nfZNddf@Qk2YpD_tEfE+X-5{?D&paj*134Y@pAzI+g0#K3>xCRk0!8g!? zv{Qq{yT_H5t!D!&NeQf^iTyzT(^M6`am|naVrj@&TuxamH1o_)`DoW0up`FuzB`+EC5NEcP+CM=9B z#*#Hu7QxQ?M*5fphHCi0K^JP2xX315-|w{BwS+LA&$x--cgG37PHwX z)E~mQh=d$`6=gSr#f<5&F>+NDpU#A%oHHqto5}VF^pa`Xtf0(vDG2o}P4YpyDr%5KHOJ=k{YK<0T^% z)2h7Us`{}YV?+zYIR{if>uQ8r07~X@Ogh_UEMtcbk_hR?iU7Kk95m;=kBxkfx(iP6 zb35$;ncpFrc4vle&jvN?r73mLa!N^i7an5L&(g}coq}iV)mx4WW2Nq?5!75vdW%-( zL8$>TrcDV?X6JSBi}tD?J6n0BC{8sXJ|%kXCTc1W+!l>oY7ESc4dX8G+%eZdr;7tn zrdEb24R=z`gN{+hVQ}E?l3KW+T8V(u)N5(FA^QftMf@Ap27;qRd~^1=_!VywqoZy4 z2gta&0l&RMW}R{R(5ZTs?3EpQ23Dzh=I?2H7Vmj|6zru(W8WkNovz{2{g+;Pfx3~T z;m{km&T;6_)w4Eg;(*1;YV|fF${tvyVSSklPm7r`V??)mB)l7)R_iAuMlGKv>77}> z@+?!;tviEVOAk+jkDMiyj zX;xx5*rb>u;Cm-~3|m=Lo-*|`#pfbGJMA}i6=TI5=eyQ1eH@w(N`_T}>XV8F;;4z4 z+cB)s2#<$lngDgtJ)`(>_& zLBX*z=q3vD%=qNMqflZPv%C&{Glw*wkDih{89U zRq^=23qE|S3oSkgv&4!<-hBc2&VG@;jYCAy3uc#`?uppyB3{1LZU^$6C1%Fmj`IeQ zr{u}g=O=GmZnB}&$J4Q)&ab>8Wac(my9d35?+~@{iG>CT>W;l)Y@%%SL$*W5AKya1 zN1o9b{Lv#op(wb7dkF&SA&=23?|o(p z^yN0MDa`RVeV{-jm?p%14p-8KjEyitb`cu3MJM%&7=s72F#C+)VU8-AmGyX}MO3kR zeow~VVq?FxJtDX@EZrtQ4bE}p&jtRjza%%ww}U2*er>R|Ek;iJ`nY&W#*3F{?AHTk z#@mNfWDiBZ7%3khCtqs^d%(VfXBsc`hAPZ4aG-VYx}w-6)O*hQfaKredl%=QfiPv1EE%k5>F zqGx#4R{TDjqKA6l^NsJY4S5*8;Egc1i};|%4>)loLMdmCW^*Y8SCiQZ&_Qlhm04Mh zM!FdUr=5qJjWJz2gWkwAwMOQ&Q98JNeQU`WuznnSLY7op?MbOa0Pbl)6ws47#AZFh zhMvM$9JS8Y#N{L0%B04}LU&vx!q|C7X_{Irn3jhX1x+C|0b7ZN@)W+xyP8w(y}5wNAYTz zaiT&fg$$G{&J1pP{v}nVGd;FgB(Ao!i`>{#o0_v^pamU#m+>OJ6>%o3`s#^@U`|#~ z0C3)TSg90+j7fu}b*E{N1x9M{NsZ`7klNQpRTG&Z+s*TNM>q#C86CILOSE1MRANZK z$8AQF2M2-T?sF%?;eWX?$B8mZ{T70XrgAj~`|?#s^+n30lY}cIQWyfEc+>mvtJ&pi{AERUPVV$|0xL6@ zZOSFrP7B$orHXrOv^`aVrr-DWx|x(oKtS#oigPLbpJ~U!XWJ3ITpOBR5rrn;N3q z_olWZb`!&GHf#5)NH$uFt2o>@lBPl4t6_*4TZ6ksTcasaz0Aa~oLZ)qu}Sx2J4E(x z)3G-t!e2H;W$8qCV{hQ-W+*=-)(uQ_Ly{i$(-GVsjUD!peM7t927skI$Ht^i;r(jn zcvj~Qhc$a0Nd8E+tU30^xcdqoihXyT9eX`JZHDV&{k?I(w6Gj~^8v2@Wv1>JU%{dJ zG@rAMe(+#M9@Y)2gZj7b{D&;*lf{J2UwrbO=^VXUB7E>6)z3nx7rc zkXL#1pg_7RtEIJ#lK@vkmw1!EcWwqlk=ys$h)DM?r?eJQmm-!1C1_Vn^?Q9h}8wMx^PDE zo;q{jJXd%Cc=Le0tyd||WE2R2*4Gpr0{TW+k%>?s<810%<8>|BdNYNkE7c*Ew> z@>Ia;@g;ExQxGEQ^uXz*`3I9kI z5Xktv5Xm<}{9d@6AwLBBLM}M1Cn2<|Jy3uREj17yust|4@T{oAz@pm{el?Lkms1{} zX)8T^_k*=D*SA8YLGu;C;PQ$dS0r#=@#8u!SB)6An7| zW*y=_RK?kyvenmPbP2F4?c14u4F4^#`lwffS zZ(om6j2;8a-~bt3j*wXmJ#rJp`_~I2)E~<^kXL{pacWwtX0W_xEJYCIA5V zd;O=QGL9A_&HMQh=fx)3MKa!m7CCHkULR|Z zU31|dTN8P6#*wqpSMNvM+t1$D9^2lB!Bkz+0@}}e0?~8%qW2P(-Gmc)>G{v}sBaz# z=cf{(-4_Jk!)F4}GkT+I`r>!FxSfJquyfC+UxFTS-x?Xcif6WgDuTY`nm;=Ex2f~| zbNp0K@_-+v!QZ43(NDF48nQoRk3V>MKXKpus2{Zi)urr#DzZPc(?1fAz`y_K#vl9u zJqf3`S1?dc0n$O%fg@kRE||PX9>O;a_$$#J=M5MOUKFtdR~4M1Hq>j0Q3rNKP@~kS zv`Mx60yk%01u;jjRcm9D@DvTu)r+fm)zomtIsFsoo-!?Hs@r#45$l+m~B!6Wy{E?8SXrGbd9q;rhDHaF5HH?HHLbAzP-i6=W%MV)w`PO_s_W(1|}XP z7w?3})vLhasm`9~GSD#SFq~?M8hXMjLG3mnGPi{MQ->yf4%ib-iNHEbW>A7=tif-l zv532vf);&_Yf5WvBG$?U_OWp3;3d{5?@XTP;YC!UDT5t}i!r?$C~Wz(KCVt>o;Cl9 z&Dibfpd?Qg+7!e_i^3J5c-DIY825O~iWJfvTi$wqJ>1=6B^#RF)or3;s=;YS^0cqw zCDaOMu8#62JyGMT&II!zJLhSmG>T+#qabUzp&mm7Moy!{yxnrBr#|}V~%AmkN zcZV-ne=VZFcv0p;fCvze5q2aHutj&Z?RhfHFQ16%8Bcv8_&tVdr+Parqm zP%_xov?62W+RFf37P;lxiiV^S=V4MtBhxm8kC)RNles2hr%Ye4S@j08YLpAC9^F(8 zT}a=C3^?>Iq1zL>{d#a+U`iD;X;8YzT4QFM``GMunWhr&Zzf#D!&XLK&mTNZ3I;}M zH0nIaq?E?HoiQbWo=8husr8TP^LP^NN7RMdmIT@G2|&M+MQAW7+C{@7Z+SW8_Cg`J zGwnr)$wEv9I{oeO^%D8V!5%^ZNA7~2cgJ=gEVNDQ^ z0$Ct#dSPM14Gu7IP)|%OR^%;_4$>5*367RxIxeCei==1s3mjKgm{|a9sxTZ@Y9yx` z@+u$V1fH;^h`91HeR~SBo;Lp4U&9jTMiBaHAYueHohq`bn`>_C;}A9?vDH!Mrs-DH zen=*Af`xq8;FXPaenXPzI{791m%T_xdbP^;@yanjQ?)W{HZtd) zMgQfKe0u~;^+0E%W?5S;%Iha6biqs2n+i_o(xV0iU(O>lOYnXi=faR&7u}X4t0eQf zb3O-m`m5sZB;@GCZfPlTKgc}Pp1zKi7;y#3an0mBv4xUx6YnNByFU~UcGJWSYMi=i z)*{iximr>a)3ydzly215=zyg}6>nb=@slnY{sCk0-V!SQBpU>p8OPTZsmv>EG#=8i z@4AJ?T5hiLLEl5{nAodz0udAU*pTWgK%JIDpJX8fUGY}%p;HZ(Qehs}q-bhf*&f+_ zr_pj0E;;rQGT%Yz*z>oto6xZ&o-#+pLTb_25*=@DF%I6MwOKM{=6<@?HjI3_+AsBE z${e+K6byprT!pu$iPwAWvA$txa=Hgmhpf&Lhp0m$Qz5LzK9lu@iUOS+0Wez$Hj<&l zSJM{M6p3Wo^_K7JN)lzq+Vluf+&t3SLaLkALPl+AAPN(8y3v3z6e4{(E1BTaDU~-G z9qfQ$l$W*ACp)ZPhroXM24tJa6lGN8>uMau514$F4>W}}l&0Gol@FXgxfAerfmFS^ z3JS_i2Yp-#NNDeb!Tfm-;GmrFkD*L#x@vf;eDpW&A`~^+7b)=p9lulY2j8U+;^89$ z;~aDfS5bXbj$`j|q4-N44nKn?@Q-5&S8B8A>_Eq-B(m~PY`X6~okvzh zPf5HOC-8<@%%35BV+z`Dw;g}Pa!9m81w30oGV23?1HqPDj1+j(*w8rix(ET%wcuPo z%pT{Up-z&KLYs#~^JuEepCq*4&Gu%*1W4XkT%gO02NqPPji<^U=kOwVY$HoDr!+YK z8uha_sraReXo6rT)?*O1;DAHdX1jVKDzv}dUh^ia6{V7_Db;&v#OC*WmiOqk=_!n$ z^#YQlKGpM=;sB^j3;=qZxf9>~Vx+Y%7EuK1t`rk%?E5gGi9oS&lIM%g4>+9NmU#hu0{HE-Sk0=<^yLwy~3D8#xfFB0CQXu%DEI!$jN7Uoslc2{6GhCWj_)CFcdko7>X8VPD7hH*=@=BMN5FWRmOiew{TWoLmP3TLsnXt$0w(0L9P3KB z39(R<;(Us$XsiS!o*4;o4Ko~p6eBmk@hte+ltRGgX;bsWd|2V}vB*GyZ;MTyy0gpd zm-9QrZ?p$mCD9_zBWQO`^fHH>3Z2r6S^9WWQ~f?NH>j9ouWCQYIoR5_WsCRIr>`djw|=@m1G4C;@HA@Eb$A( zrb4?FZ54ULCArYDR5)%8*3PX)4Oni6MrIEb1d9G~;3q^6m?u1PcO`p|6UeEgF;Dty z|6TFgyjz{3=XlT!1`zNd`gt}dcKFurj>XIM^UC{Wx7-3d&1hT8RQ{vf(&$tPYuI<) z0!^v2F?W33o{#I5th-Cx0P+0|LxgWUj$;nz1;`H6!%g!6#XW!*79~(`9D_glZ)hKg zA0RWU^Cle<{7}y}0Smc95?Y(ts!iP0W&lef-3e75H&e)I?~LFW{4qan#~pBowgJ+V zC%Zr+m-O+k6GW=w8dTV5W{U{$^b03pKd2T_Zd92gL^~5F^QV| zsq{ygr7z^>hmK4264`ajDHGL?O|XAj3NuS_ADbSTu62vF<3%@c+&iIz74)ofZa5s?FIebxIKd2SDLUKwbmkyt16?M7f

N(DARnfPMFG|;(rIGZH1uB1rN;y7UlJ8 znb!RwO#5WS_%cPPlwSw94PTKP64}}J!~E1}ch9``2jvUrB*#@up8L&*`tqgq ztTAS@^33w-5hFZAH&{j)?l0<)9X(d`N|yLk!E=iT%PD-FTJ!|hqyj%RFFP`SaL;|_ z$(+VYhKm)K@Oe~+eZK(6ElQNdfimBrdKjeVl57_7p^|)jrzt|wyRonj$j9Bji!


f)EE4q$t9yObmyG04W0z zwEAra3WPkn>3Fb9s8^;JsD2U=J6G7s&CUebJEw+&=yoE*5?$-5j`#sxPl0^y-Nr5f zqODD$5Yec*Q%egs>4=qVe6nv3ffzozQ=Q){+(I-_?VSTi`{dk4@98oU1+Xtx3~B}K zYz=68@z@s5-T1<7tXF^>56vl# z58_Nqz!y-iJ+67h#|Q=}D!^}=s*eO@Y-td)8erJkZxGjR*`DK^rOIeP2<-!0FE>;# z_OWgl^eNX*lnJve=cWYR46lVZ=AlV|p3D5zU?m3qyx2*j8=?;SN-bYo6*=D1Sg&7Y3#^FT*@Odq-Z;-7>QjtU_L^=fm4iA4$-Q>6hmA zRIlHQF-50@Wj_&2!!tn^AW)czs8ybBv96Z%y6@Zh++jREJP+vPs$8uLU;6v)1AzzoXl^+Y(8ayi``o z&7K1gRo6gigwS58-c-J= zk~u7=EQOuN0vTL~k)W5tRTNoAFD8;wMuU8oLTCO5`(q=uhmAg@)=PHx5BZWJV3$9>@tgfGF?th{E_!`6G3pbet--D+P?`sQ$q;Zx z%t`hA!7mSNYBqbm(<&6CGMIfI1yAS~T5gA6nXvS$h>h>wN#+4=OY?AM^bd_h=<%PE%0+efQ zT519u=4vMv>vGC$(Oiv-Z@$I?SJ}mxji%pfti(2zDbrPwfIBq0P-pPg!!Jv~tQD1F zTv)BN(-QI>NYha>=3JRhcV%iBL`_Q!Xat>vr_(U{?OHzS0)dsC3fx41)1>vdi15?TlT$mal%d(AU}&53zZYUUxEieJ z<+tX27~QLrZAwE*+E3R9Nj6(q7ssUbir40&RAiUQoTDqy^EO$UV-mM7JtLpMVa>cui;PDaQ8w<{p=jt0S%`-6Dhm zWls zyQ*A00#tGit}tCy=>eITPG#jlVU^%6m0z(zZ*XiX8}_S9yL!tt5P{BQ)qc?qmxZiH!IXdss0`rYp5n# z9oA?qNyp`%*q~AVu8Y8;=Hg%;;Z)__( z=xL^@qCVbhoXRP`|Kt{~g;>p7?6~^|7h0Y!jnMPgs3+a3u{Wu_ka<&$KAaHcve?M5 z*W=6Q_Nruw^4y&qKoQxui1+J>U{eY#N`&ah(VE59r_frKCL!uBcmUJN`EDfJR-r6p z##}B56~NoHD1Jdi++w6l`B4nLXBk2hSZ&KgKW@C{A7i#pk#9z^H& zPZIxP#3CC)9s^{IT?H!89Y0(MV&8k#CA%C6Dg~9j=gA=V0?ZXa@*QB7`I9n@4yOTE zItq!LXP4b{JHSw50JHrxJtvG0&pqxwvfKDCWSaxo1}y407iZgen=BF{$sIEKCwYajZAQ_j`7Wo3m7%)cYm94mCz{x< zte2=rYlGL>GhB0ITZamFt$Xl?vrot#zt`2%g1gCH-|PbF{ay_cuYeoFr%!t|e-|id zDCDAT3dAnKOZy4lQZ8BjKoHk}F*p143&wCtu2q?%UDE1MKEIknUX5^^o!?R^St54< zyDkS?@9_V0hy9`i6T*L)49#c&02Kc@dH8SQji{Tkq4R%p?~~PC^{|&Qf3k_i8yxJz ztW5X)AON`=jG3h+gv@w=N_5oaltNq1e|M~*8)b83Go49jnyJ%TOQO$#;-1@>g~PT9 zNN>(9bidMVd(O$ed%K#R7ilfrh3+0`IH9j-9wp!Qc5mi1c> zw9!Ur;6w@aTNv!=5um|0bP}q#(DlYBMP@wJUVc13(Ai}N0KTI=qiH5XJ+_CNV zNQZO=A6+AM37@!5%yb@IDuCRkyz?@3u?M`4fBInZA@qYAf5*Xu4z`g8z(>x+Lfm#M zIvs?mv(oA^KRD}xyhaYg2QgB!z>ke*KRnMf;6)vH;Y95brsK!#86tY|1c(#8iGbur z?I|~SvqXs(u2C4}ro1yV;b{Af-u;e$XlLNV7p3nZkm|u0PQ5c`yrx$4Le-5txO@`> z*;T3QDy3)TT3Bs1Zn8DA8%>G-#vLRU9_%JAG=wtv>TKH9FjbqBbtYP;MZs@)#}1*n~=)XfJe-TDf9D-jJB{iK$w(g16V)y*_UNhqV5!X}8mbdyTE=p{I>UHuV-sbK#}b96 z&^f1XpDOFbmcb#UTd|+izeSDM8wb9HN`azk+;yvyz50~bN$91h|E!viQ#|#Embdn| zN35bAR1CW47}}(Qozx}PFG0Ch?$)R$$vP;Ld8yPxZNBgn7>b~K+L7Ib<|yKYEd%59 z7}QI=Y^lYJYSR{T7%g1D%mpjWRw+4739FpVl7J4G-|F5gOH6}3BG#OgETFAn@rK3c z8!D2>?jH_QimsmC7`rA*H*ekeW;oGX!zi>5Q1rt7s;Efvn zO|?tR7x`%U^TNe5NGZYt38ym%h+qM^%!2kKROY;hf}yZRfsgP@#eik?#oCNgGnJp* z0rww?`rUH3J*w<21FlrN`5J8%kSQ&J-{jPk#CFS38y#hvU0S)>8DC{5@fe^$7m{hC zO0q;;BU|b#%(z5)0#tu`yUJE`Q=v2}&$f*hG+mN5D49nzVv+j>&pclt%>C$X?nQ_x1>RX!2; zk%IY6%Cn6oD%WBvRiX?cBdXU*4%RW0^$W`e`sh&k`{m1N4yhaHs`Dz}F!6rfJ8YF5 zoEFps7^pXrt9}Ym_)vykG>h?xra7lR|8lsyi~vqOWOumJtSF>1~RNWW!4#>2b8XQ=thuT1fi6eN#2^v|}E&rvRR>c+bwm z2QFq@s(LpD`54^VJk3Nu#9WMqx9X@OT7foumh$2z-CV!ynNv(_Pn%lKL#esBfQX;H z1nuD!8$UfV`rKA5pWazsrBR%KZMf~W?K z(AbBjx)Yo9+J*R*Neucs*z+JB)hlu+oIYb-a&k-ABVt)mhKjdbT9huyGbXk?>-y!- z0(QkGlMPjT>DH8FqCa4HvnETjbyE{g540?X+hV%Ip}LztD50lqjEo| zPx*FYM)E=}7j^pcd|1O{D|A>0Rj|(05E;f?w4QDLBnr z?c9uk9uYbs^QAcb2O@tEhmfqr=i(&r1P!sHJ8=JOZrlnhAL!uC>W#CcaOKt;Gszmh z!>Gv|s<_s!Z)=`kWuM$+-`osmcQbEwtKRIS&+J?Xo9UoC@bGUwcggbT;$;X<4!+JE zG#(`n&Of(9myY>rBMey347i&Oy~Esra=@Y|oDh-JrRbs;!e2r>dT0g09`z<6(e+QS zg>}}A_n!k1*)gXGjmk|Bp{4Z|1+HzwxkNmYhASO0oU)qE{yY=V@9*M!WU1aH>dh~dAVC3@ysAiglYcrUWP5-gLWNqRPAqe z^B>(kzh8y&WqoYsJJ~>bgbuHWluQwmW)5%e+^AJYmujIk-Qd5>skriFtlx?qc9Sdz zD8@ONpc{Goib=ts)VUZU4N2YSdJr>zc?Ka>0TMWv&4tbZzRX?#83<5k|x5DoqdM5+EW5dGKhYyXC${}r46cRkw;c@*^< zd{W1~8;ls+O0W)17DwjPp zRLwgt&MpBsdX+mO)MJNs9D21oBzm2T;cAB$CRF-SYLqS|(dMn%k;P(4(kwdHSIJ^2TjZz%#_H}N++3cLG(h2F%W zuQ1n_+&nB^dA?=}edrx>{3YOq9tKn#7NmvY<#hfRc+Bw)PeH6DqYEJdc}H%xyZ$%d z3c9vV@U%$%rMQWx=Qh&(w*B1QtBFO}rMFA0LT4M&PA8%)l*^@A2uB+E0mw-|fUq&6CFMb^f~e^-hV4NpL_ zG}Ev>9;82|UDVl&n9~s1(z+}>RIvo}SZGL%fz+>XL_!Wi;o+R)^QPB5A-nra9!4|b z9p8G<7)cgKH&~5C8BLUwP2N*Tr5eKdBcGv=niowuFG`zu#OEzGNPiy`qPxF}b>J2ga@n8Q+i#2dDK~g~5ALr@C%8>tsZB#x zw_)74%99h8?h$l;c7?Ng2eU;%`#L&YGLen3Qhk1-G7;9;MoPM!dvs^&A5AyZsjj1h zM!rB^m~un$2mLd-U-3+#;xg+>y-We=#TM$jW*`5pG{jeu{#!HR1%GSI!y2boLv~5hy3W553S&&&T z5u|~{UrS0k$cadZ&eeAt8>A#s{*Y<0=ify(CgS7{RW?`H8{fU8d z@)}Q@=be+ro2d}$xyEVGhBn_D{k)+g(V`SYx0_9M^Ut;TO7e8)7AC-fnK&$K}ru2%w{>TNOOo4 zHy0>z?sp#h8gU@>q&&JSq}qKM&nkHlsN>t%ckHr7cwy~!xSZ_9DRr_xMv%o_mTV~h z4`b&TT?x0X>56UJww+XL+qUggDzJY-`^?Ri%iT;t zTGRFQ`rdezhA5`VMuMq4P*Tu?tHOST#N$ZCSJWTH5#ZI(WxRH=;jiN>u$pE9cL z98HeORByGr!#qTztg6ui|Y(v^qXBd`6|#3HmJBE_``TzGCc+{s7{R=$_NxddPK{FcS+9td=A~<7{wWUIEo{cuDYLTl zg+JjIa!sn*L}mA9{j_|tzO|mrF+}Y#XyE~|dvIsxb+5N`ozqje{HEOgZ;Mh3lF>sY)WZ|M~1LJ(9nL>1ij)E1&!BX$8R3?=S$Y<)L z^HC=xwEc>CCVg5MNRsGjS@&cQ092Yy^u_tUHRKVvu*!&2l_~cubzB;H+hnyd6BU-R zrin?Z9lZbuda4szuGA2Vqd{>ly`;HI?(=FkI4HG5z>aYtPkihJ!5A^TdrGx%b< z5NFLR5d(TNijz!@17lQAZPg3*4UPLss2J(79Q_;$VcLugsvI`UQjzcK-~5u7o^EZJ z-*bjD(EoQN#6SF!|4m!@HU_C8sUm;zFcL6Cgpq4hkXJSYk@q)N`jG=_SO|fDG&VVl zW$8PmgvLXJY`C^BuXZkbH@XN@Av|PcW$iWl+!%g^eL`7ZO%VSSC>VzN-1avGg4mT2?Uk@+(2ai(|4{DnoS_LklCtv^+A}fpBKhg*TyPyT*-Y{f<>;wIA z4;c;*ZX05=5=!>AtQfHW#vCu}W=9<_3yB1}%wmv$r&gP-pgUuj!CDULOeN(g z642NRX)azS-3DrWYQn0M?%+77b&Hi0HFXx^>gqH{xKQR#R)scA4Y9$>jotd9K@c?D ziUuLUg6KK>D3%4qNM zkeYIyw8}efDy5XNAHegla|tfxxg_y%#FD0ZO6@_zRKOyW$zW%YhNyO+h)4(z{p@xm z9+lmIOEG|^0bJPTmQlv_FTN&t$xW8LYYB`=R`o$reX|CDyYLK-6+%L=68;W9$4861 zg~-vy2b!ow_4K=f`$994SwJMyZYkK9!XM-1Q@1lnz1^~g58oM?nQ%8ZT%|8pq8>n+i_?G$|CM3YMETR7RsDmfTsewm@0)k(<)x`y@_Hypo+> zD^uX;O570WN}WCz%hUorP+-;rYBdHpJEXuB+2rgo(?L+B>&}aMS@zZx+7RNK!c?!z z!j`T%jZ1qtt9GHMmUduJYTyu6b}Hbm%AbGW%?7n9A=tq9 zM?Txh419O`2FRZ0gQt|dqUe;oLaUX$B5l2%RR-L>j`~1Qw(em0@CC@qr7>sq;mgp% z3XI{9)}x<81sb-v3&{{G@}-v8Q7L=|>3Ac`T0$f#eT)-GU7SaxSR@k_Q|Nx5Vjzih zkS0qZhjj01UI}{TH_cCcC+OKll0)MyRqa;nE2OHK2 zZ)Q3av0?&AP7jl8Q3hF0&ga33%ZsarRe)&jxss?5)o`g@CiVdk8X0+3lEzemXmJ)5 zcusCJB)K(T_Hidpio4BbN~C57TGFZphplzph1XLel+7c~L=O*IJlRi%0SHYB z$&nI~Bp=}e1b-@EnNf!*Jfcq_7rqGVkyAlrVJKlG4&-ezoqS+EcA1M@orO_4l2zWI zI`g`lzZxR-8TY)S5%SrLkI5DaA2duMrl`g^Pnt$Ou6`A1*SNj1@Q~>Wc%H48`d(h@ zY2O^>8nh+!Zd8+S9f&SZoy7a@KzlSM1H-|9GaCW=JSMh>@=C*jJVRp z$#C=&&QBjnhTxti%8ib_Jc5WjS9s^AXex221Rj^H$z>r)k{9$i!fF^9P zfF{X(WpEQv9z{=>MscHyYXW|f*OajQdHkeUZZa5t^8>Rd8{BCq4uv4;{F^p{2%{@{ z(lc$GP_WYu`_)60axe*Ko}gSZU%>DN=}izjA3wN`pj0iD?*$Acj<0r1c^H{*Ft4rd z1Iv5BjXZToLd4EV^!X0)KKaUwdaom3yjWsDP&%w2Zit{>U=Mc17Dbt~pgUjycdDJk z<>@FjSX&UUv;df%KzTr!1R0@66rBX|9yKeyN%71QpnE{FOB;9&s=R5xzTo+pjipF^ z<&v7v(u6X$QCe(Ak={aWQ5+ETyd{{sQeZTlXumGGqdB8l7-14O4spg$(g*{t0AW=? z7$Ua|rx+I%^T=Fy16_CpXkMj{WFrS?n}_jBKO9`IT+J7?7JN;JOJjhyA>79bjjTox zI*&;4hxR>yPg>lTl<;A$GF45Wh|YUx<-O(aUXmD^=$z$n>jD&Z>av+MinjFo-eyBC z?f`B$F0u0M9xMIUHrQV85MoGim!xL7P~mk%B3q%N_l{gt7-byBUtj+Q8#*siVXFuD@k0gZ#}D@ZS;P33IX7Y{TSI*-A@gsu zfw_V6{~2gcRM3>f`lj(rnrtjMEwpr+ozaMUhpdgMoTMwj7s`QClJh?6aiv3#47XvC zra#&?PRkwp^X2eKc$h#J)(RZ=O=hgQruKcdy|}~ZK~0&`2bvnYsj<$4aj1A#ypV!=Zs<^-F6grsBbIPS{qi8Q|xe1oAIc|h&x8WZCP`PAuKU(XVE3_tJ9WUgIWed2`o9JWQvI5B4t?I#ulXDX=`QNyvkwk?N)7 z6e-{9cY#ymT^Yxpdm91oHOyH0q}Vgdee06f82L-=*;-!|^;hz_2W8|$dpp$~w(WvZ zM#etSMqINvJL&D}HekXH{!d>GUkoX*Yle$_ndQ%4(dUC2;=+re(Q%S1l;DLy>c-B9 zSQhW5ZtqhG@R)GefrIdJrRd>Jed+zw*^U|7-M`14@{b4Lkw1KqITTcReXzqh^=*_OobQX!Py4 z=n09bH=$gv{O&xvVUx~Z5;pv{WY*R9lBaF|Rm@ro3?}3F9(eSC`SF9`e-4Cyg-!*k zm}_Ev8&O5Y(q_JG6ZEy;S=_GhIf;#-s7wZC1kwPoBC?oqvoqKUU|k`GvB`d6dV8Vy zoRfIEQ=#}$i*?&_DUFt39Ph_A+y~tUl=T)DxVRn(}el2HcN` z9X!rg0z&luJnSSV*fGpoPTK9fFh5unVH{K|9Fh)VFwskUXE*ZlmV({7C|0c*gaKuo z?7pMIS18P`l0C^5(qOu?Z)phA?~82%EBCD0{JAYE`3453dOICcWPexFVXIu>wk*ij z(oMS0mDx+R?}_F`>-w-V)dGI<}$A+x2y$*<90 z>#)=M?u%rPYr0>x_z8x-SzjjKPf>x(EOQK+rH^VFv}tL>spI zLVJw4=he85x+IAtV>7A3=O^P75oXN9KN^?orE`!rlUZtpzZBLHHTCTkuf)Z~Hfk;W z?CG*-OS%?0GErPmx_dk>_2PdvFEgP%0#B~Z*K9`Y%dqS0P=3JKuqgkT-4TaEQtG7q zF2w(4vYc=LF~kTpUVM(+#F3R}+;9$g)E`%(AmWBL8XoQk3^p0bL{hGmfx`IF6lX{` za!z_)=Oodaov+${PH|jy;8=8?IEtH#W)i#U-yiaFxr&&`Vh~y(mBa<;e(Jh-uBejl z9}6)_x!9R?i>;zU2w>22^@q>DILy@7A>!9FPXO+OY-I>84TX4+&cXrBqY4 zAL`z+U+TtGfvJ#G^THLORaR#xE2mtw#u_uw&Re|PqKx@Ymcv$l2d4sb~p4UZCQNea@(9`B>C1-lb3LwrO?;ymZ!8gUo zN}HenRt6jRxiVta1`8D&;Jk7SA?Eh;eIADbMl;HTUm9MbAYI1fnl;+BjfCF8`?fPK zVWfRLGsNqyr59jj>fXBun_92#h3EqC?d}{N5qEtZ^}yHiReXyzKG+N^>>SY}n=;Lz8> z3vPt-zyhSppg)QenIKN^>QZ9?Do5UspnauZFk`eRpzU6*jkoE(@mTo9(g0iNHl*>D+#{_q8+p6%3TD<*DmjA$)zz`0Rxrka zuoP3!DU)Lm0<#6|9#X{#cqd<=dO@xvsKt8aQj2D_16sGX50$b0{f!L0Y&L(_6s6%x(HXo^pA@)vj#w0h zxT1&9zTSa}VNMl|avD2?&#{3wTPnfo7tQ(lH#gG_T%n8n_jxP({rHQd`VYb=jq5+q zK{Wq`PPO|c4ba;CZ@8%9>Mii; z63O`YJHhx)3(>!y4V=xbjA$H;4UNt1oc{JUSY-Ka`tad9u2jqL@t29gXj_%b9K`1> z8@pEt81(>}Uf(&T8Jkl#QfHP)q&_=@BnJvIz|RF+g2Wp2Ga~l|>?c5$%GS!^x&XAI z7#d`4tz?hi0F=o-wrAoM!3Ns%*&*vX5kK)85<2}gt7!Cz_smhOsE^4ES|i|3Np`es zTT=mwCG3V!{*=zg#3M*CefE*;d-$aM5zz2qyY0G4HS$_I*$@kru%l1*B3l}-{}JX1 z<6o%oa%BtKd_=0}ZIV$Fx1zB5ZoHiEH^c2;-@x~W{@;9ExbMIJMt(K4GXEDC?q4sD z8NN^A{w6^welr3Y{`2Mh27fto4V?sSt*yVQI#T8~#@|FJmv2z)e|vNjm9)R9u*f_> zP~lWfA=Z^!({Km*PHViW0%G7ZW&&jhv;9NH7)#cA$T5f;DXg21+3la+_!Je&a3h}EFpS7f2;GrIle4=64_S3i2=^pRd0%Jh# zJWfc&sGtZuHj zaBN&?A%N-JUREYu045jVeV>zG(8Y0S%J+5Fpl6)ELyNuP#XSzco=H&H^^;VI61#E! z-ctRQ>RS&x-a;UdoXBMnZ^u*@VO44Q@y0KM>}nPXriV$@Ksp4VCLDIYAt{zdoj+MA zpOyC}qC(XE0u>vL7LtW5L1Y%FU>~r&34U`m2T5hb?+#Hh=R;JYgnlGLNnxA0S<~Gv zD;tof=;j-oP(B$8!Olu{gg(TVHpo}>Otx>ZtSLFUJ1m*M{zM-oBEf)qx@c#v87XC78)PQn1XbZ6voRUKZ7Vbgn zcPXJU2NZv>qviGuMpV>lv*W$v!!y}D`)~ssh7Sf86bd-DvT543u1u*JmR^(4zOK*gbMjMEDuvs!>0Y=oE!Ra1tvZ zt{u8pxRXaz@FgaG$^qnMdJM7!7~utq?wS1>`400ylj`+v`;>wJ1Ww8KvU~a#M!ElU z+5P8dl{R;DG`BI8wfn1V<##as_Q^XL|Fa>Vs4Y9EhdlH(#oAVRW|V{9#fX;BiEkL< z>r3iK#~{PpqvxjzSCPuHp*V}WMb~jNi1mT5BbG;W(+js9%$QY7-N9}>?@vQSQmn37~FOfezEfHlAZItBPql%M1Q{=pKZ4` za{-gw&guX76MRF5sdeudwohxNu6&?uf~rVoogs2JO}X4&o&rnY>4P-tXA;F|7yIQ zCT*B9jq@yFQCUh7eFTs!(%7R@&Mk8W3DBh!&kUvt>zzqfPq4vs|mrvoZRUMB8d>? zuXy=<4AC!3Mr9g*-253N_2fb?g=@&}lW!R0*dkcQcCD?LtZ!1sLl<${Xi!}Ql}xZP zfnomYJ3ydnt|sG83_`#`z==V4!D~+7L3(@sBiCz(toN-TXc*fFmvqV%UGFNl4vt;i zG{1{OCKgyWPEBOVJOX68@JHD`l(SG5iyP#=!Y`{`a+oMTCiXLXGfBWn!7y12{M4`C zb~r$RrJM;@)-AHQv=>;cb|XK?ND>R+N6_eTeQiM@21!yJBANvG*bdNbf9^$M&$S@u zpmOv4l#iPFY?e*DJclwkFAtvc62wael-4KoT_+f;*{T7m`DilIVN+gSuNl+XD|7;h z*AZ5qViIKm!VofJCow~KL88(JzC}~%6`p0f7ovRpTki1JYVW9!W{mw_0sh|y&tLfY ze>s#mE=Ib^3Y2?ZoQQ(V7 zgcO8A)FL23hi(>K6hW)Ij9ex?S9g!3gL&QnhLR4}f5TlSTq*@DE!dql)1SKBuhwig z?}w)7wtgVrjCaEy!k}Bs)aDq@_y&t-m(%8h3Z=_(qO16b#L8Flz{f2S(l${^*RvCfSf~> z>9Zn|+=zYA=G+Tf2n+K@%Zb+^KzJ8if&w4f{Mf9}vTRW0sk7iO<;ugnc^Xso6yiuE zC|p8^Pda;h8Hj5OSpWKg5%g%>hrq8GTK7O#Ht}=y5Ras}EpWL=VX$lM-eM7|)P`ka z!A2ZM0{^!WplofGq5qD%Zj|wkW_y$^M;G*d=>iY#oHu;gUOq5sjER``(L{}XpLv@? z1r2JS8(kwh?&BYbH1stG%pU#cATvyp*UTP99sz%mT~r=*7%d3NcKy{_qCve9CEL5UI{;F>6cGm9+<54iq+%D zWr8Q-64F)ZSy<$Er0clj;vbTjHb9*q2TS#$ZW*{?Z|YN^tZ@yEn2_-V0P^>F@Wbcv zH}n8xV_yDdw)!j9kBMMzMZYsr$?tgoACj!U#rpTo?ria_Q=K^bf*(J#c0zNMz{%?Yz8HdTm`>D027vgI1Ui=07R5{1T3 zeSJS`{cQv3_VeZybQ^jC5ptPPe@%Ep*uR_O$gh~k?=|yGayFDp`T$W8s1vez;o+FCh+tXE$dLg-=5@e!e=_C0fbbB)onMG&GGkOJI@WL? zWPM8L{V9hY97S@TXi^E@)R#p&h8*=g@rObb;KHtPrS7WM zo3+=mP$maI$ANLQGasC?=Gx~jrTBHu zKfkXy5Bcs3er^}*`vK*lrs z#!JIsEbZr9mU#ay-{3HuR4SuNeL7b2$}OagkS>a7dDsOa)j3BG(=53y;B9|vERx%D6wc-0K52!H4E~^If4hhxHJgpeRj>xu zAPCVb^jeXUgg$TO{{+C;zlo^k8gDM0(xuEXv#zu5+gq`(xx(0f5j&q^(+1dnde^s5 zv#tbTiQyjWWe-@s{FHX_cqXc)Kr^lK#|o!h#K|@Ka9mSIW6Q4G6=PS5)ag+oHMtIu zL?p6%wW8zP*;&((X0ifu3}@lOn;(NxoUY--TBq(nn0FW+A{y%F_SP5NiF!uchU88h zk#$GI-E7Yost%|7%BZ&`k_*} zxWMUbu|A8l(4e)ja5=9$p)`lFCGcU-yZ3~{Sur$Rx3w+KdPM;uyNB^RbEBv%nq(s% zgVkBUalXJh63d>aYEys3!U|!522qBJ-G7U+1%!>t4OI|w(m<>?p}Q%McFU3-);KYn z!|5RBml8^U{lpw`%%foep}f# z%X?t*5(sO-0!9?(QhXCGQFi}=384p2wV0b?k0$lI^}BNK7Vx}5V%aw0CPK?2(4)og zD3Ycq?4kt_yNR(=en9ClbNu@vG&=9!ZM&U}X3X=e<}}4t=yN4=wshAbIOm#b&i7U* zZXRWjown56x#>igCB@~*I?3x8LDL%CUA|nEK{}b>JR%#R0W7iZ(Z{t((57r?FUClH ze~P<%NZ5(KZgk3ks2bFyTr<)hCs{34cqA7SF@8Y0IqVeP>fm5PjhLSl-!}n9(S0@? zM1q9#bSrg5*`uATcQAu8Mj5c8M>NE~2EFIH7?PHp@Ft?H*C0f|-dQlq> zlpJ2K3xcL^np%4c`Y6~B@7}!Z6opx}@|y7*eZ-ig>u4V`ni|B1KB+`KJ(56^{6_Dy z*pOvhCrG~<@^4O(IwdXiaqQ`_i#2I81o+59;gH31sdTDWSL{Z1(28?~z?~h&U|Ut8 zTuyfvFc zE-<@8?wvWEMph9jhoH*7A>I@^ON=q==LS&c4x_w5XAO&Qk;o9Jbi>Mbi-7RFER11S0kejO>|V_8=u^;<5Yd1?CR1h zyOSGm%;FqCLoPw$CIOY;rtVqM_oi!CmLYJ5H{K5wjk z>{;2Cv!rtUiOu?|!S?WCg_k$ujEVQ?I~6EXVC!Sd38;z^)lI#DK)m0m3Gc>3|{#lV6t$3G{|ahW@qQ)1{l`&XeaKz@ zK#FO9NJYC~Rek74z4P zQ%A$EDxVKfx$dY4=0l_VTUEG266#_2T5>~(F+?2+wb(q4 zYxJZYYer&+7jMv7BfL{+ZJ5t2w6oIywX$Uy?MklI+|qKEIXQ^6=?X#I!}!CNHYWG@{9*is zcN~z{nD#*YYwAIwTjSjZ@78X5gsW*kx>;>3&?n3iY;&?S3kwzPN{=Z0h49~z_=>Hp zdz(G6I(K22m_Cp@YrW28(}Of15K6GmPPOV($nFcISAa&xRhZ6_cWK=DiC;L4Cm2Pq z)zDZs>Z`;Strl#VXO+S*Tk_{=3AtzMc~O3s^c&Fdt3`sg;%wrNg9zO?-Q{N_{2dFL}Qs^g-O1C29~ zM^%dPbcVmXY&)5`z3-io39gg!H-20wX_!~VWbg)G`vU{`-(T)ZxC9c!CI0Z$=LXLH zNhyE)o;e)XP&J-GU=MHu#U*-6)<#QkG3ipWH~>}f+~sK_#O?338nze?jK)AdoeA6% z-G)scEZ=$$9{mwtu?-=COf5-XPT77L|z=L ziVf#msb?+)&v92M9v1-pj2_r;*#N0Ospd3U2aqG2LfnhJf;9a0Y(D;cMvXho$?q-89d!S&LxM*&}lJZtOcT7_gytU!U?Z*SNcE+SWDjP)O;dQ0Nz7h-d)J zjV)$`X-;3I=6#eJav<$SQhLmgjdz6E5G&o|mkRJFhv`F$)aLAxqUN^@&_7Mh_0TUM zul<;x!%wmnHG17)MGMns-mqW_N`nCqB%?#Uvhk$VJyHpL{D>TE1X!r0Vi3aXg?&{E zib00SRaR&iewrt_MG(vLX0H8cpqinT>e4j?i)pCk31~RS?OlDw-N)gKi6Kn)`|gM! zFunl?dW*2V`SCuY6dy~KBkKJy{qc*0*6340i{gb!UMeKd)SkA5Q&PuBd}pcAlaR2t z>-%z@2j*>K_UN7;sZcR>P0_>YMB7)+daa;cKSz~%9QO<3yZOBA%F^UKVb)wOj&myTp9$z=wZe$d{X4k$zJ^Ha zsDKFta^THB#e56I1#^UJl|_|ewbT!1-#R~_I_@hE3gH?Qd%x#bUi$@2U&&qtSA9fP zj8^I-i{e8kvlg;8Y+e8G+~WQEdd2chzOlyUq9-xrjAE5?*5led?uIrAyf1PaC$R&% zgIMpUxp9*mT!UB-qBP_e;fz8$aA9}%o(y1CEtqdfiEMmUqptJ6cHcv zL^LYjKTc9lnr874?JPf}jI!A;Vm4J17)sD#RxUQMM0{NQgHvh)vp{`VgssUI-bdyx zAb(+CEY6g90!D(n3SWcCGVhQ|nvUsAgkjGpKRxQM>DnVE7PO(LJ}uFdq#8I_ zb^K%OT1v4u#V9EWhSTjSJ$+es$IQd;zF&XQ3PkUiCb?2ZqM__Aoh>#P*3 zvC&~b&qPzec1p=9KL-NTY1TEfKL4bqnk82XanZc5<`Sf~sThnMSMx(v6hr|j@)%yro| zzSV34>Q0`9juA2lSFNOo`fvYE$j1;-5i?52%iXMqH%MGPsh+pzp8~FivPNDd+eBXD zu!~yJXU0uj3wdjhkNSW7WUov8fCOHlv%@dY?iq9~1-A6?=o&R4XVLX`jx1eqoOKP9 zdQ_h^de{hEw!$fugS{MfqLN&-6viudU3ACQI6d)Fv)VnPcp!B_5DnT~&1F>gHu+NVko=Cn_P3n4>;mzLyx(HH!33^}c+z;To%NhS(<^ybXXd2HkbnZo^g zDtb}^E>32?>Y_MQlt~CtA+ZTy9b+oaQt_3~RR z^Sh+sC$^sMvNP-sfHp^~9Hk*?UtQFF21yXzV{Qp7d_=hjwdjnq1V*_9*VYvq`1pzM zm=<~X8;WA z=c`tw$jnK$P~o@?nBWAssI`o73@1-`ThCD@JL~wNOhz={85ExtZ>a?W&JmB2=yraD z;<^CDonf#2pfurCQMZ(esgis0RGa0{*D+ZP?ihioKNq_a(r=N|^fO10I}1wh@)}T_ zePe#))kFri{W*<;!(V=CBwMFA7=gE;=y_VLnk9uj}v7mlz`59+-<+97z zDs6(4E!?%2`~-3YcZ&4^zB96^vucE~Y5qqRK1q+t;Br6hrN>IJHubcRi$M$qu6|ZE z!lC-7_8^BAnfsw#>>mL-kkM*)hylBBmm@8}j3E%ZM#UZ-m*6s{9vzvc)Xk_Oz+ol zj(P4V;t*sVElsx;hz2GgYvhYnB{Egrh;(@I3$=jC5--aNn**9yrnw`pdtQmNEUImv zbpM(YWmsuV6@RO}MgM6_{h#}o{})LyQ9=7JTPjbzdcBLZbVJ&%YXpS|g$=SUF`?N{ zWIxDQ?q^o6%#U&ulzp+vVpwMK(F~>uB-qEQ06YUlbP*DSz|n|pYI=cP)s84N~cp4Onv2v5L*T@;Dm0}NaOTX!--sRJhK2lDBb=2v?K zmR%zO`a6#!!)hD$ncy3Y>(kZijS2#6gjvLXAqprOHpFl7CPh423oPyX1m)@>ad}x7^|FQ9x<(3n9-G zsV0MawQly66UV*8u;dREi6gFS`hEm$oEly9wQU42RWK-h21`e3-28MMC~T0V=-R_x zhHy;zzM(E~$Lv*^9$81b?Seau7UsnnGZ}p}UR0l4ny{6`qnGwPIndCQP?e_*B*2Kl z{U2uitRUML+3jlB4`ihFjqO$0Pl}bYr8x z3I6}o_f`MtM_mi~PPhi^gbga#^#Z8#*`+nW5H!ATtYX+EE*M<4o&|^;kjo{=M_@3I zuM$r#kc_jDc}k?UNxv_>X!B|FvdsPr@;OWX3~RgUWI{y5w0Qm9`t7e+d&_d13iNYsHybBBE?jQX~tJu4AQx z&#D>?`Eg341WI2eN0DEBrR`9M^-4*?ZI*v;!bQR@$q;$c#Jj=DD4#jIa=qKEjyeP7 z!1qCx6^{V5cfa0vnxb64>mjbK$@Xo9e8$h2SZbZN2@+_m9c<&BOF?^n&y<6j*E~shk*Fba`rwlV~ zeJ88EP?cQH7D50rqJp`odZvU8H;vcs>5)erm}7B1tfEAHx%%*VIROoZ!vCwwr2SB+ z@HxO5BF{e@&j_RZHA`8x1oG1I(qck6#)64mzJ63#F+ruVteB=)g61Hv#0tKn8y07+ z)<&-jM^dD5Q`VE|0<&*iqS;cSAg-iY;tri--K7P_S6if(oF|KIl*JLNY9)P! z<;olE;Vgg;E64Lm=ZkOqG^*90I`zTL-`by~o6B**CsP6TND?Le7XL`pw~Xaxu-G;>;@M_ckag7OK^bA*$Yb5xg*k+ zN^Fb97}e4=;P@G~t9;k<-Nvd=d*I3W{Rf|t-87zO{z;Do?Z#^lf+@}55o*#(HRq&( z#8C9Lp^r>cDsaYEYeQ7_b}=@vAm`*Z1P)$zu=6`K7Nt+sokmFqEQ6M?S zfd^=D6?Gc#;RkNf{j{DlxpwV_(@cj{!2p7M3JA)dS$h~PPM=69P9J}$3!$dk0{jew z1KEZtoJp0jFRfZ4jZ2X^Q|cL?QGj6rCPCan*UfD)VH*vw22o;dvyPldgtU=#RuD=sQfZ*D|8F1im}vUFW2L+6DGWVR#CvyRnIM+Dsl zsw#bmdru&Ga6nIgP}1MYz&OGF5q^3ujWTSjj`X4Z;RB%#sg9#qI0^Q6zf4G9fY>7f zTGsF>F9pzdvQ*n@`38Be>wH(w62g1bkC}Sf!Wm6fNNq2S)w%Cpym;-Gm{4fqV4V57JPtj3k6l6t`M3bfVzm{k53x2qbn0 zu@i<2LeXN1Gp)|}A*>2%g93_g3bP}m6s5B7J^TJx2@PF zz{Fxc{Q8IY;*VtlhT;y5?JX@st?aHy-7KsY zSK4HD{A8sDb2Qwomb<5QnEOBVfm_gDM3_O(sw711WJ9nR1i#!J?tjeS5)FbeOen_Q zu-A`n!#{!4rEM$Hqa&oUqI+R7#r3e$Oznsh&Kw_6WCf?Ip=i{@sAT8%L!8xn1d-)Y z@~jZC+1bg+N!*{ni<)GLNK~dh)?Cj3c-bI<#2&Gwrt10qN>K8(r0cg&9{3$ zY;G{c8&Bc3g_-TI4rcxetY&GEK&(8j;yrW;X#rI$C8)y}Fgku6R{;77Cckmq+pC_HR67oV>NUE8V`#lRS>LMpVg)@!@<&*)6csYv=->IX z&$>oMfG~Ljsg=V$MNBtBJeSp16u|A%=9bz&050!?I`txTK;rmQso{EY)4QtFHNQ&` z?t2!Fxn?`xZM-^5Aq$>zUKKR^|+6~n5R_|EEadbuo z3q}xoTdHj`u=Z{n@sV(+#{G229Gz((AqfMT!2Bi+1wvD@`Ne?Gy67BDySxY%?2iV4 zI|-zmOOYI#6P@ceV(W^(PXPVZSP$oCvGV#(wV=LJEzbWepucajw=gzz`hNQ7)%Jfo zc>m4Dm>DN2+xrtaa0&!i$cs;|FYmk?7!%2Pk4Qd(DvucbNsudv!8#Zk2;xgZm6Y}! z;FEk0xr||1Xpj2xB!gq?-lfR)imv*{W3A>-R4jL^!`ehqir@=u7w{D%1W0cYF;z>~ z04c?`jGA>sf-fh+;jGBMwv%YB4~5IFc8{7=u>y&b`K|Jt&R0;GFKU z1Yla0@L1@v1z=jLFcn0}iz`{_!@n7W7_C&BB)%m@;BR3>HdVT|K@&;z*I26b9JDJKJsp-inNVkZv73I#bX)pN9pbKlef zsiWXZ>vJ(9(bbM1-`+k;v4JNJLQIabVQG;>OU#(^y6nwDDlUU?mcLxO@?TvlQRP+xHj-Rsfc!lY(x3M^TNy9Y`!o)W<~MiczO>l!{RP*dz~5bzmRQE#pdW57mq?)|r>)nwMsa zkdGHrx#)v0U;G6USD%PRH~BjpQGI=&vqlJ&YySpYEYv{g-H$ptL9aZKd>jC(7Z`!J z;11nI@SP|@;0>LvmzRA+M=J#q+bWhKNPKT5wLO8;*O?;p|nPYF*Q z!b@qP^{Z>#!PJHpo)7?3oiN;p#1|3YDkvl@?gwZOcu4X-DMre8Kq>@$Af-g5MsgVn z$eB)IQx!P`Ls+A8^$WU_0*G&^_J&_<=GkO$FHN!)Nv_V(#N4_&&iB$yNK7> zm)Ft$M07TnjF98=1pY?kdv$XS{Yu>+&Ng%%(N7i$vN@l#r*i+ z{Ev0AMIV@!m|(XY!)-G89JK+@QbY^sP@pT!crP_ClnmoF7 zpVchAd3kBbq65FCj65q`!`G~Wy~d37wDzS-*owrgo;zXG_d-Auv+Zoj)ABgLv<1H& z$Wx7%sq_lHX9abOS2L}jOuj|Uq%&md))Yp3&R0J|Z30}UjJL*YWS&e6+Ieke2>moqYvV zmD}32bW3-mba#o;9nuZb-QC^Y-QC^YCEYC`U4lqS{M)PN(}Uh~&-mXl_INjAu;yH~ zS3K)k^WjNYn#)CP5JJWhO6o6+vgtnKudXto{CGf@L;bFD#W<|546sJhF#?%6Vc1fb zYflruQ3er)eKD;fUQnu0W4?XhPYqZ1g|fc1NWH^JDPpr~(CnRvj2IrW_?940W#{Oa-j7eik%NKi1yS7V!CQg- z4O3=BhqR{Prp8$bCv|GubJw|vVgpJp7S7^kPT8pK9k_(t=vZZD(Vsn)dnWJPo%f|WcQ z6t;tBgn9gxO1hzsUZ^k37zo5z-L!R^hg3&7HDkrgSC!|2W|sI4a;Ng) z9O1%|Gu$2o%Q1EWAj)G zHJYF=HO-KcCVB{ess6TAL!>V*p~2U=5i*IN5uDHCJ)l(l1Z@}}130X&}8ucp1 zw?GR^R~+}FN4LS(2j?+ek=IQ>QQv|2SZptQ>Jg71S|Y z+bTXng^S{`&8ZWYVh~68f-#aw-mpAyK*!4G6e()}PIAFASHL)CGS1 zQbcqV!Em==_fsDVdOf8+Bl=`)kTSW?WoCSm_HnU}FMvnzaUtGpWkh1kR`xRJsp%TH zR`L0I&2GxT=TwC66-!1F4+j2*7L#obH;~z#XD=e>^$^+kvsyEKP&;!)h_QWJxbW%` zg*L~X(BAi(me~uT1UIV9A*z-SLS^yFM13LJI~CY>(YkyRX_#UC(S7=2Vpdc-WkGe5 zGr~0zF~Z4bx@YB<)oqUY+wYaZSH&9)@8EnohGRD&d3(Hix9>Oy**S z^G=M}GeX;KZtQIC*gKYD62^184r>%IGT6+Kf|nkToG!nvoddrAj{60g9FVMQAbCiwXA0b+-}=(gNky$|v-Iw|Pjg@Xu|I)6oP z;b_URSEt>0lloP^OYY3*M5L$d>(N#CdCYW6uEvhjbegaVuFo36QH_h0h1qzi{Ry$@rLSPqa@kOm`kU4d=xf|C`o<>a z`?5}3Y-Y^;eDb(QQS8gNJ13~VFq9wq`3M1Z9_wd!Ev3mtuoS|zNq^B17b#NpQlHSW zw}``bewEZrj~3S$Tb?k8-5XBB7(GZR+ynzk388$P(GcX{)7Ye*iY;zyCc&1aDpx&K zw}MAFnU>W}Oha+U$Z9&@kQgZ9VSj8I6|?xB%hK> zMtP`qWt2I?{?v8XQdEtARi~qfrrr}#agCIGB)3qif9mQplH#OLy|PFwE6C=dy%9ZPVi0VjX9a5S>qh7DZ2v#9(vKujb!2Y`vj5EcW28 z^RrGMrNE#~;Jw2GQ&Af|yGL@TCZu)7pgttkoJKsqik=hmDnRvd`7}F;M4c05i?$k) zt`#%wX8R^e`-^9fF|rcWac{K-w0GLtjM$CPkWcxf+?v>na3uIo)S%3h)~@K@s<>&Q z29ysvW_Zs%_E$yVwFBHP5Zo|r>L;9nDU=l4Lj^A<3Ja!8??qc@F-yIT6nLBy@w)D` zE(8uMK0NYWkU9Al?LNC9!#8ccmz$W8%1IecCzirTW%x2h-o}*Qo)MfpOwpLo&k}nz z$);x2N@#%}X23CMAwt`GVVC@Ns|5DOd2hz&&T&wYttx;7H`m)edF7>80Ta%S3!T~u zUjc3|R3_{V_p7>q{Ml>12fXCx-dqHUS&;gEu3%!$dl$wX63U>#NxUU~wFvG`w6Z2* zm3wMb6!IaGvb7o+e9-lT8E+(5w;|(jvx(j&_}n6FU&(^u$lnmfdlvT78VB6DF;T(; zF)BFTq~XTdUZnT52+GDL^EFjeXB2lD+Ha)dB~$j=xa`3i70iP2df{<=CP4KECbuJm zUM1-HjO9Apm7SSbdds8otn8E6MY3{^LCp+qymRt)tN%UEYuC-~o?6)Ik9xs}@A307 z`G$!3o2?h`{Cn`n%a5|aP?4nYP^E+lf!D*B@HV)@SY)ZyMR%vsRD=?uf;^UuDD7k! z)kUanUnmb&D)1{~bBP^aAo=Zc)`q!57hjR{;!8uMWs*f?VnpOfrt@<)CT^;Uilj@a zuLyHGy*S=9n;A{BWk1cMyar$DiI~uEhwX@%dabr!v7u=6rh{+(EWnoQG2DFf%>?zG zVsqS^{N>LtzY<@%M7~=c^sktj|J3G_KcREM<_!O0QCHkY*PjbU*^~pWMIw)MPh^VS zE7k*=(mT?)BpL4Adge4`-u%ANgi&Od2DYbuM?hVA@2QG=cskFx(Doe-m6e z-vyq(Ya`Pqi%8Xh$h_(6gc+gnuAO`GKxw&g1HF{fD<^HKgh) z1{FWLA&@J7Oi|sc5Z+dhz?)Hz6~ey!iqP?9dpoFmiz1LU!e_s5MO*%J*2-ZJGTJN)?|!iy zBk;S=fQ2?paKb)nD0P;|umN5lpxf;XsS22GbBn1t0v0 z*!7bFJ>Ulepw}iqB_k=G-ga%a_I!F+nqLjU#3!Y8J8gI894X_NjXkx(xz?i7br3p6 zcV21LAeo{d5p9i2(KkI4S0JomP7$L+v283(NC%m0_7twWa!VPN@k$r zvifupB*g30?XOdd)xzz|+c0=a!Iw&Xhi2xttIr ztF0u;8z(800i9S@b1W*0r44BvI<%}sPj5ujYTVwph13Y|M2dtW^5PTTkP&7@hiV1a z(jqd;5uR2TmL018N-%5XyVgO_>F!T=`)uP})ptS@feC+FwRC#fv)94~sIA9f%Hf*o zmS%qPsxfSBTm1rWo%hWL#XX@rj{C%Q-~^ObT<*S4@t&yaVDI81;j~YM_RT)cRen9b zFms03xB-%YSl|j;TqmmSC{ZZ&DiuOFaW5vs&URf`e*2-|Og9cq2q?_V^XuuP3x+C8 zxUsl5M;zLoTZX%5B>efv1>Y@VG(qq9R0N?{z|Q$<k$DaGhZqcMJyk(=q- z)Hfi7OD^{~IxG>aQ?J&9R1VI)k7nLhO0f;}MrHe)!YVhYHBZC^AGsaysg(H{P0dR)0X$(Mm+;>5oPEV-5grf|uFo=W zq~yFG{f3X{YrS8~ttmkpQM@(3r@Y6ug~>Ygd>uZlsfAm#22oko*=KzV|7j4!VZ%m< zWRLPzGp8==fzR^@@iq*k`nWRG(5bDw8PUixF2>Xz)_fsJw0+c$MA zsP*hnA52~e9=D+g`n?cor)KT|985zB^fKUbp>Tbi=(RSwbOBnJznYFFA?I=_s%hu- zk|J@JDi<%PRvg+c6DI8ZiV89y#vImp6~W~H04n?#h&GX-mC`ZMcfpE+=uyCx*n%b4 zl$3<0lZtVawQDt#o9PBC8v5cOag+}nvUWGCLy@Ni!oFRNrv)9N8xnP1Bh`O;dcyq` z-0=XeVF%_zToRcy7BQaLCUav2as2tf zmU+p9?ltDIdu@h*3-wOOg!}VjJHv{rok=*uH}JRElWU;OUvP3A?z=pmxGrnLzn;ng zSW(FVXVHxR#)`_L54h6*-4ns)yOF9a?muqJ1CI^ZhkM}IWP#%_-rO*;S=oW~(yow0 z{K&RJt@I8ixU=QV4gzN{uGL)$gG94~@H^r4UNw~DR7ZK!OE{0SU#+aO@2=S_XLPjR zKYQCB430XDRh_s`DxyeVLKx-*M}j67D^JDn@xZ-ih^u7Nk)_A64;`+CuyK1yf7R|i zsamb6iQT$^AEC|2S?ULto{zTGU&Z4H+YVGgX@z@k?Q8Ty3R-uf^%^(ln^d>Eqnvfc zAyg$p2t9W7-h~WU01sT{Ht#sqE7>`f=*1Z0h2n%@k`R(?9+Dqw$8=OIVgsS`EDzE# zs5|woTTgFm^sGSoZZRw9vtY`oG3i>X$H0QLqw^IucGJzoFH0LSWMZ+nM7s2f(qxBF zU#&-+kKe2{pWYXdTq%M(xXi}m(Bg^o$%E6C;%+3y3~g7U#-@SYP%w()=t23^Z&-vh z-*-lp(JyT?(uTZ$5zy+YK9Yl<98B!L&40^yTDRNr**SG>K}(jQ-wu`aT&Z8eze(o{ zLC=v@eTLTA^(qf5o0B4DezW97hYykjj&Uu^ zmxTCU6rvY>?|JJVE04&dZ!-s9zZiLD1TP|M_4PPHyr#_rOmh3IRM6E}@NgCLXh5P~t85aBz?pP__)FEZHZ!hN>^dXL)V6qqD zQ&y-$J|*um=(Wx68mG+(*Y4Q+(>HJ2feJSl3Cc5LNp$j~c$EEZ$mOOI1M;*8;o$U) zil?aZEfv$%rz|ylK>XRRQed0vxE`WZpF5F+I@+azgqngrDEM%QS!*f$Q-sUC67 zr;wY`zckk1qtl%?RV+Piu=jn8KV{>!KR;Mm+-#@bB1?jFIQHaOe+$Q{N9MZS++D%` z3KH~K#Uy>bHu<#$TX!*Mz5Hht>Jt{-5Y`oVUrn|!QlO-KNX-SF<&BJar;yuFG_iZ% zeBO#J6UV`4{`2TlPOmeHlLd~Zy_w{V&@iFVyXaxhoYg^jvYKnTKdGEWAAE(DuyFqB zuHIU^Ju%=y@m?%2TnmH48Y5~aDx3;dTcgO(u~Y|>5*B$iFXMDslJA-${hj;(oH%`D zaQI>3)Th`iYw`owet_dCr%N^-!~4`XjLsth?B+Qsxckp}PXf9)Ial;B4sDw9t}ce1 zTBujRCyyO6Nl}gRi+0Ah{9oNS!rsqeNW}JwXh=#X&E*bCtI>p~1A`i>V- zVt85~VDjC0mtPBt`uoHh)Z!4{qsBb4_>Y;oa&9mYm{e)?@tw|uInv#rWT&H*S<@Qf z@tlH3WB`+LzT*oX75V@dE!3TrwB4lB`@H!>vUf__3sS}jI^0q2p3r2k3-c_`#;9(y zm3=M2&E_N{gG7mvDf;&ms=c|*(HN^ITxtSXtVVuOw=jP{Zg3>olzRsVr-%jf>>20p z!}?!xE&t}kvrIwN0ZSg`;W?~0L(-0S7Bfki2rMcvTv@#lHIwM{%)23hq97wmdrzn& z6n#tmK>kOc)ADT>%|jS7H8I7Ed)$ZTb{Sp-x|Mm#-J5Eciw36_9$!=4uD2>QJs>Q> z-Uzb=EEB~Or}p8ll?pe8ND-G3jTU5_O>#kDmWn71^dqpG-5|7c$Fp8Re98lbuLrN> z^0jj9Bjs#$BG@Ece-!SWC$ffp$jvvoMDk(9S=2^|56d2=i=MQ#Yf~61*>NM*BoQId zL5V$&*EV)tLxR3c*QZw-$IvI&V2IOJ4nrSSc@@`SDoehQk}oYUp(C14i(02xk7OgC_Bn)sCtm4d~Frq5af*t4juo+`NNp{N$W2Z$0Q6>XfP7c80IY# zY$PGLEl3g!#`Ox}738!0AA3_76q(7Os3b(3v+>Nyx09P?Dw2!!*du}47A_2JdTj%W zn27nS;P65hVEYdc!?1CET8=(rA;A!oT8cZP$=7@TPNi1|^OO%UDnXiCx}Qo@x{5Np zSMieHkm2%-pI=!JtQnF|5OsZ+uB)Px8k5BsHqy%TRCmT|Fy$0;%(jp6g|`!jR{@18 z$|W}4@!ZLTXi}bv!0hp5kba`OdR>+^w)@_gWNrrFLg&`Ntm2w%sg4r=zFH$~Pfu-0 z$wwOhN7BIZ!|uqVfqE0o<(|F=rlQJ;l1(|;O+ti|(r1{Xn~LU*s@-&%b;V?HZRK#d zv&;e3j^^Mh`D%48Mj|x;SL?=}#1& z@kv}dlI`1$ld@x+5TonwJ@&DGih%65;Ho>FppxWTmAKx?@VVy&fhQ^Y!r4ub-+5Y= zP>d2J?C zY>b76d6Q?rbupl}!R@<kQ;53$8I`;~jIgvDP2}Q`UK`+oXl^{~;}{{6wil2(8m4dhUXHf%Xo7e_ z5$+-5v3^o8**`_EGWghanAy%9>%9Pphz!%)9ni}c{OK5>TF5s2W{lFsTA6^7>q~wsF$7Le! zzKf%>PMLCLx0g$ z0GOMpejm7g^NalT!b6y>>VMQd>Kmw!iSpD?c*xMRsE32mTi=#|(i0l>=7RfJ@Np{p zf18x45j~*CN!qV7gG3|w-2mtJ<3}`kC?c*&Y3yGC=b`KDj2(}zk3jDbDam!;zLf?z zEb+qM(q&|C`v<3pP~}E?ruS1*kyxp^pB6S!c3gd|&fRPehJZ$Ld2ec^$dg|^a+$bx z?pvhjdq_>WR|MUotue9zt>5gP;9WCB#aH1RUKzU0koQuw8%aZ%he>lm4nei`2-<&~c&;}#aiPJmwBW1nLo`25)$-GJageJql_80k<$#)9s zGGq1MwS+`Sa0bPX;TyU@gx!WQ@OlslT*3STRT;fXAddECygyfWa(nxL_~+j zl)?=?h)G!oG-YWUPhx`=6|Y(w-!(VTz$SX^MXY2?X{R*pF z#HoCefoqb<$=}QLEV<$3W51KXo{mexd|^PsSh)X5AmtiZn`%Lv zKc!IB8v89loUM@2J9QuE$D#I;Zgmr;HaGF9l%WZqY_B1jDF;tUL|7t87i0Fa1acX{ zSbOe#N60+K(7`#vY)!!P}6zha!F9g|N)B_qjnIwd#>rc ztgk*GjD8cMiNMJVkLiZ*FH5?yhd70J=Y3hEZk5R7ZCoUmlW{#z#EXZFJDadHJ3x+i zR&r6lmtb0%#=qmvG55 zOkExg$13OzEjuT35khBBcU$lh{9!L&d&29bs>Z8KB@1k3jE%idvdMSYIeEDIau4C@ zR7x7z3kSzheQv~?laYc&LZ3$n!Pi#{j><@(&-{|EKwCo~icr}mMdD;eEMA8pG(l~W zj0v=2SwBl()o(z}QQz$|ynY{uk>BdtNv zCLRa|Nsl5Y=eovf<2EjwJ(cM^Cb(1E!-p_hN55t2&$J_Q`*{b_1xcS(MlV{Ax^dK3 zf{@h&nsR9$M&h{k7fr7U)6z{|;S_{UV#^db7=ZRz_j%c>&~OQ4zcq~TH>}UlCcf1?l5iSG7TZcSS#u=wO zE*S{nBk=Oes+=Mb@cKYD)q^Q&d)p8%bI|!^=B-BVIfCt%Zkl71h#Vt0<>cp-F?{I= zP}N|YZ31Zf*A{;nt@!!wWAMu{xY7+&=FG^d)=Hm#lAt3&Kgt}$F& z+*G90m$ESBa9Qgx1*TnhvE&;a80Cv>+dNP%xKd8qz!lJl91$bF9#~05O+Jj?*dkep zL(HTrvrzD&O1iajL>S;!IF6S{=`LFNezZ&}xhqmK`yKRLyD`!%DfG-xc}q<-hq$>c z?d56x0Vo2?im2K_GKPDdE~FRWRvpH#O4DRww>dVX80u~Tp4gMlP-^StO1>k4MF$j~TPpRMe1sh6 zb2*3jd;RiFqU{_2+#g*5JA!|uB*&|#Z(*$`Xk=|;D{H6yqyE3|e)|;6WC4LU+|8>k zt!fN~;o|BSgnhU*AbCo-5nvD_k%G)(Sr!^3l%{8O=NCGL5Wm0rH~77m<$T+bKsR@RPYAqPgh$hvPyD^Yq`)4UH z7OPa4fTnzYiFtewD2YXe&)pI@?S$sfGflQothbB5*lc9!I!5;~d{wE|Fs34HXa(d8 z1hc$+m}v1k)n@4-Tb2CQB8O{|=kBw`koz2WlMRfxuYx{4Uja+rftQeN12<>KGmfEH z54BQbX-b3@@&bZ|Ul*lts*&W}-*I7hkz8x2kD1+eq!S6F-$Nmr9EgK+(kTwpgqqqD z=&jW{ViiE>M1Zt3H zan#K*V`*ADOq~y3mDf{!074f#pSfEn*0l#yx{esTN2qb(;+7SBLa41Cz6e9AlIy~( z&)w@3^A>r$%k3Hj1ZFDmf^@3KuOf^!VzeyE!f^os7n z8b2$0Aqpo-gK*txDcc1vbx%L&04}szKD3JYKDkKa@C<8GUkg z6gZ7dmtm&(mfjjzgtXKaM1?K2fREPK$>=;+a>pnK@W4j2t=hbF~B zX|{BBUDT{x)%pTvDkAL-_Ss$2siY4Eh|knCxKlOy$PW;4JRNBa2=RJg8U-5ZzGR5J zc9pnijlRSG`xp}Qj5Fz*8}%JvjAs9RjFxq>vDGvCH#UW|=n>H#ZWRCVg%Y#6`Z?oS zffZ(6Wd2@1^hh*x8QQn|?#X!5Q7@56rg_&y6}@2q*E5hvjSz}>dX-ZdKaW3-rZ%;D zw6+6v0+}Wdz=si;qGT!ijslyaW(p8^48I~7htgfTjpVK$84%7~GQe9CUquXd;joUC zIkgGl;GFrcsUGJ{sLPl<5DgKUCkERk-Oo0mST29Gv zC_DH|N31?Sm|W&F0pMJrOq|}g1BxhKTR@^_<%aInW&QX}>^#TDj%9U|m2hR#Ha&&_ z~LO*9X*SDjokS72wU0y1ee; z{s3(GY(NlenT26tEZcYs)1GREnh7#VG5sQY-dC>8ikFVFYl67co@*aZBlK(eE!pjB z7tz&s1b4_;ugs)U^=)_jd{?U8W|cTc1ui5#66BR|v_tYGz^kruhowd#@vYl|x9{3| zpD7Jyl}CP*FPK{P?N)N#Z!s;}+mrnW7G0@vnjRvyam^c^s*(GO-I!GpN}0A5S_F!D zippRUlF}=cx295zjN}$>t-vPuJ$XxG8m8$^B+N%Gf{MZRwE6KV8|aU6gPiQO6E8jA zmeBfh7#^BoXJjB3KO#$1x^($rHJ);{U56zl#+#GD!zg>pdmyu1s!G7PI348}W(h2) z=5w8#tb2yv?w$}3wJN!v` z-PyZ@b>f9#i3_j&A%KieGhAr?D7k9%)J&gK_C1*wmEqv1$fj6)e{NaQ$8(g73+4=_ z^h~4zuCT2J%LF}4^4CRLeYNa4{$Hu^YxoJjqW`^H3D!eiaRF8v!%%;;KmOjW{&TGK zUltpOGShDn9wb#EbAd#`dO5ZAGO2695Gx(Y=OnMiEQtrrXM>ak0O0HE^hDVefcw{ra51UjT75kZB4Db<#UfxSEI7 z-%_lz(sNmjk%G4~(UTLnU%=5y$~W*UFdn2Z-Aszb3@^d(MA}rC+Dn7M5+~y5(UPd# z_9{Y?5^{N2G~Jv`46AB9MdsPo0lL{k(}xN_Vh!r55PW`>OZDG~_w(BOO{ttUjeZ^IdVTP&2; z2i8kvj6M+4ZDf!lhN2=doFN4$9S_PqHRc0fiKh?}2|e*Um2Ox(Mq740AFcP3Q3gxR z`4%PvvD^m4alT@W?{QOdmh4*J)dRZ<5es;PG3(94+R5(6w=j<(?hq-)DVI)VVbc##HAY+6 zzC0)%bd&N3pxYCvLrFRCLssy|GEbi*3V(%LD&U-$;fPn zqdt)15>z9e2V#grSm=^1BE++AQkMv`2eo-r@ZJ;LF_6SN}_LGe@5LQXc$6YNr&@sXX>xwMLIE|aTo=5B|i!ik{dY}uGBWam#lU|%q zYC^0{T}{}%O=Npyz>QE15jhuV>f*A7ce(HS-apqV-wjygg=(~XMw1!wA+ZmvtdJd@ zcVXDL!;jt*hM$xSWb|V5;N_5f_WUa%=fLiHZc=RwAP?g{1k$#IJ@rpQDzM0S==wqV zuQs2k@FdSjX9xiXc>%x&AMp91!w2jezS%A5 z{J&%pJdz@U0D{d>Y6F%W(OF!a{d&jI}FEa3CvNAhp4S}!cX0_+zN zM5tbbqX9~92`Kr0n&1a$t=Gf<0DQWv11#_yop|hQ4FUSIMmj&mm7g;19x2%r16Y;; zAEF;@-(Iy|_JBP6p$H;>mErp?^C=!^k@Kn=pajx@)YN~&dj~KU{{ioNU~+kY1iY|? znVz_Xg^8WzpP_L!)tCDKAh&>C`t3ycucy`v0`ia00Nq_vI~%|)GC?C#Jsuq$JsTSd zEpsh{zoH#H&AU#8SMxhS-Vp!>y}#!j_xT?Q6u-yD0N6V8jSTDn64n4Y_dn-d+6~ue z8&D;ffV|WFm2tqk)@u-;E%1kGdD@=BfPf9A|1IO@hXg%X0N)TRKsLYKTl(v%_4`q>gm}1pXm5g)bQ@uPecGzKL9GlUy%PPK0d%O^9R)L{rCs=w@m-JBAy0N{R_I* zD@gEiR!<|wLgV_sx^ z=C zzWm)Q_GzY{IvxHb_?-MN2!0)<{#=5mE?++h=F)y6_-mH0@h4Sa;XhIRkGb^eDceujy`q1D{V`zt z!w`yT~*Y9Ibd^H}j4%`dP&3iSQ;4`bg`L*Y++h3bES t|KH7qPwVTc?c*oWQQiM74F8)Y '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum -warn ( ) { +warn () { echo "$*" -} +} >&2 -die ( ) { +die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -82,83 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 8a0b282a..25da30db 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,4 +1,20 @@ -@if "%DEBUG%" == "" @echo off +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -8,26 +24,30 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -35,54 +55,36 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/jitpack.yml b/jitpack.yml new file mode 100644 index 00000000..09bbb514 --- /dev/null +++ b/jitpack.yml @@ -0,0 +1,2 @@ +before_install: + - ./gradlew setupCIWorkspace \ No newline at end of file diff --git a/repositories.gradle b/repositories.gradle new file mode 100644 index 00000000..7e002f2b --- /dev/null +++ b/repositories.gradle @@ -0,0 +1,5 @@ +// Add any additional repositories for your dependencies here. + +repositories { + +} diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000..69d2d74c --- /dev/null +++ b/settings.gradle @@ -0,0 +1,21 @@ + +pluginManagement { + repositories { + maven { + // RetroFuturaGradle + name "GTNH Maven" + url "https://nexus.gtnewhorizons.com/repository/public/" + mavenContent { + includeGroup("com.gtnewhorizons") + includeGroupByRegex("com\\.gtnewhorizons\\..+") + } + } + gradlePluginPortal() + mavenCentral() + mavenLocal() + } +} + +plugins { + id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.14' +} diff --git a/src/api/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/api/java/dan200/computercraft/api/ComputerCraftAPI.java index 9b8833d2..23c09c86 100644 --- a/src/api/java/dan200/computercraft/api/ComputerCraftAPI.java +++ b/src/api/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -6,137 +6,147 @@ package dan200.computercraft.api; +import java.lang.reflect.Method; + +import net.minecraft.world.World; + import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.media.IMediaProvider; import dan200.computercraft.api.peripheral.IPeripheralProvider; import dan200.computercraft.api.redstone.IBundledRedstoneProvider; import dan200.computercraft.api.turtle.ITurtleUpgrade; -import net.minecraft.world.World; - -import java.lang.reflect.Method; /** * The static entry point to the ComputerCraft API. * Members in this class must be called after mod_ComputerCraft has been initialised, * but may be called before it is fully loaded. */ -public final class ComputerCraftAPI -{ - /** - * Creates a numbered directory in a subfolder of the save directory for a given world, and returns that number.
- * Use in conjuction with createSaveDirMount() to create a unique place for your peripherals or media items to store files.
- * @param world The world for which the save dir should be created. This should be the serverside world object. - * @param parentSubPath The folder path within the save directory where the new directory should be created. eg: "computercraft/disk" - * @return The numerical value of the name of the new folder, or -1 if the folder could not be created for some reason.
- * eg: if createUniqueNumberedSaveDir( world, "computer/disk" ) was called returns 42, then "computer/disk/42" is now available for writing. - * @see #createSaveDirMount(World, String, long) - */ - public static int createUniqueNumberedSaveDir( World world, String parentSubPath ) - { - findCC(); - if( computerCraft_createUniqueNumberedSaveDir != null ) - { - try { - return ((Integer)computerCraft_createUniqueNumberedSaveDir.invoke( null, world, parentSubPath )).intValue(); - } catch (Exception e){ - // It failed - } - } - return -1; - } - - /** - * Creates a file system mount that maps to a subfolder of the save directory for a given world, and returns it.
- * Use in conjuction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a folder from the - * users save directory onto a computers file system.
- * @param world The world for which the save dir can be found. This should be the serverside world object. - * @param subPath The folder path within the save directory that the mount should map to. eg: "computer/disk/42".
- * Use createUniqueNumberedSaveDir() to create a new numbered folder to use. - * @param capacity The ammount of data that can be stored in the directory before it fills up, in bytes. - * @return The mount, or null if it could be created for some reason. Use IComputerAccess.mount() or IComputerAccess.mountWritable() - * to mount this on a Computers' file system. - * @see #createUniqueNumberedSaveDir(World, String) - * @see dan200.computercraft.api.peripheral.IComputerAccess#mount(String, dan200.computercraft.api.filesystem.IMount) - * @see dan200.computercraft.api.peripheral.IComputerAccess#mountWritable(String, dan200.computercraft.api.filesystem.IWritableMount) - * @see dan200.computercraft.api.filesystem.IMount - * @see IWritableMount - */ - public static IWritableMount createSaveDirMount( World world, String subPath, long capacity ) - { - findCC(); - if( computerCraft_createSaveDirMount != null ) - { - try { - return (IWritableMount)computerCraft_createSaveDirMount.invoke( null, world, subPath, capacity ); - } catch (Exception e){ - // It failed - } - } - return null; - } - - /** - * Creates a file system mount to a resource folder, and returns it.
- * Use in conjuction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a resource folder onto a computers file system.
- * The files in this mount will be a combination of files in the specified mod jar, and resource packs that contain resources with the same domain and path.
- * @param modClass A class in whose jar to look first for the resources to mount. Using your main mod class is recommended. eg: MyMod.class - * @param domain The domain under which to look for resources. eg: "mymod" - * @param subPath The domain under which to look for resources. eg: "mymod/lua/myfiles" - * @return The mount, or null if it could be created for some reason. Use IComputerAccess.mount() or IComputerAccess.mountWritable() - * to mount this on a Computers' file system. - * @see dan200.computercraft.api.peripheral.IComputerAccess#mount(String, dan200.computercraft.api.filesystem.IMount) - * @see dan200.computercraft.api.peripheral.IComputerAccess#mountWritable(String, IWritableMount) - * @see dan200.computercraft.api.filesystem.IMount - */ - public static IMount createResourceMount( Class modClass, String domain, String subPath ) - { - findCC(); - if( computerCraft_createResourceMount != null ) - { - try { - return (IMount)computerCraft_createResourceMount.invoke( null, modClass, domain, subPath ); - } catch (Exception e){ - // It failed - } - } - return null; - } - - /** - * Registers a peripheral handler to convert blocks into IPeripheral implementations. - * @see dan200.computercraft.api.peripheral.IPeripheral - * @see dan200.computercraft.api.peripheral.IPeripheralProvider - */ - public static void registerPeripheralProvider( IPeripheralProvider handler ) - { - findCC(); - if ( computerCraft_registerPeripheralProvider != null) - { - try { - computerCraft_registerPeripheralProvider.invoke( null, handler ); - } catch (Exception e){ - // It failed - } - } - } +public final class ComputerCraftAPI { + + /** + * Creates a numbered directory in a subfolder of the save directory for a given world, and returns that number.
+ * Use in conjuction with createSaveDirMount() to create a unique place for your peripherals or media items to store + * files.
+ * + * @param world The world for which the save dir should be created. This should be the serverside world + * object. + * @param parentSubPath The folder path within the save directory where the new directory should be created. eg: + * "computercraft/disk" + * @return The numerical value of the name of the new folder, or -1 if the folder could not be created for some + * reason.
+ * eg: if createUniqueNumberedSaveDir( world, "computer/disk" ) was called returns 42, then + * "computer/disk/42" is now available for writing. + * @see #createSaveDirMount(World, String, long) + */ + public static int createUniqueNumberedSaveDir(World world, String parentSubPath) { + findCC(); + if (computerCraft_createUniqueNumberedSaveDir != null) { + try { + return ((Integer) computerCraft_createUniqueNumberedSaveDir.invoke(null, world, parentSubPath)) + .intValue(); + } catch (Exception e) { + // It failed + } + } + return -1; + } + + /** + * Creates a file system mount that maps to a subfolder of the save directory for a given world, and returns it.
+ * Use in conjuction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a folder from the + * users save directory onto a computers file system.
+ * + * @param world The world for which the save dir can be found. This should be the serverside world object. + * @param subPath The folder path within the save directory that the mount should map to. eg: + * "computer/disk/42".
+ * Use createUniqueNumberedSaveDir() to create a new numbered folder to use. + * @param capacity The ammount of data that can be stored in the directory before it fills up, in bytes. + * @return The mount, or null if it could be created for some reason. Use IComputerAccess.mount() or + * IComputerAccess.mountWritable() + * to mount this on a Computers' file system. + * @see #createUniqueNumberedSaveDir(World, String) + * @see dan200.computercraft.api.peripheral.IComputerAccess#mount(String, + * dan200.computercraft.api.filesystem.IMount) + * @see dan200.computercraft.api.peripheral.IComputerAccess#mountWritable(String, + * dan200.computercraft.api.filesystem.IWritableMount) + * @see dan200.computercraft.api.filesystem.IMount + * @see IWritableMount + */ + public static IWritableMount createSaveDirMount(World world, String subPath, long capacity) { + findCC(); + if (computerCraft_createSaveDirMount != null) { + try { + return (IWritableMount) computerCraft_createSaveDirMount.invoke(null, world, subPath, capacity); + } catch (Exception e) { + // It failed + } + } + return null; + } + + /** + * Creates a file system mount to a resource folder, and returns it.
+ * Use in conjuction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a resource folder onto + * a computers file system.
+ * The files in this mount will be a combination of files in the specified mod jar, and resource packs that contain + * resources with the same domain and path.
+ * + * @param modClass A class in whose jar to look first for the resources to mount. Using your main mod class is + * recommended. eg: MyMod.class + * @param domain The domain under which to look for resources. eg: "mymod" + * @param subPath The domain under which to look for resources. eg: "mymod/lua/myfiles" + * @return The mount, or null if it could be created for some reason. Use IComputerAccess.mount() or + * IComputerAccess.mountWritable() + * to mount this on a Computers' file system. + * @see dan200.computercraft.api.peripheral.IComputerAccess#mount(String, + * dan200.computercraft.api.filesystem.IMount) + * @see dan200.computercraft.api.peripheral.IComputerAccess#mountWritable(String, IWritableMount) + * @see dan200.computercraft.api.filesystem.IMount + */ + public static IMount createResourceMount(Class modClass, String domain, String subPath) { + findCC(); + if (computerCraft_createResourceMount != null) { + try { + return (IMount) computerCraft_createResourceMount.invoke(null, modClass, domain, subPath); + } catch (Exception e) { + // It failed + } + } + return null; + } + + /** + * Registers a peripheral handler to convert blocks into IPeripheral implementations. + * + * @see dan200.computercraft.api.peripheral.IPeripheral + * @see dan200.computercraft.api.peripheral.IPeripheralProvider + */ + public static void registerPeripheralProvider(IPeripheralProvider handler) { + findCC(); + if (computerCraft_registerPeripheralProvider != null) { + try { + computerCraft_registerPeripheralProvider.invoke(null, handler); + } catch (Exception e) { + // It failed + } + } + } /** * Registers a new turtle turtle for use in ComputerCraft. After calling this, * users should be able to craft Turtles with your new turtle. It is recommended to call * this during the load() method of your mod. + * * @see dan200.computercraft.api.turtle.ITurtleUpgrade */ - public static void registerTurtleUpgrade( ITurtleUpgrade upgrade ) - { - if( upgrade != null ) - { + public static void registerTurtleUpgrade(ITurtleUpgrade upgrade) { + if (upgrade != null) { findCC(); - if( computerCraft_registerTurtleUpgrade != null ) - { + if (computerCraft_registerTurtleUpgrade != null) { try { - computerCraft_registerTurtleUpgrade.invoke( null, upgrade ); - } catch( Exception e ) { + computerCraft_registerTurtleUpgrade.invoke(null, upgrade); + } catch (Exception e) { // It failed } } @@ -145,15 +155,14 @@ public static void registerTurtleUpgrade( ITurtleUpgrade upgrade ) /** * Registers a bundled redstone handler to provide bundled redstone output for blocks + * * @see dan200.computercraft.api.redstone.IBundledRedstoneProvider */ - public static void registerBundledRedstoneProvider( IBundledRedstoneProvider handler ) - { + public static void registerBundledRedstoneProvider(IBundledRedstoneProvider handler) { findCC(); - if( computerCraft_registerBundledRedstoneProvider != null ) - { + if (computerCraft_registerBundledRedstoneProvider != null) { try { - computerCraft_registerBundledRedstoneProvider.invoke( null, handler ); + computerCraft_registerBundledRedstoneProvider.invoke(null, handler); } catch (Exception e) { // It failed } @@ -162,18 +171,19 @@ public static void registerBundledRedstoneProvider( IBundledRedstoneProvider han /** * If there is a Computer or Turtle at a certain position in the world, get it's bundled redstone output. + * * @see dan200.computercraft.api.redstone.IBundledRedstoneProvider - * @return If there is a block capable of emitting bundled redstone at the location, it's signal (0-65535) will be returned. - * If there is no block capable of emitting bundled redstone at the location, -1 will be returned. + * @return If there is a block capable of emitting bundled redstone at the location, it's signal (0-65535) will be + * returned. + * If there is no block capable of emitting bundled redstone at the location, -1 will be returned. */ - public static int getBundledRedstoneOutput( World world, int x, int y, int z, int side ) - { + public static int getBundledRedstoneOutput(World world, int x, int y, int z, int side) { findCC(); - if( computerCraft_getDefaultBundledRedstoneOutput != null ) - { + if (computerCraft_getDefaultBundledRedstoneOutput != null) { try { - return ((Integer)computerCraft_getDefaultBundledRedstoneOutput.invoke( null, world, x, y, z, side )).intValue(); - } catch (Exception e){ + return ((Integer) computerCraft_getDefaultBundledRedstoneOutput.invoke(null, world, x, y, z, side)) + .intValue(); + } catch (Exception e) { // It failed } } @@ -182,82 +192,78 @@ public static int getBundledRedstoneOutput( World world, int x, int y, int z, in /** * Registers a media handler to provide IMedia implementations for Items + * * @see dan200.computercraft.api.media.IMediaProvider */ - public static void registerMediaProvider( IMediaProvider handler ) - { + public static void registerMediaProvider(IMediaProvider handler) { findCC(); - if( computerCraft_registerMediaProvider != null ) - { + if (computerCraft_registerMediaProvider != null) { try { - computerCraft_registerMediaProvider.invoke( null, handler ); - } catch (Exception e){ + computerCraft_registerMediaProvider.invoke(null, handler); + } catch (Exception e) { // It failed } } } - // The functions below here are private, and are used to interface with the non-API ComputerCraft classes. - // Reflection is used here so you can develop your mod in MCP without decompiling ComputerCraft and including - // it in your solution. - - private static void findCC() - { - if( !ccSearched ) { - try { - computerCraft = Class.forName( "dan200.computercraft.ComputerCraft" ); - computerCraft_createUniqueNumberedSaveDir = findCCMethod( "createUniqueNumberedSaveDir", new Class[]{ - World.class, String.class - } ); - computerCraft_createSaveDirMount = findCCMethod( "createSaveDirMount", new Class[] { - World.class, String.class, Long.TYPE - } ); - computerCraft_createResourceMount = findCCMethod( "createResourceMount", new Class[] { - Class.class, String.class, String.class - } ); - computerCraft_registerPeripheralProvider = findCCMethod( "registerPeripheralProvider", new Class[] { - IPeripheralProvider.class - } ); - computerCraft_registerTurtleUpgrade = findCCMethod( "registerTurtleUpgrade", new Class[] { - ITurtleUpgrade.class - } ); - computerCraft_registerBundledRedstoneProvider = findCCMethod( "registerBundledRedstoneProvider", new Class[] { - IBundledRedstoneProvider.class - } ); - computerCraft_getDefaultBundledRedstoneOutput = findCCMethod( "getDefaultBundledRedstoneOutput", new Class[] { - World.class, Integer.TYPE, Integer.TYPE, Integer.TYPE, Integer.TYPE - } ); - computerCraft_registerMediaProvider = findCCMethod( "registerMediaProvider", new Class[] { - IMediaProvider.class - } ); - } catch( Exception e ) { - System.out.println( "ComputerCraftAPI: ComputerCraft not found." ); - } finally { - ccSearched = true; - } - } - } + // The functions below here are private, and are used to interface with the non-API ComputerCraft classes. + // Reflection is used here so you can develop your mod in MCP without decompiling ComputerCraft and including + // it in your solution. - private static Method findCCMethod( String name, Class[] args ) - { - try { - if( computerCraft != null ) - { - return computerCraft.getMethod( name, args ); + private static void findCC() { + if (!ccSearched) { + try { + computerCraft = Class.forName("dan200.computercraft.ComputerCraft"); + computerCraft_createUniqueNumberedSaveDir = findCCMethod( + "createUniqueNumberedSaveDir", + new Class[] { World.class, String.class }); + computerCraft_createSaveDirMount = findCCMethod( + "createSaveDirMount", + new Class[] { World.class, String.class, Long.TYPE }); + computerCraft_createResourceMount = findCCMethod( + "createResourceMount", + new Class[] { Class.class, String.class, String.class }); + computerCraft_registerPeripheralProvider = findCCMethod( + "registerPeripheralProvider", + new Class[] { IPeripheralProvider.class }); + computerCraft_registerTurtleUpgrade = findCCMethod( + "registerTurtleUpgrade", + new Class[] { ITurtleUpgrade.class }); + computerCraft_registerBundledRedstoneProvider = findCCMethod( + "registerBundledRedstoneProvider", + new Class[] { IBundledRedstoneProvider.class }); + computerCraft_getDefaultBundledRedstoneOutput = findCCMethod( + "getDefaultBundledRedstoneOutput", + new Class[] { World.class, Integer.TYPE, Integer.TYPE, Integer.TYPE, Integer.TYPE }); + computerCraft_registerMediaProvider = findCCMethod( + "registerMediaProvider", + new Class[] { IMediaProvider.class }); + } catch (Exception e) { + System.out.println("ComputerCraftAPI: ComputerCraft not found."); + } finally { + ccSearched = true; } + } + } + + private static Method findCCMethod(String name, Class[] args) { + try { + if (computerCraft != null) { + return computerCraft.getMethod(name, args); + } + return null; + } catch (NoSuchMethodException e) { + System.out.println("ComputerCraftAPI: ComputerCraft method " + name + " not found."); return null; - } catch( NoSuchMethodException e ) { - System.out.println( "ComputerCraftAPI: ComputerCraft method " + name + " not found." ); - return null; - } - } - - private static boolean ccSearched = false; - private static Class computerCraft = null; - private static Method computerCraft_createUniqueNumberedSaveDir = null; - private static Method computerCraft_createSaveDirMount = null; - private static Method computerCraft_createResourceMount = null; - private static Method computerCraft_registerPeripheralProvider = null; + } + } + + private static boolean ccSearched = false; + private static Class computerCraft = null; + private static Method computerCraft_createUniqueNumberedSaveDir = null; + private static Method computerCraft_createSaveDirMount = null; + private static Method computerCraft_createResourceMount = null; + private static Method computerCraft_registerPeripheralProvider = null; private static Method computerCraft_registerTurtleUpgrade = null; private static Method computerCraft_registerBundledRedstoneProvider = null; private static Method computerCraft_getDefaultBundledRedstoneOutput = null; diff --git a/src/api/java/dan200/computercraft/api/filesystem/IMount.java b/src/api/java/dan200/computercraft/api/filesystem/IMount.java index e340496b..077e2fc8 100644 --- a/src/api/java/dan200/computercraft/api/filesystem/IMount.java +++ b/src/api/java/dan200/computercraft/api/filesystem/IMount.java @@ -11,47 +11,55 @@ import java.util.List; /** - * Represents a read only part of a virtual filesystem that can be mounted onto a computercraft using IComputerAccess.mount(). - * Ready made implementations of this interface can be created using ComputerCraftAPI.createSaveDirMount() or ComputerCraftAPI.createResourceMount(), or you're free to implement it yourselves! + * Represents a read only part of a virtual filesystem that can be mounted onto a computercraft using + * IComputerAccess.mount(). + * Ready made implementations of this interface can be created using ComputerCraftAPI.createSaveDirMount() or + * ComputerCraftAPI.createResourceMount(), or you're free to implement it yourselves! + * * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String) * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String) * @see dan200.computercraft.api.peripheral.IComputerAccess#mount(String, IMount) * @see IWritableMount */ -public interface IMount -{ - /** - * Returns whether a file with a given path exists or not. - * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" - * @return true if the file exists, false otherwise - */ - public boolean exists( String path ) throws IOException; - - /** - * Returns whether a file with a given path is a directory or not. - * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms" - * @return true if the file exists and is a directory, false otherwise - */ - public boolean isDirectory( String path ) throws IOException; - - /** - * Returns the file names of all the files in a directory. - * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms" - * @param contents A list of strings. Add all the file names to this list - */ - public void list( String path, List contents ) throws IOException; - - /** - * Returns the size of a file with a given path, in bytes - * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" - * @return the size of the file, in bytes - */ - public long getSize( String path ) throws IOException; - - /** - * Opens a file with a given path, and returns an inputstream representing it's contents. - * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" - * @return a stream representing the contents of the file - */ - public InputStream openForRead( String path ) throws IOException; +public interface IMount { + + /** + * Returns whether a file with a given path exists or not. + * + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" + * @return true if the file exists, false otherwise + */ + public boolean exists(String path) throws IOException; + + /** + * Returns whether a file with a given path is a directory or not. + * + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms" + * @return true if the file exists and is a directory, false otherwise + */ + public boolean isDirectory(String path) throws IOException; + + /** + * Returns the file names of all the files in a directory. + * + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms" + * @param contents A list of strings. Add all the file names to this list + */ + public void list(String path, List contents) throws IOException; + + /** + * Returns the size of a file with a given path, in bytes + * + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" + * @return the size of the file, in bytes + */ + public long getSize(String path) throws IOException; + + /** + * Opens a file with a given path, and returns an inputstream representing it's contents. + * + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" + * @return a stream representing the contents of the file + */ + public InputStream openForRead(String path) throws IOException; } diff --git a/src/api/java/dan200/computercraft/api/filesystem/IWritableMount.java b/src/api/java/dan200/computercraft/api/filesystem/IWritableMount.java index 9c3bb43d..280dee12 100644 --- a/src/api/java/dan200/computercraft/api/filesystem/IWritableMount.java +++ b/src/api/java/dan200/computercraft/api/filesystem/IWritableMount.java @@ -10,43 +10,53 @@ import java.io.OutputStream; /** - * Represents a part of a virtual filesystem that can be mounted onto a computercraft using IComputerAccess.mount() or IComputerAccess.mountWritable(), that can also be written to. - * Ready made implementations of this interface can be created using ComputerCraftAPI.createSaveDirMount(), or you're free to implement it yourselves! + * Represents a part of a virtual filesystem that can be mounted onto a computercraft using IComputerAccess.mount() or + * IComputerAccess.mountWritable(), that can also be written to. + * Ready made implementations of this interface can be created using ComputerCraftAPI.createSaveDirMount(), or you're + * free to implement it yourselves! + * * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String) - * @see dan200.computercraft.api.peripheral.IComputerAccess#mountWritable(String, dan200.computercraft.api.filesystem.IMount) + * @see dan200.computercraft.api.peripheral.IComputerAccess#mountWritable(String, + * dan200.computercraft.api.filesystem.IMount) * @see dan200.computercraft.api.filesystem.IMount */ -public interface IWritableMount extends IMount -{ - /** - * Creates a directory at a given path inside the virtual file system. - * @param path A file path in normalised format, relative to the mount location. ie: "programs/mynewprograms" - */ - public void makeDirectory( String path ) throws IOException; - - /** - * Deletes a directory at a given path inside the virtual file system. - * @param path A file path in normalised format, relative to the mount location. ie: "programs/myoldprograms" - */ - public void delete( String path ) throws IOException; - - /** - * Opens a file with a given path, and returns an outputstream for writing to it. - * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" - * @return a stream for writing to - */ - public OutputStream openForWrite( String path ) throws IOException; - - /** - * Opens a file with a given path, and returns an outputstream for appending to it. - * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" - * @return a stream for writing to - */ - public OutputStream openForAppend( String path ) throws IOException; - - /** - * Get the ammount of free space on the mount, in bytes. You should decrease this value as the user writes to the mount, and write operations should fail once it reaches zero. - * @return The ammount of free space, in bytes. - */ - public long getRemainingSpace() throws IOException; +public interface IWritableMount extends IMount { + + /** + * Creates a directory at a given path inside the virtual file system. + * + * @param path A file path in normalised format, relative to the mount location. ie: "programs/mynewprograms" + */ + public void makeDirectory(String path) throws IOException; + + /** + * Deletes a directory at a given path inside the virtual file system. + * + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myoldprograms" + */ + public void delete(String path) throws IOException; + + /** + * Opens a file with a given path, and returns an outputstream for writing to it. + * + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" + * @return a stream for writing to + */ + public OutputStream openForWrite(String path) throws IOException; + + /** + * Opens a file with a given path, and returns an outputstream for appending to it. + * + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" + * @return a stream for writing to + */ + public OutputStream openForAppend(String path) throws IOException; + + /** + * Get the ammount of free space on the mount, in bytes. You should decrease this value as the user writes to the + * mount, and write operations should fail once it reaches zero. + * + * @return The ammount of free space, in bytes. + */ + public long getRemainingSpace() throws IOException; } diff --git a/src/api/java/dan200/computercraft/api/lua/ILuaContext.java b/src/api/java/dan200/computercraft/api/lua/ILuaContext.java index 787a93d4..de663e15 100644 --- a/src/api/java/dan200/computercraft/api/lua/ILuaContext.java +++ b/src/api/java/dan200/computercraft/api/lua/ILuaContext.java @@ -12,33 +12,47 @@ * This is very useful if you need to signal work to be performed on the main thread, and don't want to return * until the work has been completed. */ -public interface ILuaContext -{ - /** - * Wait for an event to occur on the computercraft, suspending the thread until it arises. This method is exactly equivalent to os.pullEvent() in lua. - * @param filter A specific event to wait for, or null to wait for any event - * @return An object array containing the name of the event that occurred, and any event parameters - * @throws Exception If the user presses CTRL+T to terminate the current program while pullEvent() is waiting for an event, a "Terminated" exception will be thrown here. - * Do not attempt to common this exception, unless you wish to prevent termination, which is not recommended. - * @throws InterruptedException If the user shuts down or reboots the computercraft while pullEvent() is waiting for an event, InterruptedException will be thrown. This exception must not be caught or intercepted, or the computercraft will leak memory and end up in a broken state. - */ - public Object[] pullEvent( String filter ) throws LuaException, InterruptedException; - - /** - * The same as pullEvent(), except "terminated" events are ignored. Only use this if you want to prevent program termination, which is not recommended. This method is exactly equivalent to os.pullEventRaw() in lua. - * @param filter A specific event to wait for, or null to wait for any event - * @return An object array containing the name of the event that occurred, and any event parameters - * @throws InterruptedException If the user shuts down or reboots the computercraft while pullEventRaw() is waiting for an event, InterruptedException will be thrown. This exception must not be caught or intercepted, or the computercraft will leak memory and end up in a broken state. - * @see #pullEvent(String) - */ - public Object[] pullEventRaw( String filter ) throws InterruptedException; - - /** - * Yield the current coroutine with some arguments until it is resumed. This method is exactly equivalent to coroutine.yield() in lua. Use pullEvent() if you wish to wait for events. - * @param arguments An object array containing the arguments to pass to coroutine.yield() - * @return An object array containing the return values from coroutine.yield() - * @throws InterruptedException If the user shuts down or reboots the computercraft the coroutine is suspended, InterruptedException will be thrown. This exception must not be caught or intercepted, or the computercraft will leak memory and end up in a broken state. - * @see #pullEvent(String) - */ - public Object[] yield( Object[] arguments ) throws InterruptedException; +public interface ILuaContext { + + /** + * Wait for an event to occur on the computercraft, suspending the thread until it arises. This method is exactly + * equivalent to os.pullEvent() in lua. + * + * @param filter A specific event to wait for, or null to wait for any event + * @return An object array containing the name of the event that occurred, and any event parameters + * @throws Exception If the user presses CTRL+T to terminate the current program while pullEvent() is + * waiting for an event, a "Terminated" exception will be thrown here. + * Do not attempt to common this exception, unless you wish to prevent termination, + * which is not recommended. + * @throws InterruptedException If the user shuts down or reboots the computercraft while pullEvent() is waiting for + * an event, InterruptedException will be thrown. This exception must not be caught or + * intercepted, or the computercraft will leak memory and end up in a broken state. + */ + public Object[] pullEvent(String filter) throws LuaException, InterruptedException; + + /** + * The same as pullEvent(), except "terminated" events are ignored. Only use this if you want to prevent program + * termination, which is not recommended. This method is exactly equivalent to os.pullEventRaw() in lua. + * + * @param filter A specific event to wait for, or null to wait for any event + * @return An object array containing the name of the event that occurred, and any event parameters + * @throws InterruptedException If the user shuts down or reboots the computercraft while pullEventRaw() is waiting + * for an event, InterruptedException will be thrown. This exception must not be caught + * or intercepted, or the computercraft will leak memory and end up in a broken state. + * @see #pullEvent(String) + */ + public Object[] pullEventRaw(String filter) throws InterruptedException; + + /** + * Yield the current coroutine with some arguments until it is resumed. This method is exactly equivalent to + * coroutine.yield() in lua. Use pullEvent() if you wish to wait for events. + * + * @param arguments An object array containing the arguments to pass to coroutine.yield() + * @return An object array containing the return values from coroutine.yield() + * @throws InterruptedException If the user shuts down or reboots the computercraft the coroutine is suspended, + * InterruptedException will be thrown. This exception must not be caught or + * intercepted, or the computercraft will leak memory and end up in a broken state. + * @see #pullEvent(String) + */ + public Object[] yield(Object[] arguments) throws InterruptedException; } diff --git a/src/api/java/dan200/computercraft/api/lua/ILuaObject.java b/src/api/java/dan200/computercraft/api/lua/ILuaObject.java index 4005bbf8..958f93a8 100644 --- a/src/api/java/dan200/computercraft/api/lua/ILuaObject.java +++ b/src/api/java/dan200/computercraft/api/lua/ILuaObject.java @@ -10,17 +10,23 @@ * An interface for representing custom objects returned by IPeripheral.callMethod() calls. * Return objects implementing this interface to expose objects with methods to lua. */ -public interface ILuaObject -{ - /** - * Get the names of the methods that this object implements. This works the same as IPeripheral.getMethodNames(). See that method for detailed documentation. - * @see dan200.computercraft.api.peripheral.IPeripheral#getMethodNames() - */ +public interface ILuaObject { + + /** + * Get the names of the methods that this object implements. This works the same as IPeripheral.getMethodNames(). + * See that method for detailed documentation. + * + * @see dan200.computercraft.api.peripheral.IPeripheral#getMethodNames() + */ public String[] getMethodNames(); - /** - * Called when a user calls one of the methods that this object implements. This works the same as IPeripheral.callMethod(). See that method for detailed documentation. - * @see dan200.computercraft.api.peripheral.IPeripheral#callMethod(dan200.computercraft.api.peripheral.IComputerAccess, ILuaContext, int, Object[]) - */ - public Object[] callMethod( ILuaContext context, int method, Object[] arguments ) throws LuaException, InterruptedException; + /** + * Called when a user calls one of the methods that this object implements. This works the same as + * IPeripheral.callMethod(). See that method for detailed documentation. + * + * @see dan200.computercraft.api.peripheral.IPeripheral#callMethod(dan200.computercraft.api.peripheral.IComputerAccess, + * ILuaContext, int, Object[]) + */ + public Object[] callMethod(ILuaContext context, int method, Object[] arguments) + throws LuaException, InterruptedException; } diff --git a/src/api/java/dan200/computercraft/api/lua/LuaException.java b/src/api/java/dan200/computercraft/api/lua/LuaException.java index 29874bdc..006a1656 100644 --- a/src/api/java/dan200/computercraft/api/lua/LuaException.java +++ b/src/api/java/dan200/computercraft/api/lua/LuaException.java @@ -9,23 +9,20 @@ /** * An exception representing an error in Lua, like that raised by the error() function */ -public class LuaException extends Exception -{ +public class LuaException extends Exception { + private final int m_level; - public LuaException( String message ) - { - this( message, 1 ); + public LuaException(String message) { + this(message, 1); } - public LuaException( String message, int level ) - { - super( message ); + public LuaException(String message, int level) { + super(message); m_level = level; } - public int getLevel() - { + public int getLevel() { return m_level; } } diff --git a/src/api/java/dan200/computercraft/api/media/IMedia.java b/src/api/java/dan200/computercraft/api/media/IMedia.java index 637a2970..ec18927b 100644 --- a/src/api/java/dan200/computercraft/api/media/IMedia.java +++ b/src/api/java/dan200/computercraft/api/media/IMedia.java @@ -6,54 +6,63 @@ package dan200.computercraft.api.media; -import dan200.computercraft.api.filesystem.IMount; import net.minecraft.item.ItemStack; import net.minecraft.world.World; +import dan200.computercraft.api.filesystem.IMount; + /** * Represents an item that can be placed in a disk drive and used by a Computer. * Implement this interface on your Item class to allow it to be used in the drive. */ -public interface IMedia -{ - /** - * Get a string representing the label of this item. Will be called vi disk.getLabel() in lua. - * @param stack The itemstack to inspect - * @return The label. ie: "Dan's Programs" - */ - public String getLabel( ItemStack stack ); - - /** - * Set a string representing the label of this item. Will be called vi disk.setLabel() in lua. - * @param stack The itemstack to modify. - * @param label The string to set the label to. - * @return true if the label was updated, false if the label may not be modified. - */ - public boolean setLabel( ItemStack stack, String label ); - - /** - * If this disk represents an item with audio (like a record), get the readable name of the audio track. ie: "Jonathon Coulton - Still Alive" - * @param stack The itemstack to inspect. - * @return The name, or null if this item does not represent an item with audio. - */ - public String getAudioTitle( ItemStack stack ); - - /** - * If this disk represents an item with audio (like a record), get the resource name of the audio track to play. - * @param stack The itemstack to inspect. - * @return The name, or null if this item does not represent an item with audio. - */ - public String getAudioRecordName( ItemStack stack ); - - /** - * If this disk represents an item with data (like a floppy disk), get a mount representing it's contents. This will be mounted onto the filesystem of the computercraft while the media is in the disk drive. - * @param stack The itemstack to inspect. - * @param world The world in which the item and disk drive reside. - * @return The mount, or null if this item does not represent an item with data. If the IMount returned also implements IWritableMount, it will mounted using mountWritable() - * @see dan200.computercraft.api.filesystem.IMount - * @see dan200.computercraft.api.filesystem.IWritableMount - * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String, long) - * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String) - */ - public IMount createDataMount( ItemStack stack, World world ); +public interface IMedia { + + /** + * Get a string representing the label of this item. Will be called vi disk.getLabel() in lua. + * + * @param stack The itemstack to inspect + * @return The label. ie: "Dan's Programs" + */ + public String getLabel(ItemStack stack); + + /** + * Set a string representing the label of this item. Will be called vi disk.setLabel() in lua. + * + * @param stack The itemstack to modify. + * @param label The string to set the label to. + * @return true if the label was updated, false if the label may not be modified. + */ + public boolean setLabel(ItemStack stack, String label); + + /** + * If this disk represents an item with audio (like a record), get the readable name of the audio track. ie: + * "Jonathon Coulton - Still Alive" + * + * @param stack The itemstack to inspect. + * @return The name, or null if this item does not represent an item with audio. + */ + public String getAudioTitle(ItemStack stack); + + /** + * If this disk represents an item with audio (like a record), get the resource name of the audio track to play. + * + * @param stack The itemstack to inspect. + * @return The name, or null if this item does not represent an item with audio. + */ + public String getAudioRecordName(ItemStack stack); + + /** + * If this disk represents an item with data (like a floppy disk), get a mount representing it's contents. This will + * be mounted onto the filesystem of the computercraft while the media is in the disk drive. + * + * @param stack The itemstack to inspect. + * @param world The world in which the item and disk drive reside. + * @return The mount, or null if this item does not represent an item with data. If the IMount returned also + * implements IWritableMount, it will mounted using mountWritable() + * @see dan200.computercraft.api.filesystem.IMount + * @see dan200.computercraft.api.filesystem.IWritableMount + * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String, long) + * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String) + */ + public IMount createDataMount(ItemStack stack, World world); } diff --git a/src/api/java/dan200/computercraft/api/media/IMediaProvider.java b/src/api/java/dan200/computercraft/api/media/IMediaProvider.java index 33e53ed4..53baa2e6 100644 --- a/src/api/java/dan200/computercraft/api/media/IMediaProvider.java +++ b/src/api/java/dan200/computercraft/api/media/IMediaProvider.java @@ -10,14 +10,16 @@ /** * This interface is used to provide IMedia implementations for ItemStack + * * @see dan200.computercraft.api.ComputerCraftAPI#registerMediaProvider(IMediaProvider) */ -public interface IMediaProvider -{ +public interface IMediaProvider { + /** * Produce an IMedia implementation from an ItemStack. + * * @see dan200.computercraft.api.ComputerCraftAPI#registerMediaProvider(IMediaProvider) * @return an IMedia implementation, or null if the item is not something you wish to handle */ - public IMedia getMedia( ItemStack stack ); + public IMedia getMedia(ItemStack stack); } diff --git a/src/api/java/dan200/computercraft/api/peripheral/IComputerAccess.java b/src/api/java/dan200/computercraft/api/peripheral/IComputerAccess.java index 7d4b6e73..a233fe92 100644 --- a/src/api/java/dan200/computercraft/api/peripheral/IComputerAccess.java +++ b/src/api/java/dan200/computercraft/api/peripheral/IComputerAccess.java @@ -14,79 +14,94 @@ * that they can call. This should not be implemented by your classes. Do not interact * with computers except via this interface. */ -public interface IComputerAccess -{ - /** - * Mount a mount onto the computers' file system in a read only mode.
- * @param desiredLocation The location on the computercraft's file system where you would like the mount to be mounted. - * @param mount The mount object to mount on the computercraft. These can be obtained by calling ComputerCraftAPI.createSaveDirMount(), ComputerCraftAPI.createResourceMount() or by creating your own objects that implement the IMount interface. - * @return The location on the computercraft's file system where you the mount mounted, or null if there was already a file in the desired location. Store this value if you wish to unmount the mount later. - * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String) - * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String) - * @see #mountWritable(String, dan200.computercraft.api.filesystem.IWritableMount) - * @see #unmount(String) - * @see dan200.computercraft.api.filesystem.IMount - */ - public String mount( String desiredLocation, IMount mount ); - - /** - * Mount a mount onto the computers' file system in a writable mode.
- * @param desiredLocation The location on the computercraft's file system where you would like the mount to be mounted. - * @param mount The mount object to mount on the computercraft. These can be obtained by calling ComputerCraftAPI.createSaveDirMount() or by creating your own objects that implement the IWritableMount interface. - * @return The location on the computercraft's file system where you the mount mounted, or null if there was already a file in the desired location. Store this value if you wish to unmount the mount later. - * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String) - * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String) - * @see #mount(String, IMount) - * @see #unmount(String) - * @see IMount - */ - public String mountWritable( String desiredLocation, IWritableMount mount ); - - /** - * Unmounts a directory previously mounted onto the computers file system by mount() or mountWritable().
- * When a directory is unmounted, it will disappear from the computers file system, and the user will no longer be able to - * access it. All directories mounted by a mount or mountWritable are automatically unmounted when the peripheral - * is attached if they have not been explicitly unmounted. - * @param location The desired location in the computers file system of the directory to unmount. - * This must be the location of a directory previously mounted by mount() or mountWritable(), as - * indicated by their return value. - * @see #mount(String, IMount) - * @see #mountWritable(String, IWritableMount) - */ - public void unmount( String location ); - - /** - * Returns the numerical ID of this computercraft.
- * This is the same number obtained by calling os.getComputerID() or running the "id" program from lua, - * and is guarunteed unique. This number will be positive. - * @return The identifier. - */ - public int getID(); +public interface IComputerAccess { - /** - * Causes an event to be raised on this computercraft, which the computercraft can respond to by calling - * os.pullEvent(). This can be used to notify the computercraft when things happen in the world or to - * this peripheral. - * @param event A string identifying the type of event that has occurred, this will be - * returned as the first value from os.pullEvent(). It is recommended that you - * you choose a name that is unique, and recognisable as originating from your - * peripheral. eg: If your peripheral type is "button", a suitable event would be - * "button_pressed". - * @param arguments In addition to a name, you may pass an array of extra arguments to the event, that will - * be supplied as extra return values to os.pullEvent(). Objects in the array will be converted - * to lua data types in the same fashion as the return values of IPeripheral.callMethod().
- * You may supply null to indicate that no arguments are to be supplied. - * @see dan200.computercraft.api.peripheral.IPeripheral#callMethod - */ - public void queueEvent( String event, Object[] arguments ); + /** + * Mount a mount onto the computers' file system in a read only mode.
+ * + * @param desiredLocation The location on the computercraft's file system where you would like the mount to be + * mounted. + * @param mount The mount object to mount on the computercraft. These can be obtained by calling + * ComputerCraftAPI.createSaveDirMount(), ComputerCraftAPI.createResourceMount() or by + * creating your own objects that implement the IMount interface. + * @return The location on the computercraft's file system where you the mount mounted, or null if there was already + * a file in the desired location. Store this value if you wish to unmount the mount later. + * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String) + * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String) + * @see #mountWritable(String, dan200.computercraft.api.filesystem.IWritableMount) + * @see #unmount(String) + * @see dan200.computercraft.api.filesystem.IMount + */ + public String mount(String desiredLocation, IMount mount); - /** - * Get a string, unique to the computercraft, by which the computercraft refers to this peripheral. - * For directly attached peripherals this will be "left","right","front","back",etc, but - * for peripherals attached remotely it will be different. It is good practice to supply - * this string when raising events to the computercraft, so that the computercraft knows from - * which peripheral the event came. - * @return A string unique to the computercraft, but not globally. - */ - public String getAttachmentName(); + /** + * Mount a mount onto the computers' file system in a writable mode.
+ * + * @param desiredLocation The location on the computercraft's file system where you would like the mount to be + * mounted. + * @param mount The mount object to mount on the computercraft. These can be obtained by calling + * ComputerCraftAPI.createSaveDirMount() or by creating your own objects that implement the + * IWritableMount interface. + * @return The location on the computercraft's file system where you the mount mounted, or null if there was already + * a file in the desired location. Store this value if you wish to unmount the mount later. + * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String) + * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String) + * @see #mount(String, IMount) + * @see #unmount(String) + * @see IMount + */ + public String mountWritable(String desiredLocation, IWritableMount mount); + + /** + * Unmounts a directory previously mounted onto the computers file system by mount() or mountWritable().
+ * When a directory is unmounted, it will disappear from the computers file system, and the user will no longer be + * able to + * access it. All directories mounted by a mount or mountWritable are automatically unmounted when the peripheral + * is attached if they have not been explicitly unmounted. + * + * @param location The desired location in the computers file system of the directory to unmount. + * This must be the location of a directory previously mounted by mount() or mountWritable(), as + * indicated by their return value. + * @see #mount(String, IMount) + * @see #mountWritable(String, IWritableMount) + */ + public void unmount(String location); + + /** + * Returns the numerical ID of this computercraft.
+ * This is the same number obtained by calling os.getComputerID() or running the "id" program from lua, + * and is guarunteed unique. This number will be positive. + * + * @return The identifier. + */ + public int getID(); + + /** + * Causes an event to be raised on this computercraft, which the computercraft can respond to by calling + * os.pullEvent(). This can be used to notify the computercraft when things happen in the world or to + * this peripheral. + * + * @param event A string identifying the type of event that has occurred, this will be + * returned as the first value from os.pullEvent(). It is recommended that you + * you choose a name that is unique, and recognisable as originating from your + * peripheral. eg: If your peripheral type is "button", a suitable event would be + * "button_pressed". + * @param arguments In addition to a name, you may pass an array of extra arguments to the event, that will + * be supplied as extra return values to os.pullEvent(). Objects in the array will be converted + * to lua data types in the same fashion as the return values of IPeripheral.callMethod().
+ * You may supply null to indicate that no arguments are to be supplied. + * @see dan200.computercraft.api.peripheral.IPeripheral#callMethod + */ + public void queueEvent(String event, Object[] arguments); + + /** + * Get a string, unique to the computercraft, by which the computercraft refers to this peripheral. + * For directly attached peripherals this will be "left","right","front","back",etc, but + * for peripherals attached remotely it will be different. It is good practice to supply + * this string when raising events to the computercraft, so that the computercraft knows from + * which peripheral the event came. + * + * @return A string unique to the computercraft, but not globally. + */ + public String getAttachmentName(); } diff --git a/src/api/java/dan200/computercraft/api/peripheral/IPeripheral.java b/src/api/java/dan200/computercraft/api/peripheral/IPeripheral.java index 99396dd9..676cdd29 100644 --- a/src/api/java/dan200/computercraft/api/peripheral/IPeripheral.java +++ b/src/api/java/dan200/computercraft/api/peripheral/IPeripheral.java @@ -14,87 +14,97 @@ * TileEntity of any common that you wish to be interacted with by * computercraft or turtle. */ -public interface IPeripheral -{ - /** - * Should return a string that uniquely identifies this type of peripheral. - * This can be queried from lua by calling peripheral.getType() - * @return A string identifying the type of peripheral. - */ +public interface IPeripheral { + + /** + * Should return a string that uniquely identifies this type of peripheral. + * This can be queried from lua by calling peripheral.getType() + * + * @return A string identifying the type of peripheral. + */ public String getType(); - - /** - * Should return an array of strings that identify the methods that this - * peripheral exposes to Lua. This will be called once before each attachment, - * and should not change when called multiple times. - * @return An array of strings representing method names. - * @see #callMethod - */ + + /** + * Should return an array of strings that identify the methods that this + * peripheral exposes to Lua. This will be called once before each attachment, + * and should not change when called multiple times. + * + * @return An array of strings representing method names. + * @see #callMethod + */ public String[] getMethodNames(); - - /** - * This is called when a lua program on an attached computercraft calls peripheral.call() with - * one of the methods exposed by getMethodNames().
- *
- * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe - * when interacting with minecraft objects. - * @param computer The interface to the computercraft that is making the call. Remember that multiple - * computers can be attached to a peripheral at once. - * @param context The context of the currently running lua thread. This can be used to wait for events - * or otherwise yield. - * @param method An integer identifying which of the methods from getMethodNames() the computercraft - * wishes to call. The integer indicates the index into the getMethodNames() table - * that corresponds to the string passed into peripheral.call() - * @param arguments An array of objects, representing the arguments passed into peripheral.call().
- * Lua values of type "string" will be represented by Object type String.
- * Lua values of type "number" will be represented by Object type Double.
- * Lua values of type "boolean" will be represented by Object type Boolean.
- * Lua values of any other type will be represented by a null object.
- * This array will be empty if no arguments are passed. - * @return An array of objects, representing values you wish to return to the lua program.
- * Integers, Doubles, Floats, Strings, Booleans and null be converted to their corresponding lua type.
- * All other types will be converted to nil.
- * You may return null to indicate no values should be returned. - * @throws Exception If you throw any exception from this function, a lua error will be raised with the - * same message as your exception. Use this to throw appropriate errors if the wrong - * arguments are supplied to your method. - * @see #getMethodNames - */ - public Object[] callMethod( IComputerAccess computer, ILuaContext context, int method, Object[] arguments ) throws LuaException, InterruptedException; - - /** - * Is called when canAttachToSide has returned true, and a computercraft is attaching to the peripheral. - * This will occur when a peripheral is placed next to an active computercraft, when a computercraft is turned on next to a peripheral, - * or when a turtle travels into a square next to a peripheral. - * Between calls to attach() and detach(), the attached computercraft can make method calls on the peripheral using peripheral.call(). - * This method can be used to keep track of which computers are attached to the peripheral, or to take action when attachment - * occurs.
- *
- * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe - * when interacting with minecraft objects. - * @param computer The interface to the computercraft that is being attached. Remember that multiple - * computers can be attached to a peripheral at once. - * @see #detach - */ - public void attach( IComputerAccess computer ); - /** - * Is called when a computercraft is detaching from the peripheral. - * This will occur when a computercraft shuts down, when the peripheral is removed while attached to computers, - * or when a turtle moves away from a square attached to a peripheral. - * This method can be used to keep track of which computers are attached to the peripheral, or to take action when detachment - * occurs.
- *
- * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe - * when interacting with minecraft objects. - * @param computer The interface to the computercraft that is being detached. Remember that multiple - * computers can be attached to a peripheral at once. - * @see #detach - */ - public void detach( IComputerAccess computer ); + /** + * This is called when a lua program on an attached computercraft calls peripheral.call() with + * one of the methods exposed by getMethodNames().
+ *
+ * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe + * when interacting with minecraft objects. + * + * @param computer The interface to the computercraft that is making the call. Remember that multiple + * computers can be attached to a peripheral at once. + * @param context The context of the currently running lua thread. This can be used to wait for events + * or otherwise yield. + * @param method An integer identifying which of the methods from getMethodNames() the computercraft + * wishes to call. The integer indicates the index into the getMethodNames() table + * that corresponds to the string passed into peripheral.call() + * @param arguments An array of objects, representing the arguments passed into peripheral.call().
+ * Lua values of type "string" will be represented by Object type String.
+ * Lua values of type "number" will be represented by Object type Double.
+ * Lua values of type "boolean" will be represented by Object type Boolean.
+ * Lua values of any other type will be represented by a null object.
+ * This array will be empty if no arguments are passed. + * @return An array of objects, representing values you wish to return to the lua program.
+ * Integers, Doubles, Floats, Strings, Booleans and null be converted to their corresponding lua type.
+ * All other types will be converted to nil.
+ * You may return null to indicate no values should be returned. + * @throws Exception If you throw any exception from this function, a lua error will be raised with the + * same message as your exception. Use this to throw appropriate errors if the wrong + * arguments are supplied to your method. + * @see #getMethodNames + */ + public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) + throws LuaException, InterruptedException; + + /** + * Is called when canAttachToSide has returned true, and a computercraft is attaching to the peripheral. + * This will occur when a peripheral is placed next to an active computercraft, when a computercraft is turned on + * next to a peripheral, + * or when a turtle travels into a square next to a peripheral. + * Between calls to attach() and detach(), the attached computercraft can make method calls on the peripheral using + * peripheral.call(). + * This method can be used to keep track of which computers are attached to the peripheral, or to take action when + * attachment + * occurs.
+ *
+ * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe + * when interacting with minecraft objects. + * + * @param computer The interface to the computercraft that is being attached. Remember that multiple + * computers can be attached to a peripheral at once. + * @see #detach + */ + public void attach(IComputerAccess computer); + + /** + * Is called when a computercraft is detaching from the peripheral. + * This will occur when a computercraft shuts down, when the peripheral is removed while attached to computers, + * or when a turtle moves away from a square attached to a peripheral. + * This method can be used to keep track of which computers are attached to the peripheral, or to take action when + * detachment + * occurs.
+ *
+ * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe + * when interacting with minecraft objects. + * + * @param computer The interface to the computercraft that is being detached. Remember that multiple + * computers can be attached to a peripheral at once. + * @see #detach + */ + public void detach(IComputerAccess computer); /** * TODO: Document me */ - public boolean equals( IPeripheral other ); + public boolean equals(IPeripheral other); } diff --git a/src/api/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java b/src/api/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java index aeb354f3..3b88bdeb 100644 --- a/src/api/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java +++ b/src/api/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java @@ -10,14 +10,16 @@ /** * This interface is used to create peripheral implementations for blocks + * * @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider) */ -public interface IPeripheralProvider -{ +public interface IPeripheralProvider { + /** * Produce an peripheral implementation from a block location. + * * @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider) * @return a peripheral, or null if there is not a peripheral here you'd like to handle. */ - public IPeripheral getPeripheral( World world, int x, int y, int z, int side ); + public IPeripheral getPeripheral(World world, int x, int y, int z, int side); } diff --git a/src/api/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java b/src/api/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java index 6d5d400d..5321dd97 100644 --- a/src/api/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java +++ b/src/api/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java @@ -10,14 +10,17 @@ /** * This interface is used to provide bundled redstone output for blocks + * * @see dan200.computercraft.api.ComputerCraftAPI#registerBundledRedstoneProvider(IBundledRedstoneProvider) */ -public interface IBundledRedstoneProvider -{ +public interface IBundledRedstoneProvider { + /** * Produce an bundled redstone output from a block location. + * * @see dan200.computercraft.api.ComputerCraftAPI#registerBundledRedstoneProvider(IBundledRedstoneProvider) - * @return a number in the range 0-65535 to indicate this block is providing output, or -1 if you do not wish to handle this block + * @return a number in the range 0-65535 to indicate this block is providing output, or -1 if you do not wish to + * handle this block */ - public int getBundledRedstoneOutput( World world, int x, int y, int z, int side ); + public int getBundledRedstoneOutput(World world, int x, int y, int z, int side); } diff --git a/src/api/java/dan200/computercraft/api/turtle/ITurtleAccess.java b/src/api/java/dan200/computercraft/api/turtle/ITurtleAccess.java index e7e96810..59cfcfe6 100644 --- a/src/api/java/dan200/computercraft/api/turtle/ITurtleAccess.java +++ b/src/api/java/dan200/computercraft/api/turtle/ITurtleAccess.java @@ -6,71 +6,77 @@ package dan200.computercraft.api.turtle; -import dan200.computercraft.api.lua.ILuaContext; -import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.api.peripheral.IPeripheral; import net.minecraft.inventory.IInventory; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ChunkCoordinates; import net.minecraft.util.Vec3; import net.minecraft.world.World; +import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.peripheral.IPeripheral; + /** * The interface passed to turtle by turtles, providing methods that they can call. - * This should not be implemented by your classes. Do not interact with turtles except via this interface and ITurtleUpgrade. + * This should not be implemented by your classes. Do not interact with turtles except via this interface and + * ITurtleUpgrade. */ -public interface ITurtleAccess -{ - /** - * Returns the world in which the turtle resides. - * @return the world in which the turtle resides. - */ - public World getWorld(); +public interface ITurtleAccess { + + /** + * Returns the world in which the turtle resides. + * + * @return the world in which the turtle resides. + */ + public World getWorld(); - /** - * Returns a vector containing the integer co-ordinates at which the turtle resides. - * @return a vector containing the integer co-ordinates at which the turtle resides. - */ - public ChunkCoordinates getPosition(); + /** + * Returns a vector containing the integer co-ordinates at which the turtle resides. + * + * @return a vector containing the integer co-ordinates at which the turtle resides. + */ + public ChunkCoordinates getPosition(); /** * TODO: Document me */ - public boolean teleportTo( World world, int x, int y, int z ); + public boolean teleportTo(World world, int x, int y, int z); - /** - * Returns a vector containing the floating point co-ordinates at which the turtle is rendered. - * This will shift when the turtle is moving. - * @param f The subframe fraction - * @return a vector containing the floating point co-ordinates at which the turtle resides. - */ - public Vec3 getVisualPosition( float f ); + /** + * Returns a vector containing the floating point co-ordinates at which the turtle is rendered. + * This will shift when the turtle is moving. + * + * @param f The subframe fraction + * @return a vector containing the floating point co-ordinates at which the turtle resides. + */ + public Vec3 getVisualPosition(float f); /** * TODO: Document me */ - public float getVisualYaw( float f ); + public float getVisualYaw(float f); - /** - * Returns the world direction the turtle is currently facing. - * @return the world direction the turtle is currently facing. - */ - public int getDirection(); + /** + * Returns the world direction the turtle is currently facing. + * + * @return the world direction the turtle is currently facing. + */ + public int getDirection(); /** * TODO: Document me */ - public void setDirection( int dir ); + public void setDirection(int dir); /** * TODO: Document me */ - public int getSelectedSlot(); + public int getSelectedSlot(); /** * TODO: Document me */ - public void setSelectedSlot( int slot ); + public void setSelectedSlot(int slot); /** * TODO: Document me @@ -82,15 +88,15 @@ public interface ITurtleAccess */ public boolean isFuelNeeded(); - /** - * TODO: Document me - */ - public int getFuelLevel(); + /** + * TODO: Document me + */ + public int getFuelLevel(); /** * TODO: Document me */ - public void setFuelLevel( int fuel ); + public void setFuelLevel(int fuel); /** * TODO: Document me @@ -98,59 +104,68 @@ public interface ITurtleAccess public int getFuelLimit(); /** - * Removes some fuel from the turtles fuel supply. Negative numbers can be passed in to INCREASE the fuel level of the turtle. - * @return Whether the turtle was able to consume the ammount of fuel specified. Will return false if you supply a number - * greater than the current fuel level of the turtle. - */ - public boolean consumeFuel( int fuel ); + * Removes some fuel from the turtles fuel supply. Negative numbers can be passed in to INCREASE the fuel level of + * the turtle. + * + * @return Whether the turtle was able to consume the ammount of fuel specified. Will return false if you supply a + * number + * greater than the current fuel level of the turtle. + */ + public boolean consumeFuel(int fuel); /** * TODO: Document me */ - public void addFuel( int fuel ); + public void addFuel(int fuel); /** - * Adds a custom command to the turtles command queue. Unlike peripheral methods, these custom commands will be executed + * Adds a custom command to the turtles command queue. Unlike peripheral methods, these custom commands will be + * executed * on the main thread, so are guaranteed to be able to access Minecraft objects safely, and will be queued up * with the turtles standard movement and tool commands. An issued command will return an unique integer, which will - * be supplied as a parameter to a "turtle_response" event issued to the turtle after the command has completed. Look at the + * be supplied as a parameter to a "turtle_response" event issued to the turtle after the command has completed. + * Look at the * lua source code for "rom/apis/turtle" for how to build a lua wrapper around this functionality. + * * @param command an object which will execute the custom command when its point in the queue is reached * @return the objects the command returned when executed. you should probably return these to the player - * unchanged if called from a peripheral method. + * unchanged if called from a peripheral method. * @see ITurtleCommand */ - public Object[] executeCommand( ILuaContext context, ITurtleCommand command ) throws LuaException, InterruptedException; + public Object[] executeCommand(ILuaContext context, ITurtleCommand command) + throws LuaException, InterruptedException; /** * TODO: Document me */ - public void playAnimation( TurtleAnimation animation ); + public void playAnimation(TurtleAnimation animation); - /** - * Returns the turtle on the specified side of the turtle, if there is one. - * @return the turtle on the specified side of the turtle, if there is one. - */ - public ITurtleUpgrade getUpgrade( TurtleSide side ); + /** + * Returns the turtle on the specified side of the turtle, if there is one. + * + * @return the turtle on the specified side of the turtle, if there is one. + */ + public ITurtleUpgrade getUpgrade(TurtleSide side); /** * TODO: Document me */ - public void setUpgrade( TurtleSide side, ITurtleUpgrade upgrade ); + public void setUpgrade(TurtleSide side, ITurtleUpgrade upgrade); - /** - * Returns the peripheral created by the upgrade on the specified side of the turtle, if there is one. - * @return the peripheral created by the upgrade on the specified side of the turtle, if there is one. - */ - public IPeripheral getPeripheral( TurtleSide side ); + /** + * Returns the peripheral created by the upgrade on the specified side of the turtle, if there is one. + * + * @return the peripheral created by the upgrade on the specified side of the turtle, if there is one. + */ + public IPeripheral getPeripheral(TurtleSide side); /** * TODO: Document me */ - public NBTTagCompound getUpgradeNBTData( TurtleSide side ); + public NBTTagCompound getUpgradeNBTData(TurtleSide side); /** * TODO: Document me */ - public void updateUpgradeNBTData( TurtleSide side ); + public void updateUpgradeNBTData(TurtleSide side); } diff --git a/src/api/java/dan200/computercraft/api/turtle/ITurtleCommand.java b/src/api/java/dan200/computercraft/api/turtle/ITurtleCommand.java index a551b649..9c5c35b3 100644 --- a/src/api/java/dan200/computercraft/api/turtle/ITurtleCommand.java +++ b/src/api/java/dan200/computercraft/api/turtle/ITurtleCommand.java @@ -8,18 +8,20 @@ /** * An interface for objects executing custom turtle commands, used with ITurtleAccess.issueCommand + * * @see ITurtleAccess#executeCommand(dan200.computercraft.api.lua.ILuaContext,ITurtleCommand) */ -public interface ITurtleCommand -{ - /** - * Will be called by the turtle on the main thread when it is time to execute the custom command. - * The handler should either perform the work of the command, and return success, or return - * failure with an error message to indicate the command cannot be executed at this time. - * @param turtle access to the turtle for whom the command was issued - * @return TurtleCommandResult.success() or TurtleCommandResult.failure( errorMessage ) +public interface ITurtleCommand { + + /** + * Will be called by the turtle on the main thread when it is time to execute the custom command. + * The handler should either perform the work of the command, and return success, or return + * failure with an error message to indicate the command cannot be executed at this time. + * + * @param turtle access to the turtle for whom the command was issued + * @return TurtleCommandResult.success() or TurtleCommandResult.failure( errorMessage ) * @see ITurtleAccess#executeCommand(dan200.computercraft.api.lua.ILuaContext,ITurtleCommand) * @see dan200.computercraft.api.turtle.TurtleCommandResult - */ - public TurtleCommandResult execute( ITurtleAccess turtle ); + */ + public TurtleCommandResult execute(ITurtleAccess turtle); } diff --git a/src/api/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java b/src/api/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java index 461d6e2b..5268d8c7 100644 --- a/src/api/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java +++ b/src/api/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java @@ -6,89 +6,97 @@ package dan200.computercraft.api.turtle; -import dan200.computercraft.api.peripheral.IPeripheral; import net.minecraft.item.ItemStack; import net.minecraft.util.IIcon; +import dan200.computercraft.api.peripheral.IPeripheral; + /** * The primary interface for defining an turtle for Turtles. A turtle turtle * can either be a new tool, or a new peripheral. - * @see dan200.computercraft.api.ComputerCraftAPI#registerTurtleUpgrade( dan200.computercraft.api.turtle.ITurtleUpgrade ) + * + * @see dan200.computercraft.api.ComputerCraftAPI#registerTurtleUpgrade( dan200.computercraft.api.turtle.ITurtleUpgrade + * ) */ -public interface ITurtleUpgrade -{ - /** - * Gets a unique numerical identifier representing this type of turtle turtle. - * Like Minecraft common and item IDs, you should strive to make this number unique - * among all turtle turtle that have been released for ComputerCraft. - * The ID must be in the range 64 to 255, as the ID is stored as an 8-bit value, - * and 0-64 is reserved for future use by ComputerCraft. The turtle will - * fail registration if an already used ID is specified. - * @see dan200.computercraft.api.ComputerCraftAPI#registerTurtleUpgrade( dan200.computercraft.api.turtle.ITurtleUpgrade ) - */ - public int getUpgradeID(); - - /** - * Return a String to describe this type of turtle in turtle item names. - * Examples of built-in adjectives are "Wireless", "Mining" and "Crafty". - */ - public String getUnlocalisedAdjective(); +public interface ITurtleUpgrade { + + /** + * Gets a unique numerical identifier representing this type of turtle turtle. + * Like Minecraft common and item IDs, you should strive to make this number unique + * among all turtle turtle that have been released for ComputerCraft. + * The ID must be in the range 64 to 255, as the ID is stored as an 8-bit value, + * and 0-64 is reserved for future use by ComputerCraft. The turtle will + * fail registration if an already used ID is specified. + * + * @see dan200.computercraft.api.ComputerCraftAPI#registerTurtleUpgrade( + * dan200.computercraft.api.turtle.ITurtleUpgrade ) + */ + public int getUpgradeID(); - /** - * Return whether this turtle adds a tool or a peripheral to the turtle. - * Currently, turtle crafting is restricted to one tool & one peripheral per turtle. - * @see TurtleUpgradeType for the differences between the two. - */ - public TurtleUpgradeType getType(); - - /** - * Return an item stack representing the type of item that a turtle must be crafted - * with to create a turtle which holds this turtle. - * Currently, turtle crafting is restricted to one tool & one peripheral per turtle. - */ - public ItemStack getCraftingItem(); + /** + * Return a String to describe this type of turtle in turtle item names. + * Examples of built-in adjectives are "Wireless", "Mining" and "Crafty". + */ + public String getUnlocalisedAdjective(); /** - * Will only be called for Peripheral turtle. Creates a peripheral for a turtle - * being placed using this turtle. The peripheral created will be stored - * for the lifetime of the turtle, will have update() called once-per-tick, and will be - * attach'd detach'd and have methods called in the same manner as a Computer peripheral. - * + * Return whether this turtle adds a tool or a peripheral to the turtle. + * Currently, turtle crafting is restricted to one tool & one peripheral per turtle. + * + * @see TurtleUpgradeType for the differences between the two. + */ + public TurtleUpgradeType getType(); + + /** + * Return an item stack representing the type of item that a turtle must be crafted + * with to create a turtle which holds this turtle. + * Currently, turtle crafting is restricted to one tool & one peripheral per turtle. + */ + public ItemStack getCraftingItem(); + + /** + * Will only be called for Peripheral turtle. Creates a peripheral for a turtle + * being placed using this turtle. The peripheral created will be stored + * for the lifetime of the turtle, will have update() called once-per-tick, and will be + * attach'd detach'd and have methods called in the same manner as a Computer peripheral. + * * @param turtle Access to the turtle that the peripheral is being created for. - * @param side Which side of the turtle (left or right) that the turtle resides on. + * @param side Which side of the turtle (left or right) that the turtle resides on. * @return The newly created peripheral. You may return null if this turtle is a Tool - * and this method is not expected to be called. - */ - public IPeripheral createPeripheral( ITurtleAccess turtle, TurtleSide side ); + * and this method is not expected to be called. + */ + public IPeripheral createPeripheral(ITurtleAccess turtle, TurtleSide side); - /** - * Will only be called for Tool turtle. Called when turtle.dig() or turtle.attack() is called - * by the turtle, and the tool is required to do some work. - * @param turtle Access to the turtle that the tool resides on. - * @param side Which side of the turtle (left or right) the tool resides on. - * @param verb Which action (dig or attack) the turtle is being called on to perform. - * @param direction Which world direction the action should be performed in, relative to the turtles - * position. This will either be up, down, or the direction the turtle is facing, depending on - * whether dig, digUp or digDown was called. - * @return Whether the turtle was able to perform the action, and hence whether the turtle.dig() - * or turtle.attack() lua method should return true. If true is returned, the tool will perform - * a swinging animation. You may return null if this turtle is a Peripheral - * and this method is not expected to be called. - */ - public TurtleCommandResult useTool( ITurtleAccess turtle, TurtleSide side, TurtleVerb verb, int direction ); + /** + * Will only be called for Tool turtle. Called when turtle.dig() or turtle.attack() is called + * by the turtle, and the tool is required to do some work. + * + * @param turtle Access to the turtle that the tool resides on. + * @param side Which side of the turtle (left or right) the tool resides on. + * @param verb Which action (dig or attack) the turtle is being called on to perform. + * @param direction Which world direction the action should be performed in, relative to the turtles + * position. This will either be up, down, or the direction the turtle is facing, depending on + * whether dig, digUp or digDown was called. + * @return Whether the turtle was able to perform the action, and hence whether the turtle.dig() + * or turtle.attack() lua method should return true. If true is returned, the tool will perform + * a swinging animation. You may return null if this turtle is a Peripheral + * and this method is not expected to be called. + */ + public TurtleCommandResult useTool(ITurtleAccess turtle, TurtleSide side, TurtleVerb verb, int direction); - /** - * Called to obtain the IIcon to be used when rendering a turtle peripheral. Needs to be a "common" - * type IIcon for now, as there is no way to determine which texture sheet an IIcon is from by the - * IIcon itself. - * @param turtle Access to the turtle that the peripheral resides on. - * @param side Which side of the turtle (left or right) the peripheral resides on. - * @return The IIcon that you wish to be used to render your turtle peripheral. - */ - public IIcon getIcon( ITurtleAccess turtle, TurtleSide side ); + /** + * Called to obtain the IIcon to be used when rendering a turtle peripheral. Needs to be a "common" + * type IIcon for now, as there is no way to determine which texture sheet an IIcon is from by the + * IIcon itself. + * + * @param turtle Access to the turtle that the peripheral resides on. + * @param side Which side of the turtle (left or right) the peripheral resides on. + * @return The IIcon that you wish to be used to render your turtle peripheral. + */ + public IIcon getIcon(ITurtleAccess turtle, TurtleSide side); /** * TODO: Document me */ - public void update( ITurtleAccess turtle, TurtleSide side ); + public void update(ITurtleAccess turtle, TurtleSide side); } diff --git a/src/api/java/dan200/computercraft/api/turtle/TurtleAnimation.java b/src/api/java/dan200/computercraft/api/turtle/TurtleAnimation.java index b907e624..cb08a149 100644 --- a/src/api/java/dan200/computercraft/api/turtle/TurtleAnimation.java +++ b/src/api/java/dan200/computercraft/api/turtle/TurtleAnimation.java @@ -6,8 +6,7 @@ package dan200.computercraft.api.turtle; -public enum TurtleAnimation -{ +public enum TurtleAnimation { None, MoveForward, MoveBack, diff --git a/src/api/java/dan200/computercraft/api/turtle/TurtleCommandResult.java b/src/api/java/dan200/computercraft/api/turtle/TurtleCommandResult.java index 7a94ae6f..c522eaf1 100644 --- a/src/api/java/dan200/computercraft/api/turtle/TurtleCommandResult.java +++ b/src/api/java/dan200/computercraft/api/turtle/TurtleCommandResult.java @@ -6,29 +6,23 @@ package dan200.computercraft.api.turtle; -public final class TurtleCommandResult -{ - private static final TurtleCommandResult s_success = new TurtleCommandResult( true, null ); - private static final TurtleCommandResult s_emptyFailure = new TurtleCommandResult( false, null ); +public final class TurtleCommandResult { - public static TurtleCommandResult success() - { + private static final TurtleCommandResult s_success = new TurtleCommandResult(true, null); + private static final TurtleCommandResult s_emptyFailure = new TurtleCommandResult(false, null); + + public static TurtleCommandResult success() { return s_success; } - public static TurtleCommandResult failure() - { - return failure( null ); + public static TurtleCommandResult failure() { + return failure(null); } - public static TurtleCommandResult failure( String errorMessage ) - { - if( errorMessage != null ) - { - return new TurtleCommandResult( false, errorMessage ); - } - else - { + public static TurtleCommandResult failure(String errorMessage) { + if (errorMessage != null) { + return new TurtleCommandResult(false, errorMessage); + } else { return s_emptyFailure; } } @@ -36,19 +30,16 @@ public static TurtleCommandResult failure( String errorMessage ) private final boolean m_success; private final String m_errorMessage; - private TurtleCommandResult( boolean success, String errorMessage ) - { + private TurtleCommandResult(boolean success, String errorMessage) { m_success = success; m_errorMessage = errorMessage; } - public boolean isSuccess() - { + public boolean isSuccess() { return m_success; } - public String getErrorMessage() - { + public String getErrorMessage() { return m_errorMessage; } } diff --git a/src/api/java/dan200/computercraft/api/turtle/TurtleSide.java b/src/api/java/dan200/computercraft/api/turtle/TurtleSide.java index e125d801..b03392bf 100644 --- a/src/api/java/dan200/computercraft/api/turtle/TurtleSide.java +++ b/src/api/java/dan200/computercraft/api/turtle/TurtleSide.java @@ -9,15 +9,14 @@ /** * An enum representing the two sides of the turtle that a turtle turtle might reside. */ -public enum TurtleSide -{ - /** - * The turtles left side (where the pickaxe usually is on a Wireless Mining Turtle) - */ - Left, +public enum TurtleSide { + /** + * The turtles left side (where the pickaxe usually is on a Wireless Mining Turtle) + */ + Left, - /** - * The turtles right side (where the modem usually is on a Wireless Mining Turtle) - */ - Right, + /** + * The turtles right side (where the modem usually is on a Wireless Mining Turtle) + */ + Right, } diff --git a/src/api/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java b/src/api/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java index ef84ee9b..c2d1f340 100644 --- a/src/api/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java +++ b/src/api/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java @@ -9,19 +9,19 @@ /** * An enum representing the two different types of turtle that an ITurtleUpgrade * implementation can add to a turtle. + * * @see ITurtleUpgrade */ -public enum TurtleUpgradeType -{ - /** - * A tool is rendered as an item on the side of the turtle, and responds to the turtle.dig() - * and turtle.attack() methods (Such as pickaxe or sword on Mining and Melee turtles). - */ - Tool, - - /** - * A peripheral adds a special peripheral which is attached to the side of the turtle, - * and can be interacted with the peripheral API (Such as the modem on Wireless Turtles). - */ - Peripheral, +public enum TurtleUpgradeType { + /** + * A tool is rendered as an item on the side of the turtle, and responds to the turtle.dig() + * and turtle.attack() methods (Such as pickaxe or sword on Mining and Melee turtles). + */ + Tool, + + /** + * A peripheral adds a special peripheral which is attached to the side of the turtle, + * and can be interacted with the peripheral API (Such as the modem on Wireless Turtles). + */ + Peripheral, } diff --git a/src/api/java/dan200/computercraft/api/turtle/TurtleVerb.java b/src/api/java/dan200/computercraft/api/turtle/TurtleVerb.java index 3a8fb092..d7db5cce 100644 --- a/src/api/java/dan200/computercraft/api/turtle/TurtleVerb.java +++ b/src/api/java/dan200/computercraft/api/turtle/TurtleVerb.java @@ -9,18 +9,18 @@ /** * An enum representing the two different actions that an ITurtleUpgrade of type * Tool may be called on to perform by a turtle. + * * @see ITurtleUpgrade * @see ITurtleUpgrade#useTool */ -public enum TurtleVerb -{ - /** - * The turtle called turtle.dig(), turtle.digUp() or turtle.digDown() - */ - Dig, - - /** - * The turtle called turtle.attack(), turtle.attackUp() or turtle.attackDown() - */ - Attack, +public enum TurtleVerb { + /** + * The turtle called turtle.dig(), turtle.digUp() or turtle.digDown() + */ + Dig, + + /** + * The turtle called turtle.attack(), turtle.attackUp() or turtle.attackDown() + */ + Attack, } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/FactoryRegistry.java b/src/api/java/powercrystals/minefactoryreloaded/api/FactoryRegistry.java index 8eff88d4..42e23a64 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/FactoryRegistry.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/FactoryRegistry.java @@ -1,113 +1,113 @@ package powercrystals.minefactoryreloaded.api; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.event.FMLInterModComms; import cpw.mods.fml.common.event.FMLInterModComms.IMCMessage; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; - /** * @author PowerCrystals * - * Class used to register plants and other farming-related things with MFR. Will do nothing if MFR does not exist. + * Class used to register plants and other farming-related things with MFR. Will do nothing if MFR does not + * exist. * */ -public class FactoryRegistry -{ - /* - * This may be called at any time during pre-init, init or post-init, assuming all blocks and items - * that are being accessed from the registry have been appropriately registered. - * Possible messages: - * - * // Registration: - * addLaserPreferredOre | NBTTag with an ItemStack saved on it, with the color on the "value" attribute, - * | A ValuedItem with item and value set. - * registerAutoSpawnerBlacklist | The String identifier of an entity, - * | A subclass of EntityLivingBase. - * registerFertilizable | An instance of IFactoryFertilizable. - * registerFertilizer | An instance of IFactoryFertilizer. - * registerFruitLog | The String identifier of a block. - * registerGrindable | An instance of IFactoryGrindable. - * registerGrinderBlacklist | A subclass of EntityLivingBase. - * registerHarvestable | An instance of IFactoryHarvestable. - * registerLaserOre | NBTTag with an ItemStack saved on it, with the weight on the "value" attribute, - * | A ValuedItem with item and value set. - * registerLiquidDrinkHandler | A ValuedItem with key and object set; ILiquidDrinkHandler expected. - * registerMobEggHandler | An instance of IMobEggHandler. - * registerPickableFruit | An instance of IFactoryFruit. - * registerPlantable | An instance of IFactoryPlantable. - * registerRanchable | An instance of IFactoryRanchable. - * registerRedNetLogicCircuit | An instance of IRedNetLogicCircuit. - * registerRubberTreeBiome | The biomeName field of a biome to white list for rubber trees to spawn in. - * registerSafariNetBlacklist | A subclass of EntityLivingBase. - * registerSafariNetHandler | An instance of ISafariNetHandler. - * registerSludgeDrop | NBTTag with an ItemStack saved on it, with the weight on the "value" attribute, - * | A ValuedItem with item and value set. - * registerSpawnHandler | An instance of IMobSpawnHandler. - * registerVillagerTradeMob | An instance of IRandomMobProvider. - * - * // Simple implementations: - * { Harvestables - * registerHarvestable_Standard | The String identifier of a block. - * registerHarvestable_Log | The String identifier of a block. - * registerHarvestable_Leaves | The String identifier of a block. - * registerHarvestable_Vine | The String identifier of a block. - * registerHarvestable_Shrub | The String identifier of a block. - * registerHarvestable_Mushroom | The String identifier of a block. - * registerHarvestable_Crop | An ItemStack of a block, with a damage value indicating the meta value to harvest at. - * | A ValuedItem with value and object set; Block expected. - * registerHarvestable_Gourd | An NBTTag with the stem and fruit attributes, both String identifiers of blocks. - * } - * { Plantables - * registerPlantable_Standard | An NBTTag with the seed (Item, String identifier), and - * crop (Block, String identifier) attributes set, optionally - * also having the meta (Integer, placed metadata value) attribute set. - * No special checks for location, just sustainability. - * registerPlantable_Crop | An NBTTag with the seed (Item, String identifier), and - * crop (Block, String identifier) attributes set, optionally - * also having the meta (Integer, placed metadata value) attribute set. - * Will automatically hoe dirt and grass into farmland when planting. - * registerPlantable_Sapling | An NBTTag with the sapling (Block, String identifier), and optionally - * the seed (Item, String identifier) attributes set. - * } - * { Fertilizer - * registerFertilizer | An NBTTag with the fert (Item, String identifier), meta (Integer), and - * type (Integer, index into FertilizerType.values()) attributes set. - * } - * { Fertilizables - * registerFertilizable_Grass | The String identifier of a block. Will bonemeal the block and expect - * tall grass be planted above and around it, must be IGrowable. Works with - * the GrowPlant and Grass type fertilizers, not recommended for crop plants. - * registerFertilizable_Gourd | The String identifier of a block. Must be IGrowable, and expects identical - * behavior to vanilla stems. Works with the GrowPlant fertilizers. - * registerFertilizable_Crop | An NBTTag with the plant (Block, String identifier, IGrowable), and - * meta (Integer, max growth phase) attributes set, optionally also having - * the type (Integer, index into FertilizerType) attribute set. - * registerFertilizable_Cocoa | An NBTTag with the plant (Block, String identifier), and optionally also - * the type (Integer, index into FertilizerType) attributes set. - * Expects metadata of the block to exactly match cocoa pods. - * registerFertilizable_Standard | An NBTTag with the plant (Block, String identifier, IGrowable), and - * optionally also the type (Integer, index into FertilizerType) attributes set. - * Expects the block to change when successfully grown (e.g., saplings). - * } - */ - public static void sendMessage(String message, Object value) - { - if (!Loader.isModLoaded("MineFactoryReloaded") || - Loader.instance().activeModContainer() == null) - return; - try - { - Method m = FMLInterModComms.class.getDeclaredMethod("enqueueMessage", Object.class, String.class, IMCMessage.class); - m.setAccessible(true); - Constructor c = IMCMessage.class.getDeclaredConstructor(String.class, Object.class); - c.setAccessible(true); - m.invoke(null, Loader.instance().activeModContainer(), "MineFactoryReloaded", c.newInstance(message, value)); - } - catch(Exception e) - { - e.printStackTrace(); - } - } +public class FactoryRegistry { + + /* + * This may be called at any time during pre-init, init or post-init, assuming all blocks and items + * that are being accessed from the registry have been appropriately registered. + * Possible messages: + * // Registration: + * addLaserPreferredOre | NBTTag with an ItemStack saved on it, with the color on the "value" attribute, + * | A ValuedItem with item and value set. + * registerAutoSpawnerBlacklist | The String identifier of an entity, + * | A subclass of EntityLivingBase. + * registerFertilizable | An instance of IFactoryFertilizable. + * registerFertilizer | An instance of IFactoryFertilizer. + * registerFruitLog | The String identifier of a block. + * registerGrindable | An instance of IFactoryGrindable. + * registerGrinderBlacklist | A subclass of EntityLivingBase. + * registerHarvestable | An instance of IFactoryHarvestable. + * registerLaserOre | NBTTag with an ItemStack saved on it, with the weight on the "value" attribute, + * | A ValuedItem with item and value set. + * registerLiquidDrinkHandler | A ValuedItem with key and object set; ILiquidDrinkHandler expected. + * registerMobEggHandler | An instance of IMobEggHandler. + * registerPickableFruit | An instance of IFactoryFruit. + * registerPlantable | An instance of IFactoryPlantable. + * registerRanchable | An instance of IFactoryRanchable. + * registerRedNetLogicCircuit | An instance of IRedNetLogicCircuit. + * registerRubberTreeBiome | The biomeName field of a biome to white list for rubber trees to spawn in. + * registerSafariNetBlacklist | A subclass of EntityLivingBase. + * registerSafariNetHandler | An instance of ISafariNetHandler. + * registerSludgeDrop | NBTTag with an ItemStack saved on it, with the weight on the "value" attribute, + * | A ValuedItem with item and value set. + * registerSpawnHandler | An instance of IMobSpawnHandler. + * registerVillagerTradeMob | An instance of IRandomMobProvider. + * // Simple implementations: + * { Harvestables + * registerHarvestable_Standard | The String identifier of a block. + * registerHarvestable_Log | The String identifier of a block. + * registerHarvestable_Leaves | The String identifier of a block. + * registerHarvestable_Vine | The String identifier of a block. + * registerHarvestable_Shrub | The String identifier of a block. + * registerHarvestable_Mushroom | The String identifier of a block. + * registerHarvestable_Crop | An ItemStack of a block, with a damage value indicating the meta value to harvest at. + * | A ValuedItem with value and object set; Block expected. + * registerHarvestable_Gourd | An NBTTag with the stem and fruit attributes, both String identifiers of blocks. + * } + * { Plantables + * registerPlantable_Standard | An NBTTag with the seed (Item, String identifier), and + * crop (Block, String identifier) attributes set, optionally + * also having the meta (Integer, placed metadata value) attribute set. + * No special checks for location, just sustainability. + * registerPlantable_Crop | An NBTTag with the seed (Item, String identifier), and + * crop (Block, String identifier) attributes set, optionally + * also having the meta (Integer, placed metadata value) attribute set. + * Will automatically hoe dirt and grass into farmland when planting. + * registerPlantable_Sapling | An NBTTag with the sapling (Block, String identifier), and optionally + * the seed (Item, String identifier) attributes set. + * } + * { Fertilizer + * registerFertilizer | An NBTTag with the fert (Item, String identifier), meta (Integer), and + * type (Integer, index into FertilizerType.values()) attributes set. + * } + * { Fertilizables + * registerFertilizable_Grass | The String identifier of a block. Will bonemeal the block and expect + * tall grass be planted above and around it, must be IGrowable. Works with + * the GrowPlant and Grass type fertilizers, not recommended for crop plants. + * registerFertilizable_Gourd | The String identifier of a block. Must be IGrowable, and expects identical + * behavior to vanilla stems. Works with the GrowPlant fertilizers. + * registerFertilizable_Crop | An NBTTag with the plant (Block, String identifier, IGrowable), and + * meta (Integer, max growth phase) attributes set, optionally also having + * the type (Integer, index into FertilizerType) attribute set. + * registerFertilizable_Cocoa | An NBTTag with the plant (Block, String identifier), and optionally also + * the type (Integer, index into FertilizerType) attributes set. + * Expects metadata of the block to exactly match cocoa pods. + * registerFertilizable_Standard | An NBTTag with the plant (Block, String identifier, IGrowable), and + * optionally also the type (Integer, index into FertilizerType) attributes set. + * Expects the block to change when successfully grown (e.g., saplings). + * } + */ + public static void sendMessage(String message, Object value) { + if (!Loader.isModLoaded("MineFactoryReloaded") || Loader.instance() + .activeModContainer() == null) return; + try { + Method m = FMLInterModComms.class + .getDeclaredMethod("enqueueMessage", Object.class, String.class, IMCMessage.class); + m.setAccessible(true); + Constructor c = IMCMessage.class.getDeclaredConstructor(String.class, Object.class); + c.setAccessible(true); + m.invoke( + null, + Loader.instance() + .activeModContainer(), + "MineFactoryReloaded", + c.newInstance(message, value)); + } catch (Exception e) { + e.printStackTrace(); + } + } } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/FertilizerType.java b/src/api/java/powercrystals/minefactoryreloaded/api/FertilizerType.java index 63ae32e6..9da80a92 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/FertilizerType.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/FertilizerType.java @@ -3,25 +3,25 @@ /** * @author PowerCrystals * - * Determines what kind of action a given fertilizer can perform. Your IFactoryFertilizable instances should check this before - * performing any action to maintain future compatibility. + * Determines what kind of action a given fertilizer can perform. Your IFactoryFertilizable instances should + * check this before + * performing any action to maintain future compatibility. */ -public enum FertilizerType -{ - /** - * The fertilizer will fertilize nothing. - */ - None, - /** - * The fertilizer will fertilize grass. - */ - Grass, - /** - * The fertilizer will grow a plant. - */ - GrowPlant, - /** - * The fertilizer will grow magical crops. - */ - GrowMagicalCrop, -} \ No newline at end of file +public enum FertilizerType { + /** + * The fertilizer will fertilize nothing. + */ + None, + /** + * The fertilizer will fertilize grass. + */ + Grass, + /** + * The fertilizer will grow a plant. + */ + GrowPlant, + /** + * The fertilizer will grow magical crops. + */ + GrowMagicalCrop, +} diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/HarvestType.java b/src/api/java/powercrystals/minefactoryreloaded/api/HarvestType.java index a56208ee..ccd5daa4 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/HarvestType.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/HarvestType.java @@ -3,42 +3,41 @@ /** * @author PowerCrystals * - * Determines what algorithm the Harvester uses when it encounters this IFactoryHarvestable in the world. + * Determines what algorithm the Harvester uses when it encounters this IFactoryHarvestable in the world. */ -public enum HarvestType -{ - /** - * Just break the single block - no special action needed. e.g. Carrots, flowers, wheat. - */ - Normal, - /** - * Search for harvestable blocks adjacent to this block but leave this block. e.g. Pumpkin, melon - */ - Gourd, - /** - * Search for identical blocks above. - */ - Column, - /** - * Search for identical blocks above but leave the bottom one for the future. e.g. Cactus, sugarcane. - */ - LeaveBottom, - /** - * This block is the base of a tree and the harvester should enter tree-cutting mode. - */ - Tree, - /** - * This block is the base of the tree and the harvester should enter tree-cutting mode. - * The tree is searched for in the negative y axis instead. - */ - TreeFlipped, - /** - * This block is part of a tree as above. - */ - TreeLeaf, - /** - * This block is part of a tree as above, but fruits are cut before logs. e.g. cocoa - * The tree is not searched for. - */ - TreeFruit +public enum HarvestType { + /** + * Just break the single block - no special action needed. e.g. Carrots, flowers, wheat. + */ + Normal, + /** + * Search for harvestable blocks adjacent to this block but leave this block. e.g. Pumpkin, melon + */ + Gourd, + /** + * Search for identical blocks above. + */ + Column, + /** + * Search for identical blocks above but leave the bottom one for the future. e.g. Cactus, sugarcane. + */ + LeaveBottom, + /** + * This block is the base of a tree and the harvester should enter tree-cutting mode. + */ + Tree, + /** + * This block is the base of the tree and the harvester should enter tree-cutting mode. + * The tree is searched for in the negative y axis instead. + */ + TreeFlipped, + /** + * This block is part of a tree as above. + */ + TreeLeaf, + /** + * This block is part of a tree as above, but fruits are cut before logs. e.g. cocoa + * The tree is not searched for. + */ + TreeFruit } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/IDeepStorageUnit.java b/src/api/java/powercrystals/minefactoryreloaded/api/IDeepStorageUnit.java index ac718c2b..b0f24517 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/IDeepStorageUnit.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/IDeepStorageUnit.java @@ -2,28 +2,28 @@ import net.minecraft.item.ItemStack; -public interface IDeepStorageUnit -{ - /** - * @return A populated ItemStack with stackSize for the full amount of materials in the DSU. - * May have a stackSize > getMaxStackSize(). May have a stackSize of 0 (indicating locked contents). - */ - ItemStack getStoredItemType(); - - /** - * Sets the total amount of the item currently being stored, or zero if all items are to be removed. - */ - void setStoredItemCount(int amount); - - /** - * Sets the type of the stored item and initializes the number of stored items to amount. - * Will overwrite any existing stored items. - */ - void setStoredItemType(ItemStack type, int amount); - - /** - * @return The maximum number of items the DSU can hold. - * May change based on the current type stored. - */ - int getMaxStoredCount(); +public interface IDeepStorageUnit { + + /** + * @return A populated ItemStack with stackSize for the full amount of materials in the DSU. + * May have a stackSize > getMaxStackSize(). May have a stackSize of 0 (indicating locked contents). + */ + ItemStack getStoredItemType(); + + /** + * Sets the total amount of the item currently being stored, or zero if all items are to be removed. + */ + void setStoredItemCount(int amount); + + /** + * Sets the type of the stored item and initializes the number of stored items to amount. + * Will overwrite any existing stored items. + */ + void setStoredItemType(ItemStack type, int amount); + + /** + * @return The maximum number of items the DSU can hold. + * May change based on the current type stored. + */ + int getMaxStoredCount(); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryFertilizable.java b/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryFertilizable.java index a690df51..bbe52d0e 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryFertilizable.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryFertilizable.java @@ -8,34 +8,36 @@ /** * @author PowerCrystals * - * Defines a fertilizable block, and the process to fertilize it. You can assume that you will never have to check that block ID matches the one returned by - * getFertilizableBlockId(). + * Defines a fertilizable block, and the process to fertilize it. You can assume that you will never have to + * check that block ID matches the one returned by + * getFertilizableBlockId(). */ -public interface IFactoryFertilizable -{ - /** - * @return The block this instance is managing. - */ - public Block getPlant(); - - /** - * @param world The world this block belongs to. - * @param x The X coordinate of this block. - * @param y The Y coordinate of this block. - * @param z The Z coordinate of this block. - * @param fertilizerType The kind of fertilizer being used. - * @return True if the block at (x,y,z) can be fertilized with the given type of fertilizer. - */ - public boolean canFertilize(World world, int x, int y, int z, FertilizerType fertilizerType); - - /** - * @param world The world this block belongs to. - * @param rand A Random instance to use when fertilizing, if necessary. - * @param x The X coordinate of this block. - * @param y The Y coordinate of this block. - * @param z The Z coordinate of this block. - * @param fertilizerType The kind of fertilizer being used. - * @return True if fertilization was successful. If false, the Fertilizer will not consume a fertilizer item and will not drain power. - */ - public boolean fertilize(World world, Random rand, int x, int y, int z, FertilizerType fertilizerType); +public interface IFactoryFertilizable { + + /** + * @return The block this instance is managing. + */ + public Block getPlant(); + + /** + * @param world The world this block belongs to. + * @param x The X coordinate of this block. + * @param y The Y coordinate of this block. + * @param z The Z coordinate of this block. + * @param fertilizerType The kind of fertilizer being used. + * @return True if the block at (x,y,z) can be fertilized with the given type of fertilizer. + */ + public boolean canFertilize(World world, int x, int y, int z, FertilizerType fertilizerType); + + /** + * @param world The world this block belongs to. + * @param rand A Random instance to use when fertilizing, if necessary. + * @param x The X coordinate of this block. + * @param y The Y coordinate of this block. + * @param z The Z coordinate of this block. + * @param fertilizerType The kind of fertilizer being used. + * @return True if fertilization was successful. If false, the Fertilizer will not consume a fertilizer item and + * will not drain power. + */ + public boolean fertilize(World world, Random rand, int x, int y, int z, FertilizerType fertilizerType); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryFertilizer.java b/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryFertilizer.java index f230ccc4..7a53f750 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryFertilizer.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryFertilizer.java @@ -6,24 +6,25 @@ /** * @author PowerCrystals * - * Defines a fertilizer item for use in the Fertilizer. + * Defines a fertilizer item for use in the Fertilizer. */ -public interface IFactoryFertilizer -{ - /** - * @return The ID of this fertilizer item. - */ - Item getFertilizer(); - - /** - * @return The type of fertilizer this is. - */ - FertilizerType getFertilizerType(ItemStack stack); - - /** - * Called when a fertilization is successful. If you set the ItemStack size to 0, it will be deleted by the fertilizer. - * - * @param fertilizer The ItemStack used to fertilize. - */ - void consume(ItemStack fertilizer); +public interface IFactoryFertilizer { + + /** + * @return The ID of this fertilizer item. + */ + Item getFertilizer(); + + /** + * @return The type of fertilizer this is. + */ + FertilizerType getFertilizerType(ItemStack stack); + + /** + * Called when a fertilization is successful. If you set the ItemStack size to 0, it will be deleted by the + * fertilizer. + * + * @param fertilizer The ItemStack used to fertilize. + */ + void consume(ItemStack fertilizer); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryFruit.java b/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryFruit.java index 44c0d4bb..8f66f1eb 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryFruit.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryFruit.java @@ -13,63 +13,71 @@ * @author powercrystals * */ -public interface IFactoryFruit -{ - /** - * @return The block this fruit has in the world. - */ - public Block getPlant(); - - /** - * Used to determine if this fruit can be picked (is it ripe yet, etc) - * @param world The world where the fruit is being picked - * @param x The x-coordinate of the fruit - * @param y The y-coordinate of the fruit - * @param z The z-coordinate of the fruit - * @return True if the fruit can be picked - */ - public boolean canBePicked(World world, int x, int y, int z); - - /** - * @return Whether or not the Fruit Picker should break the block when harvesting. If false, no changes will be performed by the Fruit Picker itself. - */ - public boolean breakBlock(); - - /** - * Called by the Fruit Picker to determine what block to replace the picked block with. Only ID and meta/damage will be used. - * At the time this method is called, the fruit still exists. Do not pass an item ID as the return value. - * @param world The world where the fruit is being picked - * @param x The x-coordinate of the fruit - * @param y The y-coordinate of the fruit - * @param z The z-coordinate of the fruit - * @return The block to replace the fruit block with, or null for air. - */ - public ReplacementBlock getReplacementBlock(World world, int x, int y, int z); - - /** - * Called by the Fruit Picker before the fruit is picked. - * @param world The world where the fruit is being picked - * @param x The x-coordinate of the fruit - * @param y The y-coordinate of the fruit - * @param z The z-coordinate of the fruit - */ - public void prePick(World world, int x, int y, int z); - - /** - * Called by the Fruit Picker to determine what drops to generate. At the time this method is called, the fruit still exists. - * @param world The world where the fruit is being picked - * @param x The x-coordinate of the fruit - * @param y The y-coordinate of the fruit - * @param z The z-coordinate of the fruit - */ - public List getDrops(World world, Random rand, int x, int y, int z); - - /** - * Called by the Fruit Picker after the fruit is picked. - * @param world The world where the fruit is being picked - * @param x The x-coordinate of the fruit - * @param y The y-coordinate of the fruit - * @param z The z-coordinate of the fruit - */ - public void postPick(World world, int x, int y, int z); +public interface IFactoryFruit { + + /** + * @return The block this fruit has in the world. + */ + public Block getPlant(); + + /** + * Used to determine if this fruit can be picked (is it ripe yet, etc) + * + * @param world The world where the fruit is being picked + * @param x The x-coordinate of the fruit + * @param y The y-coordinate of the fruit + * @param z The z-coordinate of the fruit + * @return True if the fruit can be picked + */ + public boolean canBePicked(World world, int x, int y, int z); + + /** + * @return Whether or not the Fruit Picker should break the block when harvesting. If false, no changes will be + * performed by the Fruit Picker itself. + */ + public boolean breakBlock(); + + /** + * Called by the Fruit Picker to determine what block to replace the picked block with. Only ID and meta/damage will + * be used. + * At the time this method is called, the fruit still exists. Do not pass an item ID as the return value. + * + * @param world The world where the fruit is being picked + * @param x The x-coordinate of the fruit + * @param y The y-coordinate of the fruit + * @param z The z-coordinate of the fruit + * @return The block to replace the fruit block with, or null for air. + */ + public ReplacementBlock getReplacementBlock(World world, int x, int y, int z); + + /** + * Called by the Fruit Picker before the fruit is picked. + * + * @param world The world where the fruit is being picked + * @param x The x-coordinate of the fruit + * @param y The y-coordinate of the fruit + * @param z The z-coordinate of the fruit + */ + public void prePick(World world, int x, int y, int z); + + /** + * Called by the Fruit Picker to determine what drops to generate. At the time this method is called, the fruit + * still exists. + * + * @param world The world where the fruit is being picked + * @param x The x-coordinate of the fruit + * @param y The y-coordinate of the fruit + * @param z The z-coordinate of the fruit + */ + public List getDrops(World world, Random rand, int x, int y, int z); + + /** + * Called by the Fruit Picker after the fruit is picked. + * + * @param world The world where the fruit is being picked + * @param x The x-coordinate of the fruit + * @param y The y-coordinate of the fruit + * @param z The z-coordinate of the fruit + */ + public void postPick(World world, int x, int y, int z); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryGrindable.java b/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryGrindable.java index edfb8c99..6736a29a 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryGrindable.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryGrindable.java @@ -9,27 +9,28 @@ /** * @author PowerCrystals * - * Defines a grindable entity for the Grinder. + * Defines a grindable entity for the Grinder. */ -public interface IFactoryGrindable -{ - /** - * @return The class that this grindable instance is handling. This must be a subtype of EntityLivingBase or the entity will never - * be noticed by the Grinder. - */ - public Class getGrindableEntity(); +public interface IFactoryGrindable { - /** - * @param world The world this entity is in. - * @param entity The entity instance being ground. - * @param random A Random instance. - * @return The drops generated when this entity is killed. - */ - public List grind(World world, EntityLivingBase entity, Random random); + /** + * @return The class that this grindable instance is handling. This must be a subtype of EntityLivingBase or the + * entity will never + * be noticed by the Grinder. + */ + public Class getGrindableEntity(); - /** - * @param entity The entity instance being ground. - * @return Whether this entity has been fully processed or not. - */ - public boolean processEntity(EntityLivingBase entity); + /** + * @param world The world this entity is in. + * @param entity The entity instance being ground. + * @param random A Random instance. + * @return The drops generated when this entity is killed. + */ + public List grind(World world, EntityLivingBase entity, Random random); + + /** + * @param entity The entity instance being ground. + * @return Whether this entity has been fully processed or not. + */ + public boolean processEntity(EntityLivingBase entity); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryHarvestable.java b/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryHarvestable.java index d4e620a8..1f39feed 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryHarvestable.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryHarvestable.java @@ -11,61 +11,66 @@ /** * @author PowerCrystals * - * Defines a harvestable block for the Harvester. + * Defines a harvestable block for the Harvester. */ -public interface IFactoryHarvestable -{ - /** - * @return The block this harvestable instance is managing. - */ - public Block getPlant(); - - /** - * @return The type of harvest the Harvester should perform on this block. - */ - public HarvestType getHarvestType(); - - /** - * @return Whether or not the Harvester should break the block when harvesting. If false, no changes will be performed by the Harvester itself. - */ - public boolean breakBlock(); - - /** - * @param world The world this block is in. - * @param harvesterSettings The harvester's current settings. Do not modify these. - * @param x The X coordinate of the block being harvested. - * @param y The Y coordinate of the block being harvested. - * @param z The Z coordinate of the block being harvested. - * @return True if this block can be harvested. - */ - public boolean canBeHarvested(World world, Map harvesterSettings, int x, int y, int z); - - /** - * @param world The world this block is in. - * @param rand A Random instance to use when generating drops. - * @param harvesterSettings The harvester's current settings. Do not modify these. - * @param x The X coordinate of the block being harvested. - * @param y The Y coordinate of the block being harvested. - * @param z The Z coordinate of the block being harvested. - * @return The drops generated by breaking this block. For a default implementation, calling Block.getBlockDropped() is usually sufficient. - */ - public List getDrops(World world, Random rand, Map harvesterSettings, int x, int y, int z); - - /** - * Called before the block is going to be harvested. Usually empty. - * @param world The world this block is in. - * @param x The X coordinate of the block being harvested. - * @param y The Y coordinate of the block being harvested. - * @param z The Z coordinate of the block being harvested. - */ - public void preHarvest(World world, int x, int y, int z); - - /** - * Called after the block is going to be harvested. Used to re-till soil, for example. - * @param world The world this block is in. - * @param x The X coordinate of the block being harvested. - * @param y The Y coordinate of the block being harvested. - * @param z The Z coordinate of the block being harvested. - */ - public void postHarvest(World world, int x, int y, int z); +public interface IFactoryHarvestable { + + /** + * @return The block this harvestable instance is managing. + */ + public Block getPlant(); + + /** + * @return The type of harvest the Harvester should perform on this block. + */ + public HarvestType getHarvestType(); + + /** + * @return Whether or not the Harvester should break the block when harvesting. If false, no changes will be + * performed by the Harvester itself. + */ + public boolean breakBlock(); + + /** + * @param world The world this block is in. + * @param harvesterSettings The harvester's current settings. Do not modify these. + * @param x The X coordinate of the block being harvested. + * @param y The Y coordinate of the block being harvested. + * @param z The Z coordinate of the block being harvested. + * @return True if this block can be harvested. + */ + public boolean canBeHarvested(World world, Map harvesterSettings, int x, int y, int z); + + /** + * @param world The world this block is in. + * @param rand A Random instance to use when generating drops. + * @param harvesterSettings The harvester's current settings. Do not modify these. + * @param x The X coordinate of the block being harvested. + * @param y The Y coordinate of the block being harvested. + * @param z The Z coordinate of the block being harvested. + * @return The drops generated by breaking this block. For a default implementation, calling Block.getBlockDropped() + * is usually sufficient. + */ + public List getDrops(World world, Random rand, Map harvesterSettings, int x, int y, + int z); + + /** + * Called before the block is going to be harvested. Usually empty. + * + * @param world The world this block is in. + * @param x The X coordinate of the block being harvested. + * @param y The Y coordinate of the block being harvested. + * @param z The Z coordinate of the block being harvested. + */ + public void preHarvest(World world, int x, int y, int z); + + /** + * Called after the block is going to be harvested. Used to re-till soil, for example. + * + * @param world The world this block is in. + * @param x The X coordinate of the block being harvested. + * @param y The Y coordinate of the block being harvested. + * @param z The Z coordinate of the block being harvested. + */ + public void postHarvest(World world, int x, int y, int z); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryLaserTarget.java b/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryLaserTarget.java index 26ded7ab..990e36ab 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryLaserTarget.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryLaserTarget.java @@ -5,21 +5,21 @@ /** * @author skyboy * - * Defines a target for the Laser Drill Precharger + * Defines a target for the Laser Drill Precharger */ -public interface IFactoryLaserTarget -{ - /** - * @param from The direction the laser is coming from - * @return true if the precharger can form a beam from this side - */ - public boolean canFormBeamWith(ForgeDirection from); - - /** - * @param from The direction the energy is coming from - * @param energy The amount of energy being transferred - * @param simulate true if this transaction will only be simulated - * @return The amount of energy not consumed - */ - public int addEnergy(ForgeDirection from, int energy, boolean simulate); +public interface IFactoryLaserTarget { + + /** + * @param from The direction the laser is coming from + * @return true if the precharger can form a beam from this side + */ + public boolean canFormBeamWith(ForgeDirection from); + + /** + * @param from The direction the energy is coming from + * @param energy The amount of energy being transferred + * @param simulate true if this transaction will only be simulated + * @return The amount of energy not consumed + */ + public int addEnergy(ForgeDirection from, int energy, boolean simulate); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryPlantable.java b/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryPlantable.java index acec9ab3..e3759a89 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryPlantable.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryPlantable.java @@ -7,59 +7,61 @@ /** * @author PowerCrystals * - * Defines a plantable object for use in the Planter. + * Defines a plantable object for use in the Planter. */ -public interface IFactoryPlantable -{ - /** - * @return The item this plantable is managing. - */ - public Item getSeed(); +public interface IFactoryPlantable { - /** - * @param stack The stack being planted. - * @param forFermenting True if this stack will be converted to biofuel - * @return True if this plantable can be planted (useful for metadata items). - */ - public boolean canBePlanted(ItemStack stack, boolean forFermenting); - - /** - * @param world The world instance this block or item will be placed into. - * @param x The destination X coordinate. - * @param y The destination Y coordinate. - * @param z The destination Z coordinate. - * @param stack The stack being planted. - * @return The block that will be placed into the world. - */ - public ReplacementBlock getPlantedBlock(World world, int x, int y, int z, ItemStack stack); - - /** - * @param world The world instance this block or item will be placed into. - * @param x The destination X coordinate. - * @param y The destination Y coordinate. - * @param z The destination Z coordinate. - * @param stack The stack being planted. - * @return True if this plantable can be placed at the provided coordinates. - */ - public boolean canBePlantedHere(World world, int x, int y, int z, ItemStack stack); - - /** - * Called before planting is performed. Used to till soil, for example. - * @param world The world instance this block or item will be placed into. - * @param x The destination X coordinate. - * @param y The destination Y coordinate. - * @param z The destination Z coordinate. - * @param stack The stack being planted. - */ - public void prePlant(World world, int x, int y, int z, ItemStack stack); - - /** - * Called after planting is performed. Usually empty. - * @param world The world instance this block or item will be placed into. - * @param x The destination X coordinate. - * @param y The destination Y coordinate. - * @param z The destination Z coordinate. - * @param stack The stack being planted. - */ - public void postPlant(World world, int x, int y, int z, ItemStack stack); + /** + * @return The item this plantable is managing. + */ + public Item getSeed(); + + /** + * @param stack The stack being planted. + * @param forFermenting True if this stack will be converted to biofuel + * @return True if this plantable can be planted (useful for metadata items). + */ + public boolean canBePlanted(ItemStack stack, boolean forFermenting); + + /** + * @param world The world instance this block or item will be placed into. + * @param x The destination X coordinate. + * @param y The destination Y coordinate. + * @param z The destination Z coordinate. + * @param stack The stack being planted. + * @return The block that will be placed into the world. + */ + public ReplacementBlock getPlantedBlock(World world, int x, int y, int z, ItemStack stack); + + /** + * @param world The world instance this block or item will be placed into. + * @param x The destination X coordinate. + * @param y The destination Y coordinate. + * @param z The destination Z coordinate. + * @param stack The stack being planted. + * @return True if this plantable can be placed at the provided coordinates. + */ + public boolean canBePlantedHere(World world, int x, int y, int z, ItemStack stack); + + /** + * Called before planting is performed. Used to till soil, for example. + * + * @param world The world instance this block or item will be placed into. + * @param x The destination X coordinate. + * @param y The destination Y coordinate. + * @param z The destination Z coordinate. + * @param stack The stack being planted. + */ + public void prePlant(World world, int x, int y, int z, ItemStack stack); + + /** + * Called after planting is performed. Usually empty. + * + * @param world The world instance this block or item will be placed into. + * @param x The destination X coordinate. + * @param y The destination Y coordinate. + * @param z The destination Z coordinate. + * @param stack The stack being planted. + */ + public void postPlant(World world, int x, int y, int z, ItemStack stack); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryRanchable.java b/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryRanchable.java index 27c173fa..c486033a 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryRanchable.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/IFactoryRanchable.java @@ -9,20 +9,21 @@ /** * @author PowerCrystals * - * Defines a ranchable entity for use in the Rancher. + * Defines a ranchable entity for use in the Rancher. */ -public interface IFactoryRanchable -{ - /** - * @return The entity being ranched. Must be a subtype of EntityLivingBase. - */ - public Class getRanchableEntity(); - - /** - * @param world The world this entity is in. - * @param entity The entity instance being ranched. - * @param rancher The rancher instance doing the ranching. Used to access the Rancher's inventory when milking cows, for example. - * @return A list of drops. - */ - public List ranch(World world, EntityLivingBase entity, IInventory rancher); +public interface IFactoryRanchable { + + /** + * @return The entity being ranched. Must be a subtype of EntityLivingBase. + */ + public Class getRanchableEntity(); + + /** + * @param world The world this entity is in. + * @param entity The entity instance being ranched. + * @param rancher The rancher instance doing the ranching. Used to access the Rancher's inventory when milking cows, + * for example. + * @return A list of drops. + */ + public List ranch(World world, EntityLivingBase entity, IInventory rancher); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/ILiquidDrinkHandler.java b/src/api/java/powercrystals/minefactoryreloaded/api/ILiquidDrinkHandler.java index 31eba004..63c838a2 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/ILiquidDrinkHandler.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/ILiquidDrinkHandler.java @@ -2,7 +2,7 @@ import net.minecraft.entity.EntityLivingBase; -public interface ILiquidDrinkHandler -{ - public void onDrink(EntityLivingBase player); +public interface ILiquidDrinkHandler { + + public void onDrink(EntityLivingBase player); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/IMFRHammer.java b/src/api/java/powercrystals/minefactoryreloaded/api/IMFRHammer.java index 00fcbe9c..76b45f38 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/IMFRHammer.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/IMFRHammer.java @@ -2,8 +2,8 @@ /** * @author PowerCrystals - * Defines a tool that can rotate MFR machines. Implement on an Item class. Requires no additional work on your part. + * Defines a tool that can rotate MFR machines. Implement on an Item class. Requires no additional work on your + * part. */ -public interface IMFRHammer -{ +public interface IMFRHammer { } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/IMobEggHandler.java b/src/api/java/powercrystals/minefactoryreloaded/api/IMobEggHandler.java index 01693a73..92f8deb4 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/IMobEggHandler.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/IMobEggHandler.java @@ -6,13 +6,14 @@ /** * @author PowerCrystals * - * Defines a class that MFR will use to local egg info for a given mob. This is used to color the Safari Net based on the captured mob. + * Defines a class that MFR will use to local egg info for a given mob. This is used to color the Safari Net + * based on the captured mob. */ -public interface IMobEggHandler -{ - /** - * @param safariNet The Safari Net that is looking for egg info. - * @return An EntityEggInfo, or null if this instance cannot handle this mob. - */ - public EntityEggInfo getEgg(ItemStack safariNet); +public interface IMobEggHandler { + + /** + * @param safariNet The Safari Net that is looking for egg info. + * @return An EntityEggInfo, or null if this instance cannot handle this mob. + */ + public EntityEggInfo getEgg(ItemStack safariNet); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/IMobSpawnHandler.java b/src/api/java/powercrystals/minefactoryreloaded/api/IMobSpawnHandler.java index 46e295ea..92cf19f0 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/IMobSpawnHandler.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/IMobSpawnHandler.java @@ -5,23 +5,23 @@ /** * @author skyboy * - * Defines a handler for mob spawns from the autospawner. - * Added primarily to solve item duping on exact spawn & entity inventories + * Defines a handler for mob spawns from the autospawner. + * Added primarily to solve item duping on exact spawn & entity inventories */ -public interface IMobSpawnHandler -{ - /** - * @return The class that this instance is handling. - */ - public Class getMobClass(); - - /** - * @param entity The entity instance being spawned. Typically your regular spawn code 100% handles this - */ - public void onMobSpawn(EntityLivingBase entity); +public interface IMobSpawnHandler { - /** - * @param entity The entity instance being exact-copied. Clear your inventories & etc. here - */ - public void onMobExactSpawn(EntityLivingBase entity); + /** + * @return The class that this instance is handling. + */ + public Class getMobClass(); + + /** + * @param entity The entity instance being spawned. Typically your regular spawn code 100% handles this + */ + public void onMobSpawn(EntityLivingBase entity); + + /** + * @param entity The entity instance being exact-copied. Clear your inventories & etc. here + */ + public void onMobExactSpawn(EntityLivingBase entity); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/INeedleAmmo.java b/src/api/java/powercrystals/minefactoryreloaded/api/INeedleAmmo.java index 74dae7e8..fec69b91 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/INeedleAmmo.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/INeedleAmmo.java @@ -5,9 +5,12 @@ import net.minecraft.item.ItemStack; import net.minecraft.world.World; -public interface INeedleAmmo -{ - public boolean onHitEntity(ItemStack stac, EntityPlayer owner, Entity hit, double distance); - public void onHitBlock(ItemStack stac, EntityPlayer owner, World world, int x, int y, int z, int side, double distance); - public float getSpread(ItemStack stack); +public interface INeedleAmmo { + + public boolean onHitEntity(ItemStack stac, EntityPlayer owner, Entity hit, double distance); + + public void onHitBlock(ItemStack stac, EntityPlayer owner, World world, int x, int y, int z, int side, + double distance); + + public float getSpread(ItemStack stack); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/IRandomMobProvider.java b/src/api/java/powercrystals/minefactoryreloaded/api/IRandomMobProvider.java index b03d6f08..6052640f 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/IRandomMobProvider.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/IRandomMobProvider.java @@ -4,8 +4,7 @@ import net.minecraft.world.World; +public interface IRandomMobProvider { -public interface IRandomMobProvider -{ - public List getRandomMobs(World world); -} \ No newline at end of file + public List getRandomMobs(World world); +} diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/ISafariNetHandler.java b/src/api/java/powercrystals/minefactoryreloaded/api/ISafariNetHandler.java index 2a4457bb..7ff18a6b 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/ISafariNetHandler.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/ISafariNetHandler.java @@ -8,20 +8,21 @@ /** * @author PowerCrystals * - * Defines an object that can display information about a captured mob in a Safari net. + * Defines an object that can display information about a captured mob in a Safari net. */ -public interface ISafariNetHandler -{ - /** - * @return The class of mob that this handler applies to. - */ - public Class validFor(); - - /** - * @param safariNetStack The Safari Net that is requesting information. - * @param player The player holding the Safari Net. - * @param infoList The current list of information strings. Add yours to this. - * @param advancedTooltips True if the advanced tooltips option is on. - */ - public void addInformation(ItemStack safariNetStack, EntityPlayer player, List infoList, boolean advancedTooltips); +public interface ISafariNetHandler { + + /** + * @return The class of mob that this handler applies to. + */ + public Class validFor(); + + /** + * @param safariNetStack The Safari Net that is requesting information. + * @param player The player holding the Safari Net. + * @param infoList The current list of information strings. Add yours to this. + * @param advancedTooltips True if the advanced tooltips option is on. + */ + public void addInformation(ItemStack safariNetStack, EntityPlayer player, List infoList, + boolean advancedTooltips); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/ISyringe.java b/src/api/java/powercrystals/minefactoryreloaded/api/ISyringe.java index 5e876e80..275def05 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/ISyringe.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/ISyringe.java @@ -7,40 +7,44 @@ /** * @author PowerCrystals * - * Defines a syringe for use in the Vet machine. + * Defines a syringe for use in the Vet machine. */ -public interface ISyringe -{ - /** - * Called when the vet is deciding if it should use this syringe. - * @param world The world instance. - * @param entity The entity being injected. - * @param syringe The syringe ItemStack. - * @return True if the entity can be injected by this syringe. - */ - public boolean canInject(World world, EntityLivingBase entity, ItemStack syringe); - - /** - * Called to perform an injection. - * @param world The world instance. - * @param entity The entity being injected. - * @param syringe The syringe ItemStack. - * @return True if injection was successful. - */ - public boolean inject(World world, EntityLivingBase entity, ItemStack syringe); - - /** - * Called to check if a syringe is empty - * @param syringe The syringe ItemStack. - * @return True if the syringe is empty - */ - public boolean isEmpty(ItemStack syringe); - - /** - * Called to get the empty syringe - * Note: this will replace the syringe, max stacksize should be 1 - * @param syringe The syringe ItemStack. - * @return An empty syringe ItemStack - */ - public ItemStack getEmptySyringe(ItemStack syringe); +public interface ISyringe { + + /** + * Called when the vet is deciding if it should use this syringe. + * + * @param world The world instance. + * @param entity The entity being injected. + * @param syringe The syringe ItemStack. + * @return True if the entity can be injected by this syringe. + */ + public boolean canInject(World world, EntityLivingBase entity, ItemStack syringe); + + /** + * Called to perform an injection. + * + * @param world The world instance. + * @param entity The entity being injected. + * @param syringe The syringe ItemStack. + * @return True if injection was successful. + */ + public boolean inject(World world, EntityLivingBase entity, ItemStack syringe); + + /** + * Called to check if a syringe is empty + * + * @param syringe The syringe ItemStack. + * @return True if the syringe is empty + */ + public boolean isEmpty(ItemStack syringe); + + /** + * Called to get the empty syringe + * Note: this will replace the syringe, max stacksize should be 1 + * + * @param syringe The syringe ItemStack. + * @return An empty syringe ItemStack + */ + public ItemStack getEmptySyringe(ItemStack syringe); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/MobDrop.java b/src/api/java/powercrystals/minefactoryreloaded/api/MobDrop.java index 7f5dd7cc..c2d0a965 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/MobDrop.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/MobDrop.java @@ -3,19 +3,17 @@ import net.minecraft.item.ItemStack; import net.minecraft.util.WeightedRandom; -public class MobDrop extends WeightedRandom.Item -{ - private ItemStack _stack; - - public MobDrop(int weight, ItemStack stack) - { - super(weight); - _stack = stack; - } - - public ItemStack getStack() - { - if(_stack == null) return null; - return _stack.copy(); - } +public class MobDrop extends WeightedRandom.Item { + + private ItemStack _stack; + + public MobDrop(int weight, ItemStack stack) { + super(weight); + _stack = stack; + } + + public ItemStack getStack() { + if (_stack == null) return null; + return _stack.copy(); + } } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/RanchedItem.java b/src/api/java/powercrystals/minefactoryreloaded/api/RanchedItem.java index 86791cc5..faa29b99 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/RanchedItem.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/RanchedItem.java @@ -8,61 +8,52 @@ /** * @author skyboy026 * - * Defines an ItemStack or a FluidStack that is the result of an entity being ranched + * Defines an ItemStack or a FluidStack that is the result of an entity being ranched */ public final class RanchedItem { - private final ItemStack item; - private final FluidStack fluid; - - public RanchedItem(Block item, int amount, int meta) - { - this(new ItemStack(item, amount, meta)); - } - - public RanchedItem(Block item, int amount) - { - this(new ItemStack(item, amount)); - } - public RanchedItem(Block item) - { - this(new ItemStack(item)); - } - - public RanchedItem(Item item, int amount, int meta) - { - this(new ItemStack(item, amount, meta)); - } - - public RanchedItem(Item item, int amount) - { - this(new ItemStack(item, amount)); - } - - public RanchedItem(Item item) - { - this(new ItemStack(item)); - } - - public RanchedItem(ItemStack item) - { - this.item = item; - fluid = null; - } - - public RanchedItem(FluidStack fluid) - { - this.fluid = fluid; - item = null; - } - - public boolean hasFluid() - { - return item == null & fluid != null; - } - - public Object getResult() - { - return item == null ? fluid : item; - } + private final ItemStack item; + private final FluidStack fluid; + + public RanchedItem(Block item, int amount, int meta) { + this(new ItemStack(item, amount, meta)); + } + + public RanchedItem(Block item, int amount) { + this(new ItemStack(item, amount)); + } + + public RanchedItem(Block item) { + this(new ItemStack(item)); + } + + public RanchedItem(Item item, int amount, int meta) { + this(new ItemStack(item, amount, meta)); + } + + public RanchedItem(Item item, int amount) { + this(new ItemStack(item, amount)); + } + + public RanchedItem(Item item) { + this(new ItemStack(item)); + } + + public RanchedItem(ItemStack item) { + this.item = item; + fluid = null; + } + + public RanchedItem(FluidStack fluid) { + this.fluid = fluid; + item = null; + } + + public boolean hasFluid() { + return item == null & fluid != null; + } + + public Object getResult() { + return item == null ? fluid : item; + } } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/RandomMob.java b/src/api/java/powercrystals/minefactoryreloaded/api/RandomMob.java index 2ffa56b1..76c8a36f 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/RandomMob.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/RandomMob.java @@ -3,26 +3,23 @@ import net.minecraft.entity.Entity; import net.minecraft.util.WeightedRandom; -public class RandomMob extends WeightedRandom.Item -{ - private Entity _mob; - public final boolean shouldInit; - - public RandomMob(Entity savedMob, int weight, boolean init) - { - super(weight); - _mob = savedMob; - shouldInit = init; - } - - public RandomMob(Entity savedMob, int weight) - { - this(savedMob, weight, true); - } - - public Entity getMob() - { - if(_mob == null) return null; - return _mob; - } +public class RandomMob extends WeightedRandom.Item { + + private Entity _mob; + public final boolean shouldInit; + + public RandomMob(Entity savedMob, int weight, boolean init) { + super(weight); + _mob = savedMob; + shouldInit = init; + } + + public RandomMob(Entity savedMob, int weight) { + this(savedMob, weight, true); + } + + public Entity getMob() { + if (_mob == null) return null; + return _mob; + } } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/ReplacementBlock.java b/src/api/java/powercrystals/minefactoryreloaded/api/ReplacementBlock.java index 88cd7a86..f56a90e2 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/ReplacementBlock.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/ReplacementBlock.java @@ -8,130 +8,119 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; -public class ReplacementBlock -{ - protected byte _hasMeta; - protected int _meta; - protected final Block _block; - protected final NBTTagCompound _tileTag; - - /** - * Called to replace a block in the world. - * @param world The world object - * @param x The X coord - * @param y The Y coord - * @param z The Z coord - * @param stack The ItemStack being used to replace the block (may be null) - * @return True if the block was set successfully - */ - public boolean replaceBlock(World world, int x, int y, int z, ItemStack stack) - { - int meta = getMeta(world, x, y, z, stack); - if (world.setBlock(x, y, z, _block, meta, 3)) - { - if (hasTag(stack) && _block.hasTileEntity(meta)) - { - TileEntity tile = world.getTileEntity(x, y, z); - if (tile != null) - tile.readFromNBT(getTag(world, x, y, z, stack)); - } - return true; - } - return false; - } +public class ReplacementBlock { - /** - * Called to get the metadata of the replacement block in the world. - * @param world The world object - * @param x The X coord - * @param y The Y coord - * @param z The Z coord - * @param stack The ItemStack being used to replace the block (may be null) - * @return The metadata of the block - */ - protected int getMeta(World world, int x, int y, int z, ItemStack stack) - { - int m = 0; - if (_hasMeta > 0) - { - if (_hasMeta > 1) - return _meta; - m = stack.getItemDamage(); - Item item = stack.getItem(); - if (item instanceof ItemBlock) - m = ((ItemBlock)item).getMetadata(m); - } - return m; - } - - /** - * Called to set the metdata of this ReplacementBlock to a fixed value - * @param meta The metadata of the block - * @return This instance - */ - public ReplacementBlock setMeta(int meta) - { - if (meta >= 0) - { - _hasMeta = 2; - _meta = meta; - } - return this; - } - - /** - * Called to set the metdata of this ReplacementBlock to a value read from an ItemStack - * @param meta The metadata of the block - * @return This instance - */ - public ReplacementBlock setMeta(boolean hasMeta) - { - _hasMeta = (byte) (hasMeta ? 1 : 0); - return this; - } - - /** - * Called to get the NBTTagCompound a TileEntity will read its state from - * @param world The world object - * @param x The X coord - * @param y The Y coord - * @param z The Z coord - * @param stack The ItemStack being used to replace the block (may be null) - * @return The NBTTagCompound a TileEntity will read its state from - */ - protected NBTTagCompound getTag(World world, int x, int y, int z, ItemStack stack) - { - return _tileTag; - } - - /** - * Called to see if a TileEntity should have its state set - * @param stack The ItemStack being used to replace the block (may be null) - * @return True if the TileEntity should have its state set - */ - protected boolean hasTag(ItemStack stack) - { - return _tileTag != null; - } - - public ReplacementBlock(Item block) - { - this(Block.getBlockFromItem(block)); - } - - public ReplacementBlock(Item block, NBTTagCompound tag) - { - this(Block.getBlockFromItem(block), tag); - } - - public ReplacementBlock(Block block) - { - this(block, null); - } - - public ReplacementBlock(Block block, NBTTagCompound tag) - { - _block = block; - _tileTag = tag; - } + protected byte _hasMeta; + protected int _meta; + protected final Block _block; + protected final NBTTagCompound _tileTag; + + /** + * Called to replace a block in the world. + * + * @param world The world object + * @param x The X coord + * @param y The Y coord + * @param z The Z coord + * @param stack The ItemStack being used to replace the block (may be null) + * @return True if the block was set successfully + */ + public boolean replaceBlock(World world, int x, int y, int z, ItemStack stack) { + int meta = getMeta(world, x, y, z, stack); + if (world.setBlock(x, y, z, _block, meta, 3)) { + if (hasTag(stack) && _block.hasTileEntity(meta)) { + TileEntity tile = world.getTileEntity(x, y, z); + if (tile != null) tile.readFromNBT(getTag(world, x, y, z, stack)); + } + return true; + } + return false; + } + + /** + * Called to get the metadata of the replacement block in the world. + * + * @param world The world object + * @param x The X coord + * @param y The Y coord + * @param z The Z coord + * @param stack The ItemStack being used to replace the block (may be null) + * @return The metadata of the block + */ + protected int getMeta(World world, int x, int y, int z, ItemStack stack) { + int m = 0; + if (_hasMeta > 0) { + if (_hasMeta > 1) return _meta; + m = stack.getItemDamage(); + Item item = stack.getItem(); + if (item instanceof ItemBlock) m = ((ItemBlock) item).getMetadata(m); + } + return m; + } + + /** + * Called to set the metdata of this ReplacementBlock to a fixed value + * + * @param meta The metadata of the block + * @return This instance + */ + public ReplacementBlock setMeta(int meta) { + if (meta >= 0) { + _hasMeta = 2; + _meta = meta; + } + return this; + } + + /** + * Called to set the metdata of this ReplacementBlock to a value read from an ItemStack + * + * @param meta The metadata of the block + * @return This instance + */ + public ReplacementBlock setMeta(boolean hasMeta) { + _hasMeta = (byte) (hasMeta ? 1 : 0); + return this; + } + + /** + * Called to get the NBTTagCompound a TileEntity will read its state from + * + * @param world The world object + * @param x The X coord + * @param y The Y coord + * @param z The Z coord + * @param stack The ItemStack being used to replace the block (may be null) + * @return The NBTTagCompound a TileEntity will read its state from + */ + protected NBTTagCompound getTag(World world, int x, int y, int z, ItemStack stack) { + return _tileTag; + } + + /** + * Called to see if a TileEntity should have its state set + * + * @param stack The ItemStack being used to replace the block (may be null) + * @return True if the TileEntity should have its state set + */ + protected boolean hasTag(ItemStack stack) { + return _tileTag != null; + } + + public ReplacementBlock(Item block) { + this(Block.getBlockFromItem(block)); + } + + public ReplacementBlock(Item block, NBTTagCompound tag) { + this(Block.getBlockFromItem(block), tag); + } + + public ReplacementBlock(Block block) { + this(block, null); + } + + public ReplacementBlock(Block block, NBTTagCompound tag) { + _block = block; + _tileTag = tag; + } } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/ValuedItem.java b/src/api/java/powercrystals/minefactoryreloaded/api/ValuedItem.java index 3d075fa3..7efc7dd9 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/ValuedItem.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/ValuedItem.java @@ -2,71 +2,64 @@ import net.minecraft.item.ItemStack; -public class ValuedItem -{ - public final int value; - public final ItemStack item; - public final String key; - public final Object object; - - public ValuedItem(int v, ItemStack i) - { - value = v; - item = i; - key = null; - object = null; - } - - public ValuedItem(String v, Object i) - { - value = -1; - item = null; - key = v; - object = i; - } - - /** - * Presently unused but included so that if they do get used in the future, - * people including this in their jar and loading before MFR don't destroy everyone - */ - - public ValuedItem(int v, Object i) - { - value = v; - item = null; - key = null; - object = i; - } - - public ValuedItem(String v, ItemStack i) - { - value = -1; - item = i; - key = v; - object = null; - } - - public ValuedItem(int v, String k, ItemStack i) - { - value = v; - item = i; - key = k; - object = null; - } - - public ValuedItem(int v, String k, Object i) - { - value = v; - item = null; - key = k; - object = i; - } - - public ValuedItem(int v, String k, ItemStack i, Object o) - { - value = v; - item = i; - key = k; - object = o; - } +public class ValuedItem { + + public final int value; + public final ItemStack item; + public final String key; + public final Object object; + + public ValuedItem(int v, ItemStack i) { + value = v; + item = i; + key = null; + object = null; + } + + public ValuedItem(String v, Object i) { + value = -1; + item = null; + key = v; + object = i; + } + + /** + * Presently unused but included so that if they do get used in the future, + * people including this in their jar and loading before MFR don't destroy everyone + */ + + public ValuedItem(int v, Object i) { + value = v; + item = null; + key = null; + object = i; + } + + public ValuedItem(String v, ItemStack i) { + value = -1; + item = i; + key = v; + object = null; + } + + public ValuedItem(int v, String k, ItemStack i) { + value = v; + item = i; + key = k; + object = null; + } + + public ValuedItem(int v, String k, Object i) { + value = v; + item = null; + key = k; + object = i; + } + + public ValuedItem(int v, String k, ItemStack i, Object o) { + value = v; + item = i; + key = k; + object = o; + } } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetInfo.java b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetInfo.java index 0fc75c78..f2ac297d 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetInfo.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetInfo.java @@ -8,21 +8,22 @@ import net.minecraftforge.common.util.ForgeDirection; /** - * Defines a Block that can print information about itself using the RedNet Meter. This must be implemented on your Block class. + * Defines a Block that can print information about itself using the RedNet Meter. This must be implemented on your + * Block class. */ -public interface IRedNetInfo -{ - /** - * This function appends information to a list provided to it. - * - * @param world Reference to the world. - * @param x X coordinate of the block. - * @param y Y coordinate of the block. - * @param z Z coordinate of the block. - * @param side The side of the block that is being queried. - * @param player Player doing the querying - this can be NULL. - * @param info The list that the information should be appended to. - */ - public void getRedNetInfo(IBlockAccess world, int x, int y, int z, - ForgeDirection side, EntityPlayer player, List info); +public interface IRedNetInfo { + + /** + * This function appends information to a list provided to it. + * + * @param world Reference to the world. + * @param x X coordinate of the block. + * @param y Y coordinate of the block. + * @param z Z coordinate of the block. + * @param side The side of the block that is being queried. + * @param player Player doing the querying - this can be NULL. + * @param info The list that the information should be appended to. + */ + public void getRedNetInfo(IBlockAccess world, int x, int y, int z, ForgeDirection side, EntityPlayer player, + List info); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetInputNode.java b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetInputNode.java index a814af3c..16f3bee1 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetInputNode.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetInputNode.java @@ -1,10 +1,10 @@ package powercrystals.minefactoryreloaded.api.rednet; -import powercrystals.minefactoryreloaded.api.rednet.connectivity.IRedNetConnection; - import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; +import powercrystals.minefactoryreloaded.api.rednet.connectivity.IRedNetConnection; + /** * Defines a Block that can connect to RedNet cables. This must be implemented on your Block class. *

@@ -20,33 +20,33 @@ * 0:White, 1:Orange, 2:Magenta, 3:LightBlue, 4:Yellow, 5:Lime, 6:Pink, 7:Gray, * 8:LightGray, 9:Cyan, 10:Purple, 11:Blue, 12:Brown, 13:Green, 14:Red, 15:Black */ -public interface IRedNetInputNode extends IRedNetConnection -{ - /** - * Called when the input values to this block change. Only called if your block is connected in "All" mode. - * Do not issue a network value update from inside this method call; it will be ignored. Issue your updates - * on the next tick. - * - * @param world The world this block is in. - * @param x This block's X coordinate. - * @param y This block's Y coordinate. - * @param z This block's Z coordinate. - * @param side The side the input values are being changed on. - * @param inputValues The new set of input values. This array will be 16 elements long. Do not alter or cache. - */ - public void onInputsChanged(World world, int x, int y, int z, ForgeDirection side, int[] inputValues); +public interface IRedNetInputNode extends IRedNetConnection { + + /** + * Called when the input values to this block change. Only called if your block is connected in "All" mode. + * Do not issue a network value update from inside this method call; it will be ignored. Issue your updates + * on the next tick. + * + * @param world The world this block is in. + * @param x This block's X coordinate. + * @param y This block's Y coordinate. + * @param z This block's Z coordinate. + * @param side The side the input values are being changed on. + * @param inputValues The new set of input values. This array will be 16 elements long. Do not alter or cache. + */ + public void onInputsChanged(World world, int x, int y, int z, ForgeDirection side, int[] inputValues); - /** - * Called when the input value to this block changes. Only called if your block is connected in "Single" mode. - * Do not issue a network value update from inside this method call; it will be ignored. Issue your updates - * on the next tick. - * - * @param world The world this block is in. - * @param x This block's X coordinate. - * @param y This block's Y coordinate. - * @param z This block's Z coordinate. - * @param side The side the input values are being changed on. - * @param inputValue The new input value - */ - public void onInputChanged(World world, int x, int y, int z, ForgeDirection side, int inputValue); + /** + * Called when the input value to this block changes. Only called if your block is connected in "Single" mode. + * Do not issue a network value update from inside this method call; it will be ignored. Issue your updates + * on the next tick. + * + * @param world The world this block is in. + * @param x This block's X coordinate. + * @param y This block's Y coordinate. + * @param z This block's Z coordinate. + * @param side The side the input values are being changed on. + * @param inputValue The new input value + */ + public void onInputChanged(World world, int x, int y, int z, ForgeDirection side, int inputValue); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetLogicCircuit.java b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetLogicCircuit.java index 981ce06b..6c60ddf3 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetLogicCircuit.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetLogicCircuit.java @@ -2,18 +2,21 @@ import net.minecraft.nbt.NBTTagCompound; -public interface IRedNetLogicCircuit -{ - public byte getInputCount(); - - public byte getOutputCount(); - - public int[] recalculateOutputValues(long worldTime, int[] inputValues); - - public String getUnlocalizedName(); - public String getInputPinLabel(int pin); - public String getOutputPinLabel(int pin); - - public void readFromNBT(NBTTagCompound tag); - public void writeToNBT(NBTTagCompound tag); +public interface IRedNetLogicCircuit { + + public byte getInputCount(); + + public byte getOutputCount(); + + public int[] recalculateOutputValues(long worldTime, int[] inputValues); + + public String getUnlocalizedName(); + + public String getInputPinLabel(int pin); + + public String getOutputPinLabel(int pin); + + public void readFromNBT(NBTTagCompound tag); + + public void writeToNBT(NBTTagCompound tag); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetLogicPoint.java b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetLogicPoint.java index dd05969e..d7ee9a14 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetLogicPoint.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetLogicPoint.java @@ -4,33 +4,33 @@ * * @author skyboy */ -public interface IRedNetLogicPoint -{ - /** - * - * @param out - * @return - */ - public void transformOutput(int[] out); +public interface IRedNetLogicPoint { - /** - * - * @param out - * @return - */ - public void transformOutput(int out); + /** + * + * @param out + * @return + */ + public void transformOutput(int[] out); - /** - * - * @param in - * @return - */ - public int[] transformInput(int[] in); + /** + * + * @param out + * @return + */ + public void transformOutput(int out); - /** - * - * @param in - * @return - */ - public int transformInput(int in); + /** + * + * @param in + * @return + */ + public int[] transformInput(int[] in); + + /** + * + * @param in + * @return + */ + public int transformInput(int in); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetNetworkContainer.java b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetNetworkContainer.java index c9fb0bf8..6f87f628 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetNetworkContainer.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetNetworkContainer.java @@ -5,28 +5,31 @@ /** * - * You should not implement this yourself. Instead, use this to look for cables to notify from your IRedNetOmniNode as this does not + * You should not implement this yourself. Instead, use this to look for cables to notify from your IRedNetOmniNode as + * this does not * require a block update. This will be implemented on the cable's Block class. * */ -public interface IRedNetNetworkContainer -{ - /** - * Tells the network to recalculate all subnets. - * @param world The world this cable is in. - * @param x The x-coordinate of this cable. - * @param x The y-coordinate of this cable. - * @param x The z-coordinate of this cable. - */ - public void updateNetwork(World world, int x, int y, int z, ForgeDirection from); - - /** - * Tells the network to recalculate a specific subnet. - * @param world The world this cable is in. - * @param x The x-coordinate of this cable. - * @param x The y-coordinate of this cable. - * @param x The z-coordinate of this cable. - * @param subnet The subnet to recalculate. - */ - public void updateNetwork(World world, int x, int y, int z, int subnet, ForgeDirection from); +public interface IRedNetNetworkContainer { + + /** + * Tells the network to recalculate all subnets. + * + * @param world The world this cable is in. + * @param x The x-coordinate of this cable. + * @param x The y-coordinate of this cable. + * @param x The z-coordinate of this cable. + */ + public void updateNetwork(World world, int x, int y, int z, ForgeDirection from); + + /** + * Tells the network to recalculate a specific subnet. + * + * @param world The world this cable is in. + * @param x The x-coordinate of this cable. + * @param x The y-coordinate of this cable. + * @param x The z-coordinate of this cable. + * @param subnet The subnet to recalculate. + */ + public void updateNetwork(World world, int x, int y, int z, int subnet, ForgeDirection from); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetOmniNode.java b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetOmniNode.java index f2bdf397..2577d0d0 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetOmniNode.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetOmniNode.java @@ -16,7 +16,6 @@ * 0:White, 1:Orange, 2:Magenta, 3:LightBlue, 4:Yellow, 5:Lime, 6:Pink, 7:Gray, * 8:LightGray, 9:Cyan, 10:Purple, 11:Blue, 12:Brown, 13:Green, 14:Red, 15:Black */ -public interface IRedNetOmniNode extends IRedNetInputNode, IRedNetOutputNode -{ - // this is merely provided for convenience +public interface IRedNetOmniNode extends IRedNetInputNode, IRedNetOutputNode { + // this is merely provided for convenience } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetOutputNode.java b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetOutputNode.java index 34281875..c38d0ce8 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetOutputNode.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/IRedNetOutputNode.java @@ -19,33 +19,33 @@ * 0:White, 1:Orange, 2:Magenta, 3:LightBlue, 4:Yellow, 5:Lime, 6:Pink, 7:Gray, * 8:LightGray, 9:Cyan, 10:Purple, 11:Blue, 12:Brown, 13:Green, 14:Red, 15:Black */ -public interface IRedNetOutputNode extends IRedNetConnection -{ - /** - * Returns the output values of this RedNet node. - * This array must be 16 elements long. - * Only called if your block is connected in "All" mode. - * - * @param world The world this block is in. - * @param x This block's X coordinate. - * @param y This block's Y coordinate. - * @param z This block's Z coordinate. - * @param side The side the output values are required for. - * @return The output values. - */ - public int[] getOutputValues(World world, int x, int y, int z, ForgeDirection side); +public interface IRedNetOutputNode extends IRedNetConnection { - /** - * Returns the output value of this RedNet node for a given subnet. - * Must be the same as getOutputValues(world, x, y, z, side)[subnet]. - * - * @param world The world this block is in. - * @param x This block's X coordinate. - * @param y This block's Y coordinate. - * @param z This block's Z coordinate. - * @param side The side the output value is required for. - * @param subnet The subnet to get the output value for (0-15). - * @return The output value. - */ - public int getOutputValue(World world, int x, int y, int z, ForgeDirection side, int subnet); + /** + * Returns the output values of this RedNet node. + * This array must be 16 elements long. + * Only called if your block is connected in "All" mode. + * + * @param world The world this block is in. + * @param x This block's X coordinate. + * @param y This block's Y coordinate. + * @param z This block's Z coordinate. + * @param side The side the output values are required for. + * @return The output values. + */ + public int[] getOutputValues(World world, int x, int y, int z, ForgeDirection side); + + /** + * Returns the output value of this RedNet node for a given subnet. + * Must be the same as getOutputValues(world, x, y, z, side)[subnet]. + * + * @param world The world this block is in. + * @param x This block's X coordinate. + * @param y This block's Y coordinate. + * @param z This block's Z coordinate. + * @param side The side the output value is required for. + * @param subnet The subnet to get the output value for (0-15). + * @return The output value. + */ + public int getOutputValue(World world, int x, int y, int z, ForgeDirection side, int subnet); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/connectivity/IRedNetConnection.java b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/connectivity/IRedNetConnection.java index 003800d8..de457605 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/connectivity/IRedNetConnection.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/connectivity/IRedNetConnection.java @@ -6,21 +6,21 @@ /** * Defines a Block that can connect to RedNet cables. This must be implemented on your Block class. */ -public interface IRedNetConnection -{ - /** - * Returns the connection type of this Block. If this value must be changed - * while the block is alive, it must notify neighbors of a change. - *

- * For nodes that want to interact with rednet, - * see IRedNetInputNode, IRedNetOutputNode, and IRedNetOmniNode - * - * @param world The world this block is in. - * @param x This block's X coordinate. - * @param y This block's Y coordinate. - * @param z This block's Z coordinate. - * @param side The side that connection information is required for. - * @return The connection type. - */ - public RedNetConnectionType getConnectionType(World world, int x, int y, int z, ForgeDirection side); +public interface IRedNetConnection { + + /** + * Returns the connection type of this Block. If this value must be changed + * while the block is alive, it must notify neighbors of a change. + *

+ * For nodes that want to interact with rednet, + * see IRedNetInputNode, IRedNetOutputNode, and IRedNetOmniNode + * + * @param world The world this block is in. + * @param x This block's X coordinate. + * @param y This block's Y coordinate. + * @param z This block's Z coordinate. + * @param side The side that connection information is required for. + * @return The connection type. + */ + public RedNetConnectionType getConnectionType(World world, int x, int y, int z, ForgeDirection side); } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/connectivity/IRedNetDecorative.java b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/connectivity/IRedNetDecorative.java index 89de12b1..95a3959e 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/connectivity/IRedNetDecorative.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/connectivity/IRedNetDecorative.java @@ -5,7 +5,6 @@ *

* RedNet cables will treat your block similar to a vanilla block that's not redstone active. */ -public interface IRedNetDecorative -{ +public interface IRedNetDecorative { } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/connectivity/IRedNetNoConnection.java b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/connectivity/IRedNetNoConnection.java index 16225a74..e00841cc 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/connectivity/IRedNetNoConnection.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/connectivity/IRedNetNoConnection.java @@ -7,7 +7,6 @@ *
* This behavior can be overridden in subclasses by IRedNetConnection */ -public interface IRedNetNoConnection -{ - +public interface IRedNetNoConnection { + } diff --git a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/connectivity/RedNetConnectionType.java b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/connectivity/RedNetConnectionType.java index 08ba24c1..99a3b9c9 100644 --- a/src/api/java/powercrystals/minefactoryreloaded/api/rednet/connectivity/RedNetConnectionType.java +++ b/src/api/java/powercrystals/minefactoryreloaded/api/rednet/connectivity/RedNetConnectionType.java @@ -6,81 +6,84 @@ /** * Defines how RedNet cable connects to a block *

- * None: RedNet will never connect to this block (if this is all you want: use IRedNetNoConnection) + * None: RedNet will never connect to this block (if this is all you want: use IRedNetNoConnection) *

- * CableSingle: Connections will use the cable renderer with a single band, best used for whole blocks + * CableSingle: Connections will use the cable renderer with a single band, best used for whole blocks *
- * PlateSingle: Connections will use the plate renderer with a single band, used for conveyers and rails + * PlateSingle: Connections will use the plate renderer with a single band, used for conveyers and rails *

- * CableAll: Connections permit access to all 16 bands + * CableAll: Connections permit access to all 16 bands *
- * PlateAll: Connections permit access to all 16 bands - *

+ * PlateAll: Connections permit access to all 16 bands + *

+ *

* Forced connection modes are best used for decoration blocks: RedNet will not connect normally, * but will if the user forces it. Typically, IRedNetDecorative is desired for this instead *

- * ForcedCableSingle: Connections permit access to a single band, only when the cable is in forced connection mode + * ForcedCableSingle: Connections permit access to a single band, only when the cable is in forced connection mode *
- * ForcedPlateSingle: Connections permit access to a single band, only when the cable is in forced connection mode + * ForcedPlateSingle: Connections permit access to a single band, only when the cable is in forced connection mode *

- * ForcedCableAll: Connections permit access to all 16 bands, only when the cable is in forced connection mode + * ForcedCableAll: Connections permit access to all 16 bands, only when the cable is in forced connection mode *
- * ForcedPlateAll: Connections permit access to all 16 bands, only when the cable is in forced connection mode - *

+ * ForcedPlateAll: Connections permit access to all 16 bands, only when the cable is in forced connection mode + *

+ *

* The decorative nodes are for when you want rednet to decide how to connect to your block, * but also need to receive full updates from the network. *

- * DecorativeSingle: Connections permit access to a single band, using standard connection logic + * DecorativeSingle: Connections permit access to a single band, using standard connection logic *
- * DecorativeAll: Connections permit access to all 16 bands, using standard connection logic + * DecorativeAll: Connections permit access to all 16 bands, using standard connection logic *
- * ForcedDecorativeSingle: Connections permit access to a single band, only when the cable is in forced connection mode + * ForcedDecorativeSingle: Connections permit access to a single band, only when the cable is in forced connection mode *
- * ForcedDecorativeAll: Connections permit access to all 16 bands, only when the cable is in forced connection mode + * ForcedDecorativeAll: Connections permit access to all 16 bands, only when the cable is in forced connection mode */ -public enum RedNetConnectionType -{ - None, // 0; 0000000 - CableSingle, // 11; 0001011 - PlateSingle, // 13; 0001101 - CableAll, // 19; 0010011 - PlateAll, // 21; 0010101 - ForcedCableSingle, // 43; 0101011 - ForcedPlateSingle, // 45; 0101101 - ForcedCableAll, // 51; 0110011 - ForcedPlateAll, // 53; 0110101 - DecorativeSingle, // NA; 0001001 - DecorativeAll, // NA; 0010001 - ForcedDecorativeSingle, // NA; 0101001 - ForcedDecorativeAll; // NA; 0110001 - - public final boolean isConnected = this.ordinal() != 0; // 0 bit (mask: 1) - public final boolean isSingleSubnet = this.name().endsWith("Single"); // 3 bit (mask: 8) - public final boolean isAllSubnets = this.name().endsWith("All"); // 4 bit (mask: 16) - public final boolean isPlate = this.name().contains("Plate"); // 2 bit (mask: 4) - public final boolean isCable = this.name().contains("Cable"); // 1 bit (mask: 2) - public final boolean isConnectionForced = this.name().startsWith("Forced"); // 5 bit (mask: 32) - public final boolean isDecorative = this.name().contains("Decorative"); - public final short flags = toFlags(isConnected, isCable, isPlate, - isSingleSubnet, isAllSubnets, isConnectionForced); - - public static final RedNetConnectionType fromFlags(short flags) - { - return connections.get(flags); - } - - private static final short toFlags(boolean ...flags) - { - short ret = 0; - for (int i = flags.length; i --> 0;) - ret |= (flags[i] ? 1 : 0) << i; - return ret; - } - - private static final Map connections = new HashMap(); - - static { - for (RedNetConnectionType type : RedNetConnectionType.values()) - connections.put(type.flags, type); - } +public enum RedNetConnectionType { + + None, // 0; 0000000 + CableSingle, // 11; 0001011 + PlateSingle, // 13; 0001101 + CableAll, // 19; 0010011 + PlateAll, // 21; 0010101 + ForcedCableSingle, // 43; 0101011 + ForcedPlateSingle, // 45; 0101101 + ForcedCableAll, // 51; 0110011 + ForcedPlateAll, // 53; 0110101 + DecorativeSingle, // NA; 0001001 + DecorativeAll, // NA; 0010001 + ForcedDecorativeSingle, // NA; 0101001 + ForcedDecorativeAll; // NA; 0110001 + + public final boolean isConnected = this.ordinal() != 0; // 0 bit (mask: 1) + public final boolean isSingleSubnet = this.name() + .endsWith("Single"); // 3 bit (mask: 8) + public final boolean isAllSubnets = this.name() + .endsWith("All"); // 4 bit (mask: 16) + public final boolean isPlate = this.name() + .contains("Plate"); // 2 bit (mask: 4) + public final boolean isCable = this.name() + .contains("Cable"); // 1 bit (mask: 2) + public final boolean isConnectionForced = this.name() + .startsWith("Forced"); // 5 bit (mask: 32) + public final boolean isDecorative = this.name() + .contains("Decorative"); + public final short flags = toFlags(isConnected, isCable, isPlate, isSingleSubnet, isAllSubnets, isConnectionForced); + + public static final RedNetConnectionType fromFlags(short flags) { + return connections.get(flags); + } + + private static final short toFlags(boolean... flags) { + short ret = 0; + for (int i = flags.length; i-- > 0;) ret |= (flags[i] ? 1 : 0) << i; + return ret; + } + + private static final Map connections = new HashMap(); + + static { + for (RedNetConnectionType type : RedNetConnectionType.values()) connections.put(type.flags, type); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/api/IHeatEntity.java b/src/main/java/erogenousbeef/bigreactors/api/IHeatEntity.java index 0cdffd0e..588314ca 100644 --- a/src/main/java/erogenousbeef/bigreactors/api/IHeatEntity.java +++ b/src/main/java/erogenousbeef/bigreactors/api/IHeatEntity.java @@ -1,34 +1,37 @@ package erogenousbeef.bigreactors.api; public interface IHeatEntity { - public static final float ambientHeat = 20.0f; // Normal ambient temperature - - /** - * Returns the amount of heat in the entity, in celsius. - * @return The amount of heat in the entity, in celsius. - */ - public float getHeat(); - - /** - * The thermal conductivity of the entity. - * This is the amount of heat (in C) that this entity transfers - * over a unit area (1x1 square) in one tick, per degree-C difference. - * (Yes, I know centigrade != joules, it's an abstraction) - * @return Thermal conductivity constant, see above. - */ - public float getThermalConductivity(); - - // RF to transfer per tick per degree centigrade of difference on a single exposed face (1x1) - public static final float conductivityAir = 0.05f; - public static final float conductivityRubber = 0.01f; - public static final float conductivityWater = 0.1f; - public static final float conductivityStone = 0.15f; - public static final float conductivityGlass = 0.3f; - public static final float conductivityIron = 0.6f; // Stainless steel, really. - public static final float conductivityCopper = 1f; - public static final float conductivitySilver = 1.5f; - public static final float conductivityGold = 2f; - public static final float conductivityEmerald = 2.5f; - public static final float conductivityDiamond = 3f; - public static final float conductivityGraphene = 5f; + + public static final float ambientHeat = 20.0f; // Normal ambient temperature + + /** + * Returns the amount of heat in the entity, in celsius. + * + * @return The amount of heat in the entity, in celsius. + */ + public float getHeat(); + + /** + * The thermal conductivity of the entity. + * This is the amount of heat (in C) that this entity transfers + * over a unit area (1x1 square) in one tick, per degree-C difference. + * (Yes, I know centigrade != joules, it's an abstraction) + * + * @return Thermal conductivity constant, see above. + */ + public float getThermalConductivity(); + + // RF to transfer per tick per degree centigrade of difference on a single exposed face (1x1) + public static final float conductivityAir = 0.05f; + public static final float conductivityRubber = 0.01f; + public static final float conductivityWater = 0.1f; + public static final float conductivityStone = 0.15f; + public static final float conductivityGlass = 0.3f; + public static final float conductivityIron = 0.6f; // Stainless steel, really. + public static final float conductivityCopper = 1f; + public static final float conductivitySilver = 1.5f; + public static final float conductivityGold = 2f; + public static final float conductivityEmerald = 2.5f; + public static final float conductivityDiamond = 3f; + public static final float conductivityGraphene = 5f; } diff --git a/src/main/java/erogenousbeef/bigreactors/api/IRadiationModerator.java b/src/main/java/erogenousbeef/bigreactors/api/IRadiationModerator.java index 10d57462..55c0b53d 100644 --- a/src/main/java/erogenousbeef/bigreactors/api/IRadiationModerator.java +++ b/src/main/java/erogenousbeef/bigreactors/api/IRadiationModerator.java @@ -4,5 +4,6 @@ import erogenousbeef.bigreactors.common.data.RadiationPacket; public interface IRadiationModerator { - public void moderateRadiation(RadiationData returnData, RadiationPacket radiation); + + public void moderateRadiation(RadiationData returnData, RadiationPacket radiation); } diff --git a/src/main/java/erogenousbeef/bigreactors/api/IReactorFuel.java b/src/main/java/erogenousbeef/bigreactors/api/IReactorFuel.java index 58c503c6..e890300f 100644 --- a/src/main/java/erogenousbeef/bigreactors/api/IReactorFuel.java +++ b/src/main/java/erogenousbeef/bigreactors/api/IReactorFuel.java @@ -6,53 +6,60 @@ * Implement this interface to provide information on fuel for Big Reactors. */ public interface IReactorFuel { - /** - * Is this fuel equal to another? Should be identical to equals(otherFuel) - * @param otherFuel The IReactorFuel to compare. - * @return True if these fuels are equal, false otherwise. - */ - public boolean isFuelEqual(IReactorFuel otherFuel); - - /** - * Does this ReactorFuel object govern data related to this fluid? - * Essentially an isFluidEqual check. - * - * @param fluid The Fluid to compare. - * @return True if the reference fluid is equal to the parameter. - */ - public boolean isFuelEqual(Fluid fluid); - - /** - * Return the reference fluid for this fuel. This is the Forge Fluid for which - * this ReactorFuel object defines properties. - * @return The Fluid which this Reactor Fuel object governs. - */ - public Fluid getReferenceFluid(); - - /** - * Returns the basic color of your fuel in RRGGBB format. This will be used for - * color blending in fuel rods. In hex format, colors are 0xRRGGBB. - * @return A color in 0xRRGGBB format. - */ - public int getFuelColor(); - - /** - * Standard Java equals operator. This is used by the registry, so it's required. - * Fuels should generally be equal if their reference items are equal. - * @param otherObject The other object with which you should compare. - * @return True if the fuels are equal, false otherwise. - */ - public boolean equals(Object otherObject); - - // TODO: Add fuel characteristics here - /** - * Fuels are converted into other types of Fluids as they get processed. - * For now, any given Fuel/Waste Fluid is only converted into one other. - * @return The Fluid representing the converted product of this Fuel. Null is acceptable and means the Fuel is simply consumed. - */ - public Fluid getProductFluid(); - - public boolean isFuel(); - - public boolean isWaste(); + + /** + * Is this fuel equal to another? Should be identical to equals(otherFuel) + * + * @param otherFuel The IReactorFuel to compare. + * @return True if these fuels are equal, false otherwise. + */ + public boolean isFuelEqual(IReactorFuel otherFuel); + + /** + * Does this ReactorFuel object govern data related to this fluid? + * Essentially an isFluidEqual check. + * + * @param fluid The Fluid to compare. + * @return True if the reference fluid is equal to the parameter. + */ + public boolean isFuelEqual(Fluid fluid); + + /** + * Return the reference fluid for this fuel. This is the Forge Fluid for which + * this ReactorFuel object defines properties. + * + * @return The Fluid which this Reactor Fuel object governs. + */ + public Fluid getReferenceFluid(); + + /** + * Returns the basic color of your fuel in RRGGBB format. This will be used for + * color blending in fuel rods. In hex format, colors are 0xRRGGBB. + * + * @return A color in 0xRRGGBB format. + */ + public int getFuelColor(); + + /** + * Standard Java equals operator. This is used by the registry, so it's required. + * Fuels should generally be equal if their reference items are equal. + * + * @param otherObject The other object with which you should compare. + * @return True if the fuels are equal, false otherwise. + */ + public boolean equals(Object otherObject); + + // TODO: Add fuel characteristics here + /** + * Fuels are converted into other types of Fluids as they get processed. + * For now, any given Fuel/Waste Fluid is only converted into one other. + * + * @return The Fluid representing the converted product of this Fuel. Null is acceptable and means the Fuel is + * simply consumed. + */ + public Fluid getProductFluid(); + + public boolean isFuel(); + + public boolean isWaste(); } diff --git a/src/main/java/erogenousbeef/bigreactors/api/IReactorSolid.java b/src/main/java/erogenousbeef/bigreactors/api/IReactorSolid.java index 495e822a..6d0c6bde 100644 --- a/src/main/java/erogenousbeef/bigreactors/api/IReactorSolid.java +++ b/src/main/java/erogenousbeef/bigreactors/api/IReactorSolid.java @@ -9,36 +9,38 @@ * In order for this to work, you must select an equivalent Fluid fuel. * * All solid fuels are "magically" converted into Fluids when they enter the - * reactor system. + * reactor system. + * * @author Erogenous Beef */ public interface IReactorSolid { - /** - * Get the solid itemstack to which this solid fuel maps. - */ - public ItemStack getReferenceItem(); - /** - * Get the fluid to which this solid fuel maps. - */ - public FluidStack getReferenceFluid(); + /** + * Get the solid itemstack to which this solid fuel maps. + */ + public ItemStack getReferenceItem(); + + /** + * Get the fluid to which this solid fuel maps. + */ + public FluidStack getReferenceFluid(); - // In this case, both the reference item and reference fluid must match! - /** - * @param otherFuel The IReactorSolid to compare. - * @return True if the other fuel's reference item and reference fluid both match - */ - public boolean isEqual(IReactorSolid otherFuel); + // In this case, both the reference item and reference fluid must match! + /** + * @param otherFuel The IReactorSolid to compare. + * @return True if the other fuel's reference item and reference fluid both match + */ + public boolean isEqual(IReactorSolid otherFuel); - /** - * @param otherItem An ItemStack to check for equality. - * @return True if the fuel's reference item is the same as the argument. - */ - public boolean isItemEqual(ItemStack otherItem); + /** + * @param otherItem An ItemStack to check for equality. + * @return True if the fuel's reference item is the same as the argument. + */ + public boolean isItemEqual(ItemStack otherItem); - /** - * @param otherFluid A Fluid to check for equality. - * @return True if the fuel's reference fluid is the same as the argument. - */ - public boolean isFluidEqual(Fluid otherFluid); + /** + * @param otherFluid A Fluid to check for equality. + * @return True if the fuel's reference fluid is the same as the argument. + */ + public boolean isFluidEqual(Fluid otherFluid); } diff --git a/src/main/java/erogenousbeef/bigreactors/api/data/CoilPartData.java b/src/main/java/erogenousbeef/bigreactors/api/data/CoilPartData.java index 8ef5360f..b027cf85 100644 --- a/src/main/java/erogenousbeef/bigreactors/api/data/CoilPartData.java +++ b/src/main/java/erogenousbeef/bigreactors/api/data/CoilPartData.java @@ -1,14 +1,14 @@ package erogenousbeef.bigreactors.api.data; public class CoilPartData { - - public float efficiency; - public float bonus; - public float energyExtractionRate; // 1.0 = normal - public CoilPartData(float efficiency, float bonus, float extractionRate) { - this.efficiency = efficiency; - this.bonus = bonus; - this.energyExtractionRate = extractionRate; - } + public float efficiency; + public float bonus; + public float energyExtractionRate; // 1.0 = normal + + public CoilPartData(float efficiency, float bonus, float extractionRate) { + this.efficiency = efficiency; + this.bonus = bonus; + this.energyExtractionRate = extractionRate; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/api/data/FluidToReactantMapping.java b/src/main/java/erogenousbeef/bigreactors/api/data/FluidToReactantMapping.java index 9bc12944..d34aa1ea 100644 --- a/src/main/java/erogenousbeef/bigreactors/api/data/FluidToReactantMapping.java +++ b/src/main/java/erogenousbeef/bigreactors/api/data/FluidToReactantMapping.java @@ -2,40 +2,55 @@ import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidStack; + import erogenousbeef.bigreactors.api.registry.Reactants; public class FluidToReactantMapping extends SourceProductMapping { - public FluidToReactantMapping(String fluidName, int fluidAmount, String reactantName, int reactantAmount) { - super(fluidName, fluidAmount, reactantName, reactantAmount); - } - - public FluidToReactantMapping(Fluid fluid, int fluidAmount, String reactantName, int reactantAmount) { - super(fluid.getName(), fluidAmount, reactantName, reactantAmount); - } - - public FluidToReactantMapping(FluidStack fluidStack, String reactantName, int reactantAmount) { - super(fluidStack.getFluid().getName(), fluidStack.amount, reactantName, reactantAmount); - } - - public FluidToReactantMapping(String fluidName, int fluidAmount, String reactantName) { - super(fluidName, fluidAmount, reactantName, Reactants.standardFluidReactantAmount); - } - - public FluidToReactantMapping(Fluid fluid, int fluidAmount, String reactantName) { - super(fluid.getName(), fluidAmount, reactantName, Reactants.standardFluidReactantAmount); - } - - public FluidToReactantMapping(FluidStack fluidStack, String reactantName) { - super(fluidStack.getFluid().getName(), fluidStack.amount, reactantName, Reactants.standardFluidReactantAmount); - } - - public FluidToReactantMapping(String fluidName, String reactantName) { - super(fluidName, Reactants.standardFluidReactantAmount, reactantName, Reactants.standardFluidReactantAmount); - } - - public FluidToReactantMapping(Fluid fluid, String reactantName) { - super(fluid.getName(), Reactants.standardFluidReactantAmount, reactantName, Reactants.standardFluidReactantAmount); - } - + public FluidToReactantMapping(String fluidName, int fluidAmount, String reactantName, int reactantAmount) { + super(fluidName, fluidAmount, reactantName, reactantAmount); + } + + public FluidToReactantMapping(Fluid fluid, int fluidAmount, String reactantName, int reactantAmount) { + super(fluid.getName(), fluidAmount, reactantName, reactantAmount); + } + + public FluidToReactantMapping(FluidStack fluidStack, String reactantName, int reactantAmount) { + super( + fluidStack.getFluid() + .getName(), + fluidStack.amount, + reactantName, + reactantAmount); + } + + public FluidToReactantMapping(String fluidName, int fluidAmount, String reactantName) { + super(fluidName, fluidAmount, reactantName, Reactants.standardFluidReactantAmount); + } + + public FluidToReactantMapping(Fluid fluid, int fluidAmount, String reactantName) { + super(fluid.getName(), fluidAmount, reactantName, Reactants.standardFluidReactantAmount); + } + + public FluidToReactantMapping(FluidStack fluidStack, String reactantName) { + super( + fluidStack.getFluid() + .getName(), + fluidStack.amount, + reactantName, + Reactants.standardFluidReactantAmount); + } + + public FluidToReactantMapping(String fluidName, String reactantName) { + super(fluidName, Reactants.standardFluidReactantAmount, reactantName, Reactants.standardFluidReactantAmount); + } + + public FluidToReactantMapping(Fluid fluid, String reactantName) { + super( + fluid.getName(), + Reactants.standardFluidReactantAmount, + reactantName, + Reactants.standardFluidReactantAmount); + } + } diff --git a/src/main/java/erogenousbeef/bigreactors/api/data/OreDictToReactantMapping.java b/src/main/java/erogenousbeef/bigreactors/api/data/OreDictToReactantMapping.java index 9a05f0a7..c1d6721d 100644 --- a/src/main/java/erogenousbeef/bigreactors/api/data/OreDictToReactantMapping.java +++ b/src/main/java/erogenousbeef/bigreactors/api/data/OreDictToReactantMapping.java @@ -5,24 +5,24 @@ /** * Used to map any object which is registered in the ore dictionary to * a reactant. + * * @author Erogenous Beef */ public class OreDictToReactantMapping extends SourceProductMapping { - public OreDictToReactantMapping(String oreDictName, int oreAmount, - String reactantName, int reactantAmount) { - super(oreDictName, oreAmount, reactantName, reactantAmount); - } + public OreDictToReactantMapping(String oreDictName, int oreAmount, String reactantName, int reactantAmount) { + super(oreDictName, oreAmount, reactantName, reactantAmount); + } - public OreDictToReactantMapping(String oreDictName, int oreAmount, String reactantName) { - super(oreDictName, oreAmount, reactantName, Reactants.standardSolidReactantAmount); - } + public OreDictToReactantMapping(String oreDictName, int oreAmount, String reactantName) { + super(oreDictName, oreAmount, reactantName, Reactants.standardSolidReactantAmount); + } - public OreDictToReactantMapping(String oreDictName, String reactantName, int reactantAmount) { - super(oreDictName, 1, reactantName, reactantAmount); - } - - public OreDictToReactantMapping(String oreDictName, String reactantName) { - super(oreDictName, 1, reactantName, Reactants.standardSolidReactantAmount); - } + public OreDictToReactantMapping(String oreDictName, String reactantName, int reactantAmount) { + super(oreDictName, 1, reactantName, reactantAmount); + } + + public OreDictToReactantMapping(String oreDictName, String reactantName) { + super(oreDictName, 1, reactantName, Reactants.standardSolidReactantAmount); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/api/data/ReactantData.java b/src/main/java/erogenousbeef/bigreactors/api/data/ReactantData.java index 9c3c8b54..31d66e54 100644 --- a/src/main/java/erogenousbeef/bigreactors/api/data/ReactantData.java +++ b/src/main/java/erogenousbeef/bigreactors/api/data/ReactantData.java @@ -4,56 +4,67 @@ public class ReactantData { - public enum ReactantType { - Fuel, - Waste, - }; - public static final ReactantType[] s_Types = ReactantType.values(); - - private String name; - private ReactantType type; - private int color; - - public String getName() { return name; } - public ReactantType getType() { return type; } - public int getColor() { return color; } - - /** - * Declare a new set of reactant data with a default color. - * Waste will by Cyanite Cyan and fuel will be Yellorium Yellow. - * @param name The name of this reactant. Must be unique. - * @param type The type of this reactant. Fuel/Waste. - * @param color The color to use when rendering fuel rods with this reactant in it. - */ - public ReactantData(String name, ReactantType type) { - this.name = name; - this.type = type; - this.color = type == ReactantType.Fuel ? BigReactors.defaultFluidColorFuel : BigReactors.defaultFluidColorWaste; - } - - /** - * Declare a new set of reactant data. - * @param name The name of this reactant. Must be unique. - * @param type The type of this reactant. Fuel/Waste. - * @param color The color to use when rendering fuel rods with this reactant in it. - */ - public ReactantData(String name, ReactantType type, int color) { - this.name = name; - this.type = type; - this.color = color; - } - - /** - * @return True if this reactant is considered fuel. - */ - public boolean isFuel() { - return type == ReactantType.Fuel; - } - - /** - * @return True if this reactant is considered waste. - */ - public boolean isWaste() { - return type == ReactantType.Waste; - } + public enum ReactantType { + Fuel, + Waste, + }; + + public static final ReactantType[] s_Types = ReactantType.values(); + + private String name; + private ReactantType type; + private int color; + + public String getName() { + return name; + } + + public ReactantType getType() { + return type; + } + + public int getColor() { + return color; + } + + /** + * Declare a new set of reactant data with a default color. + * Waste will by Cyanite Cyan and fuel will be Yellorium Yellow. + * + * @param name The name of this reactant. Must be unique. + * @param type The type of this reactant. Fuel/Waste. + * @param color The color to use when rendering fuel rods with this reactant in it. + */ + public ReactantData(String name, ReactantType type) { + this.name = name; + this.type = type; + this.color = type == ReactantType.Fuel ? BigReactors.defaultFluidColorFuel : BigReactors.defaultFluidColorWaste; + } + + /** + * Declare a new set of reactant data. + * + * @param name The name of this reactant. Must be unique. + * @param type The type of this reactant. Fuel/Waste. + * @param color The color to use when rendering fuel rods with this reactant in it. + */ + public ReactantData(String name, ReactantType type, int color) { + this.name = name; + this.type = type; + this.color = color; + } + + /** + * @return True if this reactant is considered fuel. + */ + public boolean isFuel() { + return type == ReactantType.Fuel; + } + + /** + * @return True if this reactant is considered waste. + */ + public boolean isWaste() { + return type == ReactantType.Waste; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/api/data/ReactantToFluidMapping.java b/src/main/java/erogenousbeef/bigreactors/api/data/ReactantToFluidMapping.java index 0cafb725..fee05c24 100644 --- a/src/main/java/erogenousbeef/bigreactors/api/data/ReactantToFluidMapping.java +++ b/src/main/java/erogenousbeef/bigreactors/api/data/ReactantToFluidMapping.java @@ -2,40 +2,55 @@ import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidStack; + import erogenousbeef.bigreactors.api.registry.Reactants; public class ReactantToFluidMapping extends SourceProductMapping { - public ReactantToFluidMapping(String reactantName, int reactantAmount, String fluidName, int fluidAmount) { - super(reactantName, reactantAmount, fluidName, fluidAmount); - } - - public ReactantToFluidMapping(String reactantName, int reactantAmount, Fluid fluid, int fluidAmount) { - super(reactantName, reactantAmount, fluid.getName(), fluidAmount); - } - - public ReactantToFluidMapping(String reactantName, int reactantAmount, FluidStack fluidStack) { - super(reactantName, reactantAmount, fluidStack.getFluid().getName(), fluidStack.amount); - } - - public ReactantToFluidMapping(String reactantName, String fluidName, int fluidAmount) { - super(reactantName, Reactants.standardFluidReactantAmount, fluidName, fluidAmount); - } - - public ReactantToFluidMapping(String reactantName, Fluid fluid, int fluidAmount) { - super(reactantName, Reactants.standardFluidReactantAmount, fluid.getName(), fluidAmount); - } - - public ReactantToFluidMapping(String reactantName, FluidStack fluidStack) { - super(reactantName, Reactants.standardFluidReactantAmount, fluidStack.getFluid().getName(), fluidStack.amount); - } - - public ReactantToFluidMapping(String reactantName, String fluidName) { - super(reactantName, Reactants.standardFluidReactantAmount, fluidName, Reactants.standardFluidReactantAmount); - } - - public ReactantToFluidMapping(String reactantName, Fluid fluid) { - super(reactantName, Reactants.standardFluidReactantAmount, fluid.getName(), Reactants.standardFluidReactantAmount); - } - + public ReactantToFluidMapping(String reactantName, int reactantAmount, String fluidName, int fluidAmount) { + super(reactantName, reactantAmount, fluidName, fluidAmount); + } + + public ReactantToFluidMapping(String reactantName, int reactantAmount, Fluid fluid, int fluidAmount) { + super(reactantName, reactantAmount, fluid.getName(), fluidAmount); + } + + public ReactantToFluidMapping(String reactantName, int reactantAmount, FluidStack fluidStack) { + super( + reactantName, + reactantAmount, + fluidStack.getFluid() + .getName(), + fluidStack.amount); + } + + public ReactantToFluidMapping(String reactantName, String fluidName, int fluidAmount) { + super(reactantName, Reactants.standardFluidReactantAmount, fluidName, fluidAmount); + } + + public ReactantToFluidMapping(String reactantName, Fluid fluid, int fluidAmount) { + super(reactantName, Reactants.standardFluidReactantAmount, fluid.getName(), fluidAmount); + } + + public ReactantToFluidMapping(String reactantName, FluidStack fluidStack) { + super( + reactantName, + Reactants.standardFluidReactantAmount, + fluidStack.getFluid() + .getName(), + fluidStack.amount); + } + + public ReactantToFluidMapping(String reactantName, String fluidName) { + super(reactantName, Reactants.standardFluidReactantAmount, fluidName, Reactants.standardFluidReactantAmount); + } + + public ReactantToFluidMapping(String reactantName, Fluid fluid) { + super( + reactantName, + Reactants.standardFluidReactantAmount, + fluid.getName(), + Reactants.standardFluidReactantAmount); + } + } diff --git a/src/main/java/erogenousbeef/bigreactors/api/data/ReactorInteriorData.java b/src/main/java/erogenousbeef/bigreactors/api/data/ReactorInteriorData.java index 92aa51c7..9a8d93d1 100644 --- a/src/main/java/erogenousbeef/bigreactors/api/data/ReactorInteriorData.java +++ b/src/main/java/erogenousbeef/bigreactors/api/data/ReactorInteriorData.java @@ -1,19 +1,20 @@ package erogenousbeef.bigreactors.api.data; public class ReactorInteriorData { - public float absorption, heatEfficiency, moderation; - public float heatConductivity; - /** - * @param absorption How much radiation this material absorbs and converts to heat. 0.0 = none, 1.0 = all. - * @param heatEfficiency How efficiently radiation is converted to heat. 0 = no heat, 1 = all heat. - * @param moderation How well this material moderates radiation. This is a divisor; should not be below 1. - * @param heatConductivity How well this material conducts heat, in RF/t/m2. - */ - public ReactorInteriorData(float absorption, float heatEfficiency, float moderation, float heatConductivity) { - this.absorption = Math.max(0f, Math.min(1f, absorption)); - this.heatEfficiency = Math.max(0f, Math.min(1f, heatEfficiency)); - this.moderation = Math.max(1f, moderation); - this.heatConductivity = Math.max(0f, heatConductivity); - } + public float absorption, heatEfficiency, moderation; + public float heatConductivity; + + /** + * @param absorption How much radiation this material absorbs and converts to heat. 0.0 = none, 1.0 = all. + * @param heatEfficiency How efficiently radiation is converted to heat. 0 = no heat, 1 = all heat. + * @param moderation How well this material moderates radiation. This is a divisor; should not be below 1. + * @param heatConductivity How well this material conducts heat, in RF/t/m2. + */ + public ReactorInteriorData(float absorption, float heatEfficiency, float moderation, float heatConductivity) { + this.absorption = Math.max(0f, Math.min(1f, absorption)); + this.heatEfficiency = Math.max(0f, Math.min(1f, heatEfficiency)); + this.moderation = Math.max(1f, moderation); + this.heatConductivity = Math.max(0f, heatConductivity); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/api/data/ReactorReaction.java b/src/main/java/erogenousbeef/bigreactors/api/data/ReactorReaction.java index b6a964f1..942fa1c7 100644 --- a/src/main/java/erogenousbeef/bigreactors/api/data/ReactorReaction.java +++ b/src/main/java/erogenousbeef/bigreactors/api/data/ReactorReaction.java @@ -2,41 +2,47 @@ public class ReactorReaction extends SourceProductMapping { - public static final float standardReactivity = 1.05f; - public static final float standardFissionRate = 0.01f; - - // An exponent applied to the number of fission events - // to determine the base amount of radiation created. - // Raising this produces more radiation per fuel unit. - protected float reactivity; - - // How fast this reaction occurs. Each tick, the reactor will multiply - // this number by the amount of source reactant to determine how - // much source reactant actually reacts. - // Raising this will cause the reactor to burn this reactant faster. - protected float fissionRate; - - /** - * This is the reaction of 1 unit of source to 1 unit of product. - * Floating-point quantities will be used, so this registration - * is for a Unit Reaction of 1 unit of reactant to 1 unit of product. - * @param sourceKey - * @param productKey - */ - public ReactorReaction(String sourceKey, String productKey) { - super(sourceKey, 1, productKey, 1); - - this.reactivity = standardReactivity; - this.fissionRate = standardFissionRate; - } - - public ReactorReaction(String sourceKey, String productKey, float reactivity, float fissionRate) { - super(sourceKey, 1, productKey, 1); - this.reactivity = reactivity; - this.fissionRate = fissionRate; - } - - public float getReactivity() { return reactivity; } - public float getFissionRate() { return fissionRate; } + public static final float standardReactivity = 1.05f; + public static final float standardFissionRate = 0.01f; + + // An exponent applied to the number of fission events + // to determine the base amount of radiation created. + // Raising this produces more radiation per fuel unit. + protected float reactivity; + + // How fast this reaction occurs. Each tick, the reactor will multiply + // this number by the amount of source reactant to determine how + // much source reactant actually reacts. + // Raising this will cause the reactor to burn this reactant faster. + protected float fissionRate; + + /** + * This is the reaction of 1 unit of source to 1 unit of product. + * Floating-point quantities will be used, so this registration + * is for a Unit Reaction of 1 unit of reactant to 1 unit of product. + * + * @param sourceKey + * @param productKey + */ + public ReactorReaction(String sourceKey, String productKey) { + super(sourceKey, 1, productKey, 1); + + this.reactivity = standardReactivity; + this.fissionRate = standardFissionRate; + } + + public ReactorReaction(String sourceKey, String productKey, float reactivity, float fissionRate) { + super(sourceKey, 1, productKey, 1); + this.reactivity = reactivity; + this.fissionRate = fissionRate; + } + + public float getReactivity() { + return reactivity; + } + + public float getFissionRate() { + return fissionRate; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/api/data/SourceProductMapping.java b/src/main/java/erogenousbeef/bigreactors/api/data/SourceProductMapping.java index a6a09b95..f2d184a3 100644 --- a/src/main/java/erogenousbeef/bigreactors/api/data/SourceProductMapping.java +++ b/src/main/java/erogenousbeef/bigreactors/api/data/SourceProductMapping.java @@ -2,59 +2,81 @@ public class SourceProductMapping { - protected String source; - protected String product; - protected int sourceAmount; - protected int productAmount; - - /** - * Maps a source item to a product item, with quantities attached. - * @param source The key of the source item, e.g. oredict name, fluidict name or reactant name - * @param product The key of the product item, e.g. oredict name, fluidict name or reactant name - * @param sourceAmount The amount of source stuff used - * @param productAmount The amount of product stuff produced - */ - public SourceProductMapping(String sourceKey, int sourceAmount, String productKey, int productAmount) { - if(sourceKey == null) { throw new IllegalArgumentException("Cannot create mapping with null source name string"); } - if(productKey == null) { throw new IllegalArgumentException("Cannot create mapping with null product name string"); } - if(sourceAmount <= 0) { throw new IllegalArgumentException("Cannot create mapping which consumes less than 1 unit of source item"); } - if(productAmount <= 0) { throw new IllegalArgumentException("Cannot create mapping which produces less than 1 unit of product item"); } - - this.source = sourceKey; - this.product = productKey; - this.sourceAmount = sourceAmount; - this.productAmount= productAmount; - } - - public String getSource() { return source; } - public String getProduct() { return product; } - public int getSourceAmount() { return sourceAmount; } - public int getProductAmount() { return productAmount; } - - public SourceProductMapping getReverse() { - return new SourceProductMapping(product, productAmount, source, sourceAmount); - } - - /** - * Returns the amount of product which can be produced from a given quantity - * of the source thing. - * If there is not enough of the source item, returns zero. - * @param sourceQty The amount of source thing available. - * @return The amount of product which can be produced. May be 0. - */ - public int getProductAmount(int sourceQty) { - return (sourceQty / sourceAmount) * productAmount; - } - - /** - * Returns the amount of source needed to produce a given quantity of product. - * Note that this may not produce the full amount you requested; you should - * check the result with getProductAmount() afterwards to see how much need be consumed. - * @param productQty The amount of product to produce - * @return The amount of source needed to produce at most productQty units of the product. - */ - public int getSourceAmount(int productQty) { - return (productQty / productAmount) * sourceAmount; - } - + protected String source; + protected String product; + protected int sourceAmount; + protected int productAmount; + + /** + * Maps a source item to a product item, with quantities attached. + * + * @param source The key of the source item, e.g. oredict name, fluidict name or reactant name + * @param product The key of the product item, e.g. oredict name, fluidict name or reactant name + * @param sourceAmount The amount of source stuff used + * @param productAmount The amount of product stuff produced + */ + public SourceProductMapping(String sourceKey, int sourceAmount, String productKey, int productAmount) { + if (sourceKey == null) { + throw new IllegalArgumentException("Cannot create mapping with null source name string"); + } + if (productKey == null) { + throw new IllegalArgumentException("Cannot create mapping with null product name string"); + } + if (sourceAmount <= 0) { + throw new IllegalArgumentException("Cannot create mapping which consumes less than 1 unit of source item"); + } + if (productAmount <= 0) { + throw new IllegalArgumentException("Cannot create mapping which produces less than 1 unit of product item"); + } + + this.source = sourceKey; + this.product = productKey; + this.sourceAmount = sourceAmount; + this.productAmount = productAmount; + } + + public String getSource() { + return source; + } + + public String getProduct() { + return product; + } + + public int getSourceAmount() { + return sourceAmount; + } + + public int getProductAmount() { + return productAmount; + } + + public SourceProductMapping getReverse() { + return new SourceProductMapping(product, productAmount, source, sourceAmount); + } + + /** + * Returns the amount of product which can be produced from a given quantity + * of the source thing. + * If there is not enough of the source item, returns zero. + * + * @param sourceQty The amount of source thing available. + * @return The amount of product which can be produced. May be 0. + */ + public int getProductAmount(int sourceQty) { + return (sourceQty / sourceAmount) * productAmount; + } + + /** + * Returns the amount of source needed to produce a given quantity of product. + * Note that this may not produce the full amount you requested; you should + * check the result with getProductAmount() afterwards to see how much need be consumed. + * + * @param productQty The amount of product to produce + * @return The amount of source needed to produce at most productQty units of the product. + */ + public int getSourceAmount(int productQty) { + return (productQty / productAmount) * sourceAmount; + } + } diff --git a/src/main/java/erogenousbeef/bigreactors/api/imc/MessageRouter.java b/src/main/java/erogenousbeef/bigreactors/api/imc/MessageRouter.java index 3af34445..7b637209 100644 --- a/src/main/java/erogenousbeef/bigreactors/api/imc/MessageRouter.java +++ b/src/main/java/erogenousbeef/bigreactors/api/imc/MessageRouter.java @@ -11,37 +11,46 @@ /** * This class routes IMC messages to their designated handlers. + * * @author Erogenous Beef */ public class MessageRouter { - protected static Map handlers = new HashMap(); - - public static void route(IMCEvent event) { - for(IMCMessage message : event.getMessages()) { - Method handler = handlers.get(message.key); - if(handler != null) { - try { - handler.invoke(message); - } catch (IllegalAccessException e) { - BRLog.warning("IllegalAccessException while handling message <%s>, ignoring. Error: %s", message.key, e.getMessage()); - e.printStackTrace(); - } catch (IllegalArgumentException e) { - BRLog.warning("IllegalArgumentException while handling message <%s>, ignoring. Error: %s", message.key, e.getMessage()); - e.printStackTrace(); - } catch (InvocationTargetException e) { - BRLog.warning("InvocationTargetException while handling message <%s>, ignoring. Error: %s", message.key, e.getMessage()); - e.printStackTrace(); - } - } - else { - BRLog.warning("Received an InterModComms event with an unrecognized key <%s>", message.key); - } - } - } + protected static Map handlers = new HashMap(); + + public static void route(IMCEvent event) { + for (IMCMessage message : event.getMessages()) { + Method handler = handlers.get(message.key); + if (handler != null) { + try { + handler.invoke(message); + } catch (IllegalAccessException e) { + BRLog.warning( + "IllegalAccessException while handling message <%s>, ignoring. Error: %s", + message.key, + e.getMessage()); + e.printStackTrace(); + } catch (IllegalArgumentException e) { + BRLog.warning( + "IllegalArgumentException while handling message <%s>, ignoring. Error: %s", + message.key, + e.getMessage()); + e.printStackTrace(); + } catch (InvocationTargetException e) { + BRLog.warning( + "InvocationTargetException while handling message <%s>, ignoring. Error: %s", + message.key, + e.getMessage()); + e.printStackTrace(); + } + } else { + BRLog.warning("Received an InterModComms event with an unrecognized key <%s>", message.key); + } + } + } + + public static void register(String key, Method handler) { + handlers.put(key, handler); + } - public static void register(String key, Method handler) { - handlers.put(key, handler); - } - } diff --git a/src/main/java/erogenousbeef/bigreactors/api/registry/Reactants.java b/src/main/java/erogenousbeef/bigreactors/api/registry/Reactants.java index af7db635..da3a6593 100644 --- a/src/main/java/erogenousbeef/bigreactors/api/registry/Reactants.java +++ b/src/main/java/erogenousbeef/bigreactors/api/registry/Reactants.java @@ -10,6 +10,7 @@ import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidStack; + import cofh.core.util.oredict.OreDictionaryArbiter; import cofh.lib.util.helpers.ItemHelper; import erogenousbeef.bigreactors.api.IReactorFuel; @@ -22,313 +23,348 @@ import erogenousbeef.bigreactors.common.data.ReactorSolidMapping; public class Reactants { - - public static final int standardSolidReactantAmount = 1000; // 1 item = 1000 mB, standard - public static final int standardFluidReactantAmount = 1; // 1 mB = 1 mB - - private static Map _reactants = new HashMap(); - - // 1:1 - private static Map _solidToReactant = new HashMap(); - private static Map _fluidToReactant = new HashMap(); - - // 1:many - private static Map> _reactantToSolid = new HashMap>(); - private static Map> _reactantToFluid = new HashMap>(); - - private static Map _reactorFluidToSolid = new HashMap(); - private static Set _reactorSolidToFuel = new CopyOnWriteArraySet(); // This won't work - private static Set _reactorSolidToWaste = new CopyOnWriteArraySet(); // This won't work - - private static Map _reactorFluids = new HashMap(); - - //// REGISTRATION - - /** - * Simple wrapper for quickly registering standard reactants. - * Sets default colors for fuel/waste. - * @param name Name of the reactant - * @param fuel True if fuel, false if waste. - */ - public static void registerReactant(String name, boolean fuel) { - registerReactant(name, - fuel ? 0 : 1, - fuel ? BigReactors.defaultFluidColorFuel : BigReactors.defaultFluidColorWaste - ); - } - - /** - * Register a new type of reactant. - * @param name The name of the reactant. - * @param type The type of the reactant. 0 = fuel, 1 = waste. Other values unsupported. - * @param color The color of the reactant, format 0xRRGGBB. - */ - public static void registerReactant(String name, int type, int color) { - if(type < 0 || type >= ReactantData.s_Types.length) { - throw new IllegalArgumentException("Unsupported type; value may only be 0 or 1"); - } - - if(_reactants.containsKey(name)) { - BRLog.warning("Overwriting data for reactant %s - someone may be altering BR game data or have duplicate reactant names!", name); - } - - ReactantData data = new ReactantData(name, ReactantData.s_Types[type], color); - _reactants.put(name, data); - } - - /** - * Register a solid ItemStack as a valid reactant for the reactor. - * For fuels, it will allow access ports to accept the item in the inlet slot. - * For wastes, it will allow access ports to eject the item into the outlet slot. - * @param itemStack The item which represents a reactant. Its quantity indicates how many items will be used to make 1000mB of reactant. - * @param reactantName The name of the reactant. - */ - public static SourceProductMapping registerSolid(ItemStack itemStack, String reactantName) { - if(!_reactants.containsKey(reactantName)) { - throw new IllegalArgumentException("Unknown reactantName " + reactantName); - } - - ArrayList oreDictNames = OreDictionaryArbiter.getAllOreNames(itemStack); - if(oreDictNames == null || oreDictNames.size() < 1) { - BRLog.warning("Reactants.registerSolid: Could not resolve ore dict name for %s", itemStack.getUnlocalizedName()); - return null; - } - - SourceProductMapping firstMapping = null; - - for(String name : oreDictNames) { - OreDictToReactantMapping mapping = new OreDictToReactantMapping(name, reactantName); - SourceProductMapping reverseMapping = mapping.getReverse(); - _solidToReactant.put(mapping.getSource(), mapping); - mapReactant(reverseMapping.getSource(), reverseMapping, _reactantToSolid); - - if(firstMapping == null) { firstMapping = mapping; } - } - - return firstMapping; - } - - /** - * Register a solid ItemStack as a valid reactant for the reactor. - * For fuels, it will allow access ports to accept the item in the inlet slot. - * For wastes, it will allow access ports to eject the item into the outlet slot. - * @param itemStack The item which represents a reactant. Its quantity indicates how many items will be used to make the defined units of reactant. - * @param reactantName The name of the reactant. - * @param reactantQty The quantity of the reactant produced by the itemStack.stackSize units of the item. - */ - public static SourceProductMapping registerSolid(ItemStack itemStack, String reactantName, int reactantQty) { - if(!_reactants.containsKey(reactantName)) { - throw new IllegalArgumentException("Unknown reactantName " + reactantName); - } - - ArrayList oreDictNames = OreDictionaryArbiter.getAllOreNames(itemStack); - if(oreDictNames == null || oreDictNames.size() < 1) { - BRLog.warning("Reactants.registerSolid: Could not resolve ore dict name for %s", itemStack.getUnlocalizedName()); - return null; - } - - SourceProductMapping firstMapping = null; - - for(String name : oreDictNames) { - OreDictToReactantMapping mapping = new OreDictToReactantMapping(name, reactantName, reactantQty); - SourceProductMapping reverseMapping = mapping.getReverse(); - _solidToReactant.put(mapping.getSource(), mapping); - mapReactant(reverseMapping.getSource(), reverseMapping, _reactantToSolid); - - if(firstMapping == null) { firstMapping = mapping; } - } - - return firstMapping; - } - - /** - * Register a raw ore dictionary name to convert to reactant. Uses standard quantities - * of 1 unit of ore = 1000 units of fuel. - * @param oreDictName OreDict name of the solid to register as a reactant. - * @param reactantName Name of the reactant. - */ - public static SourceProductMapping registerSolid(String oreDictName, String reactantName, int reactantAmount) { - if(!_reactants.containsKey(reactantName)) { - throw new IllegalArgumentException("Unknown reactantName " + reactantName); - } - - OreDictToReactantMapping mapping = new OreDictToReactantMapping(oreDictName, reactantName, reactantAmount); - - _solidToReactant.put(mapping.getSource(), mapping); - - SourceProductMapping reverseMapping = mapping.getReverse(); - mapReactant(reverseMapping.getSource(), reverseMapping, _reactantToSolid); - return mapping; - } - - /** - * Register a raw ore dictionary name to convert to reactant. Uses standard quantities - * of 1 unit of ore = 1000 units of fuel. - * @param oreDictName OreDict name of the solid to register as a reactant. - * @param reactantName Name of the reactant. - */ - public static SourceProductMapping registerSolid(String oreDictName, String reactantName) { - if(!_reactants.containsKey(reactantName)) { - throw new IllegalArgumentException("Unknown reactantName " + reactantName); - } - - OreDictToReactantMapping mapping = new OreDictToReactantMapping(oreDictName, reactantName); - SourceProductMapping reverseMapping = mapping.getReverse(); - - _solidToReactant.put(mapping.getSource(), mapping); - mapReactant(reverseMapping.getSource(), reverseMapping, _reactantToSolid); - return mapping; - } - - /** - * Register a fluid as a valid reactant for the reactor. - * Currently unused. Will be used for the fluid fueling cycle in later releases. - * This method produces a fluidStack.amount : 1 ratio of fluid to reactant. - * Generally, you should pass in fluidStacks with an amount set to 1. - * @param fluidStack The fluid representing a unit of input to convert into reactant. Generally should be 1. - * @param reactantName The name of the reactant. - */ - public static void registerFluid(FluidStack fluidStack, String reactantName) { - if(!_reactants.containsKey(reactantName)) { - throw new IllegalArgumentException("Unknown reactantName " + reactantName); - } - - FluidToReactantMapping mapping = new FluidToReactantMapping(fluidStack, reactantName); - SourceProductMapping reverseMapping = mapping.getReverse(); - - _fluidToReactant.put(mapping.getSource(), mapping); - mapReactant(reverseMapping.getSource(), reverseMapping, _reactantToFluid); - } - - /** - * Register a fluid as a valid reactant for the reactor. - * Currently unused. - * This method enforces a 1:1 ratio for fluid mB to reactant mB. - * @param fluid The input fluid to convert to reactant. - * @param reactantName The name of the created reactant. - */ - public static void registerFluid(Fluid fluid, String reactantName) { - if(!_reactants.containsKey(reactantName)) { - throw new IllegalArgumentException("Unknown reactantName " + reactantName); - } - - FluidToReactantMapping mapping = new FluidToReactantMapping(fluid, reactantName); - SourceProductMapping reverseMapping = mapping.getReverse(); - - _fluidToReactant.put(mapping.getSource(), mapping); - mapReactant(reverseMapping.getSource(), reverseMapping, _reactantToFluid); - } - - //// GETTERS - public static boolean isKnown(String reactantName) { - return _reactants.containsKey(reactantName); - } - - public static ReactantData getReactant(String name) { - return _reactants.get(name); - } - - public static OreDictToReactantMapping getSolidToReactant(ItemStack item) { - return _solidToReactant.get(ItemHelper.oreProxy.getOreName(item)); - } - - public static FluidToReactantMapping getFluidToReactant(FluidStack fluid) { - return _fluidToReactant.get(fluid.getFluid().getName()); - } - - public static FluidToReactantMapping getFluidToReactant(Fluid fluid) { - return _fluidToReactant.get(fluid.getName()); - } - - /** - * @param reactant The reactant to query - * @return A. list of Reactant => OreDict mappings. Note that reactant is the source and OreDict names are the product. - */ - public static List getReactantToSolids(String reactant) { - return _reactantToSolid.get(reactant); - } - - public static List getFluidsForReactant(String reactant) { - return _reactantToFluid.get(reactant); - } - - /// CONVENIENCE METHODS - public static boolean isFuel(ItemStack stack) { - if(stack == null) { return false; } - - return isFuel(getReactantName(stack)); - } - - /** - * Returns the first registered reactant name for a given item stack, - * based on its ore dictionary entry. - * @param stack The item stack to query. - * @return The name of the reactant represented by this item stack, or null. - */ - public static String getReactantName(ItemStack stack) { - SourceProductMapping mapping = getSolidToReactant(stack); - return mapping != null ? mapping.getProduct() : null; - } - - /** - * Returns true if a given name represents a reactant. - * @param name - * @return - */ - public static boolean isFuel(String name) { - if(name == null) { return false; } - else { - ReactantData data = getReactant(name); - return data != null && data.isFuel(); - } - } - - public static boolean isWaste(ItemStack stack) { - if(stack == null) { return false; } - - return isWaste(getReactantName(stack)); - } - - public static boolean isWaste(String name) { - if(name == null) { return false; } - else { - ReactantData data = getReactant(name); - return data != null && data.isWaste(); - } - } - - /** - * @return The smallest amount of reactant found in a given reactant<>solid mapping set - * @throws IllegalArgumentException if no reactants were mapped. - */ - public static int getMinimumReactantToProduceSolid(String reactantName) { - List mappings = getReactantToSolids(reactantName); - if(mappings == null || mappings.size() <= 0) { - throw new IllegalArgumentException("No solid products mapped for reactant " + reactantName); - } - - int minimumAmount = Integer.MAX_VALUE; - for(SourceProductMapping mapping : mappings) { - if(mapping.getSourceAmount() < minimumAmount) { - minimumAmount = mapping.getSourceAmount(); - } - } - - return minimumAmount; - } - - //// HELPERS - private static void mapReactant(String reactantName, SourceProductMapping mapping, Map> map) { - List list = null; - if(!map.containsKey(reactantName) || map.get(reactantName) == null) { - list = new ArrayList(); - map.put(reactantName, list); - } - else { - list = map.get(reactantName); - list.add(mapping); - } - - list.add(mapping); - } + + public static final int standardSolidReactantAmount = 1000; // 1 item = 1000 mB, standard + public static final int standardFluidReactantAmount = 1; // 1 mB = 1 mB + + private static Map _reactants = new HashMap(); + + // 1:1 + private static Map _solidToReactant = new HashMap(); + private static Map _fluidToReactant = new HashMap(); + + // 1:many + private static Map> _reactantToSolid = new HashMap>(); + private static Map> _reactantToFluid = new HashMap>(); + + private static Map _reactorFluidToSolid = new HashMap(); + private static Set _reactorSolidToFuel = new CopyOnWriteArraySet(); // This + // won't + // work + private static Set _reactorSolidToWaste = new CopyOnWriteArraySet(); // This + // won't + // work + + private static Map _reactorFluids = new HashMap(); + + //// REGISTRATION + + /** + * Simple wrapper for quickly registering standard reactants. + * Sets default colors for fuel/waste. + * + * @param name Name of the reactant + * @param fuel True if fuel, false if waste. + */ + public static void registerReactant(String name, boolean fuel) { + registerReactant( + name, + fuel ? 0 : 1, + fuel ? BigReactors.defaultFluidColorFuel : BigReactors.defaultFluidColorWaste); + } + + /** + * Register a new type of reactant. + * + * @param name The name of the reactant. + * @param type The type of the reactant. 0 = fuel, 1 = waste. Other values unsupported. + * @param color The color of the reactant, format 0xRRGGBB. + */ + public static void registerReactant(String name, int type, int color) { + if (type < 0 || type >= ReactantData.s_Types.length) { + throw new IllegalArgumentException("Unsupported type; value may only be 0 or 1"); + } + + if (_reactants.containsKey(name)) { + BRLog.warning( + "Overwriting data for reactant %s - someone may be altering BR game data or have duplicate reactant names!", + name); + } + + ReactantData data = new ReactantData(name, ReactantData.s_Types[type], color); + _reactants.put(name, data); + } + + /** + * Register a solid ItemStack as a valid reactant for the reactor. + * For fuels, it will allow access ports to accept the item in the inlet slot. + * For wastes, it will allow access ports to eject the item into the outlet slot. + * + * @param itemStack The item which represents a reactant. Its quantity indicates how many items will be used to + * make 1000mB of reactant. + * @param reactantName The name of the reactant. + */ + public static SourceProductMapping registerSolid(ItemStack itemStack, String reactantName) { + if (!_reactants.containsKey(reactantName)) { + throw new IllegalArgumentException("Unknown reactantName " + reactantName); + } + + ArrayList oreDictNames = OreDictionaryArbiter.getAllOreNames(itemStack); + if (oreDictNames == null || oreDictNames.size() < 1) { + BRLog.warning( + "Reactants.registerSolid: Could not resolve ore dict name for %s", + itemStack.getUnlocalizedName()); + return null; + } + + SourceProductMapping firstMapping = null; + + for (String name : oreDictNames) { + OreDictToReactantMapping mapping = new OreDictToReactantMapping(name, reactantName); + SourceProductMapping reverseMapping = mapping.getReverse(); + _solidToReactant.put(mapping.getSource(), mapping); + mapReactant(reverseMapping.getSource(), reverseMapping, _reactantToSolid); + + if (firstMapping == null) { + firstMapping = mapping; + } + } + + return firstMapping; + } + + /** + * Register a solid ItemStack as a valid reactant for the reactor. + * For fuels, it will allow access ports to accept the item in the inlet slot. + * For wastes, it will allow access ports to eject the item into the outlet slot. + * + * @param itemStack The item which represents a reactant. Its quantity indicates how many items will be used to + * make the defined units of reactant. + * @param reactantName The name of the reactant. + * @param reactantQty The quantity of the reactant produced by the itemStack.stackSize units of the item. + */ + public static SourceProductMapping registerSolid(ItemStack itemStack, String reactantName, int reactantQty) { + if (!_reactants.containsKey(reactantName)) { + throw new IllegalArgumentException("Unknown reactantName " + reactantName); + } + + ArrayList oreDictNames = OreDictionaryArbiter.getAllOreNames(itemStack); + if (oreDictNames == null || oreDictNames.size() < 1) { + BRLog.warning( + "Reactants.registerSolid: Could not resolve ore dict name for %s", + itemStack.getUnlocalizedName()); + return null; + } + + SourceProductMapping firstMapping = null; + + for (String name : oreDictNames) { + OreDictToReactantMapping mapping = new OreDictToReactantMapping(name, reactantName, reactantQty); + SourceProductMapping reverseMapping = mapping.getReverse(); + _solidToReactant.put(mapping.getSource(), mapping); + mapReactant(reverseMapping.getSource(), reverseMapping, _reactantToSolid); + + if (firstMapping == null) { + firstMapping = mapping; + } + } + + return firstMapping; + } + + /** + * Register a raw ore dictionary name to convert to reactant. Uses standard quantities + * of 1 unit of ore = 1000 units of fuel. + * + * @param oreDictName OreDict name of the solid to register as a reactant. + * @param reactantName Name of the reactant. + */ + public static SourceProductMapping registerSolid(String oreDictName, String reactantName, int reactantAmount) { + if (!_reactants.containsKey(reactantName)) { + throw new IllegalArgumentException("Unknown reactantName " + reactantName); + } + + OreDictToReactantMapping mapping = new OreDictToReactantMapping(oreDictName, reactantName, reactantAmount); + + _solidToReactant.put(mapping.getSource(), mapping); + + SourceProductMapping reverseMapping = mapping.getReverse(); + mapReactant(reverseMapping.getSource(), reverseMapping, _reactantToSolid); + return mapping; + } + + /** + * Register a raw ore dictionary name to convert to reactant. Uses standard quantities + * of 1 unit of ore = 1000 units of fuel. + * + * @param oreDictName OreDict name of the solid to register as a reactant. + * @param reactantName Name of the reactant. + */ + public static SourceProductMapping registerSolid(String oreDictName, String reactantName) { + if (!_reactants.containsKey(reactantName)) { + throw new IllegalArgumentException("Unknown reactantName " + reactantName); + } + + OreDictToReactantMapping mapping = new OreDictToReactantMapping(oreDictName, reactantName); + SourceProductMapping reverseMapping = mapping.getReverse(); + + _solidToReactant.put(mapping.getSource(), mapping); + mapReactant(reverseMapping.getSource(), reverseMapping, _reactantToSolid); + return mapping; + } + + /** + * Register a fluid as a valid reactant for the reactor. + * Currently unused. Will be used for the fluid fueling cycle in later releases. + * This method produces a fluidStack.amount : 1 ratio of fluid to reactant. + * Generally, you should pass in fluidStacks with an amount set to 1. + * + * @param fluidStack The fluid representing a unit of input to convert into reactant. Generally should be 1. + * @param reactantName The name of the reactant. + */ + public static void registerFluid(FluidStack fluidStack, String reactantName) { + if (!_reactants.containsKey(reactantName)) { + throw new IllegalArgumentException("Unknown reactantName " + reactantName); + } + + FluidToReactantMapping mapping = new FluidToReactantMapping(fluidStack, reactantName); + SourceProductMapping reverseMapping = mapping.getReverse(); + + _fluidToReactant.put(mapping.getSource(), mapping); + mapReactant(reverseMapping.getSource(), reverseMapping, _reactantToFluid); + } + + /** + * Register a fluid as a valid reactant for the reactor. + * Currently unused. + * This method enforces a 1:1 ratio for fluid mB to reactant mB. + * + * @param fluid The input fluid to convert to reactant. + * @param reactantName The name of the created reactant. + */ + public static void registerFluid(Fluid fluid, String reactantName) { + if (!_reactants.containsKey(reactantName)) { + throw new IllegalArgumentException("Unknown reactantName " + reactantName); + } + + FluidToReactantMapping mapping = new FluidToReactantMapping(fluid, reactantName); + SourceProductMapping reverseMapping = mapping.getReverse(); + + _fluidToReactant.put(mapping.getSource(), mapping); + mapReactant(reverseMapping.getSource(), reverseMapping, _reactantToFluid); + } + + //// GETTERS + public static boolean isKnown(String reactantName) { + return _reactants.containsKey(reactantName); + } + + public static ReactantData getReactant(String name) { + return _reactants.get(name); + } + + public static OreDictToReactantMapping getSolidToReactant(ItemStack item) { + return _solidToReactant.get(ItemHelper.oreProxy.getOreName(item)); + } + + public static FluidToReactantMapping getFluidToReactant(FluidStack fluid) { + return _fluidToReactant.get( + fluid.getFluid() + .getName()); + } + + public static FluidToReactantMapping getFluidToReactant(Fluid fluid) { + return _fluidToReactant.get(fluid.getName()); + } + + /** + * @param reactant The reactant to query + * @return A. list of Reactant => OreDict mappings. Note that reactant is the source and OreDict names are the + * product. + */ + public static List getReactantToSolids(String reactant) { + return _reactantToSolid.get(reactant); + } + + public static List getFluidsForReactant(String reactant) { + return _reactantToFluid.get(reactant); + } + + /// CONVENIENCE METHODS + public static boolean isFuel(ItemStack stack) { + if (stack == null) { + return false; + } + + return isFuel(getReactantName(stack)); + } + + /** + * Returns the first registered reactant name for a given item stack, + * based on its ore dictionary entry. + * + * @param stack The item stack to query. + * @return The name of the reactant represented by this item stack, or null. + */ + public static String getReactantName(ItemStack stack) { + SourceProductMapping mapping = getSolidToReactant(stack); + return mapping != null ? mapping.getProduct() : null; + } + + /** + * Returns true if a given name represents a reactant. + * + * @param name + * @return + */ + public static boolean isFuel(String name) { + if (name == null) { + return false; + } else { + ReactantData data = getReactant(name); + return data != null && data.isFuel(); + } + } + + public static boolean isWaste(ItemStack stack) { + if (stack == null) { + return false; + } + + return isWaste(getReactantName(stack)); + } + + public static boolean isWaste(String name) { + if (name == null) { + return false; + } else { + ReactantData data = getReactant(name); + return data != null && data.isWaste(); + } + } + + /** + * @return The smallest amount of reactant found in a given reactant<>solid mapping set + * @throws IllegalArgumentException if no reactants were mapped. + */ + public static int getMinimumReactantToProduceSolid(String reactantName) { + List mappings = getReactantToSolids(reactantName); + if (mappings == null || mappings.size() <= 0) { + throw new IllegalArgumentException("No solid products mapped for reactant " + reactantName); + } + + int minimumAmount = Integer.MAX_VALUE; + for (SourceProductMapping mapping : mappings) { + if (mapping.getSourceAmount() < minimumAmount) { + minimumAmount = mapping.getSourceAmount(); + } + } + + return minimumAmount; + } + + //// HELPERS + private static void mapReactant(String reactantName, SourceProductMapping mapping, + Map> map) { + List list = null; + if (!map.containsKey(reactantName) || map.get(reactantName) == null) { + list = new ArrayList(); + map.put(reactantName, list); + } else { + list = map.get(reactantName); + list.add(mapping); + } + + list.add(mapping); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/api/registry/ReactorConversions.java b/src/main/java/erogenousbeef/bigreactors/api/registry/ReactorConversions.java index 076ff691..2558ccfe 100644 --- a/src/main/java/erogenousbeef/bigreactors/api/registry/ReactorConversions.java +++ b/src/main/java/erogenousbeef/bigreactors/api/registry/ReactorConversions.java @@ -8,29 +8,37 @@ public class ReactorConversions { - // Source Reactant Name => Reaction Data - private static Map _reactions = new HashMap(); - - public static void register(String sourceName, String productName) { - if(_reactions.containsKey(sourceName)) { - BRLog.warning("Overwriting %s => %s reaction mapping! Someone may be fiddling with Big Reactors game data!", sourceName, productName); - } - - ReactorReaction mapping = new ReactorReaction(sourceName, productName); - _reactions.put(sourceName, mapping); - } - - public static void register(String sourceName, String productName, float reactivity, float fissionRate) { - if(_reactions.containsKey(sourceName)) { - BRLog.warning("Overwriting %s => %s reaction mapping! Someone may be fiddling with Big Reactors game data!", sourceName, productName); - } - - ReactorReaction mapping = new ReactorReaction(sourceName, productName, reactivity, fissionRate); - _reactions.put(sourceName, mapping); - } - - public static ReactorReaction get(String sourceReactant) { - if(sourceReactant == null) { return null; } - return _reactions.get(sourceReactant); - } + // Source Reactant Name => Reaction Data + private static Map _reactions = new HashMap(); + + public static void register(String sourceName, String productName) { + if (_reactions.containsKey(sourceName)) { + BRLog.warning( + "Overwriting %s => %s reaction mapping! Someone may be fiddling with Big Reactors game data!", + sourceName, + productName); + } + + ReactorReaction mapping = new ReactorReaction(sourceName, productName); + _reactions.put(sourceName, mapping); + } + + public static void register(String sourceName, String productName, float reactivity, float fissionRate) { + if (_reactions.containsKey(sourceName)) { + BRLog.warning( + "Overwriting %s => %s reaction mapping! Someone may be fiddling with Big Reactors game data!", + sourceName, + productName); + } + + ReactorReaction mapping = new ReactorReaction(sourceName, productName, reactivity, fissionRate); + _reactions.put(sourceName, mapping); + } + + public static ReactorReaction get(String sourceReactant) { + if (sourceReactant == null) { + return null; + } + return _reactions.get(sourceReactant); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/api/registry/ReactorInterior.java b/src/main/java/erogenousbeef/bigreactors/api/registry/ReactorInterior.java index ee53aee9..f3cedbc0 100644 --- a/src/main/java/erogenousbeef/bigreactors/api/registry/ReactorInterior.java +++ b/src/main/java/erogenousbeef/bigreactors/api/registry/ReactorInterior.java @@ -7,50 +7,53 @@ import erogenousbeef.bigreactors.common.BRLog; public class ReactorInterior { - private static Map _reactorModeratorBlocks = new HashMap(); - private static Map _reactorModeratorFluids = new HashMap(); - - /** - * @param absorption How much radiation this material absorbs and converts to heat. 0.0 = none, 1.0 = all. - * @param heatEfficiency How efficiently radiation is converted to heat. 0 = no heat, 1 = all heat. - * @param moderation How well this material moderates radiation. This is a divisor; should not be below 1. - */ - public static void registerBlock(String oreDictName, float absorption, float heatEfficiency, float moderation, float heatConductivity) { - if(_reactorModeratorBlocks.containsKey(oreDictName)) { - BRLog.warning("Overriding existing radiation moderator block data for oredict name <%s>", oreDictName); - ReactorInteriorData data = _reactorModeratorBlocks.get(oreDictName); - data.absorption = absorption; - data.heatEfficiency = heatEfficiency; - data.moderation = moderation; - } - else { - _reactorModeratorBlocks.put(oreDictName, new ReactorInteriorData(absorption, heatEfficiency, moderation, heatConductivity)); - } - } - - /** - * @param absorption How much radiation this material absorbs and converts to heat. 0.0 = none, 1.0 = all. - * @param heatEfficiency How efficiently radiation is converted to heat. 0 = no heat, 1 = all heat. - * @param moderation How well this material moderates radiation. This is a divisor; should not be below 1. - */ - public static void registerFluid(String fluidName, float absorption, float heatEfficiency, float moderation, float heatConductivity) { - if(_reactorModeratorFluids.containsKey(fluidName)) { - BRLog.warning("Overriding existing radiation moderator fluid data for fluid name <%s>", fluidName); - ReactorInteriorData data = _reactorModeratorFluids.get(fluidName); - data.absorption = absorption; - data.heatEfficiency = heatEfficiency; - data.moderation = moderation; - } - else { - _reactorModeratorFluids.put(fluidName, new ReactorInteriorData(absorption, heatEfficiency, moderation, heatConductivity)); - } - } - - public static ReactorInteriorData getBlockData(String oreDictName) { - return _reactorModeratorBlocks.get(oreDictName); - } - - public static ReactorInteriorData getFluidData(String fluidName) { - return _reactorModeratorFluids.get(fluidName); - } + + private static Map _reactorModeratorBlocks = new HashMap(); + private static Map _reactorModeratorFluids = new HashMap(); + + /** + * @param absorption How much radiation this material absorbs and converts to heat. 0.0 = none, 1.0 = all. + * @param heatEfficiency How efficiently radiation is converted to heat. 0 = no heat, 1 = all heat. + * @param moderation How well this material moderates radiation. This is a divisor; should not be below 1. + */ + public static void registerBlock(String oreDictName, float absorption, float heatEfficiency, float moderation, + float heatConductivity) { + if (_reactorModeratorBlocks.containsKey(oreDictName)) { + BRLog.warning("Overriding existing radiation moderator block data for oredict name <%s>", oreDictName); + ReactorInteriorData data = _reactorModeratorBlocks.get(oreDictName); + data.absorption = absorption; + data.heatEfficiency = heatEfficiency; + data.moderation = moderation; + } else { + _reactorModeratorBlocks + .put(oreDictName, new ReactorInteriorData(absorption, heatEfficiency, moderation, heatConductivity)); + } + } + + /** + * @param absorption How much radiation this material absorbs and converts to heat. 0.0 = none, 1.0 = all. + * @param heatEfficiency How efficiently radiation is converted to heat. 0 = no heat, 1 = all heat. + * @param moderation How well this material moderates radiation. This is a divisor; should not be below 1. + */ + public static void registerFluid(String fluidName, float absorption, float heatEfficiency, float moderation, + float heatConductivity) { + if (_reactorModeratorFluids.containsKey(fluidName)) { + BRLog.warning("Overriding existing radiation moderator fluid data for fluid name <%s>", fluidName); + ReactorInteriorData data = _reactorModeratorFluids.get(fluidName); + data.absorption = absorption; + data.heatEfficiency = heatEfficiency; + data.moderation = moderation; + } else { + _reactorModeratorFluids + .put(fluidName, new ReactorInteriorData(absorption, heatEfficiency, moderation, heatConductivity)); + } + } + + public static ReactorInteriorData getBlockData(String oreDictName) { + return _reactorModeratorBlocks.get(oreDictName); + } + + public static ReactorInteriorData getFluidData(String fluidName) { + return _reactorModeratorFluids.get(fluidName); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/api/registry/TurbineCoil.java b/src/main/java/erogenousbeef/bigreactors/api/registry/TurbineCoil.java index 575d15f0..5cc15303 100644 --- a/src/main/java/erogenousbeef/bigreactors/api/registry/TurbineCoil.java +++ b/src/main/java/erogenousbeef/bigreactors/api/registry/TurbineCoil.java @@ -7,27 +7,35 @@ import erogenousbeef.bigreactors.common.BRLog; public class TurbineCoil { - private static Map _blocks = new HashMap(); - /** - * Register a block as permissible in a turbine's inductor coil. - * @param oreDictName Name of the block, as registered in the ore dictionary - * @param efficiency Efficiency of the block. 1.0 == iron, 2.0 == gold, etc. - * @param bonus Energy bonus of the block, if any. Normally 1.0. This is an exponential term and should only be used for EXTREMELY rare blocks! - */ - public static void registerBlock(String oreDictName, float efficiency, float bonus, float extractionRate) { - if(_blocks.containsKey(oreDictName)) { - CoilPartData data = _blocks.get(oreDictName); - BRLog.warning("Overriding existing coil part data for oredict name <%s>, original values: eff %.2f / bonus %.2f, new values: eff %.2f / bonus %.2f", oreDictName, data.efficiency, data.bonus, efficiency, bonus); - data.efficiency = efficiency; - data.bonus = bonus; - } - else { - _blocks.put(oreDictName, new CoilPartData(efficiency, bonus, extractionRate)); - } - } + private static Map _blocks = new HashMap(); - public static CoilPartData getBlockData(String oreDictName) { - return _blocks.get(oreDictName); - } + /** + * Register a block as permissible in a turbine's inductor coil. + * + * @param oreDictName Name of the block, as registered in the ore dictionary + * @param efficiency Efficiency of the block. 1.0 == iron, 2.0 == gold, etc. + * @param bonus Energy bonus of the block, if any. Normally 1.0. This is an exponential term and should only + * be used for EXTREMELY rare blocks! + */ + public static void registerBlock(String oreDictName, float efficiency, float bonus, float extractionRate) { + if (_blocks.containsKey(oreDictName)) { + CoilPartData data = _blocks.get(oreDictName); + BRLog.warning( + "Overriding existing coil part data for oredict name <%s>, original values: eff %.2f / bonus %.2f, new values: eff %.2f / bonus %.2f", + oreDictName, + data.efficiency, + data.bonus, + efficiency, + bonus); + data.efficiency = efficiency; + data.bonus = bonus; + } else { + _blocks.put(oreDictName, new CoilPartData(efficiency, bonus, extractionRate)); + } + } + + public static CoilPartData getBlockData(String oreDictName) { + return _blocks.get(oreDictName); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/client/BRRenderTickHandler.java b/src/main/java/erogenousbeef/bigreactors/client/BRRenderTickHandler.java index d71dded5..4038b4d3 100644 --- a/src/main/java/erogenousbeef/bigreactors/client/BRRenderTickHandler.java +++ b/src/main/java/erogenousbeef/bigreactors/client/BRRenderTickHandler.java @@ -1,6 +1,7 @@ package erogenousbeef.bigreactors.client; import net.minecraft.client.Minecraft; + import cpw.mods.fml.common.eventhandler.SubscribeEvent; import cpw.mods.fml.common.gameevent.TickEvent; @@ -8,7 +9,7 @@ public class BRRenderTickHandler { @SubscribeEvent public void onRenderTick(TickEvent.RenderTickEvent event) { - if(event.phase == TickEvent.Phase.END) { + if (event.phase == TickEvent.Phase.END) { ClientProxy.lastRenderTime = Minecraft.getSystemTime(); } } diff --git a/src/main/java/erogenousbeef/bigreactors/client/BeefIconManager.java b/src/main/java/erogenousbeef/bigreactors/client/BeefIconManager.java index 2ccc4bc6..9bc9cd54 100644 --- a/src/main/java/erogenousbeef/bigreactors/client/BeefIconManager.java +++ b/src/main/java/erogenousbeef/bigreactors/client/BeefIconManager.java @@ -18,47 +18,54 @@ */ public abstract class BeefIconManager { - public static final int TERRAIN_TEXTURE = 0; - public static final int ITEM_TEXTURE = 1; - - private HashMap nameToIdMap; - private HashMap idToIconMap; - - public String[] iconNames = null; - - protected abstract String[] getIconNames(); - protected abstract String getPath(); - - public BeefIconManager() { - nameToIdMap = Maps.newHashMap(); + public static final int TERRAIN_TEXTURE = 0; + public static final int ITEM_TEXTURE = 1; + + private HashMap nameToIdMap; + private HashMap idToIconMap; + + public String[] iconNames = null; + + protected abstract String[] getIconNames(); + + protected abstract String getPath(); + + public BeefIconManager() { + nameToIdMap = Maps.newHashMap(); idToIconMap = Maps.newHashMap(); iconNames = getIconNames(); - } - - public void registerIcons(TextureMap textureMap) { - if(iconNames == null) { return; } - - for(int i = 0; i < iconNames.length; i++) { - nameToIdMap.put(iconNames[i], i); - idToIconMap.put(i, textureMap.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getPath() + iconNames[i])); - } - } - - public IIcon getIcon(String name) { - if(name == null || name.isEmpty()) { return null; } - - Integer id = nameToIdMap.get(name); - if(id == null) { - return null; - } - - return idToIconMap.get(id); - } - - public IIcon getIcon(int id) { - return idToIconMap.get(id); - } - - public int getTextureType() { return TERRAIN_TEXTURE; } - -} \ No newline at end of file + } + + public void registerIcons(TextureMap textureMap) { + if (iconNames == null) { + return; + } + + for (int i = 0; i < iconNames.length; i++) { + nameToIdMap.put(iconNames[i], i); + idToIconMap.put(i, textureMap.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getPath() + iconNames[i])); + } + } + + public IIcon getIcon(String name) { + if (name == null || name.isEmpty()) { + return null; + } + + Integer id = nameToIdMap.get(name); + if (id == null) { + return null; + } + + return idToIconMap.get(id); + } + + public IIcon getIcon(int id) { + return idToIconMap.get(id); + } + + public int getTextureType() { + return TERRAIN_TEXTURE; + } + +} diff --git a/src/main/java/erogenousbeef/bigreactors/client/ClientProxy.java b/src/main/java/erogenousbeef/bigreactors/client/ClientProxy.java index 855d1213..7d60cf1c 100644 --- a/src/main/java/erogenousbeef/bigreactors/client/ClientProxy.java +++ b/src/main/java/erogenousbeef/bigreactors/client/ClientProxy.java @@ -4,6 +4,7 @@ import net.minecraft.client.Minecraft; import net.minecraftforge.client.event.TextureStitchEvent; + import cpw.mods.fml.client.FMLClientHandler; import cpw.mods.fml.client.registry.ClientRegistry; import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; @@ -28,67 +29,74 @@ @SideOnly(Side.CLIENT) public class ClientProxy extends CommonProxy { - public static BeefGuiIconManager GuiIcons; - public static CommonBlockIconManager CommonBlockIcons; - - public static long lastRenderTime = Minecraft.getSystemTime(); - - public ClientProxy() { - GuiIcons = new BeefGuiIconManager(); - CommonBlockIcons = new CommonBlockIconManager(); - } - - @Override - public void preInit() {} - - @Override - public void init() - { - super.init(); - - FMLCommonHandler.instance().bus().register(new MultiblockClientTickHandler()); - FMLCommonHandler.instance().bus().register(new BRRenderTickHandler()); - - BlockFuelRod.renderId = RenderingRegistry.getNextAvailableRenderId(); - ISimpleBlockRenderingHandler fuelRodISBRH = new SimpleRendererFuelRod(); - RenderingRegistry.registerBlockHandler(BlockFuelRod.renderId, fuelRodISBRH); - - BlockTurbineRotorPart.renderId = RenderingRegistry.getNextAvailableRenderId(); - ISimpleBlockRenderingHandler rotorISBRH = new RotorSimpleRenderer(); - RenderingRegistry.registerBlockHandler(BlockTurbineRotorPart.renderId, rotorISBRH); - - if(BigReactors.blockTurbinePart != null) { - ClientRegistry.bindTileEntitySpecialRenderer(TileEntityTurbineRotorBearing.class, new RotorSpecialRenderer()); - } - } - - @Override - @SideOnly(Side.CLIENT) - @SubscribeEvent - public void registerIcons(TextureStitchEvent.Pre event) { - if(event.map.getTextureType() == BeefIconManager.TERRAIN_TEXTURE) { - BigReactors.registerNonBlockFluidIcons(event.map); - GuiIcons.registerIcons(event.map); - CommonBlockIcons.registerIcons(event.map); - } - // else if(event.map.textureType == BeefIconManager.ITEM_TEXTURE) { } - - // Reset any controllers which have TESRs which cache displaylists with UV data in 'em - // This is necessary in case a texture pack changes UV coordinates on us - Set controllers = MultiblockRegistry.getControllersFromWorld(FMLClientHandler.instance().getClient().theWorld); - if(controllers != null) { - for(MultiblockControllerBase controller: controllers) { - if(controller instanceof MultiblockTurbine) { - ((MultiblockTurbine)controller).resetCachedRotors(); - } - } - } - } - - @Override - @SideOnly(Side.CLIENT) - @SubscribeEvent - public void setIcons(TextureStitchEvent.Post event) { - BigReactors.setNonBlockFluidIcons(); - } + + public static BeefGuiIconManager GuiIcons; + public static CommonBlockIconManager CommonBlockIcons; + + public static long lastRenderTime = Minecraft.getSystemTime(); + + public ClientProxy() { + GuiIcons = new BeefGuiIconManager(); + CommonBlockIcons = new CommonBlockIconManager(); + } + + @Override + public void preInit() {} + + @Override + public void init() { + super.init(); + + FMLCommonHandler.instance() + .bus() + .register(new MultiblockClientTickHandler()); + FMLCommonHandler.instance() + .bus() + .register(new BRRenderTickHandler()); + + BlockFuelRod.renderId = RenderingRegistry.getNextAvailableRenderId(); + ISimpleBlockRenderingHandler fuelRodISBRH = new SimpleRendererFuelRod(); + RenderingRegistry.registerBlockHandler(BlockFuelRod.renderId, fuelRodISBRH); + + BlockTurbineRotorPart.renderId = RenderingRegistry.getNextAvailableRenderId(); + ISimpleBlockRenderingHandler rotorISBRH = new RotorSimpleRenderer(); + RenderingRegistry.registerBlockHandler(BlockTurbineRotorPart.renderId, rotorISBRH); + + if (BigReactors.blockTurbinePart != null) { + ClientRegistry + .bindTileEntitySpecialRenderer(TileEntityTurbineRotorBearing.class, new RotorSpecialRenderer()); + } + } + + @Override + @SideOnly(Side.CLIENT) + @SubscribeEvent + public void registerIcons(TextureStitchEvent.Pre event) { + if (event.map.getTextureType() == BeefIconManager.TERRAIN_TEXTURE) { + BigReactors.registerNonBlockFluidIcons(event.map); + GuiIcons.registerIcons(event.map); + CommonBlockIcons.registerIcons(event.map); + } + // else if(event.map.textureType == BeefIconManager.ITEM_TEXTURE) { } + + // Reset any controllers which have TESRs which cache displaylists with UV data in 'em + // This is necessary in case a texture pack changes UV coordinates on us + Set controllers = MultiblockRegistry.getControllersFromWorld( + FMLClientHandler.instance() + .getClient().theWorld); + if (controllers != null) { + for (MultiblockControllerBase controller : controllers) { + if (controller instanceof MultiblockTurbine) { + ((MultiblockTurbine) controller).resetCachedRotors(); + } + } + } + } + + @Override + @SideOnly(Side.CLIENT) + @SubscribeEvent + public void setIcons(TextureStitchEvent.Post event) { + BigReactors.setNonBlockFluidIcons(); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/client/CommonBlockIconManager.java b/src/main/java/erogenousbeef/bigreactors/client/CommonBlockIconManager.java index 7d6311ab..f5ea1785 100644 --- a/src/main/java/erogenousbeef/bigreactors/client/CommonBlockIconManager.java +++ b/src/main/java/erogenousbeef/bigreactors/client/CommonBlockIconManager.java @@ -1,29 +1,21 @@ package erogenousbeef.bigreactors.client; - public class CommonBlockIconManager extends BeefIconManager { - public static final int DEFAULT = 0; - public static final int OPEN = 1; - public static final int ITEM_RED = 2; - public static final int ITEM_GREEN = 3; - public static final int FLUID_BLUE = 4; - public static final int FLUID_WHITE = 5; - - @Override - protected String[] getIconNames() { - return new String[] { - "default", - "open", - "itemRed", - "itemGreen", - "fluidBlue", - "fluidWhite" - }; - } + public static final int DEFAULT = 0; + public static final int OPEN = 1; + public static final int ITEM_RED = 2; + public static final int ITEM_GREEN = 3; + public static final int FLUID_BLUE = 4; + public static final int FLUID_WHITE = 5; + + @Override + protected String[] getIconNames() { + return new String[] { "default", "open", "itemRed", "itemGreen", "fluidBlue", "fluidWhite" }; + } - @Override - protected String getPath() { - return "common/"; - } + @Override + protected String getPath() { + return "common/"; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/client/gui/BeefGuiBase.java b/src/main/java/erogenousbeef/bigreactors/client/gui/BeefGuiBase.java index 0877cbcc..a1260c88 100644 --- a/src/main/java/erogenousbeef/bigreactors/client/gui/BeefGuiBase.java +++ b/src/main/java/erogenousbeef/bigreactors/client/gui/BeefGuiBase.java @@ -26,130 +26,138 @@ @SideOnly(Side.CLIENT) public abstract class BeefGuiBase extends GuiContainer { - protected List controls; - protected List controlsWithTooltips; - protected List textFields; - - protected IBeefGuiGrabbable grabbedItem; - - public BeefGuiBase(Container container) { - super(container); - - grabbedItem = null; - } - - @Override - public void initGui() { - super.initGui(); - - // Refresh all controls so that the GUI is resize-proof - controls = new ArrayList(); - controlsWithTooltips = new ArrayList(); - textFields = new ArrayList(); - } - - public void registerControl(GuiTextField newTextField) { - textFields.add(newTextField); - } - - public void registerControl(IBeefGuiControl newControl) { - controls.add(newControl); - - if(newControl instanceof IBeefTooltipControl) { - controlsWithTooltips.add((IBeefTooltipControl) newControl); - } - } - - public void registerControl(GuiButton newButton) { - this.buttonList.add(newButton); - - if(newButton instanceof IBeefTooltipControl) { - controlsWithTooltips.add((IBeefTooltipControl) newButton); - } - } - - public FontRenderer getFontRenderer() { return this.fontRendererObj; } - - @Override - protected void drawGuiContainerBackgroundLayer(float gameTicks, int mouseX, int mouseY) { - GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); - this.mc.renderEngine.bindTexture(getGuiBackground()); - this.drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize); - - int relativeX, relativeY; - relativeX = mouseX - this.guiLeft; - relativeY = mouseY - this.guiTop; - for(IBeefGuiControl c : controls) { - c.drawBackground(this.mc.renderEngine, relativeX, relativeY); - } - - for(GuiTextField field : textFields) { - field.drawTextBox(); - } - } - - // Override to draw your custom controls - @Override - protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { - int absoluteX, absoluteY; - absoluteX = mouseX - this.guiLeft; - absoluteY = mouseY - this.guiTop; - for(IBeefGuiControl c : controls) { - c.drawForeground(this.mc.renderEngine, mouseX, mouseY); - } - - for(IBeefTooltipControl tc: controlsWithTooltips) { - if(tc.isVisible() && tc.isMouseOver(mouseX, mouseY)) { - String[] tooltip = tc.getTooltip(); - if(tooltip != null) { - // This prevents weird rendering issues with NEI - GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); - drawHoveringText(Arrays.asList(tooltip), absoluteX, absoluteY, fontRendererObj); - GL11.glPopAttrib(); - break; - } - } - } - - if(this.grabbedItem != null) { - // Render grabbed item next to mouse + protected List controls; + protected List controlsWithTooltips; + protected List textFields; + + protected IBeefGuiGrabbable grabbedItem; + + public BeefGuiBase(Container container) { + super(container); + + grabbedItem = null; + } + + @Override + public void initGui() { + super.initGui(); + + // Refresh all controls so that the GUI is resize-proof + controls = new ArrayList(); + controlsWithTooltips = new ArrayList(); + textFields = new ArrayList(); + } + + public void registerControl(GuiTextField newTextField) { + textFields.add(newTextField); + } + + public void registerControl(IBeefGuiControl newControl) { + controls.add(newControl); + + if (newControl instanceof IBeefTooltipControl) { + controlsWithTooltips.add((IBeefTooltipControl) newControl); + } + } + + public void registerControl(GuiButton newButton) { + this.buttonList.add(newButton); + + if (newButton instanceof IBeefTooltipControl) { + controlsWithTooltips.add((IBeefTooltipControl) newButton); + } + } + + public FontRenderer getFontRenderer() { + return this.fontRendererObj; + } + + @Override + protected void drawGuiContainerBackgroundLayer(float gameTicks, int mouseX, int mouseY) { + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + this.mc.renderEngine.bindTexture(getGuiBackground()); + this.drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize); + + int relativeX, relativeY; + relativeX = mouseX - this.guiLeft; + relativeY = mouseY - this.guiTop; + for (IBeefGuiControl c : controls) { + c.drawBackground(this.mc.renderEngine, relativeX, relativeY); + } + + for (GuiTextField field : textFields) { + field.drawTextBox(); + } + } + + // Override to draw your custom controls + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + int absoluteX, absoluteY; + absoluteX = mouseX - this.guiLeft; + absoluteY = mouseY - this.guiTop; + for (IBeefGuiControl c : controls) { + c.drawForeground(this.mc.renderEngine, mouseX, mouseY); + } + + for (IBeefTooltipControl tc : controlsWithTooltips) { + if (tc.isVisible() && tc.isMouseOver(mouseX, mouseY)) { + String[] tooltip = tc.getTooltip(); + if (tooltip != null) { + // This prevents weird rendering issues with NEI + GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); + drawHoveringText(Arrays.asList(tooltip), absoluteX, absoluteY, fontRendererObj); + GL11.glPopAttrib(); + break; + } + } + } + + if (this.grabbedItem != null) { + // Render grabbed item next to mouse this.mc.renderEngine.bindTexture(TextureMap.locationBlocksTexture); GL11.glColor4f(1f, 1f, 1f, 1f); - this.drawTexturedModelRectFromIcon(absoluteX+1, absoluteY+1, this.grabbedItem.getIcon(), 16, 16); - } - } - - @Override - protected void mouseClicked(int x, int y, int buttonIndex) { - super.mouseClicked(x, y, buttonIndex); - for(GuiTextField field : textFields) { - field.mouseClicked(x, y, buttonIndex); - } - - for(IBeefGuiControl c: controls) { - c.onMouseClicked(x, y, buttonIndex); - } - } - - public abstract ResourceLocation getGuiBackground(); - - public int getGuiLeft() { return guiLeft; } - public int getGuiTop() { return guiTop; } - - public void onListBoxSelectionChanged(BeefGuiListBox listBox, IBeefListBoxEntry selectedEntry) {} - public void onListBoxEntryClicked(BeefGuiListBox listBox, IBeefListBoxEntry clickedEntry) {} - - public void setGrabbedItem(IBeefGuiGrabbable grabbedSource) { - this.grabbedItem = grabbedSource; - } - - public IBeefGuiGrabbable getGrabbedItem() { - return this.grabbedItem; - } - - public void onControlClicked(IBeefGuiControl control) {} - - protected static boolean isAltKeyDown() { - return Keyboard.isKeyDown(Keyboard.KEY_LMENU) || Keyboard.isKeyDown(Keyboard.KEY_RMENU); - } + this.drawTexturedModelRectFromIcon(absoluteX + 1, absoluteY + 1, this.grabbedItem.getIcon(), 16, 16); + } + } + + @Override + protected void mouseClicked(int x, int y, int buttonIndex) { + super.mouseClicked(x, y, buttonIndex); + for (GuiTextField field : textFields) { + field.mouseClicked(x, y, buttonIndex); + } + + for (IBeefGuiControl c : controls) { + c.onMouseClicked(x, y, buttonIndex); + } + } + + public abstract ResourceLocation getGuiBackground(); + + public int getGuiLeft() { + return guiLeft; + } + + public int getGuiTop() { + return guiTop; + } + + public void onListBoxSelectionChanged(BeefGuiListBox listBox, IBeefListBoxEntry selectedEntry) {} + + public void onListBoxEntryClicked(BeefGuiListBox listBox, IBeefListBoxEntry clickedEntry) {} + + public void setGrabbedItem(IBeefGuiGrabbable grabbedSource) { + this.grabbedItem = grabbedSource; + } + + public IBeefGuiGrabbable getGrabbedItem() { + return this.grabbedItem; + } + + public void onControlClicked(IBeefGuiControl control) {} + + protected static boolean isAltKeyDown() { + return Keyboard.isKeyDown(Keyboard.KEY_LMENU) || Keyboard.isKeyDown(Keyboard.KEY_RMENU); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/client/gui/BeefGuiDeviceBase.java b/src/main/java/erogenousbeef/bigreactors/client/gui/BeefGuiDeviceBase.java index 7f417a2a..fb7a5833 100644 --- a/src/main/java/erogenousbeef/bigreactors/client/gui/BeefGuiDeviceBase.java +++ b/src/main/java/erogenousbeef/bigreactors/client/gui/BeefGuiDeviceBase.java @@ -2,6 +2,7 @@ import net.minecraft.client.gui.GuiButton; import net.minecraft.inventory.Container; + import cofh.lib.util.helpers.BlockHelper; import erogenousbeef.bigreactors.common.BigReactors; import erogenousbeef.bigreactors.common.block.BlockBRDevice; @@ -12,75 +13,88 @@ public abstract class BeefGuiDeviceBase extends BeefGuiBase { - protected static final int EXPOSURE_BUTTON_ID_BASE = 100; - private GuiIconButton[] exposureButtons; - - TileEntityBeefBase _entity; - - public BeefGuiDeviceBase(Container container, TileEntityBeefBase tileEntity) { - super(container); - _entity = tileEntity; - } + protected static final int EXPOSURE_BUTTON_ID_BASE = 100; + private GuiIconButton[] exposureButtons; + + TileEntityBeefBase _entity; + + public BeefGuiDeviceBase(Container container, TileEntityBeefBase tileEntity) { + super(container); + _entity = tileEntity; + } + + /** + * Used to set the icon for the front face of the machine on the exposure button panel. No other uses. + * + * @return The metadata of the machine whose icon should show up in the center of the exposure buttons. + */ + protected abstract int getBlockMetadata(); + + private void createInventoryExposureButton(int side, int x, int y) { + if (exposureButtons[side] != null) { + throw new IllegalArgumentException("Direction already exposed"); + } + + GuiIconButton newBtn = new GuiIconButton(EXPOSURE_BUTTON_ID_BASE + side, x, y, 20, 20, null); + buttonList.add(newBtn); + exposureButtons[side] = newBtn; + } - /** - * Used to set the icon for the front face of the machine on the exposure button panel. No other uses. - * @return The metadata of the machine whose icon should show up in the center of the exposure buttons. - */ - protected abstract int getBlockMetadata(); - - private void createInventoryExposureButton(int side, int x, int y) { - if(exposureButtons[side] != null) { throw new IllegalArgumentException("Direction already exposed"); } + /** + * Create GUI inventory exposure button grid + * + * @param minLeft The leftmost coordinate for the buttons, including guiLeft + * @param minTop The topmost coordinate for the buttons, including guiTop + */ + protected void createInventoryExposureButtons(int minLeft, int minTop) { + // Do this here to make the GUI resize-proof + exposureButtons = new GuiIconButton[6]; + for (int i = 0; i < 6; i++) { + exposureButtons[i] = null; + } - GuiIconButton newBtn = new GuiIconButton(EXPOSURE_BUTTON_ID_BASE + side, x, y, 20, 20, null); - buttonList.add(newBtn); - exposureButtons[side] = newBtn; - } - - /** - * Create GUI inventory exposure button grid - * @param minLeft The leftmost coordinate for the buttons, including guiLeft - * @param minTop The topmost coordinate for the buttons, including guiTop - */ - protected void createInventoryExposureButtons(int minLeft, int minTop) { - // Do this here to make the GUI resize-proof - exposureButtons = new GuiIconButton[6]; - for(int i = 0; i < 6; i++) { - exposureButtons[i] = null; - } + int facing = _entity.getFacing(); + createInventoryExposureButton(BlockHelper.SIDE_LEFT[facing], minLeft, minTop + 21); + createInventoryExposureButton(BlockHelper.SIDE_RIGHT[facing], minLeft + 42, minTop + 21); + createInventoryExposureButton(facing, minLeft + 21, minTop + 21); + createInventoryExposureButton(BlockHelper.SIDE_ABOVE[facing], minLeft + 21, minTop); + createInventoryExposureButton(BlockHelper.SIDE_BELOW[facing], minLeft + 21, minTop + 42); + createInventoryExposureButton(BlockHelper.SIDE_OPPOSITE[facing], minLeft + 42, minTop + 42); - int facing = _entity.getFacing(); - createInventoryExposureButton(BlockHelper.SIDE_LEFT[facing], minLeft, minTop + 21); - createInventoryExposureButton(BlockHelper.SIDE_RIGHT[facing], minLeft + 42, minTop + 21); - createInventoryExposureButton(facing, minLeft + 21, minTop + 21); - createInventoryExposureButton(BlockHelper.SIDE_ABOVE[facing], minLeft + 21, minTop); - createInventoryExposureButton(BlockHelper.SIDE_BELOW[facing], minLeft + 21, minTop + 42); - createInventoryExposureButton(BlockHelper.SIDE_OPPOSITE[facing], minLeft + 42, minTop + 42); + exposureButtons[facing].setIcon(BigReactors.blockDevice.getIcon(4, getBlockMetadata())); + exposureButtons[facing].enabled = false; + } - exposureButtons[facing].setIcon(BigReactors.blockDevice.getIcon(4, getBlockMetadata())); - exposureButtons[facing].enabled = false; - } + @Override + public void updateScreen() { + super.updateScreen(); + updateInventoryExposures(); + } - @Override - public void updateScreen() { - super.updateScreen(); - updateInventoryExposures(); - } + @Override + protected void actionPerformed(GuiButton button) { + super.actionPerformed(button); + if (button.id >= EXPOSURE_BUTTON_ID_BASE && button.id < EXPOSURE_BUTTON_ID_BASE + 6) { + // TODO: Figure out how to detect rightclicks + CommonPacketHandler.INSTANCE.sendToServer( + new DeviceChangeExposureMessage( + _entity.xCoord, + _entity.yCoord, + _entity.zCoord, + button.id - EXPOSURE_BUTTON_ID_BASE, + true)); + } + } - @Override - protected void actionPerformed(GuiButton button) { - super.actionPerformed(button); - if(button.id >= EXPOSURE_BUTTON_ID_BASE && button.id < EXPOSURE_BUTTON_ID_BASE + 6) { - // TODO: Figure out how to detect rightclicks - CommonPacketHandler.INSTANCE.sendToServer(new DeviceChangeExposureMessage(_entity.xCoord, _entity.yCoord, _entity.zCoord, button.id - EXPOSURE_BUTTON_ID_BASE, true)); - } - } - - protected void updateInventoryExposures() { - int facing = _entity.getFacing(); - BlockBRDevice deviceBlock = (BlockBRDevice)BigReactors.blockDevice; - for(int side = 0; side < 6; side++) { - if(side == facing) { continue; } - exposureButtons[side].setIcon( deviceBlock.getIconFromTileEntity(_entity, BlockBRDevice.META_CYANITE_REPROCESSOR, side) ); - } - } + protected void updateInventoryExposures() { + int facing = _entity.getFacing(); + BlockBRDevice deviceBlock = (BlockBRDevice) BigReactors.blockDevice; + for (int side = 0; side < 6; side++) { + if (side == facing) { + continue; + } + exposureButtons[side] + .setIcon(deviceBlock.getIconFromTileEntity(_entity, BlockBRDevice.META_CYANITE_REPROCESSOR, side)); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/client/gui/GuiCyaniteReprocessor.java b/src/main/java/erogenousbeef/bigreactors/client/gui/GuiCyaniteReprocessor.java index 5c3a571c..f2520877 100644 --- a/src/main/java/erogenousbeef/bigreactors/client/gui/GuiCyaniteReprocessor.java +++ b/src/main/java/erogenousbeef/bigreactors/client/gui/GuiCyaniteReprocessor.java @@ -3,6 +3,7 @@ import net.minecraft.client.gui.GuiButton; import net.minecraft.inventory.Container; import net.minecraft.util.ResourceLocation; + import erogenousbeef.bigreactors.common.BigReactors; import erogenousbeef.bigreactors.common.block.BlockBRDevice; import erogenousbeef.bigreactors.common.tileentity.TileEntityCyaniteReprocessor; @@ -13,63 +14,63 @@ public class GuiCyaniteReprocessor extends BeefGuiDeviceBase { - private GuiButton _togglePort; - private TileEntityCyaniteReprocessor _entity; - - private BeefGuiLabel titleString; - - private BeefGuiPowerBar powerBar; - private BeefGuiFluidBar fluidBar; - private BeefGuiProgressArrow progressArrow; - - public GuiCyaniteReprocessor(Container container, TileEntityCyaniteReprocessor entity) { - super(container, entity); - - _entity = entity; - xSize = 245; - ySize = 175; - } - - @Override - public void initGui() { - super.initGui(); - - titleString = new BeefGuiLabel(this, _entity.getInventoryName(), guiLeft + 8, guiTop + 6); - - fluidBar = new BeefGuiFluidBar(this, guiLeft + 8, guiTop + 16, _entity, 0); - powerBar = new BeefGuiPowerBar(this, guiLeft + 148, guiTop + 16, _entity); - progressArrow = new BeefGuiProgressArrow(this, guiLeft + 76, guiTop + 41, 0, 178, _entity); - - registerControl(titleString); - registerControl(powerBar); - registerControl(fluidBar); - registerControl(progressArrow); - - createInventoryExposureButtons(guiLeft + 180, guiTop + 4); - } - - @Override - public ResourceLocation getGuiBackground() { - return new ResourceLocation(BigReactors.GUI_DIRECTORY + "CyaniteReprocessor.png"); - } - - @Override - public void updateScreen() { - super.updateScreen(); - } - - @Override - public void drawScreen(int mouseX, int mouseY, float gameTicks) { - super.drawScreen(mouseX, mouseY, gameTicks); - } - - @Override - protected void actionPerformed(GuiButton button) { - super.actionPerformed(button); - } - - @Override - protected int getBlockMetadata() { - return BlockBRDevice.META_CYANITE_REPROCESSOR; - } + private GuiButton _togglePort; + private TileEntityCyaniteReprocessor _entity; + + private BeefGuiLabel titleString; + + private BeefGuiPowerBar powerBar; + private BeefGuiFluidBar fluidBar; + private BeefGuiProgressArrow progressArrow; + + public GuiCyaniteReprocessor(Container container, TileEntityCyaniteReprocessor entity) { + super(container, entity); + + _entity = entity; + xSize = 245; + ySize = 175; + } + + @Override + public void initGui() { + super.initGui(); + + titleString = new BeefGuiLabel(this, _entity.getInventoryName(), guiLeft + 8, guiTop + 6); + + fluidBar = new BeefGuiFluidBar(this, guiLeft + 8, guiTop + 16, _entity, 0); + powerBar = new BeefGuiPowerBar(this, guiLeft + 148, guiTop + 16, _entity); + progressArrow = new BeefGuiProgressArrow(this, guiLeft + 76, guiTop + 41, 0, 178, _entity); + + registerControl(titleString); + registerControl(powerBar); + registerControl(fluidBar); + registerControl(progressArrow); + + createInventoryExposureButtons(guiLeft + 180, guiTop + 4); + } + + @Override + public ResourceLocation getGuiBackground() { + return new ResourceLocation(BigReactors.GUI_DIRECTORY + "CyaniteReprocessor.png"); + } + + @Override + public void updateScreen() { + super.updateScreen(); + } + + @Override + public void drawScreen(int mouseX, int mouseY, float gameTicks) { + super.drawScreen(mouseX, mouseY, gameTicks); + } + + @Override + protected void actionPerformed(GuiButton button) { + super.actionPerformed(button); + } + + @Override + protected int getBlockMetadata() { + return BlockBRDevice.META_CYANITE_REPROCESSOR; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorAccessPort.java b/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorAccessPort.java index 9739ad13..13459d99 100644 --- a/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorAccessPort.java +++ b/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorAccessPort.java @@ -4,6 +4,7 @@ import net.minecraft.inventory.Container; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.ResourceLocation; + import erogenousbeef.bigreactors.client.ClientProxy; import erogenousbeef.bigreactors.common.BigReactors; import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorAccessPort; @@ -15,80 +16,114 @@ import erogenousbeef.bigreactors.net.message.multiblock.ReactorCommandEjectToPortMessage; public class GuiReactorAccessPort extends BeefGuiBase { - private TileEntityReactorAccessPort _port; - - protected BeefGuiLabel inventoryLabel; - - protected GuiIconButton ejectFuel; - protected GuiIconButton ejectWaste; - - protected GuiIconButton btnInlet; - protected GuiIconButton btnOutlet; - - public GuiReactorAccessPort(Container container, TileEntityReactorAccessPort accessPort) { - super(container); - - _port = accessPort; - } - - @Override - public void initGui() { - super.initGui(); - - ejectFuel = new GuiIconButton(2, guiLeft + xSize - 97, guiTop + 53, 18, 18, ClientProxy.GuiIcons.getIcon("fuelEject"), new String[] { EnumChatFormatting.AQUA + "Eject Fuel", "", "Ejects fuel contained in the", "reactor, placing ingots in the", "reactor's access ports.", "", "SHIFT: Dump excess fuel."}); - ejectWaste = new GuiIconButton(3, guiLeft + xSize - 77, guiTop + 53, 18, 18, ClientProxy.GuiIcons.getIcon("wasteEject"), new String[] { EnumChatFormatting.AQUA + "Eject Waste", "", "Ejects waste contained in the", "reactor, placing ingots in the", "reactor's access ports.", "", "SHIFT: Dump excess waste."}); - - btnInlet = new GuiIconButton(0, guiLeft + xSize - 47, guiTop + 53, 18, 18, ClientProxy.GuiIcons.getIcon("inletOn"), new String[] { EnumChatFormatting.AQUA + "Inlet Mode", "", "Sets the access port to", "inlet mode.", "", "Port WILL accept", "items from pipes/ducts.", "Port WILL NOT eject", "items to pipes/ducts."}); - btnOutlet = new GuiIconButton(1, guiLeft + xSize - 27, guiTop + 53, 18, 18, ClientProxy.GuiIcons.getIcon("outletOn"), new String[] { EnumChatFormatting.AQUA + "Outlet Mode", "", "Sets the access port to", "outlet mode.", "", "Port WILL NOT accept", "items from pipes/ducts.", "Port WILL eject", "ingots to pipes/ducts."}); - - inventoryLabel = new BeefGuiLabel(this, "Inventory", guiLeft + 8, guiTop + 64); - - registerControl(ejectFuel); - registerControl(ejectWaste); - registerControl(btnOutlet); - registerControl(btnInlet); - registerControl(inventoryLabel); - - updateIcons(); - } - - @Override - public ResourceLocation getGuiBackground() { - return new ResourceLocation(BigReactors.GUI_DIRECTORY + "ReactorAccessPort.png"); - } - - @Override - public void updateScreen() { - super.updateScreen(); - - updateIcons(); - } - - protected void updateIcons() { - if(_port.isInlet()) { - btnInlet.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.INLET_ON)); - btnOutlet.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.OUTLET_OFF)); - } - else { - btnInlet.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.INLET_OFF)); - btnOutlet.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.OUTLET_ON)); - } - } - - @Override - public void drawScreen(int mouseX, int mouseY, float gameTicks) { - super.drawScreen(mouseX, mouseY, gameTicks); - } - - @Override - protected void actionPerformed(GuiButton button) { - if(button.id == 0 || button.id == 1) { - CommonPacketHandler.INSTANCE.sendToServer(new ReactorAccessPortChangeDirectionMessage(_port, button.id == btnInlet.id)); - } - - else if(button.id == 2 || button.id == 3) { - boolean ejectFuel = button.id == 2; - CommonPacketHandler.INSTANCE.sendToServer(new ReactorCommandEjectToPortMessage(_port, ejectFuel, isShiftKeyDown())); - } - } + + private TileEntityReactorAccessPort _port; + + protected BeefGuiLabel inventoryLabel; + + protected GuiIconButton ejectFuel; + protected GuiIconButton ejectWaste; + + protected GuiIconButton btnInlet; + protected GuiIconButton btnOutlet; + + public GuiReactorAccessPort(Container container, TileEntityReactorAccessPort accessPort) { + super(container); + + _port = accessPort; + } + + @Override + public void initGui() { + super.initGui(); + + ejectFuel = new GuiIconButton( + 2, + guiLeft + xSize - 97, + guiTop + 53, + 18, + 18, + ClientProxy.GuiIcons.getIcon("fuelEject"), + new String[] { EnumChatFormatting.AQUA + "Eject Fuel", "", "Ejects fuel contained in the", + "reactor, placing ingots in the", "reactor's access ports.", "", "SHIFT: Dump excess fuel." }); + ejectWaste = new GuiIconButton( + 3, + guiLeft + xSize - 77, + guiTop + 53, + 18, + 18, + ClientProxy.GuiIcons.getIcon("wasteEject"), + new String[] { EnumChatFormatting.AQUA + "Eject Waste", "", "Ejects waste contained in the", + "reactor, placing ingots in the", "reactor's access ports.", "", "SHIFT: Dump excess waste." }); + + btnInlet = new GuiIconButton( + 0, + guiLeft + xSize - 47, + guiTop + 53, + 18, + 18, + ClientProxy.GuiIcons.getIcon("inletOn"), + new String[] { EnumChatFormatting.AQUA + "Inlet Mode", "", "Sets the access port to", "inlet mode.", "", + "Port WILL accept", "items from pipes/ducts.", "Port WILL NOT eject", "items to pipes/ducts." }); + btnOutlet = new GuiIconButton( + 1, + guiLeft + xSize - 27, + guiTop + 53, + 18, + 18, + ClientProxy.GuiIcons.getIcon("outletOn"), + new String[] { EnumChatFormatting.AQUA + "Outlet Mode", "", "Sets the access port to", "outlet mode.", "", + "Port WILL NOT accept", "items from pipes/ducts.", "Port WILL eject", "ingots to pipes/ducts." }); + + inventoryLabel = new BeefGuiLabel(this, "Inventory", guiLeft + 8, guiTop + 64); + + registerControl(ejectFuel); + registerControl(ejectWaste); + registerControl(btnOutlet); + registerControl(btnInlet); + registerControl(inventoryLabel); + + updateIcons(); + } + + @Override + public ResourceLocation getGuiBackground() { + return new ResourceLocation(BigReactors.GUI_DIRECTORY + "ReactorAccessPort.png"); + } + + @Override + public void updateScreen() { + super.updateScreen(); + + updateIcons(); + } + + protected void updateIcons() { + if (_port.isInlet()) { + btnInlet.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.INLET_ON)); + btnOutlet.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.OUTLET_OFF)); + } else { + btnInlet.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.INLET_OFF)); + btnOutlet.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.OUTLET_ON)); + } + } + + @Override + public void drawScreen(int mouseX, int mouseY, float gameTicks) { + super.drawScreen(mouseX, mouseY, gameTicks); + } + + @Override + protected void actionPerformed(GuiButton button) { + if (button.id == 0 || button.id == 1) { + CommonPacketHandler.INSTANCE + .sendToServer(new ReactorAccessPortChangeDirectionMessage(_port, button.id == btnInlet.id)); + } + + else if (button.id == 2 || button.id == 3) { + boolean ejectFuel = button.id == 2; + CommonPacketHandler.INSTANCE + .sendToServer(new ReactorCommandEjectToPortMessage(_port, ejectFuel, isShiftKeyDown())); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorControlRod.java b/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorControlRod.java index 71f95366..04d84651 100644 --- a/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorControlRod.java +++ b/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorControlRod.java @@ -21,160 +21,194 @@ public class GuiReactorControlRod extends BeefGuiBase { - TileEntityReactorControlRod entity; - - BeefGuiLabel titleString; - BeefGuiLabel rodNameLabel; - BeefGuiLabel insertionLabel; - - GuiButton setNameBtn; - - BeefGuiIcon rodInsertIcon; - GuiIconButton rodInsertBtn; - GuiIconButton rodRetractBtn; - - BeefGuiInsertionProgressBar insertionBar; - + TileEntityReactorControlRod entity; + + BeefGuiLabel titleString; + BeefGuiLabel rodNameLabel; + BeefGuiLabel insertionLabel; + + GuiButton setNameBtn; + + BeefGuiIcon rodInsertIcon; + GuiIconButton rodInsertBtn; + GuiIconButton rodRetractBtn; + + BeefGuiInsertionProgressBar insertionBar; + private GuiTextField rodName; - - public GuiReactorControlRod(Container c, TileEntityReactorControlRod controlRod) { - super(c); - - entity = controlRod; - } - - @Override - public ResourceLocation getGuiBackground() { - return new ResourceLocation (BigReactors.GUI_DIRECTORY + "BasicBackground.png"); - } - - @Override - public void initGui() { - super.initGui(); - - int leftX = guiLeft + 4; - int topY = guiTop + 4; - - Keyboard.enableRepeatEvents(true); - - titleString = new BeefGuiLabel(this, "Reactor Control Rod", leftX, topY); - topY += titleString.getHeight() + 8; - - rodNameLabel = new BeefGuiLabel(this, "Name:", leftX, topY + 6); - - rodName = new GuiTextField(fontRendererObj, leftX + 4 + rodNameLabel.getWidth(), topY, 100, 20); - rodName.setCanLoseFocus(true); - rodName.setMaxStringLength(32); - rodName.setText(entity.getName()); - rodName.setEnabled(true); - - setNameBtn = new GuiButton(2, guiLeft + 140, topY, 30, 20, "Set"); - setNameBtn.enabled = false; - topY += 28; - - rodInsertIcon = new BeefGuiIcon(this, leftX+42, topY, 16, 16, ClientProxy.GuiIcons.getIcon("controlRod"), new String[] { EnumChatFormatting.AQUA + "Rod Insertion", "", "Change the control rod's insertion.", "Higher insertion slows reaction rate.", "", "Lower reaction rates reduce heat,", "energy, radiation output, and", "fuel consumption." }); - insertionLabel = new BeefGuiLabel(this, "", leftX+62, topY+5); - topY += 20; - insertionBar = new BeefGuiInsertionProgressBar(this, leftX+40, topY); - - topY += 12; - rodRetractBtn = new GuiIconButton(0, leftX+70, topY, 20, 20, ClientProxy.GuiIcons.getIcon("upArrow"), new String[] { EnumChatFormatting.AQUA + "Insert Rod", "Increase insertion by 10.", "", "Shift: +100", "Alt: +5", "Shift+Alt: +1", "", "Ctrl: Change ALL Rods" }); - topY += 20; - rodInsertBtn = new GuiIconButton(1, leftX+70, topY, 20, 20, ClientProxy.GuiIcons.getIcon("downArrow"), new String[] { EnumChatFormatting.AQUA + "Retract Rod", "Reduce insertion by 10.", "", "Shift: -100", "Alt: -5", "Shift+Alt: -1", "", "Ctrl: Change ALL Rods" }); - topY += 32; - - registerControl(insertionBar); - registerControl(titleString); - registerControl(rodNameLabel); - registerControl(rodInsertIcon); - registerControl(insertionLabel); - - registerControl(rodName); - registerControl(rodRetractBtn); - registerControl(rodInsertBtn); - registerControl(setNameBtn); - - updateStrings(); - } - - @Override - public void onGuiClosed() { - super.onGuiClosed(); - Keyboard.enableRepeatEvents(false); - } - - @Override - public void updateScreen() { - super.updateScreen(); - updateStrings(); - } - - protected void updateStrings() { - if(entity.isConnected()) { - rodInsertBtn.enabled = true; - rodRetractBtn.enabled = true; - } - else { - rodInsertBtn.enabled = false; - rodRetractBtn.enabled = false; - } - - insertionLabel.setLabelText(String.format("%d%%", entity.getControlRodInsertion())); - this.setNameBtn.enabled = !entity.getName().equals(this.rodName.getText()); - insertionBar.setInsertion((float)entity.getControlRodInsertion() / 100f); - } - - @Override - protected void actionPerformed(GuiButton button) { - switch(button.id) { - case 2: - CommonPacketHandler.INSTANCE.sendToServer(new ControlRodChangeNameMessage(entity.xCoord, entity.yCoord, entity.zCoord, this.rodName.getText())); - this.rodName.setFocused(false); - break; - case 0: - case 1: - default: - int change = 10; - if(isShiftKeyDown()) { - if(isAltKeyDown()) { - change = 1; - } - else { - change = 100; - } - } - else if(isAltKeyDown()) { - change = 5; - } - if(button.id == 1) { change = -change; } - CommonPacketHandler.INSTANCE.sendToServer(new ControlRodChangeInsertionMessage(entity.xCoord, entity.yCoord, entity.zCoord, change, isCtrlKeyDown())); - } + public GuiReactorControlRod(Container c, TileEntityReactorControlRod controlRod) { + super(c); + + entity = controlRod; + } + + @Override + public ResourceLocation getGuiBackground() { + return new ResourceLocation(BigReactors.GUI_DIRECTORY + "BasicBackground.png"); } - - @Override - protected void keyTyped(char inputChar, int keyCode) { - if (keyCode == Keyboard.KEY_ESCAPE || - (!this.rodName.isFocused() && keyCode == this.mc.gameSettings.keyBindInventory.getKeyCode())) { + + @Override + public void initGui() { + super.initGui(); + + int leftX = guiLeft + 4; + int topY = guiTop + 4; + + Keyboard.enableRepeatEvents(true); + + titleString = new BeefGuiLabel(this, "Reactor Control Rod", leftX, topY); + topY += titleString.getHeight() + 8; + + rodNameLabel = new BeefGuiLabel(this, "Name:", leftX, topY + 6); + + rodName = new GuiTextField(fontRendererObj, leftX + 4 + rodNameLabel.getWidth(), topY, 100, 20); + rodName.setCanLoseFocus(true); + rodName.setMaxStringLength(32); + rodName.setText(entity.getName()); + rodName.setEnabled(true); + + setNameBtn = new GuiButton(2, guiLeft + 140, topY, 30, 20, "Set"); + setNameBtn.enabled = false; + topY += 28; + + rodInsertIcon = new BeefGuiIcon( + this, + leftX + 42, + topY, + 16, + 16, + ClientProxy.GuiIcons.getIcon("controlRod"), + new String[] { EnumChatFormatting.AQUA + "Rod Insertion", "", "Change the control rod's insertion.", + "Higher insertion slows reaction rate.", "", "Lower reaction rates reduce heat,", + "energy, radiation output, and", "fuel consumption." }); + insertionLabel = new BeefGuiLabel(this, "", leftX + 62, topY + 5); + topY += 20; + insertionBar = new BeefGuiInsertionProgressBar(this, leftX + 40, topY); + + topY += 12; + rodRetractBtn = new GuiIconButton( + 0, + leftX + 70, + topY, + 20, + 20, + ClientProxy.GuiIcons.getIcon("upArrow"), + new String[] { EnumChatFormatting.AQUA + "Insert Rod", "Increase insertion by 10.", "", "Shift: +100", + "Alt: +5", "Shift+Alt: +1", "", "Ctrl: Change ALL Rods" }); + topY += 20; + rodInsertBtn = new GuiIconButton( + 1, + leftX + 70, + topY, + 20, + 20, + ClientProxy.GuiIcons.getIcon("downArrow"), + new String[] { EnumChatFormatting.AQUA + "Retract Rod", "Reduce insertion by 10.", "", "Shift: -100", + "Alt: -5", "Shift+Alt: -1", "", "Ctrl: Change ALL Rods" }); + topY += 32; + + registerControl(insertionBar); + registerControl(titleString); + registerControl(rodNameLabel); + registerControl(rodInsertIcon); + registerControl(insertionLabel); + + registerControl(rodName); + registerControl(rodRetractBtn); + registerControl(rodInsertBtn); + registerControl(setNameBtn); + + updateStrings(); + } + + @Override + public void onGuiClosed() { + super.onGuiClosed(); + Keyboard.enableRepeatEvents(false); + } + + @Override + public void updateScreen() { + super.updateScreen(); + updateStrings(); + } + + protected void updateStrings() { + if (entity.isConnected()) { + rodInsertBtn.enabled = true; + rodRetractBtn.enabled = true; + } else { + rodInsertBtn.enabled = false; + rodRetractBtn.enabled = false; + } + + insertionLabel.setLabelText(String.format("%d%%", entity.getControlRodInsertion())); + this.setNameBtn.enabled = !entity.getName() + .equals(this.rodName.getText()); + insertionBar.setInsertion((float) entity.getControlRodInsertion() / 100f); + } + + @Override + protected void actionPerformed(GuiButton button) { + switch (button.id) { + case 2: + CommonPacketHandler.INSTANCE.sendToServer( + new ControlRodChangeNameMessage( + entity.xCoord, + entity.yCoord, + entity.zCoord, + this.rodName.getText())); + this.rodName.setFocused(false); + break; + case 0: + case 1: + default: + int change = 10; + if (isShiftKeyDown()) { + if (isAltKeyDown()) { + change = 1; + } else { + change = 100; + } + } else if (isAltKeyDown()) { + change = 5; + } + if (button.id == 1) { + change = -change; + } + CommonPacketHandler.INSTANCE.sendToServer( + new ControlRodChangeInsertionMessage( + entity.xCoord, + entity.yCoord, + entity.zCoord, + change, + isCtrlKeyDown())); + } + } + + @Override + protected void keyTyped(char inputChar, int keyCode) { + if (keyCode == Keyboard.KEY_ESCAPE + || (!this.rodName.isFocused() && keyCode == this.mc.gameSettings.keyBindInventory.getKeyCode())) { this.mc.thePlayer.closeScreen(); } - this.rodName.textboxKeyTyped(inputChar, keyCode); - - if(keyCode == Keyboard.KEY_TAB) { - // Tab - if(this.rodName.isFocused()) { - this.rodName.setFocused(false); - } - else { - this.rodName.setFocused(true); - } - } - - if(keyCode == Keyboard.KEY_RETURN) { - // Return/enter - this.actionPerformed((GuiButton)this.buttonList.get(2)); - } - } - + this.rodName.textboxKeyTyped(inputChar, keyCode); + + if (keyCode == Keyboard.KEY_TAB) { + // Tab + if (this.rodName.isFocused()) { + this.rodName.setFocused(false); + } else { + this.rodName.setFocused(true); + } + } + + if (keyCode == Keyboard.KEY_RETURN) { + // Return/enter + this.actionPerformed((GuiButton) this.buttonList.get(2)); + } + } + } diff --git a/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorRedNetPort.java b/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorRedNetPort.java index 9e9a665e..ea71e6d0 100644 --- a/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorRedNetPort.java +++ b/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorRedNetPort.java @@ -8,6 +8,7 @@ import net.minecraft.inventory.Container; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ResourceLocation; + import erogenousbeef.bigreactors.common.BigReactors; import erogenousbeef.bigreactors.common.multiblock.block.BlockReactorPart; import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorControlRod; @@ -26,356 +27,354 @@ public class GuiReactorRedNetPort extends BeefGuiBase { - protected static final int numChannels = 16; - - TileEntityReactorRedNetPort port; - BeefGuiLabel titleString; - BeefGuiLabel settingsString; - - BeefGuiLabel subSettingString; - BeefGuiLabel subSettingValueString; - - private GuiButton commitBtn; - - private GuiButton subSettingForwardBtn; - private GuiButton subSettingBackBtn; - - private ResourceLocation _guiBackground; - - protected static final String[] channelLabelStrings = new String[] { - "White", "Orange", "Magenta", "LightBlue", "Yellow", "Lime", "Pink", "Gray", - "LightGray", "Cyan", "Purple", "Blue", "Brown", "Green", "Red", "Black" - }; - - public static final String[] grabbableTooltips = { - "Input: Toggle reactor on/off", - "Input: Change control rod insertion", - "Input: Eject Waste", - "Output: Fuel Temp (C)", - "Output: Casing Temp (C)", - "Output: Fuel mix (% fuel, 0-100)", - "Output: Fuel amount", - "Output: Waste amount", - "Output: Energy amount (%)" - }; - - BeefGuiRedNetChannelSelector[] channelSelectors = new BeefGuiRedNetChannelSelector[numChannels]; - RedNetConfigGrabTarget[] grabTargets = new RedNetConfigGrabTarget[numChannels]; - private CoordTriplet[] subSettingCoords = new CoordTriplet[numChannels]; - private boolean[] pulseActivated = new boolean[numChannels]; - - private int selectedChannel = 0; - - public GuiReactorRedNetPort(Container container, TileEntityReactorRedNetPort redNetPort) { - super(container); - port = redNetPort; - - xSize = 255; - ySize = 214; - - _guiBackground = new ResourceLocation(BigReactors.GUI_DIRECTORY + "RedNetPort.png"); - } - - @Override - public ResourceLocation getGuiBackground() { - return _guiBackground; - } - - @Override - public void initGui() { - super.initGui(); - - int leftX = guiLeft + 4; - int topY = guiTop + 4; - - titleString = new BeefGuiLabel(this, "Reactor RedNet Port", leftX+2, topY+2); - settingsString = new BeefGuiLabel(this, "Settings", leftX+154, topY+2); - subSettingString = new BeefGuiLabel(this, "", leftX+154, topY+80); - subSettingValueString = new BeefGuiLabel(this, "", leftX+154, topY+94); - - topY += titleString.getHeight() + 8; - - selectedChannel = 0; - for(int i = 0; i < channelLabelStrings.length; i+=2) { - channelSelectors[i] = new BeefGuiRedNetChannelSelector(this, channelLabelStrings[i], i, leftX, topY, 60, 20); - grabTargets[i] = new RedNetConfigGrabTarget(this, leftX + 42, topY+2, port, i); - - if(i == 0) { - channelSelectors[i].setSelected(true); - } - - leftX += 74; - - channelSelectors[i + 1] = new BeefGuiRedNetChannelSelector(this, channelLabelStrings[i+1], i+1, leftX, topY, 60, 20); - grabTargets[i + 1] = new RedNetConfigGrabTarget(this, leftX + 42, topY+2, port, i + 1); - topY += 24; - leftX = guiLeft + 4; - - registerControl(channelSelectors[i]); - registerControl(channelSelectors[i+1]); - - registerControl(grabTargets[i]); - registerControl(grabTargets[i+1]); - } - - TileEntityReactorRedNetPort.CircuitType[] circuitTypes = TileEntityReactorRedNetPort.CircuitType.values(); - BlockReactorPart reactorPartBlock = (BlockReactorPart)BigReactors.blockReactorPart; - RedNetConfigGrabbable[] grabbables = new RedNetConfigGrabbable[circuitTypes.length - 1]; - topY = guiTop + 21; - leftX = guiLeft + 156; - for(int i = 1; i < circuitTypes.length; i++) { - grabbables[i-1] = new RedNetConfigGrabbable(grabbableTooltips[i-1], reactorPartBlock.getRedNetConfigIcon(circuitTypes[i]), circuitTypes[i]); - BeefGuiGrabSource source = new BeefGuiGrabSource(this, leftX, topY, grabbables[i - 1]); - registerControl(source); - leftX += 20; - if(leftX >= guiLeft + 230) { - leftX = guiLeft + 156; - topY += 20; - } - } - - registerControl(titleString); - registerControl(settingsString); - registerControl(subSettingString); - registerControl(subSettingValueString); - - commitBtn = new GuiButton(0, guiLeft + 190, guiTop + 190, 56, 20, "Commit"); - commitBtn.enabled = false; - - this.subSettingForwardBtn = new GuiButton(1, guiLeft + 178, guiTop + 114, 20, 20, ">"); - this.subSettingBackBtn = new GuiButton(2, guiLeft + 154, guiTop + 114, 20, 20, "<"); - this.subSettingForwardBtn.visible = false; - this.subSettingBackBtn.visible = false; - - this.buttonList.add(commitBtn); - this.buttonList.add(subSettingForwardBtn); - this.buttonList.add(subSettingBackBtn); - - // Populate all the channels with existing settings - TileEntityReactorRedNetPort.CircuitType currentCircuitType; - for(int i = 0; i < TileEntityReactorRedNetPort.numChannels; i++) { - currentCircuitType = port.getChannelCircuitType(i); - pulseActivated[i] = port.isInputActivatedOnPulse(i); - if(currentCircuitType == TileEntityReactorRedNetPort.CircuitType.DISABLED) { - grabTargets[i].setSlotContents(null); - } - else { - grabTargets[i].setSlotContents( grabbables[currentCircuitType.ordinal() - 1 ]); - } - } - - for(int i = 0; i < subSettingCoords.length; i++) { - subSettingCoords[i] = port.getMappedCoord(i); - } - - updateSubSettingValueText(); - } - - @Override - public void updateScreen() { - super.updateScreen(); - - boolean hasChanges = false; - boolean invalidSetting = false; - for(RedNetConfigGrabTarget target : grabTargets) { - if(target.hasChanged()) { - hasChanges = true; - } - } - - // See if any subsettings changed - for(int i = 0; i < subSettingCoords.length; i++) { - if(hasSubSettingChanged(i)) { - hasChanges = true; - break; - } - } - - for(int i = 0; i < numChannels; i++) { - if(port.isInputActivatedOnPulse(i) != pulseActivated[i]) { - hasChanges = true; - break; - } - } - - commitBtn.enabled = hasChanges && !invalidSetting; - } - - protected boolean hasSubSettingChanged(int idx) { - if(subSettingCoords[idx] == null) { - if(port.getMappedCoord(idx) != null) - { - return true; - } - } - else if(port.getMappedCoord(idx) == null) { - return true; - } - else if(!subSettingCoords[idx].equals(port.getMappedCoord(idx))) { - return true; - } - return false; - } - - protected boolean hasSettingChanged(int idx) { - return grabTargets[idx].hasChanged() || hasSubSettingChanged(idx) || (port.isInputActivatedOnPulse(idx) != pulseActivated[idx]); - } - - @Override - protected void actionPerformed(GuiButton button) { - if(button.id == 0) { - RedNetChange[] packetData = getUpdatePacketData(); - - if(packetData == null) { return; } + protected static final int numChannels = 16; + + TileEntityReactorRedNetPort port; + BeefGuiLabel titleString; + BeefGuiLabel settingsString; + + BeefGuiLabel subSettingString; + BeefGuiLabel subSettingValueString; + + private GuiButton commitBtn; + + private GuiButton subSettingForwardBtn; + private GuiButton subSettingBackBtn; + + private ResourceLocation _guiBackground; + + protected static final String[] channelLabelStrings = new String[] { "White", "Orange", "Magenta", "LightBlue", + "Yellow", "Lime", "Pink", "Gray", "LightGray", "Cyan", "Purple", "Blue", "Brown", "Green", "Red", "Black" }; + + public static final String[] grabbableTooltips = { "Input: Toggle reactor on/off", + "Input: Change control rod insertion", "Input: Eject Waste", "Output: Fuel Temp (C)", "Output: Casing Temp (C)", + "Output: Fuel mix (% fuel, 0-100)", "Output: Fuel amount", "Output: Waste amount", + "Output: Energy amount (%)" }; + + BeefGuiRedNetChannelSelector[] channelSelectors = new BeefGuiRedNetChannelSelector[numChannels]; + RedNetConfigGrabTarget[] grabTargets = new RedNetConfigGrabTarget[numChannels]; + private CoordTriplet[] subSettingCoords = new CoordTriplet[numChannels]; + private boolean[] pulseActivated = new boolean[numChannels]; + + private int selectedChannel = 0; + + public GuiReactorRedNetPort(Container container, TileEntityReactorRedNetPort redNetPort) { + super(container); + port = redNetPort; + + xSize = 255; + ySize = 214; + + _guiBackground = new ResourceLocation(BigReactors.GUI_DIRECTORY + "RedNetPort.png"); + } + + @Override + public ResourceLocation getGuiBackground() { + return _guiBackground; + } + + @Override + public void initGui() { + super.initGui(); + + int leftX = guiLeft + 4; + int topY = guiTop + 4; + + titleString = new BeefGuiLabel(this, "Reactor RedNet Port", leftX + 2, topY + 2); + settingsString = new BeefGuiLabel(this, "Settings", leftX + 154, topY + 2); + subSettingString = new BeefGuiLabel(this, "", leftX + 154, topY + 80); + subSettingValueString = new BeefGuiLabel(this, "", leftX + 154, topY + 94); + + topY += titleString.getHeight() + 8; + + selectedChannel = 0; + for (int i = 0; i < channelLabelStrings.length; i += 2) { + channelSelectors[i] = new BeefGuiRedNetChannelSelector( + this, + channelLabelStrings[i], + i, + leftX, + topY, + 60, + 20); + grabTargets[i] = new RedNetConfigGrabTarget(this, leftX + 42, topY + 2, port, i); + + if (i == 0) { + channelSelectors[i].setSelected(true); + } + + leftX += 74; + + channelSelectors[i + + 1] = new BeefGuiRedNetChannelSelector(this, channelLabelStrings[i + 1], i + 1, leftX, topY, 60, 20); + grabTargets[i + 1] = new RedNetConfigGrabTarget(this, leftX + 42, topY + 2, port, i + 1); + topY += 24; + leftX = guiLeft + 4; + + registerControl(channelSelectors[i]); + registerControl(channelSelectors[i + 1]); + + registerControl(grabTargets[i]); + registerControl(grabTargets[i + 1]); + } + + TileEntityReactorRedNetPort.CircuitType[] circuitTypes = TileEntityReactorRedNetPort.CircuitType.values(); + BlockReactorPart reactorPartBlock = (BlockReactorPart) BigReactors.blockReactorPart; + RedNetConfigGrabbable[] grabbables = new RedNetConfigGrabbable[circuitTypes.length - 1]; + topY = guiTop + 21; + leftX = guiLeft + 156; + for (int i = 1; i < circuitTypes.length; i++) { + grabbables[i - 1] = new RedNetConfigGrabbable( + grabbableTooltips[i - 1], + reactorPartBlock.getRedNetConfigIcon(circuitTypes[i]), + circuitTypes[i]); + BeefGuiGrabSource source = new BeefGuiGrabSource(this, leftX, topY, grabbables[i - 1]); + registerControl(source); + leftX += 20; + if (leftX >= guiLeft + 230) { + leftX = guiLeft + 156; + topY += 20; + } + } + + registerControl(titleString); + registerControl(settingsString); + registerControl(subSettingString); + registerControl(subSettingValueString); + + commitBtn = new GuiButton(0, guiLeft + 190, guiTop + 190, 56, 20, "Commit"); + commitBtn.enabled = false; + + this.subSettingForwardBtn = new GuiButton(1, guiLeft + 178, guiTop + 114, 20, 20, ">"); + this.subSettingBackBtn = new GuiButton(2, guiLeft + 154, guiTop + 114, 20, 20, "<"); + this.subSettingForwardBtn.visible = false; + this.subSettingBackBtn.visible = false; + + this.buttonList.add(commitBtn); + this.buttonList.add(subSettingForwardBtn); + this.buttonList.add(subSettingBackBtn); + + // Populate all the channels with existing settings + TileEntityReactorRedNetPort.CircuitType currentCircuitType; + for (int i = 0; i < TileEntityReactorRedNetPort.numChannels; i++) { + currentCircuitType = port.getChannelCircuitType(i); + pulseActivated[i] = port.isInputActivatedOnPulse(i); + if (currentCircuitType == TileEntityReactorRedNetPort.CircuitType.DISABLED) { + grabTargets[i].setSlotContents(null); + } else { + grabTargets[i].setSlotContents(grabbables[currentCircuitType.ordinal() - 1]); + } + } + + for (int i = 0; i < subSettingCoords.length; i++) { + subSettingCoords[i] = port.getMappedCoord(i); + } + + updateSubSettingValueText(); + } + + @Override + public void updateScreen() { + super.updateScreen(); + + boolean hasChanges = false; + boolean invalidSetting = false; + for (RedNetConfigGrabTarget target : grabTargets) { + if (target.hasChanged()) { + hasChanges = true; + } + } + + // See if any subsettings changed + for (int i = 0; i < subSettingCoords.length; i++) { + if (hasSubSettingChanged(i)) { + hasChanges = true; + break; + } + } + + for (int i = 0; i < numChannels; i++) { + if (port.isInputActivatedOnPulse(i) != pulseActivated[i]) { + hasChanges = true; + break; + } + } + + commitBtn.enabled = hasChanges && !invalidSetting; + } + + protected boolean hasSubSettingChanged(int idx) { + if (subSettingCoords[idx] == null) { + if (port.getMappedCoord(idx) != null) { + return true; + } + } else if (port.getMappedCoord(idx) == null) { + return true; + } else if (!subSettingCoords[idx].equals(port.getMappedCoord(idx))) { + return true; + } + return false; + } + + protected boolean hasSettingChanged(int idx) { + return grabTargets[idx].hasChanged() || hasSubSettingChanged(idx) + || (port.isInputActivatedOnPulse(idx) != pulseActivated[idx]); + } + + @Override + protected void actionPerformed(GuiButton button) { + if (button.id == 0) { + RedNetChange[] packetData = getUpdatePacketData(); + + if (packetData == null) { + return; + } CommonPacketHandler.INSTANCE.sendToServer(new ReactorRedNetPortChangeMessage(port, packetData)); } - - if(button.id == 1 || button.id == 2) { - changeSubSetting(button.id == 1); - } - } - - private RedNetChange[] getUpdatePacketData() { - List packetData = new LinkedList(); - - for(int i = 0; i < TileEntityReactorRedNetPort.numChannels; i++) { - if(hasSettingChanged(i)) { - CircuitType circuitType = grabTargets[i].getCircuitType(); - RedNetChange change = new RedNetChange(i, circuitType, pulseActivated[i], subSettingCoords[i]); - packetData.add(change); - } - } - - if(packetData.size() < 1) { return null; } - - RedNetChange[] changes = new RedNetChange[packetData.size()]; - changes = packetData.toArray(changes); - return changes; - } - - @Override - public void onControlClicked(IBeefGuiControl clickedControl) { - if(clickedControl instanceof BeefGuiRedNetChannelSelector) { - // Set all selectors to unselected, except the one we clicked - // Also change the subsetting selectors, in case those are visible - for(IBeefGuiControl control : controls) { - if(control instanceof BeefGuiRedNetChannelSelector) { - BeefGuiRedNetChannelSelector selector = (BeefGuiRedNetChannelSelector)control; - - boolean wasSelected = selector.isSelected(); - selector.setSelected(control == clickedControl); - if(control == clickedControl) { - this.selectedChannel = selector.getChannel(); - } - - onChannelChanged(selector.getChannel()); - } - } - } - } - - public void onChannelChanged(int changedChannel) { - if(this.selectedChannel != changedChannel) { return; } - - CircuitType currentCircuitType = grabTargets[selectedChannel].getCircuitType(); - - if(CircuitType.hasCoordinate(currentCircuitType)) { - subSettingString.setLabelText("Control Rod: "); - subSettingForwardBtn.visible = true; - subSettingBackBtn.visible = true; - } - else if(TileEntityReactorRedNetPort.isInput(currentCircuitType) && CircuitType.canBeToggledBetweenPulseAndNormal(currentCircuitType)) { - subSettingString.setLabelText("Activates On:"); - subSettingForwardBtn.visible = true; - subSettingBackBtn.visible = true; - } - else if(currentCircuitType == CircuitType.inputEjectWaste) { - subSettingString.setLabelText("Activates On:"); - subSettingForwardBtn.visible = false; - subSettingBackBtn.visible = false; - } - else { - subSettingString.setLabelText(""); - subSettingForwardBtn.visible = false; - subSettingBackBtn.visible = false; - } - - updateSubSettingValueText(); - } - - private String getControlRodLabelFromLocation(CircuitType circuitType, CoordTriplet location) { - if(location == null) { - return "-- ALL --"; - } - else { - TileEntity te = port.getWorldObj().getTileEntity(location.x, location.y, location.z); - if( te instanceof TileEntityReactorControlRod ) { - TileEntityReactorControlRod rod = (TileEntityReactorControlRod)te; - if( rod.getName().equals("")) { - return location.toString(); - } - else { - return rod.getName(); - } - } - else { - return "INVALID: " + location.toString(); - } - } - } - - private void changeSubSetting(boolean forward) { - CircuitType circuitType = grabTargets[selectedChannel].getCircuitType(); - - if( CircuitType.hasCoordinate(circuitType) ) { - // Select a new control rod - CoordTriplet[] controlRodLocations = port.getReactorController().getControlRodLocations(); - int newIdx = 0; - // Locate current idx; will be -1 if not found, which is expected. - int oldIdx = Arrays.asList(controlRodLocations).indexOf( subSettingCoords[selectedChannel] ); - if(forward) { - newIdx = oldIdx + 1; - } - else { - if(oldIdx == -1) { - newIdx = controlRodLocations.length - 1; - } - else { - newIdx = oldIdx - 1; - } - } - - if(newIdx < 0 || newIdx >= controlRodLocations.length) { - subSettingCoords[selectedChannel] = null; - } - else { - subSettingCoords[selectedChannel] = controlRodLocations[newIdx]; - } - } - else if( CircuitType.canBeToggledBetweenPulseAndNormal(circuitType) ) { - pulseActivated[selectedChannel] = !pulseActivated[selectedChannel]; - } - - updateSubSettingValueText(); - } - - private void updateSubSettingValueText() { - subSettingValueString.setLabelTooltip(""); - - - CircuitType circuitType = grabTargets[selectedChannel].getCircuitType(); - - if( CircuitType.hasCoordinate(circuitType) ) { - subSettingValueString.setLabelText( getControlRodLabelFromLocation(circuitType, subSettingCoords[selectedChannel]) ); - } - else if(TileEntityReactorRedNetPort.isInput(circuitType) && CircuitType.canBeToggledBetweenPulseAndNormal(circuitType)) { - subSettingValueString.setLabelText(pulseActivated[selectedChannel]?"Pulse":"Level"); - } - else if(circuitType == CircuitType.inputEjectWaste) { - subSettingValueString.setLabelText("Pulse"); - } - else { - subSettingValueString.setLabelText(""); - } - } + + if (button.id == 1 || button.id == 2) { + changeSubSetting(button.id == 1); + } + } + + private RedNetChange[] getUpdatePacketData() { + List packetData = new LinkedList(); + + for (int i = 0; i < TileEntityReactorRedNetPort.numChannels; i++) { + if (hasSettingChanged(i)) { + CircuitType circuitType = grabTargets[i].getCircuitType(); + RedNetChange change = new RedNetChange(i, circuitType, pulseActivated[i], subSettingCoords[i]); + packetData.add(change); + } + } + + if (packetData.size() < 1) { + return null; + } + + RedNetChange[] changes = new RedNetChange[packetData.size()]; + changes = packetData.toArray(changes); + return changes; + } + + @Override + public void onControlClicked(IBeefGuiControl clickedControl) { + if (clickedControl instanceof BeefGuiRedNetChannelSelector) { + // Set all selectors to unselected, except the one we clicked + // Also change the subsetting selectors, in case those are visible + for (IBeefGuiControl control : controls) { + if (control instanceof BeefGuiRedNetChannelSelector) { + BeefGuiRedNetChannelSelector selector = (BeefGuiRedNetChannelSelector) control; + + boolean wasSelected = selector.isSelected(); + selector.setSelected(control == clickedControl); + if (control == clickedControl) { + this.selectedChannel = selector.getChannel(); + } + + onChannelChanged(selector.getChannel()); + } + } + } + } + + public void onChannelChanged(int changedChannel) { + if (this.selectedChannel != changedChannel) { + return; + } + + CircuitType currentCircuitType = grabTargets[selectedChannel].getCircuitType(); + + if (CircuitType.hasCoordinate(currentCircuitType)) { + subSettingString.setLabelText("Control Rod: "); + subSettingForwardBtn.visible = true; + subSettingBackBtn.visible = true; + } else if (TileEntityReactorRedNetPort.isInput(currentCircuitType) + && CircuitType.canBeToggledBetweenPulseAndNormal(currentCircuitType)) { + subSettingString.setLabelText("Activates On:"); + subSettingForwardBtn.visible = true; + subSettingBackBtn.visible = true; + } else if (currentCircuitType == CircuitType.inputEjectWaste) { + subSettingString.setLabelText("Activates On:"); + subSettingForwardBtn.visible = false; + subSettingBackBtn.visible = false; + } else { + subSettingString.setLabelText(""); + subSettingForwardBtn.visible = false; + subSettingBackBtn.visible = false; + } + + updateSubSettingValueText(); + } + + private String getControlRodLabelFromLocation(CircuitType circuitType, CoordTriplet location) { + if (location == null) { + return "-- ALL --"; + } else { + TileEntity te = port.getWorldObj() + .getTileEntity(location.x, location.y, location.z); + if (te instanceof TileEntityReactorControlRod) { + TileEntityReactorControlRod rod = (TileEntityReactorControlRod) te; + if (rod.getName() + .equals("")) { + return location.toString(); + } else { + return rod.getName(); + } + } else { + return "INVALID: " + location.toString(); + } + } + } + + private void changeSubSetting(boolean forward) { + CircuitType circuitType = grabTargets[selectedChannel].getCircuitType(); + + if (CircuitType.hasCoordinate(circuitType)) { + // Select a new control rod + CoordTriplet[] controlRodLocations = port.getReactorController() + .getControlRodLocations(); + int newIdx = 0; + // Locate current idx; will be -1 if not found, which is expected. + int oldIdx = Arrays.asList(controlRodLocations) + .indexOf(subSettingCoords[selectedChannel]); + if (forward) { + newIdx = oldIdx + 1; + } else { + if (oldIdx == -1) { + newIdx = controlRodLocations.length - 1; + } else { + newIdx = oldIdx - 1; + } + } + + if (newIdx < 0 || newIdx >= controlRodLocations.length) { + subSettingCoords[selectedChannel] = null; + } else { + subSettingCoords[selectedChannel] = controlRodLocations[newIdx]; + } + } else if (CircuitType.canBeToggledBetweenPulseAndNormal(circuitType)) { + pulseActivated[selectedChannel] = !pulseActivated[selectedChannel]; + } + + updateSubSettingValueText(); + } + + private void updateSubSettingValueText() { + subSettingValueString.setLabelTooltip(""); + + CircuitType circuitType = grabTargets[selectedChannel].getCircuitType(); + + if (CircuitType.hasCoordinate(circuitType)) { + subSettingValueString + .setLabelText(getControlRodLabelFromLocation(circuitType, subSettingCoords[selectedChannel])); + } else if (TileEntityReactorRedNetPort.isInput(circuitType) + && CircuitType.canBeToggledBetweenPulseAndNormal(circuitType)) { + subSettingValueString.setLabelText(pulseActivated[selectedChannel] ? "Pulse" : "Level"); + } else if (circuitType == CircuitType.inputEjectWaste) { + subSettingValueString.setLabelText("Pulse"); + } else { + subSettingValueString.setLabelText(""); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorRedstonePort.java b/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorRedstonePort.java index 5da8aecf..04718546 100644 --- a/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorRedstonePort.java +++ b/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorRedstonePort.java @@ -23,608 +23,616 @@ public class GuiReactorRedstonePort extends BeefGuiBase { - private ResourceLocation _guiBackground; - private TileEntityReactorRedstonePort port; - - BeefGuiLabel titleString; - BeefGuiLabel settingString; - - private GuiButton commitBtn; - private GuiButton resetBtn; - - // Subsetting display - private BeefGuiLabel subSettingLabel; - private GuiButton subInputButton; - private GuiButton subInputButton2; - private BeefGuiLabel subInputRodSettingLabel; - private GuiTextField subInputRodSetting; // Also used as the pulse activation setting - private BeefGuiLabel subInputRodSettingPctLabel; - private BeefGuiLabel subInputRodSettingOffLabel; - private GuiTextField subInputRodSettingOff; - private BeefGuiLabel subInputRodSettingOffPctLabel; - - BeefGuiLabel subOutputValueLabel; - private GuiTextField subOutputValue; - // End Subsetting display - - private Map btnMap; - private int outputLevel; - private boolean greaterThan; - private boolean activeOnPulse; - private boolean retract; - - private static final int MINIMUM_SETTING_SELECTOR_ID = 10; - - public GuiReactorRedstonePort(Container container, TileEntityReactorRedstonePort tileentity) { - super(container); - _guiBackground = new ResourceLocation(BigReactors.GUI_DIRECTORY + "RedstonePort.png"); - port = tileentity; - - ySize = 204; - - btnMap = new HashMap(); - outputLevel = tileentity.getOutputLevel(); - greaterThan = tileentity.getGreaterThan(); - activeOnPulse = tileentity.isInputActiveOnPulse(); - - if(outputLevel < 0) { - retract = true; - outputLevel = Math.abs(outputLevel); - } - else { - retract = false; - } - } - - @Override - public ResourceLocation getGuiBackground() { - return _guiBackground; - } - - private void registerCircuitButton(CircuitType ct, GuiSelectableButton btn) { - this.btnMap.put(ct, btn); - registerControl(btn); - } - - @Override - public void initGui() { - super.initGui(); - - int leftX = guiLeft + 6; - int topY = guiTop + 6; - - titleString = new BeefGuiLabel(this, "Reactor Redstone Port", leftX+2, topY); - topY += titleString.getHeight() + 4; - - settingString = new BeefGuiLabel(this, "Pick a setting", leftX, topY); - topY += settingString.getHeight() + 4; - - // Setting picker - BlockReactorPart reactorPartBlock = (BlockReactorPart)BigReactors.blockReactorPart; - int buttonOrdinal = MINIMUM_SETTING_SELECTOR_ID; - leftX = guiLeft + 16; - CircuitType currentCircuitType = port.getCircuitType(); - for(CircuitType ct : CircuitType.values()) { - if(ct == CircuitType.DISABLED) { continue; } - GuiSelectableButton newBtn = new GuiSelectableButton(buttonOrdinal++, leftX, topY, reactorPartBlock.getRedNetConfigIcon(ct), 0xFF00FF00, this); - newBtn.displayString = GuiReactorRedNetPort.grabbableTooltips[ct.ordinal()-1]; - - if(ct == currentCircuitType) { - newBtn.setSelected(true); - } - - leftX += 28; - if(leftX > guiLeft + 130) { - topY += 28; - leftX = guiLeft + 16; - } - - registerCircuitButton(ct, newBtn); - } - - topY += 32; - leftX = guiLeft + 6; - - // Subsetting display - subSettingLabel = new BeefGuiLabel(this, "Settings", leftX, topY); - topY += subSettingLabel.getHeight() + 4; - - subInputButton = new GuiButton(2, leftX, topY, 100, 20, "Activate on Pulse"); - subInputButton2 = new GuiButton(3, leftX + xSize - 46, topY, 36, 20, "Mode"); - topY += 24; - - subInputRodSettingLabel = new BeefGuiLabel(this, "While On", leftX, topY); - subInputRodSettingOffLabel = new BeefGuiLabel(this, "While Off", leftX + xSize/2, topY); - - subOutputValue = new GuiTextField(this.fontRendererObj, leftX, topY, 60, 12); - subOutputValue.setCanLoseFocus(true); - subOutputValue.setMaxStringLength(7); - subOutputValue.setText("0"); - subOutputValue.setEnabled(true); - - subOutputValueLabel = new BeefGuiLabel(this, "C", leftX + 62, topY + 2); - - topY += subInputRodSettingLabel.getHeight() + 2; - - subInputRodSetting = new GuiTextField(this.fontRendererObj, leftX, topY, 32, 12); - subInputRodSetting.setCanLoseFocus(true); - subInputRodSetting.setMaxStringLength(3); - subInputRodSetting.setText("0"); - subInputRodSetting.setEnabled(true); - - subInputRodSettingPctLabel = new BeefGuiLabel(this, "%", leftX + 34, topY + 2); - - subInputRodSettingOff = new GuiTextField(this.fontRendererObj, leftX + xSize/2, topY, 32, 12); - subInputRodSettingOff.setCanLoseFocus(true); - subInputRodSettingOff.setMaxStringLength(3); - subInputRodSettingOff.setText("0"); - subInputRodSettingOff.setEnabled(true); - subInputRodSettingOffPctLabel = new BeefGuiLabel(this, "%", leftX + xSize/2 + 34, topY + 2); - - topY += 24; - - // Bottom buttons - commitBtn = new GuiButton(0, guiLeft + xSize - 60, guiTop + ySize - 24, 56, 20, "Commit"); - commitBtn.enabled = false; - - resetBtn = new GuiButton(1, guiLeft + 4, guiTop + ySize - 24, 56, 20, "Reset"); - - registerControl(titleString); - registerControl(settingString); - registerControl(subSettingLabel); - registerControl(subInputButton); - registerControl(subInputButton2); - registerControl(subInputRodSettingLabel); - registerControl(subInputRodSettingOffLabel); - registerControl(subInputRodSetting); - registerControl(subInputRodSettingOff); - registerControl(subInputRodSettingPctLabel); - registerControl(subInputRodSettingOffPctLabel); - registerControl(subOutputValue); - registerControl(subOutputValueLabel); - - registerControl(commitBtn); - registerControl(resetBtn); - - if(currentCircuitType == CircuitType.inputSetControlRod) { - subInputRodSetting.setText(Integer.toString(TileEntityReactorRedstonePort.unpackControlRodLevelOn(this.outputLevel))); - subInputRodSettingOff.setText(Integer.toString(TileEntityReactorRedstonePort.unpackControlRodLevelOff(this.outputLevel))); - } - else if(TileEntityReactorRedNetPort.isOutput(currentCircuitType)) { - subOutputValue.setText(Integer.toString(this.outputLevel)); - } - - updateSubSettings(currentCircuitType); - if(TileEntityReactorRedNetPort.isInput(currentCircuitType)) { - validateInputValues(); - } - else { - validateOutputValues(); - } - } - - @Override - public void updateScreen() { - super.updateScreen(); - - CircuitType selectedSetting = getUserSelectedCircuitType(); - updateSubSettings(selectedSetting); - - if(selectedSetting == port.getCircuitType()) { - int actualOutputLevel = this.outputLevel; - if(selectedSetting == CircuitType.inputSetControlRod && this.greaterThan && this.retract) { actualOutputLevel *= -1; } - - if(this.activeOnPulse != port.isInputActiveOnPulse() || - this.greaterThan != port.getGreaterThan() || - actualOutputLevel != port.getOutputLevel()) { - commitBtn.enabled = true; - } - else { - commitBtn.enabled = false; - } - } - else { - commitBtn.enabled = true; - } - } - - private void updateSubSettings(CircuitType selectedSetting) { - this.subSettingLabel.setLabelText(getLabelFromSelectedSubSetting(selectedSetting)); - updateSubSettingInputButton(selectedSetting); - updateSubSettingTextFields(selectedSetting); - } - - private String getLabelFromSelectedSubSetting(CircuitType selectedSetting) { - switch(selectedSetting) { - case inputActive: return "Input - Enable/Disable"; - case inputEjectWaste: return "Input - Eject Waste"; - case inputSetControlRod: return "Input - Control Rod Insertion"; - case outputFuelAmount: return "Output - Fuel Amount"; - case outputWasteAmount: return "Output - Waste Amount"; - case outputFuelMix: return "Output - Fuel Enrichment %"; - case outputFuelTemperature: return "Output - Fuel Temp (C)"; - case outputCasingTemperature: return "Output - Casing Temp (C)"; - case outputEnergyAmount: return "Output - Energy Amount (%)"; - default: - return ""; - } - } - - private void updateSubSettingInputButton(CircuitType selectedSetting) { - subInputButton.visible = true; - subInputButton2.visible = false; - switch(selectedSetting) { - case inputActive: - subInputButton.enabled = true; - if(this.activeOnPulse) { - subInputButton.displayString = "Toggle on Pulse"; - } - else { - subInputButton.displayString = "Set from Signal"; - } - break; - case inputSetControlRod: - subInputButton.enabled = true; - if(this.activeOnPulse) { - subInputButton2.visible = true; - if(this.greaterThan) { - if(this.retract) { - subInputButton.displayString = "Retract on Pulse"; - } - else { - subInputButton.displayString = "Insert on Pulse"; - } - } - else { - subInputButton.displayString = "Set on Pulse"; - } - } - else { - subInputButton.displayString = "Set from Signal"; - } - break; - case inputEjectWaste: - subInputButton.enabled = false; - subInputButton.displayString = "Eject on Pulse"; - break; - case outputFuelTemperature: - case outputCasingTemperature: - case outputFuelMix: - case outputFuelAmount: - case outputWasteAmount: - case outputEnergyAmount: - subInputButton.enabled = true; - if(this.greaterThan) { - subInputButton.displayString = "Active While Above"; - } - else { - subInputButton.displayString = "Active While Below"; - } - break; - default: - subInputButton.visible = false; - } - } - - private void updateSubSettingTextFields(CircuitType selectedSetting) { - subOutputValueLabel.setLabelText(""); - subInputRodSettingLabel.setLabelText(""); - subInputRodSettingPctLabel.setLabelText(""); - subInputRodSettingOffLabel.setLabelText(""); - subInputRodSettingOffPctLabel.setLabelText(""); - subOutputValueLabel.setLabelTooltip(""); - - subInputRodSetting.setVisible(false); - subInputRodSettingOff.setVisible(false); - subOutputValue.setVisible(false); - - switch(selectedSetting) { - case outputFuelTemperature: - case outputCasingTemperature: - subOutputValueLabel.setLabelText("C"); - subOutputValueLabel.setLabelTooltip("Degrees centigrade"); - subOutputValue.setVisible(true); - break; - case outputFuelMix: - subOutputValueLabel.setLabelText("%"); - subOutputValueLabel.setLabelTooltip("% of total contents, 0% if empty"); - subOutputValue.setVisible(true); - break; - case outputEnergyAmount: - subOutputValueLabel.setLabelText("%"); - subOutputValueLabel.setLabelTooltip("% of energy buffer filled, 0% if empty"); - subOutputValue.setVisible(true); - break; - case outputFuelAmount: - subOutputValueLabel.setLabelText("mB"); - subOutputValueLabel.setLabelTooltip("Milli-buckets"); - subOutputValue.setVisible(true); - break; - case outputWasteAmount: - subOutputValueLabel.setLabelText("mB"); - subOutputValueLabel.setLabelTooltip("Milli-buckets"); - subOutputValue.setVisible(true); - break; - case inputSetControlRod: - if(this.activeOnPulse) { - if(this.greaterThan) { - if(this.retract) { - subInputRodSettingLabel.setLabelText("Retract by"); - } - else { - subInputRodSettingLabel.setLabelText("Insert by"); - } - } - else { - subInputRodSettingLabel.setLabelText("Set to"); - } - } - else { - subInputRodSettingLabel.setLabelText("While On"); - subInputRodSettingOffLabel.setLabelText("While Off"); - subInputRodSettingOffPctLabel.setLabelText("%"); - subInputRodSettingOff.setVisible(true); - } - subInputRodSetting.setVisible(true); - subInputRodSettingPctLabel.setLabelText("%"); - break; - default: - break; - - } - } - - @Override - protected void actionPerformed(GuiButton clickedButton) { - if(clickedButton.id == 0) { - CircuitType newCircuitType = getUserSelectedCircuitType(); - int actualOutputLevel = this.outputLevel; - if(newCircuitType == CircuitType.inputSetControlRod && this.greaterThan && this.retract) { actualOutputLevel *= -1; } - - CommonPacketHandler.INSTANCE.sendToServer(new ReactorRedstonePortChangeMessage(port, newCircuitType.ordinal(), actualOutputLevel, this.greaterThan, this.activeOnPulse)); + private ResourceLocation _guiBackground; + private TileEntityReactorRedstonePort port; + + BeefGuiLabel titleString; + BeefGuiLabel settingString; + + private GuiButton commitBtn; + private GuiButton resetBtn; + + // Subsetting display + private BeefGuiLabel subSettingLabel; + private GuiButton subInputButton; + private GuiButton subInputButton2; + private BeefGuiLabel subInputRodSettingLabel; + private GuiTextField subInputRodSetting; // Also used as the pulse activation setting + private BeefGuiLabel subInputRodSettingPctLabel; + private BeefGuiLabel subInputRodSettingOffLabel; + private GuiTextField subInputRodSettingOff; + private BeefGuiLabel subInputRodSettingOffPctLabel; + + BeefGuiLabel subOutputValueLabel; + private GuiTextField subOutputValue; + // End Subsetting display + + private Map btnMap; + private int outputLevel; + private boolean greaterThan; + private boolean activeOnPulse; + private boolean retract; + + private static final int MINIMUM_SETTING_SELECTOR_ID = 10; + + public GuiReactorRedstonePort(Container container, TileEntityReactorRedstonePort tileentity) { + super(container); + _guiBackground = new ResourceLocation(BigReactors.GUI_DIRECTORY + "RedstonePort.png"); + port = tileentity; + + ySize = 204; + + btnMap = new HashMap(); + outputLevel = tileentity.getOutputLevel(); + greaterThan = tileentity.getGreaterThan(); + activeOnPulse = tileentity.isInputActiveOnPulse(); + + if (outputLevel < 0) { + retract = true; + outputLevel = Math.abs(outputLevel); + } else { + retract = false; } - else if(clickedButton.id == 1) { - for(Entry pair : btnMap.entrySet()) { - pair.getValue().setSelected(pair.getKey() == port.getCircuitType()); - } - - setSubSettingsToDefaults(port.getCircuitType()); - } - else if(clickedButton.id == 2) { - CircuitType selectedCircuitType = this.getUserSelectedCircuitType(); - if(TileEntityReactorRedNetPort.isInput(selectedCircuitType)) - this.activeOnPulse = !this.activeOnPulse; - else - this.greaterThan = !this.greaterThan; - } - else if(clickedButton.id == 3) { - if(this.greaterThan && !this.retract) { - // Insert -> Retract - this.greaterThan = true; - this.retract = true; - } - else if(this.greaterThan && this.retract) { - // Retract -> Set - this.greaterThan = false; - this.retract = false; - } - else { - // Set -> Insert - this.greaterThan = true; - this.retract = false; // Doesn't actually matter, but hey, keeping it tidy. - } - } - else if(clickedButton.id >= MINIMUM_SETTING_SELECTOR_ID && clickedButton.id < MINIMUM_SETTING_SELECTOR_ID + btnMap.size()) { - CircuitType ct = CircuitType.DISABLED; - for(Entry pair : btnMap.entrySet()) { - GuiSelectableButton btn = pair.getValue(); - btn.setSelected(btn.id == clickedButton.id); - - if(btn.isSelected()) { - ct = pair.getKey(); - } - } - - setSubSettingsToDefaults(ct); - } - } - - private void setSubSettingsToDefaults(CircuitType selectedType) { - if(port.getCircuitType() == selectedType) { - // RESTORE ALL THE DEFAULTS - this.outputLevel = port.getOutputLevel(); - this.greaterThan = port.getGreaterThan(); - this.activeOnPulse = port.isInputActiveOnPulse(); - if(this.outputLevel < 0) { - this.retract = true; - this.outputLevel = Math.abs(this.outputLevel); - } - else { - this.retract = false; - } - } - else { - this.greaterThan = true; - this.activeOnPulse = false; - this.outputLevel = 0; - - // We do this so the state of the fields is accurate for the following two methods - updateSubSettingTextFields(selectedType); - - // This should reset outputLevel from stored values - if(TileEntityReactorRedNetPort.isInput(selectedType)) { - this.validateInputValues(); - } - else { - this.validateOutputValues(); - } - } - - this.subInputRodSetting.setFocused(false); - this.subInputRodSettingOff.setFocused(false); - this.subOutputValue.setFocused(false); - } - - // Allow 0-9 (regular or numpad), backspace, delete, left/right arrows. - private boolean isKeyValidForValueInput(int keyCode) { - if(keyCode >= Keyboard.KEY_1 && keyCode <= Keyboard.KEY_0) { return true; } - switch(keyCode) { - case Keyboard.KEY_NUMPAD0: - case Keyboard.KEY_NUMPAD1: - case Keyboard.KEY_NUMPAD2: - case Keyboard.KEY_NUMPAD3: - case Keyboard.KEY_NUMPAD4: - case Keyboard.KEY_NUMPAD5: - case Keyboard.KEY_NUMPAD6: - case Keyboard.KEY_NUMPAD7: - case Keyboard.KEY_NUMPAD8: - case Keyboard.KEY_NUMPAD9: - case Keyboard.KEY_DELETE: - case Keyboard.KEY_BACK: - case Keyboard.KEY_LEFT: - case Keyboard.KEY_RIGHT: - return true; - default: - return false; - } - } - - @Override - protected void keyTyped(char inputChar, int keyCode) { - boolean isAnyTextboxFocused = this.subInputRodSetting.isFocused() || - this.subInputRodSettingOff.isFocused() || - this.subOutputValue.isFocused(); - - if (keyCode == Keyboard.KEY_ESCAPE || - (!isAnyTextboxFocused && keyCode == this.mc.gameSettings.keyBindInventory.getKeyCode())) { + } + + @Override + public ResourceLocation getGuiBackground() { + return _guiBackground; + } + + private void registerCircuitButton(CircuitType ct, GuiSelectableButton btn) { + this.btnMap.put(ct, btn); + registerControl(btn); + } + + @Override + public void initGui() { + super.initGui(); + + int leftX = guiLeft + 6; + int topY = guiTop + 6; + + titleString = new BeefGuiLabel(this, "Reactor Redstone Port", leftX + 2, topY); + topY += titleString.getHeight() + 4; + + settingString = new BeefGuiLabel(this, "Pick a setting", leftX, topY); + topY += settingString.getHeight() + 4; + + // Setting picker + BlockReactorPart reactorPartBlock = (BlockReactorPart) BigReactors.blockReactorPart; + int buttonOrdinal = MINIMUM_SETTING_SELECTOR_ID; + leftX = guiLeft + 16; + CircuitType currentCircuitType = port.getCircuitType(); + for (CircuitType ct : CircuitType.values()) { + if (ct == CircuitType.DISABLED) { + continue; + } + GuiSelectableButton newBtn = new GuiSelectableButton( + buttonOrdinal++, + leftX, + topY, + reactorPartBlock.getRedNetConfigIcon(ct), + 0xFF00FF00, + this); + newBtn.displayString = GuiReactorRedNetPort.grabbableTooltips[ct.ordinal() - 1]; + + if (ct == currentCircuitType) { + newBtn.setSelected(true); + } + + leftX += 28; + if (leftX > guiLeft + 130) { + topY += 28; + leftX = guiLeft + 16; + } + + registerCircuitButton(ct, newBtn); + } + + topY += 32; + leftX = guiLeft + 6; + + // Subsetting display + subSettingLabel = new BeefGuiLabel(this, "Settings", leftX, topY); + topY += subSettingLabel.getHeight() + 4; + + subInputButton = new GuiButton(2, leftX, topY, 100, 20, "Activate on Pulse"); + subInputButton2 = new GuiButton(3, leftX + xSize - 46, topY, 36, 20, "Mode"); + topY += 24; + + subInputRodSettingLabel = new BeefGuiLabel(this, "While On", leftX, topY); + subInputRodSettingOffLabel = new BeefGuiLabel(this, "While Off", leftX + xSize / 2, topY); + + subOutputValue = new GuiTextField(this.fontRendererObj, leftX, topY, 60, 12); + subOutputValue.setCanLoseFocus(true); + subOutputValue.setMaxStringLength(7); + subOutputValue.setText("0"); + subOutputValue.setEnabled(true); + + subOutputValueLabel = new BeefGuiLabel(this, "C", leftX + 62, topY + 2); + + topY += subInputRodSettingLabel.getHeight() + 2; + + subInputRodSetting = new GuiTextField(this.fontRendererObj, leftX, topY, 32, 12); + subInputRodSetting.setCanLoseFocus(true); + subInputRodSetting.setMaxStringLength(3); + subInputRodSetting.setText("0"); + subInputRodSetting.setEnabled(true); + + subInputRodSettingPctLabel = new BeefGuiLabel(this, "%", leftX + 34, topY + 2); + + subInputRodSettingOff = new GuiTextField(this.fontRendererObj, leftX + xSize / 2, topY, 32, 12); + subInputRodSettingOff.setCanLoseFocus(true); + subInputRodSettingOff.setMaxStringLength(3); + subInputRodSettingOff.setText("0"); + subInputRodSettingOff.setEnabled(true); + subInputRodSettingOffPctLabel = new BeefGuiLabel(this, "%", leftX + xSize / 2 + 34, topY + 2); + + topY += 24; + + // Bottom buttons + commitBtn = new GuiButton(0, guiLeft + xSize - 60, guiTop + ySize - 24, 56, 20, "Commit"); + commitBtn.enabled = false; + + resetBtn = new GuiButton(1, guiLeft + 4, guiTop + ySize - 24, 56, 20, "Reset"); + + registerControl(titleString); + registerControl(settingString); + registerControl(subSettingLabel); + registerControl(subInputButton); + registerControl(subInputButton2); + registerControl(subInputRodSettingLabel); + registerControl(subInputRodSettingOffLabel); + registerControl(subInputRodSetting); + registerControl(subInputRodSettingOff); + registerControl(subInputRodSettingPctLabel); + registerControl(subInputRodSettingOffPctLabel); + registerControl(subOutputValue); + registerControl(subOutputValueLabel); + + registerControl(commitBtn); + registerControl(resetBtn); + + if (currentCircuitType == CircuitType.inputSetControlRod) { + subInputRodSetting + .setText(Integer.toString(TileEntityReactorRedstonePort.unpackControlRodLevelOn(this.outputLevel))); + subInputRodSettingOff + .setText(Integer.toString(TileEntityReactorRedstonePort.unpackControlRodLevelOff(this.outputLevel))); + } else if (TileEntityReactorRedNetPort.isOutput(currentCircuitType)) { + subOutputValue.setText(Integer.toString(this.outputLevel)); + } + + updateSubSettings(currentCircuitType); + if (TileEntityReactorRedNetPort.isInput(currentCircuitType)) { + validateInputValues(); + } else { + validateOutputValues(); + } + } + + @Override + public void updateScreen() { + super.updateScreen(); + + CircuitType selectedSetting = getUserSelectedCircuitType(); + updateSubSettings(selectedSetting); + + if (selectedSetting == port.getCircuitType()) { + int actualOutputLevel = this.outputLevel; + if (selectedSetting == CircuitType.inputSetControlRod && this.greaterThan && this.retract) { + actualOutputLevel *= -1; + } + + if (this.activeOnPulse != port.isInputActiveOnPulse() || this.greaterThan != port.getGreaterThan() + || actualOutputLevel != port.getOutputLevel()) { + commitBtn.enabled = true; + } else { + commitBtn.enabled = false; + } + } else { + commitBtn.enabled = true; + } + } + + private void updateSubSettings(CircuitType selectedSetting) { + this.subSettingLabel.setLabelText(getLabelFromSelectedSubSetting(selectedSetting)); + updateSubSettingInputButton(selectedSetting); + updateSubSettingTextFields(selectedSetting); + } + + private String getLabelFromSelectedSubSetting(CircuitType selectedSetting) { + switch (selectedSetting) { + case inputActive: + return "Input - Enable/Disable"; + case inputEjectWaste: + return "Input - Eject Waste"; + case inputSetControlRod: + return "Input - Control Rod Insertion"; + case outputFuelAmount: + return "Output - Fuel Amount"; + case outputWasteAmount: + return "Output - Waste Amount"; + case outputFuelMix: + return "Output - Fuel Enrichment %"; + case outputFuelTemperature: + return "Output - Fuel Temp (C)"; + case outputCasingTemperature: + return "Output - Casing Temp (C)"; + case outputEnergyAmount: + return "Output - Energy Amount (%)"; + default: + return ""; + } + } + + private void updateSubSettingInputButton(CircuitType selectedSetting) { + subInputButton.visible = true; + subInputButton2.visible = false; + switch (selectedSetting) { + case inputActive: + subInputButton.enabled = true; + if (this.activeOnPulse) { + subInputButton.displayString = "Toggle on Pulse"; + } else { + subInputButton.displayString = "Set from Signal"; + } + break; + case inputSetControlRod: + subInputButton.enabled = true; + if (this.activeOnPulse) { + subInputButton2.visible = true; + if (this.greaterThan) { + if (this.retract) { + subInputButton.displayString = "Retract on Pulse"; + } else { + subInputButton.displayString = "Insert on Pulse"; + } + } else { + subInputButton.displayString = "Set on Pulse"; + } + } else { + subInputButton.displayString = "Set from Signal"; + } + break; + case inputEjectWaste: + subInputButton.enabled = false; + subInputButton.displayString = "Eject on Pulse"; + break; + case outputFuelTemperature: + case outputCasingTemperature: + case outputFuelMix: + case outputFuelAmount: + case outputWasteAmount: + case outputEnergyAmount: + subInputButton.enabled = true; + if (this.greaterThan) { + subInputButton.displayString = "Active While Above"; + } else { + subInputButton.displayString = "Active While Below"; + } + break; + default: + subInputButton.visible = false; + } + } + + private void updateSubSettingTextFields(CircuitType selectedSetting) { + subOutputValueLabel.setLabelText(""); + subInputRodSettingLabel.setLabelText(""); + subInputRodSettingPctLabel.setLabelText(""); + subInputRodSettingOffLabel.setLabelText(""); + subInputRodSettingOffPctLabel.setLabelText(""); + subOutputValueLabel.setLabelTooltip(""); + + subInputRodSetting.setVisible(false); + subInputRodSettingOff.setVisible(false); + subOutputValue.setVisible(false); + + switch (selectedSetting) { + case outputFuelTemperature: + case outputCasingTemperature: + subOutputValueLabel.setLabelText("C"); + subOutputValueLabel.setLabelTooltip("Degrees centigrade"); + subOutputValue.setVisible(true); + break; + case outputFuelMix: + subOutputValueLabel.setLabelText("%"); + subOutputValueLabel.setLabelTooltip("% of total contents, 0% if empty"); + subOutputValue.setVisible(true); + break; + case outputEnergyAmount: + subOutputValueLabel.setLabelText("%"); + subOutputValueLabel.setLabelTooltip("% of energy buffer filled, 0% if empty"); + subOutputValue.setVisible(true); + break; + case outputFuelAmount: + subOutputValueLabel.setLabelText("mB"); + subOutputValueLabel.setLabelTooltip("Milli-buckets"); + subOutputValue.setVisible(true); + break; + case outputWasteAmount: + subOutputValueLabel.setLabelText("mB"); + subOutputValueLabel.setLabelTooltip("Milli-buckets"); + subOutputValue.setVisible(true); + break; + case inputSetControlRod: + if (this.activeOnPulse) { + if (this.greaterThan) { + if (this.retract) { + subInputRodSettingLabel.setLabelText("Retract by"); + } else { + subInputRodSettingLabel.setLabelText("Insert by"); + } + } else { + subInputRodSettingLabel.setLabelText("Set to"); + } + } else { + subInputRodSettingLabel.setLabelText("While On"); + subInputRodSettingOffLabel.setLabelText("While Off"); + subInputRodSettingOffPctLabel.setLabelText("%"); + subInputRodSettingOff.setVisible(true); + } + subInputRodSetting.setVisible(true); + subInputRodSettingPctLabel.setLabelText("%"); + break; + default: + break; + + } + } + + @Override + protected void actionPerformed(GuiButton clickedButton) { + if (clickedButton.id == 0) { + CircuitType newCircuitType = getUserSelectedCircuitType(); + int actualOutputLevel = this.outputLevel; + if (newCircuitType == CircuitType.inputSetControlRod && this.greaterThan && this.retract) { + actualOutputLevel *= -1; + } + + CommonPacketHandler.INSTANCE.sendToServer( + new ReactorRedstonePortChangeMessage( + port, + newCircuitType.ordinal(), + actualOutputLevel, + this.greaterThan, + this.activeOnPulse)); + } else if (clickedButton.id == 1) { + for (Entry pair : btnMap.entrySet()) { + pair.getValue() + .setSelected(pair.getKey() == port.getCircuitType()); + } + + setSubSettingsToDefaults(port.getCircuitType()); + } else if (clickedButton.id == 2) { + CircuitType selectedCircuitType = this.getUserSelectedCircuitType(); + if (TileEntityReactorRedNetPort.isInput(selectedCircuitType)) this.activeOnPulse = !this.activeOnPulse; + else this.greaterThan = !this.greaterThan; + } else if (clickedButton.id == 3) { + if (this.greaterThan && !this.retract) { + // Insert -> Retract + this.greaterThan = true; + this.retract = true; + } else if (this.greaterThan && this.retract) { + // Retract -> Set + this.greaterThan = false; + this.retract = false; + } else { + // Set -> Insert + this.greaterThan = true; + this.retract = false; // Doesn't actually matter, but hey, keeping it tidy. + } + } else if (clickedButton.id >= MINIMUM_SETTING_SELECTOR_ID + && clickedButton.id < MINIMUM_SETTING_SELECTOR_ID + btnMap.size()) { + CircuitType ct = CircuitType.DISABLED; + for (Entry pair : btnMap.entrySet()) { + GuiSelectableButton btn = pair.getValue(); + btn.setSelected(btn.id == clickedButton.id); + + if (btn.isSelected()) { + ct = pair.getKey(); + } + } + + setSubSettingsToDefaults(ct); + } + } + + private void setSubSettingsToDefaults(CircuitType selectedType) { + if (port.getCircuitType() == selectedType) { + // RESTORE ALL THE DEFAULTS + this.outputLevel = port.getOutputLevel(); + this.greaterThan = port.getGreaterThan(); + this.activeOnPulse = port.isInputActiveOnPulse(); + if (this.outputLevel < 0) { + this.retract = true; + this.outputLevel = Math.abs(this.outputLevel); + } else { + this.retract = false; + } + } else { + this.greaterThan = true; + this.activeOnPulse = false; + this.outputLevel = 0; + + // We do this so the state of the fields is accurate for the following two methods + updateSubSettingTextFields(selectedType); + + // This should reset outputLevel from stored values + if (TileEntityReactorRedNetPort.isInput(selectedType)) { + this.validateInputValues(); + } else { + this.validateOutputValues(); + } + } + + this.subInputRodSetting.setFocused(false); + this.subInputRodSettingOff.setFocused(false); + this.subOutputValue.setFocused(false); + } + + // Allow 0-9 (regular or numpad), backspace, delete, left/right arrows. + private boolean isKeyValidForValueInput(int keyCode) { + if (keyCode >= Keyboard.KEY_1 && keyCode <= Keyboard.KEY_0) { + return true; + } + switch (keyCode) { + case Keyboard.KEY_NUMPAD0: + case Keyboard.KEY_NUMPAD1: + case Keyboard.KEY_NUMPAD2: + case Keyboard.KEY_NUMPAD3: + case Keyboard.KEY_NUMPAD4: + case Keyboard.KEY_NUMPAD5: + case Keyboard.KEY_NUMPAD6: + case Keyboard.KEY_NUMPAD7: + case Keyboard.KEY_NUMPAD8: + case Keyboard.KEY_NUMPAD9: + case Keyboard.KEY_DELETE: + case Keyboard.KEY_BACK: + case Keyboard.KEY_LEFT: + case Keyboard.KEY_RIGHT: + return true; + default: + return false; + } + } + + @Override + protected void keyTyped(char inputChar, int keyCode) { + boolean isAnyTextboxFocused = this.subInputRodSetting.isFocused() || this.subInputRodSettingOff.isFocused() + || this.subOutputValue.isFocused(); + + if (keyCode == Keyboard.KEY_ESCAPE + || (!isAnyTextboxFocused && keyCode == this.mc.gameSettings.keyBindInventory.getKeyCode())) { this.mc.thePlayer.closeScreen(); } // Allow arrow keys, 0-9, and delete - if(isKeyValidForValueInput(keyCode)) { - if(this.subInputRodSetting.isFocused()) { - this.subInputRodSetting.textboxKeyTyped(inputChar, keyCode); + if (isKeyValidForValueInput(keyCode)) { + if (this.subInputRodSetting.isFocused()) { + this.subInputRodSetting.textboxKeyTyped(inputChar, keyCode); validateInputValues(); } - if(this.subInputRodSettingOff.isFocused()) { - this.subInputRodSettingOff.textboxKeyTyped(inputChar, keyCode); + if (this.subInputRodSettingOff.isFocused()) { + this.subInputRodSettingOff.textboxKeyTyped(inputChar, keyCode); validateInputValues(); } - if(this.subOutputValue.isFocused()) { - this.subOutputValue.textboxKeyTyped(inputChar, keyCode); - validateOutputValues(); + if (this.subOutputValue.isFocused()) { + this.subOutputValue.textboxKeyTyped(inputChar, keyCode); + validateOutputValues(); + } + + } + + if (keyCode == Keyboard.KEY_TAB) { + /// ffffffuuuuuuuck tabbing + if (this.subOutputValue.isFocused()) { + this.subOutputValue.setFocused(false); + } else if (this.subOutputValue.getVisible()) { + this.subOutputValue.setFocused(true); + } + + if (this.subInputRodSettingOff.getVisible()) { + if (this.subInputRodSetting.isFocused()) { + this.subInputRodSetting.setFocused(false); + this.subInputRodSettingOff.setFocused(true); + } else if (this.subInputRodSettingOff.isFocused()) { + this.subInputRodSettingOff.setFocused(false); + } else { + this.subInputRodSetting.setFocused(true); + } + } else if (this.subInputRodSetting.getVisible()) { + if (this.subInputRodSetting.isFocused()) { + this.subInputRodSetting.setFocused(false); + } else { + this.subInputRodSetting.setFocused(true); + } + } + // Else, nothing is visible, nothing is focused, screw you. + } + + if (keyCode == Keyboard.KEY_RETURN && isAnyTextboxFocused) { + this.subInputRodSetting.setFocused(false); + this.subInputRodSettingOff.setFocused(false); + this.subOutputValue.setFocused(false); + } + } + + private void validateInputValues() { + outputLevel = 0; + String in1 = this.subInputRodSetting.getText(); + int val1; + if (in1.isEmpty()) { + val1 = 0; + } else { + val1 = Integer.parseInt(in1); + if (val1 < 0) { + val1 = 0; + } else if (val1 > 100) { + val1 = 100; + } + } + this.subInputRodSetting.setText(Integer.toString(val1)); + + if (this.subInputRodSettingOff.getVisible()) { + int val2; + String in2 = this.subInputRodSettingOff.getText(); + if (in2.isEmpty()) { + val2 = 0; + } else { + val2 = Integer.parseInt(in2); + if (val2 < 0) { + val2 = 0; + } else if (val2 > 100) { + val2 = 100; + } } - + // pack into high-order bits + this.outputLevel = (val2 << 8) & 0xFF00; + + this.subInputRodSettingOff.setText(Integer.toString(val2)); + } else { + // Preserve high-order bits + this.outputLevel = this.outputLevel & 0xFF00; } - - if(keyCode == Keyboard.KEY_TAB) { - /// ffffffuuuuuuuck tabbing - if(this.subOutputValue.isFocused()) { - this.subOutputValue.setFocused(false); - } - else if(this.subOutputValue.getVisible()) { - this.subOutputValue.setFocused(true); - } - - if(this.subInputRodSettingOff.getVisible()) { - if(this.subInputRodSetting.isFocused()) { - this.subInputRodSetting.setFocused(false); - this.subInputRodSettingOff.setFocused(true); - } - else if(this.subInputRodSettingOff.isFocused()) { - this.subInputRodSettingOff.setFocused(false); - } - else { - this.subInputRodSetting.setFocused(true); - } - } - else if(this.subInputRodSetting.getVisible()) { - if(this.subInputRodSetting.isFocused()) { - this.subInputRodSetting.setFocused(false); - } - else { - this.subInputRodSetting.setFocused(true); - } - } - // Else, nothing is visible, nothing is focused, screw you. - } - - if(keyCode == Keyboard.KEY_RETURN && isAnyTextboxFocused) { - this.subInputRodSetting.setFocused(false); - this.subInputRodSettingOff.setFocused(false); - this.subOutputValue.setFocused(false); - } - } - - private void validateInputValues() { - outputLevel = 0; - String in1 = this.subInputRodSetting.getText(); - int val1; - if(in1.isEmpty()) { - val1 = 0; - } - else { - val1 = Integer.parseInt(in1); - if(val1 < 0) { val1 = 0; } - else if(val1 > 100) { val1 = 100; } - } - this.subInputRodSetting.setText(Integer.toString(val1)); - - if(this.subInputRodSettingOff.getVisible()) { - int val2; - String in2 = this.subInputRodSettingOff.getText(); - if(in2.isEmpty()) { - val2 = 0; - } - else { - val2 = Integer.parseInt(in2); - if(val2 < 0) { val2 = 0; } - else if(val2 > 100) { val2 = 100; } - } - // pack into high-order bits - this.outputLevel = (val2 << 8) & 0xFF00; - - this.subInputRodSettingOff.setText(Integer.toString(val2)); - } - else { - // Preserve high-order bits - this.outputLevel = this.outputLevel & 0xFF00; - } - - // Pack in low-order bits - this.outputLevel |= val1 & 0xFF; - } - - private void validateOutputValues() { - CircuitType selectedType = getUserSelectedCircuitType(); - int maxVal = Integer.MAX_VALUE; - if(selectedType == CircuitType.outputFuelMix || selectedType == CircuitType.outputEnergyAmount) { - // Percentile - maxVal = 100; - } - - String in1 = this.subOutputValue.getText(); - int val1; - if(in1.isEmpty()) { - val1 = 0; - } - else { - val1 = Integer.parseInt(in1); - if(val1 < 0) { val1 = 0; } - else if(val1 > maxVal) { val1 = maxVal; } - } - this.subOutputValue.setText(Integer.toString(val1)); - - this.outputLevel = val1; - } - - private CircuitType getUserSelectedCircuitType() { - for(Entry pair : btnMap.entrySet()) { - if(pair.getValue().isSelected()) { - return pair.getKey(); - } - } - - return CircuitType.DISABLED; - } + + // Pack in low-order bits + this.outputLevel |= val1 & 0xFF; + } + + private void validateOutputValues() { + CircuitType selectedType = getUserSelectedCircuitType(); + int maxVal = Integer.MAX_VALUE; + if (selectedType == CircuitType.outputFuelMix || selectedType == CircuitType.outputEnergyAmount) { + // Percentile + maxVal = 100; + } + + String in1 = this.subOutputValue.getText(); + int val1; + if (in1.isEmpty()) { + val1 = 0; + } else { + val1 = Integer.parseInt(in1); + if (val1 < 0) { + val1 = 0; + } else if (val1 > maxVal) { + val1 = maxVal; + } + } + this.subOutputValue.setText(Integer.toString(val1)); + + this.outputLevel = val1; + } + + private CircuitType getUserSelectedCircuitType() { + for (Entry pair : btnMap.entrySet()) { + if (pair.getValue() + .isSelected()) { + return pair.getKey(); + } + } + + return CircuitType.DISABLED; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorStatus.java b/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorStatus.java index 895efe4c..6889d84b 100644 --- a/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorStatus.java +++ b/src/main/java/erogenousbeef/bigreactors/client/gui/GuiReactorStatus.java @@ -4,6 +4,7 @@ import net.minecraft.inventory.Container; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.ResourceLocation; + import erogenousbeef.bigreactors.client.ClientProxy; import erogenousbeef.bigreactors.common.BigReactors; import erogenousbeef.bigreactors.common.multiblock.MultiblockReactor; @@ -22,286 +23,365 @@ import erogenousbeef.bigreactors.net.message.multiblock.ReactorChangeWasteEjectionMessage; import erogenousbeef.bigreactors.net.message.multiblock.ReactorCommandEjectMessage; import erogenousbeef.bigreactors.utils.StaticUtils; -import erogenousbeef.core.common.CoordTriplet; public class GuiReactorStatus extends BeefGuiBase { - private GuiIconButton btnReactorOn; - private GuiIconButton btnReactorOff; - private GuiIconButton btnWasteAutoEject; - private GuiIconButton btnWasteManual; - - private GuiIconButton btnWasteEject; - - private TileEntityReactorPart part; - private MultiblockReactor reactor; - - private BeefGuiLabel titleString; - private BeefGuiLabel statusString; - - private BeefGuiIcon heatIcon; - private BeefGuiLabel heatString; - private BeefGuiIcon outputIcon; - private BeefGuiLabel outputString; - private BeefGuiIcon fuelConsumedIcon; - private BeefGuiLabel fuelConsumedString; - private BeefGuiIcon reactivityIcon; - private BeefGuiLabel reactivityString; - - private BeefGuiPowerBar powerBar; - private BeefGuiHeatBar coreHeatBar; - private BeefGuiHeatBar caseHeatBar; - private BeefGuiFuelMixBar fuelMixBar; - - private BeefGuiIcon coolantIcon; - private BeefGuiFluidBar coolantBar; - private BeefGuiIcon hotFluidIcon; - private BeefGuiFluidBar hotFluidBar; - - public GuiReactorStatus(Container container, TileEntityReactorPart tileEntityReactorPart) { - super(container); - - ySize = 186; - - this.part = tileEntityReactorPart; - this.reactor = part.getReactorController(); - } - - // Add controls, etc. - @Override - public void initGui() { - super.initGui(); - - btnReactorOn = new GuiIconButton(0, guiLeft + 4, guiTop + 164, 18, 18, ClientProxy.GuiIcons.getIcon("On_off")); - btnReactorOff = new GuiIconButton(1, guiLeft + 22, guiTop + 164, 18, 18, ClientProxy.GuiIcons.getIcon("Off_off")); - - btnReactorOn.setTooltip(new String[] { EnumChatFormatting.AQUA + "Activate Reactor" }); - btnReactorOff.setTooltip(new String[] { EnumChatFormatting.AQUA + "Deactivate Reactor", "Residual heat will still", "generate power/consume coolant,", "until the reactor cools." }); - - btnWasteAutoEject = new GuiIconButton(2, guiLeft + 4, guiTop + 144, 18, 18, ClientProxy.GuiIcons.getIcon("wasteEject_off")); - btnWasteManual = new GuiIconButton(4, guiLeft + 22, guiTop + 144, 18, 18, ClientProxy.GuiIcons.getIcon("wasteManual_off")); - btnWasteEject = new GuiIconButton(5, guiLeft + 50, guiTop + 144, 18, 18, ClientProxy.GuiIcons.getIcon("wasteEject")); - - btnWasteEject.visible = false; - - btnWasteAutoEject.setTooltip(new String[] { EnumChatFormatting.AQUA + "Auto-Eject Waste", "Waste in the core will be ejected", "as soon as possible" }); - btnWasteManual.setTooltip(new String[] { EnumChatFormatting.AQUA + "Do Not Auto-Eject Waste", EnumChatFormatting.LIGHT_PURPLE + "Waste must be manually ejected.", "", "Ejection can be done from this", "screen, or via rednet,", "redstone or computer port signals."}); - btnWasteEject.setTooltip(new String[] { EnumChatFormatting.AQUA + "Eject Waste Now", "Ejects waste from the core", "into access ports.", "Each 1000mB waste = 1 ingot", "", "SHIFT: Dump excess waste, if any"}); - - registerControl(btnReactorOn); - registerControl(btnReactorOff); - registerControl(btnWasteAutoEject); - registerControl(btnWasteManual); - registerControl(btnWasteEject); - - int leftX = guiLeft + 4; - int topY = guiTop + 4; - - titleString = new BeefGuiLabel(this, "Reactor Control", leftX, topY); - topY += titleString.getHeight() + 4; - - heatIcon = new BeefGuiIcon(this, leftX - 2, topY, 16, 16, ClientProxy.GuiIcons.getIcon("temperature"), new String[] { EnumChatFormatting.AQUA + "Core Temperature", "", "Temperature inside the reactor core.", "Higher temperatures increase fuel burnup." }); - heatString = new BeefGuiLabel(this, "", leftX + 22, topY + 4); - topY += heatIcon.getHeight() + 5; - - outputIcon = new BeefGuiIcon(this, leftX + 1, topY); - outputString = new BeefGuiLabel(this, "", leftX + 22, topY + 4); - topY += outputIcon.getHeight() + 5; - - fuelConsumedIcon = new BeefGuiIcon(this, leftX + 1, topY, 16, 16, ClientProxy.GuiIcons.getIcon("fuelUsageRate"), new String[] { EnumChatFormatting.AQUA + "Fuel Burnup Rate", "", "The rate at which fuel is", "fissioned into waste in the core."}); - fuelConsumedString = new BeefGuiLabel(this, "", leftX + 22, topY + 4); - topY += fuelConsumedIcon.getHeight() + 5; - - reactivityIcon = new BeefGuiIcon(this, leftX, topY, 16, 16, ClientProxy.GuiIcons.getIcon("reactivity"), new String[] { EnumChatFormatting.AQUA + "Fuel Reactivity", "", "How heavily irradiated the core is.", "Higher levels of radiation", "reduce fuel burnup."}); - reactivityString = new BeefGuiLabel(this, "", leftX + 22, topY + 4); - topY += reactivityIcon.getHeight() + 6; - - statusString = new BeefGuiLabel(this, "", leftX+1, topY); - topY += statusString.getHeight() + 4; - - - powerBar = new BeefGuiPowerBar(this, guiLeft + 152, guiTop + 22, this.reactor); - coreHeatBar = new BeefGuiHeatBar(this, guiLeft + 130, guiTop + 22, EnumChatFormatting.AQUA + "Core Heat", new String[] { "Heat of the reactor's fuel.", "High heat raises fuel usage.", "", "Core heat is transferred to", "the casing. Transfer rate", "is based on the design of", "the reactor's interior."}); - caseHeatBar = new BeefGuiHeatBar(this, guiLeft + 108, guiTop + 22, EnumChatFormatting.AQUA + "Casing Heat", new String[] { "Heat of the reactor's casing.", "High heat raises energy output", "and coolant conversion."}); - fuelMixBar = new BeefGuiFuelMixBar(this, guiLeft + 86, guiTop + 22, this.reactor); - - coolantIcon = new BeefGuiIcon(this, guiLeft + 132, guiTop + 91, 16, 16, ClientProxy.GuiIcons.getIcon("coolantIn"), new String[] { EnumChatFormatting.AQUA + "Coolant Fluid Tank", "", "Casing heat will superheat", "coolant in this tank." }); - coolantBar = new BeefGuiFluidBar(this, guiLeft + 131, guiTop + 108, this.reactor, MultiblockReactor.FLUID_COOLANT); - - hotFluidIcon = new BeefGuiIcon(this, guiLeft + 154, guiTop + 91, 16, 16, ClientProxy.GuiIcons.getIcon("hotFluidOut"), new String[] { EnumChatFormatting.AQUA + "Hot Fluid Tank", "", "Superheated coolant", "will pump into this tank,", "and must be piped out", "via coolant ports" }); - hotFluidBar = new BeefGuiFluidBar(this, guiLeft + 153, guiTop + 108, this.reactor, MultiblockReactor.FLUID_SUPERHEATED); - - registerControl(titleString); - registerControl(statusString); - registerControl(heatIcon); - registerControl(heatString); - registerControl(outputIcon); - registerControl(outputString); - registerControl(fuelConsumedIcon); - registerControl(fuelConsumedString); - registerControl(reactivityIcon); - registerControl(reactivityString); - registerControl(powerBar); - registerControl(coreHeatBar); - registerControl(caseHeatBar); - registerControl(fuelMixBar); - registerControl(coolantBar); - registerControl(hotFluidBar); - registerControl(coolantIcon); - registerControl(hotFluidIcon); - - updateIcons(); - } - - @Override - public ResourceLocation getGuiBackground() { - return new ResourceLocation(BigReactors.GUI_DIRECTORY + "ReactorController.png"); - } - - @Override - public void updateScreen() { - super.updateScreen(); - - updateIcons(); - - if(reactor.getActive()) { - statusString.setLabelText("Status: " + EnumChatFormatting.DARK_GREEN + "Online"); - } - else { - statusString.setLabelText("Status: " + EnumChatFormatting.DARK_RED + "Offline"); - } - - outputString.setLabelText(getFormattedOutputString()); - if(reactor.isPassivelyCooled()) { - outputString.setLabelTooltip(String.format("%.2f flux per tick", reactor.getEnergyGeneratedLastTick())); - } - else { - outputString.setLabelTooltip(String.format("%.0f millibuckets per tick", reactor.getEnergyGeneratedLastTick())); - } - - heatString.setLabelText(Integer.toString((int)reactor.getFuelHeat()) + " C"); - coreHeatBar.setHeat(reactor.getFuelHeat()); - caseHeatBar.setHeat(reactor.getReactorHeat()); - - float fuelConsumption = reactor.getFuelConsumedLastTick(); - fuelConsumedString.setLabelText(StaticUtils.Strings.formatMillibuckets(fuelConsumption) + "/t"); - fuelConsumedString.setLabelTooltip(getFuelConsumptionTooltip(fuelConsumption)); - - reactivityString.setLabelText(String.format("%2.0f%%", reactor.getFuelFertility() * 100f)); - } - - @Override - protected void actionPerformed(GuiButton button) { - if(button.id == 0 || button.id == 1) { - boolean newSetting = button.id == 0; - if(newSetting != reactor.getActive()) { + private GuiIconButton btnReactorOn; + private GuiIconButton btnReactorOff; + private GuiIconButton btnWasteAutoEject; + private GuiIconButton btnWasteManual; + + private GuiIconButton btnWasteEject; + + private TileEntityReactorPart part; + private MultiblockReactor reactor; + + private BeefGuiLabel titleString; + private BeefGuiLabel statusString; + + private BeefGuiIcon heatIcon; + private BeefGuiLabel heatString; + private BeefGuiIcon outputIcon; + private BeefGuiLabel outputString; + private BeefGuiIcon fuelConsumedIcon; + private BeefGuiLabel fuelConsumedString; + private BeefGuiIcon reactivityIcon; + private BeefGuiLabel reactivityString; + + private BeefGuiPowerBar powerBar; + private BeefGuiHeatBar coreHeatBar; + private BeefGuiHeatBar caseHeatBar; + private BeefGuiFuelMixBar fuelMixBar; + + private BeefGuiIcon coolantIcon; + private BeefGuiFluidBar coolantBar; + private BeefGuiIcon hotFluidIcon; + private BeefGuiFluidBar hotFluidBar; + + public GuiReactorStatus(Container container, TileEntityReactorPart tileEntityReactorPart) { + super(container); + + ySize = 186; + + this.part = tileEntityReactorPart; + this.reactor = part.getReactorController(); + } + + // Add controls, etc. + @Override + public void initGui() { + super.initGui(); + + btnReactorOn = new GuiIconButton(0, guiLeft + 4, guiTop + 164, 18, 18, ClientProxy.GuiIcons.getIcon("On_off")); + btnReactorOff = new GuiIconButton( + 1, + guiLeft + 22, + guiTop + 164, + 18, + 18, + ClientProxy.GuiIcons.getIcon("Off_off")); + + btnReactorOn.setTooltip(new String[] { EnumChatFormatting.AQUA + "Activate Reactor" }); + btnReactorOff.setTooltip( + new String[] { EnumChatFormatting.AQUA + "Deactivate Reactor", "Residual heat will still", + "generate power/consume coolant,", "until the reactor cools." }); + + btnWasteAutoEject = new GuiIconButton( + 2, + guiLeft + 4, + guiTop + 144, + 18, + 18, + ClientProxy.GuiIcons.getIcon("wasteEject_off")); + btnWasteManual = new GuiIconButton( + 4, + guiLeft + 22, + guiTop + 144, + 18, + 18, + ClientProxy.GuiIcons.getIcon("wasteManual_off")); + btnWasteEject = new GuiIconButton( + 5, + guiLeft + 50, + guiTop + 144, + 18, + 18, + ClientProxy.GuiIcons.getIcon("wasteEject")); + + btnWasteEject.visible = false; + + btnWasteAutoEject.setTooltip( + new String[] { EnumChatFormatting.AQUA + "Auto-Eject Waste", "Waste in the core will be ejected", + "as soon as possible" }); + btnWasteManual.setTooltip( + new String[] { EnumChatFormatting.AQUA + "Do Not Auto-Eject Waste", + EnumChatFormatting.LIGHT_PURPLE + "Waste must be manually ejected.", "", + "Ejection can be done from this", "screen, or via rednet,", "redstone or computer port signals." }); + btnWasteEject.setTooltip( + new String[] { EnumChatFormatting.AQUA + "Eject Waste Now", "Ejects waste from the core", + "into access ports.", "Each 1000mB waste = 1 ingot", "", "SHIFT: Dump excess waste, if any" }); + + registerControl(btnReactorOn); + registerControl(btnReactorOff); + registerControl(btnWasteAutoEject); + registerControl(btnWasteManual); + registerControl(btnWasteEject); + + int leftX = guiLeft + 4; + int topY = guiTop + 4; + + titleString = new BeefGuiLabel(this, "Reactor Control", leftX, topY); + topY += titleString.getHeight() + 4; + + heatIcon = new BeefGuiIcon( + this, + leftX - 2, + topY, + 16, + 16, + ClientProxy.GuiIcons.getIcon("temperature"), + new String[] { EnumChatFormatting.AQUA + "Core Temperature", "", "Temperature inside the reactor core.", + "Higher temperatures increase fuel burnup." }); + heatString = new BeefGuiLabel(this, "", leftX + 22, topY + 4); + topY += heatIcon.getHeight() + 5; + + outputIcon = new BeefGuiIcon(this, leftX + 1, topY); + outputString = new BeefGuiLabel(this, "", leftX + 22, topY + 4); + topY += outputIcon.getHeight() + 5; + + fuelConsumedIcon = new BeefGuiIcon( + this, + leftX + 1, + topY, + 16, + 16, + ClientProxy.GuiIcons.getIcon("fuelUsageRate"), + new String[] { EnumChatFormatting.AQUA + "Fuel Burnup Rate", "", "The rate at which fuel is", + "fissioned into waste in the core." }); + fuelConsumedString = new BeefGuiLabel(this, "", leftX + 22, topY + 4); + topY += fuelConsumedIcon.getHeight() + 5; + + reactivityIcon = new BeefGuiIcon( + this, + leftX, + topY, + 16, + 16, + ClientProxy.GuiIcons.getIcon("reactivity"), + new String[] { EnumChatFormatting.AQUA + "Fuel Reactivity", "", "How heavily irradiated the core is.", + "Higher levels of radiation", "reduce fuel burnup." }); + reactivityString = new BeefGuiLabel(this, "", leftX + 22, topY + 4); + topY += reactivityIcon.getHeight() + 6; + + statusString = new BeefGuiLabel(this, "", leftX + 1, topY); + topY += statusString.getHeight() + 4; + + powerBar = new BeefGuiPowerBar(this, guiLeft + 152, guiTop + 22, this.reactor); + coreHeatBar = new BeefGuiHeatBar( + this, + guiLeft + 130, + guiTop + 22, + EnumChatFormatting.AQUA + "Core Heat", + new String[] { "Heat of the reactor's fuel.", "High heat raises fuel usage.", "", + "Core heat is transferred to", "the casing. Transfer rate", "is based on the design of", + "the reactor's interior." }); + caseHeatBar = new BeefGuiHeatBar( + this, + guiLeft + 108, + guiTop + 22, + EnumChatFormatting.AQUA + "Casing Heat", + new String[] { "Heat of the reactor's casing.", "High heat raises energy output", + "and coolant conversion." }); + fuelMixBar = new BeefGuiFuelMixBar(this, guiLeft + 86, guiTop + 22, this.reactor); + + coolantIcon = new BeefGuiIcon( + this, + guiLeft + 132, + guiTop + 91, + 16, + 16, + ClientProxy.GuiIcons.getIcon("coolantIn"), + new String[] { EnumChatFormatting.AQUA + "Coolant Fluid Tank", "", "Casing heat will superheat", + "coolant in this tank." }); + coolantBar = new BeefGuiFluidBar( + this, + guiLeft + 131, + guiTop + 108, + this.reactor, + MultiblockReactor.FLUID_COOLANT); + + hotFluidIcon = new BeefGuiIcon( + this, + guiLeft + 154, + guiTop + 91, + 16, + 16, + ClientProxy.GuiIcons.getIcon("hotFluidOut"), + new String[] { EnumChatFormatting.AQUA + "Hot Fluid Tank", "", "Superheated coolant", + "will pump into this tank,", "and must be piped out", "via coolant ports" }); + hotFluidBar = new BeefGuiFluidBar( + this, + guiLeft + 153, + guiTop + 108, + this.reactor, + MultiblockReactor.FLUID_SUPERHEATED); + + registerControl(titleString); + registerControl(statusString); + registerControl(heatIcon); + registerControl(heatString); + registerControl(outputIcon); + registerControl(outputString); + registerControl(fuelConsumedIcon); + registerControl(fuelConsumedString); + registerControl(reactivityIcon); + registerControl(reactivityString); + registerControl(powerBar); + registerControl(coreHeatBar); + registerControl(caseHeatBar); + registerControl(fuelMixBar); + registerControl(coolantBar); + registerControl(hotFluidBar); + registerControl(coolantIcon); + registerControl(hotFluidIcon); + + updateIcons(); + } + + @Override + public ResourceLocation getGuiBackground() { + return new ResourceLocation(BigReactors.GUI_DIRECTORY + "ReactorController.png"); + } + + @Override + public void updateScreen() { + super.updateScreen(); + + updateIcons(); + + if (reactor.getActive()) { + statusString.setLabelText("Status: " + EnumChatFormatting.DARK_GREEN + "Online"); + } else { + statusString.setLabelText("Status: " + EnumChatFormatting.DARK_RED + "Offline"); + } + + outputString.setLabelText(getFormattedOutputString()); + if (reactor.isPassivelyCooled()) { + outputString.setLabelTooltip(String.format("%.2f flux per tick", reactor.getEnergyGeneratedLastTick())); + } else { + outputString + .setLabelTooltip(String.format("%.0f millibuckets per tick", reactor.getEnergyGeneratedLastTick())); + } + + heatString.setLabelText(Integer.toString((int) reactor.getFuelHeat()) + " C"); + coreHeatBar.setHeat(reactor.getFuelHeat()); + caseHeatBar.setHeat(reactor.getReactorHeat()); + + float fuelConsumption = reactor.getFuelConsumedLastTick(); + fuelConsumedString.setLabelText(StaticUtils.Strings.formatMillibuckets(fuelConsumption) + "/t"); + fuelConsumedString.setLabelTooltip(getFuelConsumptionTooltip(fuelConsumption)); + + reactivityString.setLabelText(String.format("%2.0f%%", reactor.getFuelFertility() * 100f)); + } + + @Override + protected void actionPerformed(GuiButton button) { + if (button.id == 0 || button.id == 1) { + boolean newSetting = button.id == 0; + if (newSetting != reactor.getActive()) { CommonPacketHandler.INSTANCE.sendToServer(new MachineCommandActivateMessage(reactor, newSetting)); - } - } - else if(button.id >= 2 && button.id <= 4) { - WasteEjectionSetting newEjectionSetting; - switch(button.id) { - case 4: - newEjectionSetting = WasteEjectionSetting.kManual; - break; - default: - newEjectionSetting = WasteEjectionSetting.kAutomatic; - break; - } - - if(reactor.getWasteEjection() != newEjectionSetting) { - CommonPacketHandler.INSTANCE.sendToServer(new ReactorChangeWasteEjectionMessage(reactor, newEjectionSetting)); - } - } - else if(button.id == 5) { + } + } else if (button.id >= 2 && button.id <= 4) { + WasteEjectionSetting newEjectionSetting; + switch (button.id) { + case 4: + newEjectionSetting = WasteEjectionSetting.kManual; + break; + default: + newEjectionSetting = WasteEjectionSetting.kAutomatic; + break; + } + + if (reactor.getWasteEjection() != newEjectionSetting) { + CommonPacketHandler.INSTANCE + .sendToServer(new ReactorChangeWasteEjectionMessage(reactor, newEjectionSetting)); + } + } else if (button.id == 5) { CommonPacketHandler.INSTANCE.sendToServer(new ReactorCommandEjectMessage(reactor, false, isShiftKeyDown())); - } - } - - protected void updateIcons() { - if(reactor.getActive()) { - btnReactorOn.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.ON_ON)); - btnReactorOff.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.OFF_OFF)); - } - else { - btnReactorOn.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.ON_OFF)); - btnReactorOff.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.OFF_ON)); - } - - if(reactor.isPassivelyCooled()) { - outputIcon.setIcon(ClientProxy.GuiIcons.getIcon("energyOutput")); - outputIcon.setTooltip(passivelyCooledTooltip); - - coolantIcon.visible = false; - coolantBar.visible = false; - hotFluidIcon.visible = false; - hotFluidBar.visible = false; - } - else { - outputIcon.setIcon(ClientProxy.GuiIcons.getIcon("hotFluidOut")); - outputIcon.setTooltip(activelyCooledTooltip); - - coolantIcon.visible = true; - coolantBar.visible = true; - hotFluidIcon.visible = true; - hotFluidBar.visible = true; - } - - - switch(reactor.getWasteEjection()) { - case kAutomatic: - btnWasteAutoEject.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.WASTE_EJECT_ON)); - btnWasteManual.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.WASTE_MANUAL_OFF)); - btnWasteEject.visible = false; - break; - case kManual: - default: - btnWasteAutoEject.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.WASTE_EJECT_OFF)); - btnWasteManual.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.WASTE_MANUAL_ON)); - btnWasteEject.visible = true; - break; - } - } - - private static final String[] passivelyCooledTooltip = new String[] { - EnumChatFormatting.AQUA + "Energy Output", - "", - "This reactor is passively cooled", - "and generates energy directly from", - "the heat of its core." - }; - - private static final String[] activelyCooledTooltip = new String[] { - EnumChatFormatting.AQUA + "Hot Fluid Output", - "", - "This reactor is actively cooled", - "by a fluid, such as water, which", - "is superheated by the core." - }; - - private String getFormattedOutputString() { - float number = reactor.getEnergyGeneratedLastTick(); // Also doubles as fluid vaporized last tick - - if(reactor.isPassivelyCooled()) { - return StaticUtils.Strings.formatRF(number) + "/t"; - } - else { - return StaticUtils.Strings.formatMillibuckets(number) + "/t"; - } - } - - private String getFuelConsumptionTooltip(float fuelConsumption) { - if(fuelConsumption <= 0.000001f) { return "0 millibuckets per tick"; } - - int exp = (int)Math.log10(fuelConsumption); - - int decimalPlaces = 0; - if(exp < 1) { - decimalPlaces = Math.abs(exp) + 2; - return String.format("%." + Integer.toString(decimalPlaces) + "f millibuckets per tick", fuelConsumption); - } - else { - return String.format("%.0f millibuckets per tick", fuelConsumption); - } - } + } + } + + protected void updateIcons() { + if (reactor.getActive()) { + btnReactorOn.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.ON_ON)); + btnReactorOff.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.OFF_OFF)); + } else { + btnReactorOn.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.ON_OFF)); + btnReactorOff.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.OFF_ON)); + } + + if (reactor.isPassivelyCooled()) { + outputIcon.setIcon(ClientProxy.GuiIcons.getIcon("energyOutput")); + outputIcon.setTooltip(passivelyCooledTooltip); + + coolantIcon.visible = false; + coolantBar.visible = false; + hotFluidIcon.visible = false; + hotFluidBar.visible = false; + } else { + outputIcon.setIcon(ClientProxy.GuiIcons.getIcon("hotFluidOut")); + outputIcon.setTooltip(activelyCooledTooltip); + + coolantIcon.visible = true; + coolantBar.visible = true; + hotFluidIcon.visible = true; + hotFluidBar.visible = true; + } + + switch (reactor.getWasteEjection()) { + case kAutomatic: + btnWasteAutoEject.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.WASTE_EJECT_ON)); + btnWasteManual.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.WASTE_MANUAL_OFF)); + btnWasteEject.visible = false; + break; + case kManual: + default: + btnWasteAutoEject.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.WASTE_EJECT_OFF)); + btnWasteManual.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.WASTE_MANUAL_ON)); + btnWasteEject.visible = true; + break; + } + } + + private static final String[] passivelyCooledTooltip = new String[] { EnumChatFormatting.AQUA + "Energy Output", "", + "This reactor is passively cooled", "and generates energy directly from", "the heat of its core." }; + + private static final String[] activelyCooledTooltip = new String[] { EnumChatFormatting.AQUA + "Hot Fluid Output", + "", "This reactor is actively cooled", "by a fluid, such as water, which", "is superheated by the core." }; + + private String getFormattedOutputString() { + float number = reactor.getEnergyGeneratedLastTick(); // Also doubles as fluid vaporized last tick + + if (reactor.isPassivelyCooled()) { + return StaticUtils.Strings.formatRF(number) + "/t"; + } else { + return StaticUtils.Strings.formatMillibuckets(number) + "/t"; + } + } + + private String getFuelConsumptionTooltip(float fuelConsumption) { + if (fuelConsumption <= 0.000001f) { + return "0 millibuckets per tick"; + } + + int exp = (int) Math.log10(fuelConsumption); + + int decimalPlaces = 0; + if (exp < 1) { + decimalPlaces = Math.abs(exp) + 2; + return String.format("%." + Integer.toString(decimalPlaces) + "f millibuckets per tick", fuelConsumption); + } else { + return String.format("%.0f millibuckets per tick", fuelConsumption); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/client/gui/GuiTurbineController.java b/src/main/java/erogenousbeef/bigreactors/client/gui/GuiTurbineController.java index 55029185..7f0ebdc3 100644 --- a/src/main/java/erogenousbeef/bigreactors/client/gui/GuiTurbineController.java +++ b/src/main/java/erogenousbeef/bigreactors/client/gui/GuiTurbineController.java @@ -4,6 +4,7 @@ import net.minecraft.inventory.Container; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.ResourceLocation; + import erogenousbeef.bigreactors.client.ClientProxy; import erogenousbeef.bigreactors.common.BigReactors; import erogenousbeef.bigreactors.common.multiblock.MultiblockTurbine; @@ -21,281 +22,428 @@ import erogenousbeef.bigreactors.net.message.multiblock.TurbineChangeInductorMessage; import erogenousbeef.bigreactors.net.message.multiblock.TurbineChangeMaxIntakeMessage; import erogenousbeef.bigreactors.net.message.multiblock.TurbineChangeVentMessage; -import erogenousbeef.core.common.CoordTriplet; public class GuiTurbineController extends BeefGuiBase { - TileEntityTurbinePartBase part; - MultiblockTurbine turbine; - - private BeefGuiLabel titleString; - private BeefGuiLabel statusString; - - private BeefGuiIcon speedIcon; - private BeefGuiLabel speedString; - - private BeefGuiIcon energyGeneratedIcon; - private BeefGuiLabel energyGeneratedString; - - private BeefGuiIcon rotorEfficiencyIcon; - private BeefGuiLabel rotorEfficiencyString; - - private BeefGuiIcon powerIcon; - private BeefGuiPowerBar powerBar; - private BeefGuiIcon steamIcon; - private BeefGuiFluidBar steamBar; - private BeefGuiIcon waterIcon; - private BeefGuiFluidBar waterBar; - - private BeefGuiIcon rpmIcon; - private BeefGuiRpmBar rpmBar; - - private BeefGuiIcon governorIcon; - private BeefGuiLabel governorString; - private GuiIconButton btnGovernorUp; - private GuiIconButton btnGovernorDown; - - private GuiIconButton btnActivate; - private GuiIconButton btnDeactivate; - - private GuiIconButton btnVentAll; - private GuiIconButton btnVentOverflow; - private GuiIconButton btnVentNone; - - private BeefGuiIcon inductorIcon; - private GuiIconButton btnInductorOn; - private GuiIconButton btnInductorOff; - - public GuiTurbineController(Container container, TileEntityTurbinePartBase part) { - super(container); - - this.part = part; - turbine = part.getTurbine(); - } - - @Override - public ResourceLocation getGuiBackground() { - return new ResourceLocation(BigReactors.GUI_DIRECTORY + "TurbineController.png"); - } - - // Add controls, etc. - @Override - public void initGui() { - super.initGui(); - - int leftX = guiLeft + 4; - int topY = guiTop + 4; - - titleString = new BeefGuiLabel(this, "Turbine Control", leftX, topY); - topY += titleString.getHeight() + 4; - - speedIcon = new BeefGuiIcon(this, leftX + 1, topY, 16, 16, ClientProxy.GuiIcons.getIcon("rpm"), new String[] { EnumChatFormatting.AQUA + "Rotor Speed", "", "Speed of the rotor in", "revolutions per minute.", "", "Rotors perform best at 900", "or 1800 RPM.", "", "Speeds over 2000PM are overspeed", "and may cause a turbine to", "fail catastrophically." }); - speedString = new BeefGuiLabel(this, "", leftX + 22, topY + 4); - topY += speedIcon.getHeight() + 4; - - energyGeneratedIcon = new BeefGuiIcon(this, leftX+1, topY, 16, 16, ClientProxy.GuiIcons.getIcon("energyOutput"), new String[] { EnumChatFormatting.AQUA + "Energy Output", "", "Turbines generate energy via", "metal induction coils placed", "around a spinning rotor.", "More, or higher-quality, coils", "generate energy faster."}); - energyGeneratedString = new BeefGuiLabel(this, "", leftX + 22, topY + 4); - topY += energyGeneratedIcon.getHeight() + 4; - - rotorEfficiencyIcon = new BeefGuiIcon(this, leftX + 1, topY, 16, 16, ClientProxy.GuiIcons.getIcon("rotorEfficiency"), new String[] { EnumChatFormatting.AQUA + "Rotor Efficiency", "", "Rotor blades can only fully", String.format("capture energy from %d mB of", MultiblockTurbine.inputFluidPerBlade), "fluid per blade.", "", "Efficiency drops if the flow", "of input fluid rises past", "capacity."}); - rotorEfficiencyString = new BeefGuiLabel(this, "", leftX + 22, topY + 4); - topY += rotorEfficiencyIcon.getHeight() + 4; - - statusString = new BeefGuiLabel(this, "", leftX, topY); - topY += statusString.getHeight() + 4; - - powerIcon = new BeefGuiIcon(this, guiLeft + 153, guiTop + 4, 16, 16, ClientProxy.GuiIcons.getIcon("energyStored"), new String[] { EnumChatFormatting.AQUA + "Energy Storage" }); - powerBar = new BeefGuiPowerBar(this, guiLeft + 152, guiTop + 22, this.turbine); - - steamIcon = new BeefGuiIcon(this, guiLeft + 113, guiTop + 4, 16, 16, ClientProxy.GuiIcons.getIcon("hotFluidIn"), new String[] { EnumChatFormatting.AQUA + "Intake Fluid Tank" }); - steamBar = new BeefGuiFluidBar(this, guiLeft + 112, guiTop + 22, turbine, MultiblockTurbine.TANK_INPUT); - - waterIcon = new BeefGuiIcon(this, guiLeft + 133, guiTop + 4, 16, 16, ClientProxy.GuiIcons.getIcon("coolantOut"), new String[] { EnumChatFormatting.AQUA + "Exhaust Fluid Tank" }); - waterBar = new BeefGuiFluidBar(this, guiLeft + 132, guiTop + 22, turbine, MultiblockTurbine.TANK_OUTPUT); - - rpmIcon = new BeefGuiIcon(this, guiLeft + 93, guiTop + 4, 16, 16, ClientProxy.GuiIcons.getIcon("rpm"), new String[] { EnumChatFormatting.AQUA + "Rotor Speed" }); - rpmBar = new BeefGuiRpmBar(this, guiLeft + 92, guiTop + 22, turbine, "Rotor Speed", new String[] {"Rotors perform best at", "900 or 1800 RPM.", "", "Rotors kept overspeed for too", "long may fail.", "", "Catastrophically."}); - - governorIcon = new BeefGuiIcon(this, guiLeft + 102, guiTop + 107, 16, 16, ClientProxy.GuiIcons.getIcon("flowRate"), new String[] { EnumChatFormatting.AQUA + "Flow Rate Governor", "", "Controls the maximum rate at", "which hot fluids are drawn", "from the turbine's intake tank", "and passed over the turbines.", "", "Effectively, the max rate at which", "the turbine will process fluids."}); - governorString = new BeefGuiLabel(this, "", guiLeft + 122, guiTop + 112); - btnGovernorUp = new GuiIconButton(2, guiLeft + 120, guiTop + 125, 18, 18, ClientProxy.GuiIcons.getIcon("upArrow"), new String[] { EnumChatFormatting.AQUA + "Increase Max Flow Rate", "", "Higher flow rates will", "increase rotor speed.", "", "SHIFT: +10 mB", "CTRL: +100mB", "CTRL+SHIFT: +1000mB"}); - btnGovernorDown = new GuiIconButton(3, guiLeft + 140, guiTop + 125, 18, 18, ClientProxy.GuiIcons.getIcon("downArrow"), new String[] { EnumChatFormatting.AQUA + "Decrease Max Flow Rate", "", "Lower flow rates will", "decrease rotor speed.", "", "SHIFT: -10 mB", "CTRL: -100mB", "CTRL+SHIFT: -1000mB"}); - - inductorIcon = new BeefGuiIcon(this, leftX, guiTop + 105, 16, 16, ClientProxy.GuiIcons.getIcon("coil"), new String[] { EnumChatFormatting.AQUA + "Induction Coils", "", "Metal coils inside the turbine", "extract energy from the rotor", "and convert it into RF.", "", "These controls engage/disengage", "the coils."}); - btnInductorOn = new GuiIconButton(7, guiLeft + 24, guiTop + 104, 18, 18, ClientProxy.GuiIcons.getIcon("On_off"), new String[] { EnumChatFormatting.AQUA + "Engage Coils", "", "Engages the induction coils.", "Energy will be extracted from", "the rotor and converted to RF.", "", "Energy extraction exerts drag", "on the rotor, slowing it down." }); - btnInductorOff = new GuiIconButton(8, guiLeft + 44, guiTop + 104, 18, 18, ClientProxy.GuiIcons.getIcon("Off_off"), new String[] { EnumChatFormatting.AQUA + "Disengage Coils", "", "Disengages the induction coils.", "Energy will NOT be extracted from", "the rotor, allowing it to", "spin faster." }); - - btnActivate = new GuiIconButton(0, guiLeft + 4, guiTop + 144, 18, 18, ClientProxy.GuiIcons.getIcon("On_off"), new String[] { EnumChatFormatting.AQUA + "Activate Turbine", "", "Enables flow of intake fluid to rotor.", "Fluid flow will spin up the rotor." }); - btnDeactivate = new GuiIconButton(1, guiLeft + 24, guiTop + 144, 18, 18, ClientProxy.GuiIcons.getIcon("Off_off"), new String[] { EnumChatFormatting.AQUA + "Deactivate Turbine", "", "Disables flow of intake fluid to rotor.", "The rotor will spin down." }); - - btnVentAll = new GuiIconButton(4, guiLeft + 4, guiTop + 124, 18, 18, ClientProxy.GuiIcons.getIcon("ventAllOff"), new String[] { EnumChatFormatting.AQUA + "Vent: All Exhaust", "", "Dump all exhaust fluids.", "The exhaust fluid tank", "will not fill."}); - btnVentOverflow = new GuiIconButton(5, guiLeft + 24, guiTop + 124, 18, 18, ClientProxy.GuiIcons.getIcon("ventOverflowOff"), new String[] { EnumChatFormatting.AQUA + "Vent: Overflow Only", "", "Dump excess exhaust fluids.", "Excess fluids will be lost", "if exhaust fluid tank is full."}); - btnVentNone = new GuiIconButton(6, guiLeft + 44, guiTop + 124, 18, 18, ClientProxy.GuiIcons.getIcon("ventNoneOff"), new String[] { EnumChatFormatting.AQUA + "Vent: Closed", "", "Preserve all exhaust fluids.", "Turbine will slow or halt", "fluid intake if exhaust", "fluid tank is full."}); - - registerControl(titleString); - registerControl(statusString); - registerControl(speedIcon); - registerControl(speedString); - registerControl(energyGeneratedIcon); - registerControl(energyGeneratedString); - registerControl(rotorEfficiencyIcon); - registerControl(rotorEfficiencyString); - registerControl(powerBar); - registerControl(steamBar); - registerControl(waterBar); - registerControl(powerIcon); - registerControl(steamIcon); - registerControl(waterIcon); - registerControl(rpmIcon); - registerControl(rpmBar); - registerControl(governorIcon); - registerControl(governorString); - registerControl(btnGovernorUp); - registerControl(btnGovernorDown); - registerControl(btnActivate); - registerControl(btnDeactivate); - registerControl(btnVentAll); - registerControl(btnVentOverflow); - registerControl(btnVentNone); - registerControl(inductorIcon); - registerControl(btnInductorOn); - registerControl(btnInductorOff); - - updateStrings(); - updateTooltips(); - } - - private void updateStrings() { - if(turbine.getActive()) { - statusString.setLabelText("Status: " + EnumChatFormatting.DARK_GREEN + "Active"); - btnActivate.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.ON_ON)); - btnDeactivate.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.OFF_OFF)); - } - else { - statusString.setLabelText("Status: " + EnumChatFormatting.DARK_RED + "Inactive"); - btnActivate.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.ON_OFF)); - btnDeactivate.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.OFF_ON)); - } - - speedString.setLabelText(String.format("%.1f RPM", turbine.getRotorSpeed())); - energyGeneratedString.setLabelText(String.format("%.0f RF/t", turbine.getEnergyGeneratedLastTick())); - governorString.setLabelText(String.format("%d mB/t", turbine.getMaxIntakeRate())); - - if(turbine.getActive()) { - if(turbine.getRotorEfficiencyLastTick() < 1f) { - rotorEfficiencyString.setLabelText(String.format("%.1f%%", turbine.getRotorEfficiencyLastTick() * 100f)); - } - else { - rotorEfficiencyString.setLabelText("100%"); - } - - int numBlades = turbine.getNumRotorBlades(); - int fluidLastTick = turbine.getFluidConsumedLastTick(); - int neededBlades = fluidLastTick / MultiblockTurbine.inputFluidPerBlade; - - rotorEfficiencyString.setLabelTooltip(String.format("%d / %d blades", numBlades, neededBlades)); - } - else { - rotorEfficiencyString.setLabelText("Unknown"); - } - - switch(turbine.getVentSetting()) { - case DoNotVent: - btnVentNone.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.VENT_NONE_ON)); - btnVentOverflow.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.VENT_OVERFLOW_OFF)); - btnVentAll.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.VENT_ALL_OFF)); - break; - case VentOverflow: - btnVentNone.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.VENT_NONE_OFF)); - btnVentOverflow.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.VENT_OVERFLOW_ON)); - btnVentAll.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.VENT_ALL_OFF)); - break; - default: - // Vent all - btnVentNone.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.VENT_NONE_OFF)); - btnVentOverflow.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.VENT_OVERFLOW_OFF)); - btnVentAll.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.VENT_ALL_ON)); - } - - if(turbine.getInductorEngaged()) - { - btnInductorOn.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.ON_ON)); - btnInductorOff.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.OFF_OFF)); - } - else - { - btnInductorOn.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.ON_OFF)); - btnInductorOff.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.OFF_ON)); - } - } - - @Override - public void updateScreen() { - super.updateScreen(); - - updateStrings(); - } - - protected void updateTooltips() { - - } - - @Override - protected void actionPerformed(GuiButton button) { - if(button.id == 0 || button.id == 1) { - boolean setActive = button.id == 0; - if(setActive != turbine.getActive()) { + TileEntityTurbinePartBase part; + MultiblockTurbine turbine; + + private BeefGuiLabel titleString; + private BeefGuiLabel statusString; + + private BeefGuiIcon speedIcon; + private BeefGuiLabel speedString; + + private BeefGuiIcon energyGeneratedIcon; + private BeefGuiLabel energyGeneratedString; + + private BeefGuiIcon rotorEfficiencyIcon; + private BeefGuiLabel rotorEfficiencyString; + + private BeefGuiIcon powerIcon; + private BeefGuiPowerBar powerBar; + private BeefGuiIcon steamIcon; + private BeefGuiFluidBar steamBar; + private BeefGuiIcon waterIcon; + private BeefGuiFluidBar waterBar; + + private BeefGuiIcon rpmIcon; + private BeefGuiRpmBar rpmBar; + + private BeefGuiIcon governorIcon; + private BeefGuiLabel governorString; + private GuiIconButton btnGovernorUp; + private GuiIconButton btnGovernorDown; + + private GuiIconButton btnActivate; + private GuiIconButton btnDeactivate; + + private GuiIconButton btnVentAll; + private GuiIconButton btnVentOverflow; + private GuiIconButton btnVentNone; + + private BeefGuiIcon inductorIcon; + private GuiIconButton btnInductorOn; + private GuiIconButton btnInductorOff; + + public GuiTurbineController(Container container, TileEntityTurbinePartBase part) { + super(container); + + this.part = part; + turbine = part.getTurbine(); + } + + @Override + public ResourceLocation getGuiBackground() { + return new ResourceLocation(BigReactors.GUI_DIRECTORY + "TurbineController.png"); + } + + // Add controls, etc. + @Override + public void initGui() { + super.initGui(); + + int leftX = guiLeft + 4; + int topY = guiTop + 4; + + titleString = new BeefGuiLabel(this, "Turbine Control", leftX, topY); + topY += titleString.getHeight() + 4; + + speedIcon = new BeefGuiIcon( + this, + leftX + 1, + topY, + 16, + 16, + ClientProxy.GuiIcons.getIcon("rpm"), + new String[] { EnumChatFormatting.AQUA + "Rotor Speed", "", "Speed of the rotor in", + "revolutions per minute.", "", "Rotors perform best at 900", "or 1800 RPM.", "", + "Speeds over 2000PM are overspeed", "and may cause a turbine to", "fail catastrophically." }); + speedString = new BeefGuiLabel(this, "", leftX + 22, topY + 4); + topY += speedIcon.getHeight() + 4; + + energyGeneratedIcon = new BeefGuiIcon( + this, + leftX + 1, + topY, + 16, + 16, + ClientProxy.GuiIcons.getIcon("energyOutput"), + new String[] { EnumChatFormatting.AQUA + "Energy Output", "", "Turbines generate energy via", + "metal induction coils placed", "around a spinning rotor.", "More, or higher-quality, coils", + "generate energy faster." }); + energyGeneratedString = new BeefGuiLabel(this, "", leftX + 22, topY + 4); + topY += energyGeneratedIcon.getHeight() + 4; + + rotorEfficiencyIcon = new BeefGuiIcon( + this, + leftX + 1, + topY, + 16, + 16, + ClientProxy.GuiIcons.getIcon("rotorEfficiency"), + new String[] { EnumChatFormatting.AQUA + "Rotor Efficiency", "", "Rotor blades can only fully", + String.format("capture energy from %d mB of", MultiblockTurbine.inputFluidPerBlade), "fluid per blade.", + "", "Efficiency drops if the flow", "of input fluid rises past", "capacity." }); + rotorEfficiencyString = new BeefGuiLabel(this, "", leftX + 22, topY + 4); + topY += rotorEfficiencyIcon.getHeight() + 4; + + statusString = new BeefGuiLabel(this, "", leftX, topY); + topY += statusString.getHeight() + 4; + + powerIcon = new BeefGuiIcon( + this, + guiLeft + 153, + guiTop + 4, + 16, + 16, + ClientProxy.GuiIcons.getIcon("energyStored"), + new String[] { EnumChatFormatting.AQUA + "Energy Storage" }); + powerBar = new BeefGuiPowerBar(this, guiLeft + 152, guiTop + 22, this.turbine); + + steamIcon = new BeefGuiIcon( + this, + guiLeft + 113, + guiTop + 4, + 16, + 16, + ClientProxy.GuiIcons.getIcon("hotFluidIn"), + new String[] { EnumChatFormatting.AQUA + "Intake Fluid Tank" }); + steamBar = new BeefGuiFluidBar(this, guiLeft + 112, guiTop + 22, turbine, MultiblockTurbine.TANK_INPUT); + + waterIcon = new BeefGuiIcon( + this, + guiLeft + 133, + guiTop + 4, + 16, + 16, + ClientProxy.GuiIcons.getIcon("coolantOut"), + new String[] { EnumChatFormatting.AQUA + "Exhaust Fluid Tank" }); + waterBar = new BeefGuiFluidBar(this, guiLeft + 132, guiTop + 22, turbine, MultiblockTurbine.TANK_OUTPUT); + + rpmIcon = new BeefGuiIcon( + this, + guiLeft + 93, + guiTop + 4, + 16, + 16, + ClientProxy.GuiIcons.getIcon("rpm"), + new String[] { EnumChatFormatting.AQUA + "Rotor Speed" }); + rpmBar = new BeefGuiRpmBar( + this, + guiLeft + 92, + guiTop + 22, + turbine, + "Rotor Speed", + new String[] { "Rotors perform best at", "900 or 1800 RPM.", "", "Rotors kept overspeed for too", + "long may fail.", "", "Catastrophically." }); + + governorIcon = new BeefGuiIcon( + this, + guiLeft + 102, + guiTop + 107, + 16, + 16, + ClientProxy.GuiIcons.getIcon("flowRate"), + new String[] { EnumChatFormatting.AQUA + "Flow Rate Governor", "", "Controls the maximum rate at", + "which hot fluids are drawn", "from the turbine's intake tank", "and passed over the turbines.", "", + "Effectively, the max rate at which", "the turbine will process fluids." }); + governorString = new BeefGuiLabel(this, "", guiLeft + 122, guiTop + 112); + btnGovernorUp = new GuiIconButton( + 2, + guiLeft + 120, + guiTop + 125, + 18, + 18, + ClientProxy.GuiIcons.getIcon("upArrow"), + new String[] { EnumChatFormatting.AQUA + "Increase Max Flow Rate", "", "Higher flow rates will", + "increase rotor speed.", "", "SHIFT: +10 mB", "CTRL: +100mB", "CTRL+SHIFT: +1000mB" }); + btnGovernorDown = new GuiIconButton( + 3, + guiLeft + 140, + guiTop + 125, + 18, + 18, + ClientProxy.GuiIcons.getIcon("downArrow"), + new String[] { EnumChatFormatting.AQUA + "Decrease Max Flow Rate", "", "Lower flow rates will", + "decrease rotor speed.", "", "SHIFT: -10 mB", "CTRL: -100mB", "CTRL+SHIFT: -1000mB" }); + + inductorIcon = new BeefGuiIcon( + this, + leftX, + guiTop + 105, + 16, + 16, + ClientProxy.GuiIcons.getIcon("coil"), + new String[] { EnumChatFormatting.AQUA + "Induction Coils", "", "Metal coils inside the turbine", + "extract energy from the rotor", "and convert it into RF.", "", "These controls engage/disengage", + "the coils." }); + btnInductorOn = new GuiIconButton( + 7, + guiLeft + 24, + guiTop + 104, + 18, + 18, + ClientProxy.GuiIcons.getIcon("On_off"), + new String[] { EnumChatFormatting.AQUA + "Engage Coils", "", "Engages the induction coils.", + "Energy will be extracted from", "the rotor and converted to RF.", "", "Energy extraction exerts drag", + "on the rotor, slowing it down." }); + btnInductorOff = new GuiIconButton( + 8, + guiLeft + 44, + guiTop + 104, + 18, + 18, + ClientProxy.GuiIcons.getIcon("Off_off"), + new String[] { EnumChatFormatting.AQUA + "Disengage Coils", "", "Disengages the induction coils.", + "Energy will NOT be extracted from", "the rotor, allowing it to", "spin faster." }); + + btnActivate = new GuiIconButton( + 0, + guiLeft + 4, + guiTop + 144, + 18, + 18, + ClientProxy.GuiIcons.getIcon("On_off"), + new String[] { EnumChatFormatting.AQUA + "Activate Turbine", "", "Enables flow of intake fluid to rotor.", + "Fluid flow will spin up the rotor." }); + btnDeactivate = new GuiIconButton( + 1, + guiLeft + 24, + guiTop + 144, + 18, + 18, + ClientProxy.GuiIcons.getIcon("Off_off"), + new String[] { EnumChatFormatting.AQUA + "Deactivate Turbine", "", + "Disables flow of intake fluid to rotor.", "The rotor will spin down." }); + + btnVentAll = new GuiIconButton( + 4, + guiLeft + 4, + guiTop + 124, + 18, + 18, + ClientProxy.GuiIcons.getIcon("ventAllOff"), + new String[] { EnumChatFormatting.AQUA + "Vent: All Exhaust", "", "Dump all exhaust fluids.", + "The exhaust fluid tank", "will not fill." }); + btnVentOverflow = new GuiIconButton( + 5, + guiLeft + 24, + guiTop + 124, + 18, + 18, + ClientProxy.GuiIcons.getIcon("ventOverflowOff"), + new String[] { EnumChatFormatting.AQUA + "Vent: Overflow Only", "", "Dump excess exhaust fluids.", + "Excess fluids will be lost", "if exhaust fluid tank is full." }); + btnVentNone = new GuiIconButton( + 6, + guiLeft + 44, + guiTop + 124, + 18, + 18, + ClientProxy.GuiIcons.getIcon("ventNoneOff"), + new String[] { EnumChatFormatting.AQUA + "Vent: Closed", "", "Preserve all exhaust fluids.", + "Turbine will slow or halt", "fluid intake if exhaust", "fluid tank is full." }); + + registerControl(titleString); + registerControl(statusString); + registerControl(speedIcon); + registerControl(speedString); + registerControl(energyGeneratedIcon); + registerControl(energyGeneratedString); + registerControl(rotorEfficiencyIcon); + registerControl(rotorEfficiencyString); + registerControl(powerBar); + registerControl(steamBar); + registerControl(waterBar); + registerControl(powerIcon); + registerControl(steamIcon); + registerControl(waterIcon); + registerControl(rpmIcon); + registerControl(rpmBar); + registerControl(governorIcon); + registerControl(governorString); + registerControl(btnGovernorUp); + registerControl(btnGovernorDown); + registerControl(btnActivate); + registerControl(btnDeactivate); + registerControl(btnVentAll); + registerControl(btnVentOverflow); + registerControl(btnVentNone); + registerControl(inductorIcon); + registerControl(btnInductorOn); + registerControl(btnInductorOff); + + updateStrings(); + updateTooltips(); + } + + private void updateStrings() { + if (turbine.getActive()) { + statusString.setLabelText("Status: " + EnumChatFormatting.DARK_GREEN + "Active"); + btnActivate.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.ON_ON)); + btnDeactivate.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.OFF_OFF)); + } else { + statusString.setLabelText("Status: " + EnumChatFormatting.DARK_RED + "Inactive"); + btnActivate.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.ON_OFF)); + btnDeactivate.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.OFF_ON)); + } + + speedString.setLabelText(String.format("%.1f RPM", turbine.getRotorSpeed())); + energyGeneratedString.setLabelText(String.format("%.0f RF/t", turbine.getEnergyGeneratedLastTick())); + governorString.setLabelText(String.format("%d mB/t", turbine.getMaxIntakeRate())); + + if (turbine.getActive()) { + if (turbine.getRotorEfficiencyLastTick() < 1f) { + rotorEfficiencyString + .setLabelText(String.format("%.1f%%", turbine.getRotorEfficiencyLastTick() * 100f)); + } else { + rotorEfficiencyString.setLabelText("100%"); + } + + int numBlades = turbine.getNumRotorBlades(); + int fluidLastTick = turbine.getFluidConsumedLastTick(); + int neededBlades = fluidLastTick / MultiblockTurbine.inputFluidPerBlade; + + rotorEfficiencyString.setLabelTooltip(String.format("%d / %d blades", numBlades, neededBlades)); + } else { + rotorEfficiencyString.setLabelText("Unknown"); + } + + switch (turbine.getVentSetting()) { + case DoNotVent: + btnVentNone.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.VENT_NONE_ON)); + btnVentOverflow.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.VENT_OVERFLOW_OFF)); + btnVentAll.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.VENT_ALL_OFF)); + break; + case VentOverflow: + btnVentNone.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.VENT_NONE_OFF)); + btnVentOverflow.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.VENT_OVERFLOW_ON)); + btnVentAll.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.VENT_ALL_OFF)); + break; + default: + // Vent all + btnVentNone.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.VENT_NONE_OFF)); + btnVentOverflow.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.VENT_OVERFLOW_OFF)); + btnVentAll.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.VENT_ALL_ON)); + } + + if (turbine.getInductorEngaged()) { + btnInductorOn.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.ON_ON)); + btnInductorOff.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.OFF_OFF)); + } else { + btnInductorOn.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.ON_OFF)); + btnInductorOff.setIcon(ClientProxy.GuiIcons.getIcon(BeefGuiIconManager.OFF_ON)); + } + } + + @Override + public void updateScreen() { + super.updateScreen(); + + updateStrings(); + } + + protected void updateTooltips() { + + } + + @Override + protected void actionPerformed(GuiButton button) { + if (button.id == 0 || button.id == 1) { + boolean setActive = button.id == 0; + if (setActive != turbine.getActive()) { CommonPacketHandler.INSTANCE.sendToServer(new MachineCommandActivateMessage(turbine, setActive)); } - } - - if(button.id == 2 || button.id == 3) { - int exponent = 0; + } - if(isShiftKeyDown()) { - exponent += 1; - } - if(isCtrlKeyDown()) { - exponent += 2; - } + if (button.id == 2 || button.id == 3) { + int exponent = 0; - int newMax = (int) Math.round(Math.pow(10, exponent)); + if (isShiftKeyDown()) { + exponent += 1; + } + if (isCtrlKeyDown()) { + exponent += 2; + } + + int newMax = (int) Math.round(Math.pow(10, exponent)); + + if (button.id == 3) { + newMax *= -1; + } - if(button.id == 3) { newMax *= -1; } - - newMax = Math.max(0, Math.min(turbine.getMaxIntakeRateMax(), turbine.getMaxIntakeRate() + newMax)); + newMax = Math.max(0, Math.min(turbine.getMaxIntakeRateMax(), turbine.getMaxIntakeRate() + newMax)); - if(newMax != turbine.getMaxIntakeRate()) { + if (newMax != turbine.getMaxIntakeRate()) { CommonPacketHandler.INSTANCE.sendToServer(new TurbineChangeMaxIntakeMessage(turbine, newMax)); - } - } - - if(button.id >= 4 && button.id <= 6) { - VentStatus newStatus; - switch(button.id) { - case 5: - newStatus = VentStatus.VentOverflow; - break; - case 6: - newStatus = VentStatus.DoNotVent; - break; - default: - newStatus = VentStatus.VentAll; - break; - } - - if(newStatus != turbine.getVentSetting()) { + } + } + + if (button.id >= 4 && button.id <= 6) { + VentStatus newStatus; + switch (button.id) { + case 5: + newStatus = VentStatus.VentOverflow; + break; + case 6: + newStatus = VentStatus.DoNotVent; + break; + default: + newStatus = VentStatus.VentAll; + break; + } + + if (newStatus != turbine.getVentSetting()) { CommonPacketHandler.INSTANCE.sendToServer(new TurbineChangeVentMessage(turbine, newStatus)); - } - } - - if(button.id == 7 || button.id == 8) - { - boolean newStatus = button.id == 7; - if(newStatus != turbine.getInductorEngaged()) - { + } + } + + if (button.id == 7 || button.id == 8) { + boolean newStatus = button.id == 7; + if (newStatus != turbine.getInductorEngaged()) { CommonPacketHandler.INSTANCE.sendToServer(new TurbineChangeInductorMessage(turbine, newStatus)); - } - } - } + } + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/client/renderer/RotorSimpleRenderer.java b/src/main/java/erogenousbeef/bigreactors/client/renderer/RotorSimpleRenderer.java index 7df2b9af..56fc3514 100644 --- a/src/main/java/erogenousbeef/bigreactors/client/renderer/RotorSimpleRenderer.java +++ b/src/main/java/erogenousbeef/bigreactors/client/renderer/RotorSimpleRenderer.java @@ -20,99 +20,108 @@ public class RotorSimpleRenderer implements ISimpleBlockRenderingHandler { - protected static final double rotorSize = 0.2D; - - public RotorSimpleRenderer() { - } - - @Override - public void renderInventoryBlock(Block block, int metadata, int modelID, - RenderBlocks renderer) { - if(metadata == BlockTurbineRotorPart.METADATA_SHAFT) { - - Tessellator tessellator = Tessellator.instance; - - GL11.glTranslatef(-0.5F, -0.5F, -0.5F); - tessellator.startDrawingQuads(); - tessellator.setNormal(0.0F, -1.0F, 0.0F); - - renderRotorShaft(block, renderer, metadata, ForgeDirection.UP, new boolean[] { true, true, true, true }, 0, 0, 0, true); - - tessellator.draw(); - GL11.glTranslatef(0.5F, 0.5F, 0.5F); - } - else { - Tessellator tessellator = Tessellator.instance; - - GL11.glTranslatef(-0.5F, -0.5F, -0.5F); - tessellator.startDrawingQuads(); - tessellator.setNormal(0.0F, -1.0F, 0.0F); - renderBlade(renderer, 0, 0, 0, block, metadata, ForgeDirection.UP); - tessellator.draw(); - GL11.glTranslatef(0.5F, 0.5F, 0.5F); - } - } - - @Override - public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, - Block block, int modelId, RenderBlocks renderer) { - int metadata = world.getBlockMetadata(x, y, z); - TileEntity te = world.getTileEntity(x, y, z); - - if(te instanceof TileEntityTurbineRotorPart) { - TileEntityTurbineRotorPart rotorPart = (TileEntityTurbineRotorPart)te; - if(rotorPart.isConnected() && rotorPart.getTurbine().isAssembled() && rotorPart.getTurbine().getActive()) { - // Don't draw if the turbine's active. - return false; - } - } - - if(BlockTurbineRotorPart.isRotorShaft(metadata)) { - ForgeDirection majorAxis = findRotorMajorAxis(world, x, y, z, block); - - boolean[] hasBlades = findBlades(world, x, y, z, block, majorAxis); - - renderRotorShaft(block, renderer, metadata, majorAxis, hasBlades, x, y, z, false); - } - else { - renderBladeFromWorld(renderer, world, x, y, z, block, metadata); - } - return true; - } - - @Override - public boolean shouldRender3DInInventory(int modelID) { - return true; - } - - @Override - public int getRenderId() { - return BlockTurbineRotorPart.renderId; - } - - public static void renderRotorShaft(Block block, RenderBlocks renderer, int metadata, ForgeDirection majorAxis, boolean[] hasBlades, int x, int y, int z, boolean drawOuterRectangle) { - double xMin, yMin, zMin; - double xMax, yMax, zMax; - xMin = yMin = zMin = 0.5D - rotorSize; - xMax = yMax = zMax = 0.5D + rotorSize; - - if(majorAxis.offsetX != 0) { - xMax = 1D; - xMin = 0D; - } - if(majorAxis.offsetY != 0) { - yMax = 1D; - yMin = 0D; - } - if(majorAxis.offsetZ != 0) { - zMax = 1D; - zMin = 0D; - } + protected static final double rotorSize = 0.2D; + + public RotorSimpleRenderer() {} + + @Override + public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer) { + if (metadata == BlockTurbineRotorPart.METADATA_SHAFT) { + + Tessellator tessellator = Tessellator.instance; + + GL11.glTranslatef(-0.5F, -0.5F, -0.5F); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, -1.0F, 0.0F); + + renderRotorShaft( + block, + renderer, + metadata, + ForgeDirection.UP, + new boolean[] { true, true, true, true }, + 0, + 0, + 0, + true); + + tessellator.draw(); + GL11.glTranslatef(0.5F, 0.5F, 0.5F); + } else { + Tessellator tessellator = Tessellator.instance; + + GL11.glTranslatef(-0.5F, -0.5F, -0.5F); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, -1.0F, 0.0F); + renderBlade(renderer, 0, 0, 0, block, metadata, ForgeDirection.UP); + tessellator.draw(); + GL11.glTranslatef(0.5F, 0.5F, 0.5F); + } + } + + @Override + public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, + RenderBlocks renderer) { + int metadata = world.getBlockMetadata(x, y, z); + TileEntity te = world.getTileEntity(x, y, z); + + if (te instanceof TileEntityTurbineRotorPart) { + TileEntityTurbineRotorPart rotorPart = (TileEntityTurbineRotorPart) te; + if (rotorPart.isConnected() && rotorPart.getTurbine() + .isAssembled() + && rotorPart.getTurbine() + .getActive()) { + // Don't draw if the turbine's active. + return false; + } + } + + if (BlockTurbineRotorPart.isRotorShaft(metadata)) { + ForgeDirection majorAxis = findRotorMajorAxis(world, x, y, z, block); + + boolean[] hasBlades = findBlades(world, x, y, z, block, majorAxis); + + renderRotorShaft(block, renderer, metadata, majorAxis, hasBlades, x, y, z, false); + } else { + renderBladeFromWorld(renderer, world, x, y, z, block, metadata); + } + return true; + } + + @Override + public boolean shouldRender3DInInventory(int modelID) { + return true; + } + + @Override + public int getRenderId() { + return BlockTurbineRotorPart.renderId; + } + + public static void renderRotorShaft(Block block, RenderBlocks renderer, int metadata, ForgeDirection majorAxis, + boolean[] hasBlades, int x, int y, int z, boolean drawOuterRectangle) { + double xMin, yMin, zMin; + double xMax, yMax, zMax; + xMin = yMin = zMin = 0.5D - rotorSize; + xMax = yMax = zMax = 0.5D + rotorSize; + + if (majorAxis.offsetX != 0) { + xMax = 1D; + xMin = 0D; + } + if (majorAxis.offsetY != 0) { + yMax = 1D; + yMin = 0D; + } + if (majorAxis.offsetZ != 0) { + zMax = 1D; + zMin = 0D; + } Tessellator.instance.setColorRGBA(255, 255, 255, 255); renderer.setRenderBoundsFromBlock(block); renderer.setOverrideBlockTexture(null); - + renderer.setRenderBounds(xMin, yMin, zMin, xMax, yMax, zMax); renderer.renderFaceYNeg(block, x, y, z, renderer.getBlockIconFromSideAndMetadata(block, 0, metadata)); renderer.setRenderBounds(xMin, yMin, zMin, xMax, yMax, zMax); @@ -126,108 +135,118 @@ public static void renderRotorShaft(Block block, RenderBlocks renderer, int meta renderer.setRenderBounds(xMin, yMin, zMin, xMax, yMax, zMax); renderer.renderFaceXPos(block, x, y, z, renderer.getBlockIconFromSideAndMetadata(block, 5, metadata)); renderer.setRenderBounds(0D, 0D, 0D, 1D, 1D, 1D); - + // Render blade surfaces, if present ForgeDirection[] bladeDirs = StaticUtils.neighborsBySide[majorAxis.ordinal()]; - for(int i = 0; i < bladeDirs.length; i++) { - if(hasBlades[i]) { - renderRotorBladeConnection(renderer, block, metadata, majorAxis, bladeDirs[i], x, y, z, drawOuterRectangle); - } + for (int i = 0; i < bladeDirs.length; i++) { + if (hasBlades[i]) { + renderRotorBladeConnection( + renderer, + block, + metadata, + majorAxis, + bladeDirs[i], + x, + y, + z, + drawOuterRectangle); + } } renderer.setRenderBounds(0D, 0D, 0D, 1D, 1D, 1D); - } - - private void renderBladeFromWorld(RenderBlocks renderer, IBlockAccess world, int x, int y, int z, Block block, int metadata) { - TileEntity te = world.getTileEntity(x, y, z); - ForgeDirection rotorDir = ForgeDirection.UNKNOWN; - if(te instanceof TileEntityTurbineRotorPart) { - TileEntityTurbineRotorPart rotorPart = (TileEntityTurbineRotorPart)te; - if(rotorPart.isConnected()) { - rotorDir = rotorPart.getTurbine().getRotorDirection(); - } - } - - if(rotorDir == ForgeDirection.UNKNOWN) { - // Go walkies! - ArrayList bladeDirs = new ArrayList(); - - // First check, surrounding area. - ForgeDirection[] dirsToCheck = ForgeDirection.VALID_DIRECTIONS; - for(ForgeDirection dir : dirsToCheck) { - Block neighborBlock = world.getBlock(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ); - if(neighborBlock == block) { - // Blade or rotor?! - int neighborMetadata = world.getBlockMetadata(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ); - if(BlockTurbineRotorPart.isRotorShaft(neighborMetadata)) { - // SEXY TIMES - rotorDir = findRotorMajorAxis(world, x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ, block); - break; - } - else if(BlockTurbineRotorPart.isRotorBlade(neighborMetadata)) { - // We'll move in that direction then... - bladeDirs.add(dir); - } - } - } - - // Still no luck eh? - while(rotorDir == ForgeDirection.UNKNOWN && !bladeDirs.isEmpty()) { - ForgeDirection dir = bladeDirs.remove(bladeDirs.size() - 1); // Trim off the end to avoid shifting crap in memory - int curX = x + dir.offsetX; - int curY = y + dir.offsetY; - int curZ = z + dir.offsetZ; - - int dist = 0; - while(world.getBlock(curX, curY, curZ) == block && dist < 32) { // only go up to 32 blocks in any direction without finding a rotor, for sanity - int curMeta = world.getBlockMetadata(curX, curY, curZ); - if(BlockTurbineRotorPart.isRotorShaft(curMeta)) { - // Huz ZAH! - rotorDir = findRotorMajorAxis(world, curX, curY, curZ, block); - break; - } - else if(BlockTurbineRotorPart.isRotorBlade(curMeta)) { - curX += dir.offsetX; - curY += dir.offsetY; - curZ += dir.offsetZ; - dist++; - } - else { - break; - } - } - } - } - - renderBlade(renderer, x, y, z, block, metadata, rotorDir); - } - - public static void renderBlade(RenderBlocks renderer, int x, int y, int z, Block block, int metadata, ForgeDirection rotorDir) { - if(rotorDir == ForgeDirection.UNKNOWN) { - rotorDir = ForgeDirection.UP; - } - - double xMin, yMin, zMin, xMax, yMax, zMax; - xMin = yMin = zMin = 0D; - xMax = yMax = zMax = 1D; - - if(rotorDir.offsetX != 0) { - xMin = 0.45D; - xMax = 0.55D; - } - else if(rotorDir.offsetY != 0) { - yMin = 0.45D; - yMax = 0.55D; - } - else if(rotorDir.offsetZ != 0) { - zMin = 0.45D; - zMax = 0.55D; - } - + } + + private void renderBladeFromWorld(RenderBlocks renderer, IBlockAccess world, int x, int y, int z, Block block, + int metadata) { + TileEntity te = world.getTileEntity(x, y, z); + ForgeDirection rotorDir = ForgeDirection.UNKNOWN; + if (te instanceof TileEntityTurbineRotorPart) { + TileEntityTurbineRotorPart rotorPart = (TileEntityTurbineRotorPart) te; + if (rotorPart.isConnected()) { + rotorDir = rotorPart.getTurbine() + .getRotorDirection(); + } + } + + if (rotorDir == ForgeDirection.UNKNOWN) { + // Go walkies! + ArrayList bladeDirs = new ArrayList(); + + // First check, surrounding area. + ForgeDirection[] dirsToCheck = ForgeDirection.VALID_DIRECTIONS; + for (ForgeDirection dir : dirsToCheck) { + Block neighborBlock = world.getBlock(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ); + if (neighborBlock == block) { + // Blade or rotor?! + int neighborMetadata = world.getBlockMetadata(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ); + if (BlockTurbineRotorPart.isRotorShaft(neighborMetadata)) { + // SEXY TIMES + rotorDir = findRotorMajorAxis(world, x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ, block); + break; + } else if (BlockTurbineRotorPart.isRotorBlade(neighborMetadata)) { + // We'll move in that direction then... + bladeDirs.add(dir); + } + } + } + + // Still no luck eh? + while (rotorDir == ForgeDirection.UNKNOWN && !bladeDirs.isEmpty()) { + ForgeDirection dir = bladeDirs.remove(bladeDirs.size() - 1); // Trim off the end to avoid shifting crap + // in memory + int curX = x + dir.offsetX; + int curY = y + dir.offsetY; + int curZ = z + dir.offsetZ; + + int dist = 0; + while (world.getBlock(curX, curY, curZ) == block && dist < 32) { // only go up to 32 blocks in any + // direction without finding a rotor, + // for sanity + int curMeta = world.getBlockMetadata(curX, curY, curZ); + if (BlockTurbineRotorPart.isRotorShaft(curMeta)) { + // Huz ZAH! + rotorDir = findRotorMajorAxis(world, curX, curY, curZ, block); + break; + } else if (BlockTurbineRotorPart.isRotorBlade(curMeta)) { + curX += dir.offsetX; + curY += dir.offsetY; + curZ += dir.offsetZ; + dist++; + } else { + break; + } + } + } + } + + renderBlade(renderer, x, y, z, block, metadata, rotorDir); + } + + public static void renderBlade(RenderBlocks renderer, int x, int y, int z, Block block, int metadata, + ForgeDirection rotorDir) { + if (rotorDir == ForgeDirection.UNKNOWN) { + rotorDir = ForgeDirection.UP; + } + + double xMin, yMin, zMin, xMax, yMax, zMax; + xMin = yMin = zMin = 0D; + xMax = yMax = zMax = 1D; + + if (rotorDir.offsetX != 0) { + xMin = 0.45D; + xMax = 0.55D; + } else if (rotorDir.offsetY != 0) { + yMin = 0.45D; + yMax = 0.55D; + } else if (rotorDir.offsetZ != 0) { + zMin = 0.45D; + zMax = 0.55D; + } + Tessellator.instance.setColorRGBA(255, 255, 255, 255); renderer.setRenderBoundsFromBlock(block); renderer.setOverrideBlockTexture(null); - + renderer.setRenderBounds(xMin, yMin, zMin, xMax, yMax, zMax); renderer.renderFaceYNeg(block, x, y, z, renderer.getBlockIconFromSideAndMetadata(block, 0, metadata)); renderer.setRenderBounds(xMin, yMin, zMin, xMax, yMax, zMax); @@ -241,165 +260,172 @@ else if(rotorDir.offsetZ != 0) { renderer.setRenderBounds(xMin, yMin, zMin, xMax, yMax, zMax); renderer.renderFaceXPos(block, x, y, z, renderer.getBlockIconFromSideAndMetadata(block, 5, metadata)); renderer.setRenderBounds(0D, 0D, 0D, 1D, 1D, 1D); - } - - /** - * @param world - * @param x - * @param y - * @param z - * @param block - * @return The major axis of the rotor. This is always one of the positive directions. - */ - private static ForgeDirection findRotorMajorAxis(IBlockAccess world, int x, int y, int z, Block block) { - ForgeDirection retDir = ForgeDirection.UP; - - for(ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { - if(world.getBlock(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ) == block && - BlockTurbineRotorPart.isRotorShaft(world.getBlockMetadata(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ))) { - retDir = dir; - break; - } - } - - if(retDir == ForgeDirection.DOWN || retDir == ForgeDirection.NORTH || retDir == ForgeDirection.WEST) { - retDir = retDir.getOpposite(); - } - - return retDir; // Defaults to up if there's no neighbors of the same type - } - - private static boolean[] findBlades(IBlockAccess world, int x, int y, int z, Block block, ForgeDirection majorAxis) { - boolean[] ret = new boolean[4]; - ForgeDirection[] dirsToCheck = StaticUtils.neighborsBySide[majorAxis.ordinal()]; - - for(int i = 0; i < dirsToCheck.length; i++) { - ForgeDirection dir = dirsToCheck[i]; - if(world.getBlock(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ) == block && - BlockTurbineRotorPart.isRotorBlade(world.getBlockMetadata(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ))) { - ret[i] = true; - } - else { - ret[i] = false; - } - } - - return ret; - } - - private static ForgeDirection[][] normals = { - {ForgeDirection.UNKNOWN, ForgeDirection.UNKNOWN, ForgeDirection.WEST, ForgeDirection.EAST, ForgeDirection.NORTH, ForgeDirection.SOUTH}, // DOWN - {ForgeDirection.UNKNOWN, ForgeDirection.UNKNOWN, ForgeDirection.WEST, ForgeDirection.EAST, ForgeDirection.NORTH, ForgeDirection.SOUTH}, // UP - {ForgeDirection.EAST, ForgeDirection.WEST, ForgeDirection.UNKNOWN, ForgeDirection.UNKNOWN, ForgeDirection.DOWN, ForgeDirection.UP}, // NORTH - {ForgeDirection.EAST, ForgeDirection.WEST, ForgeDirection.UNKNOWN, ForgeDirection.UNKNOWN, ForgeDirection.DOWN, ForgeDirection.UP}, // SOUTH - {ForgeDirection.SOUTH, ForgeDirection.NORTH, ForgeDirection.DOWN, ForgeDirection.UP, ForgeDirection.UNKNOWN, ForgeDirection.UNKNOWN}, // WEST - {ForgeDirection.SOUTH, ForgeDirection.NORTH, ForgeDirection.DOWN, ForgeDirection.UP, ForgeDirection.UNKNOWN, ForgeDirection.UNKNOWN}, // EAST - }; - - private static ForgeDirection findNormal(ForgeDirection majorAxis, ForgeDirection minorAxis) { - return normals[majorAxis.ordinal()][minorAxis.ordinal()]; - } - - private static void renderRotorBladeConnection(RenderBlocks renderer, Block block, int metadata, - ForgeDirection rotorDir, ForgeDirection bladeDir, int x, int y, int z, boolean drawOuterRectangle) { - - // This is the dimension in which the blade expands - ForgeDirection normal = findNormal(rotorDir, bladeDir); - - // Used for proper calculation of the IJK coords - int rotorDirMultiplier = rotorDir.offsetX < 0 || rotorDir.offsetY < 0 || rotorDir.offsetZ < 0 ? -1 : 1; - int bladeDirMultiplier = bladeDir.offsetX < 0 || bladeDir.offsetY < 0 || bladeDir.offsetZ < 0 ? -1 : 1; - int normalDirMultiplier = normal.offsetX < 0 || normal.offsetY < 0 || normal.offsetZ < 0 ? -1 : 1; - - // Compute the 8 coordinates of the inner and outer rectangles in IJK space, which we'll re-orient later - // I = blade dir, J = rotor dir, K = normal dir - double rotorDirectionOffset = 0.05D; - double bladeInnerOffset = 0.2D; - double bladeOuterOffset = 0.5D; - double normalInnerOffset = 0.2D; - double normalOuterOffset = 0.4D; - - double rotorOffsets[] = new double[8]; - rotorOffsets[0] = rotorOffsets[3] = rotorOffsets[4] = rotorOffsets[7] = 0.5D + (rotorDirMultiplier * rotorDirectionOffset); - rotorOffsets[1] = rotorOffsets[2] = rotorOffsets[5] = rotorOffsets[6] = 0.5D - (rotorDirMultiplier * rotorDirectionOffset); - - double bladeOffsets[] = new double[8]; - bladeOffsets[0] = bladeOffsets[1] = bladeOffsets[2] = bladeOffsets[3] = 0.5D + (bladeDirMultiplier * bladeInnerOffset); - bladeOffsets[4] = bladeOffsets[5] = bladeOffsets[6] = bladeOffsets[7] = 0.5D + (bladeDirMultiplier * bladeOuterOffset); - - double normalOffsets[] = new double[8]; - normalOffsets[0] = normalOffsets[1] = 0.5D - (normalDirMultiplier * normalInnerOffset); - normalOffsets[2] = normalOffsets[3] = 0.5D + (normalDirMultiplier * normalInnerOffset); - normalOffsets[4] = normalOffsets[5] = 0.5D - (normalDirMultiplier * normalOuterOffset); - normalOffsets[6] = normalOffsets[7] = 0.5D + (normalDirMultiplier * normalOuterOffset); - - // Now calculate our 8 coordinates in XYZ space from IJK space - double[] xCoords = {0D, 0D, 0D, 0D, 0D, 0D, 0D, 0D}; - double[] yCoords = {0D, 0D, 0D, 0D, 0D, 0D, 0D, 0D}; - double[] zCoords = {0D, 0D, 0D, 0D, 0D, 0D, 0D, 0D}; - - int xMagRotor = Math.abs(rotorDir.offsetX); - int xMagBlade = Math.abs(bladeDir.offsetX); - int xMagNormal = Math.abs(normal.offsetX); - int yMagRotor = Math.abs(rotorDir.offsetY); - int yMagBlade = Math.abs(bladeDir.offsetY); - int yMagNormal = Math.abs(normal.offsetY); - int zMagRotor = Math.abs(rotorDir.offsetZ); - int zMagBlade = Math.abs(bladeDir.offsetZ); - int zMagNormal = Math.abs(normal.offsetZ); - - for(int i = 0; i < 8; i++) { - xCoords[i] = rotorOffsets[i] * xMagRotor + bladeOffsets[i] * xMagBlade + normalOffsets[i] * xMagNormal; - yCoords[i] = rotorOffsets[i] * yMagRotor + bladeOffsets[i] * yMagBlade + normalOffsets[i] * yMagNormal; - zCoords[i] = rotorOffsets[i] * zMagRotor + bladeOffsets[i] * zMagBlade + normalOffsets[i] * zMagNormal; - } - - // Calculate UV coords for each face. - double[] u = {0D, 0D, 16D, 16D}; - double[] v = {0D, 16D, 16D, 0D}; - - IIcon IIcon = BigReactors.blockTurbineRotorPart.getRotorConnectorIcon(); - for(int i = 0; i < 4; i++) { - u[i] = IIcon.getInterpolatedU(u[i]); - v[i] = IIcon.getInterpolatedV(v[i]); - } - - // Element buffer, which of these do we draw? - int[][] quads; - if(rotorDir.offsetX != 0 || (bladeDir.offsetX != 0 && rotorDir.offsetY != 0)) { - quads = quadSet2; - } - else { - quads = quadSet1; - } - - Tessellator tessellator = Tessellator.instance; - tessellator.addTranslation(x, y, z); - - for(int face = drawOuterRectangle ? 0 : 1; face < quads.length; face++) { - for(int vertex = 0; vertex < quads[face].length; vertex++) { - int idx = quads[face][vertex]; - tessellator.addVertexWithUV(xCoords[idx], yCoords[idx], zCoords[idx], u[vertex], v[vertex]); - } - } - - tessellator.addTranslation(-x, -y, -z); - renderer.setRenderBounds(0D, 0D, 0D, 1D, 1D, 1D); - } - - private static final int[][] quadSet1 = { - {4, 5, 6, 7}, // Outer rectangular face of the rotor - {7, 3, 0, 4}, // "top" rhombus - {6, 5, 1, 2}, // "bottom" rhombus - {0, 1, 5, 4}, // "left" irregular rectangle - {7, 6, 2, 3}, // "right irregular rectangle - }; - - private static final int[][] quadSet2 = { - {7, 6, 5, 4}, // Outer rectangular face of the rotor - {4, 0, 3, 7}, // "top" rhombus - {2, 1, 5, 6}, // "bottom" rhombus - {4, 5, 1, 0}, // "left" irregular rectangle - {3, 2, 6, 7}, // "right irregular rectangle - }; + } + + /** + * @param world + * @param x + * @param y + * @param z + * @param block + * @return The major axis of the rotor. This is always one of the positive directions. + */ + private static ForgeDirection findRotorMajorAxis(IBlockAccess world, int x, int y, int z, Block block) { + ForgeDirection retDir = ForgeDirection.UP; + + for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { + if (world.getBlock(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ) == block && BlockTurbineRotorPart + .isRotorShaft(world.getBlockMetadata(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ))) { + retDir = dir; + break; + } + } + + if (retDir == ForgeDirection.DOWN || retDir == ForgeDirection.NORTH || retDir == ForgeDirection.WEST) { + retDir = retDir.getOpposite(); + } + + return retDir; // Defaults to up if there's no neighbors of the same type + } + + private static boolean[] findBlades(IBlockAccess world, int x, int y, int z, Block block, + ForgeDirection majorAxis) { + boolean[] ret = new boolean[4]; + ForgeDirection[] dirsToCheck = StaticUtils.neighborsBySide[majorAxis.ordinal()]; + + for (int i = 0; i < dirsToCheck.length; i++) { + ForgeDirection dir = dirsToCheck[i]; + if (world.getBlock(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ) == block && BlockTurbineRotorPart + .isRotorBlade(world.getBlockMetadata(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ))) { + ret[i] = true; + } else { + ret[i] = false; + } + } + + return ret; + } + + private static ForgeDirection[][] normals = { + { ForgeDirection.UNKNOWN, ForgeDirection.UNKNOWN, ForgeDirection.WEST, ForgeDirection.EAST, + ForgeDirection.NORTH, ForgeDirection.SOUTH }, // DOWN + { ForgeDirection.UNKNOWN, ForgeDirection.UNKNOWN, ForgeDirection.WEST, ForgeDirection.EAST, + ForgeDirection.NORTH, ForgeDirection.SOUTH }, // UP + { ForgeDirection.EAST, ForgeDirection.WEST, ForgeDirection.UNKNOWN, ForgeDirection.UNKNOWN, ForgeDirection.DOWN, + ForgeDirection.UP }, // NORTH + { ForgeDirection.EAST, ForgeDirection.WEST, ForgeDirection.UNKNOWN, ForgeDirection.UNKNOWN, ForgeDirection.DOWN, + ForgeDirection.UP }, // SOUTH + { ForgeDirection.SOUTH, ForgeDirection.NORTH, ForgeDirection.DOWN, ForgeDirection.UP, ForgeDirection.UNKNOWN, + ForgeDirection.UNKNOWN }, // WEST + { ForgeDirection.SOUTH, ForgeDirection.NORTH, ForgeDirection.DOWN, ForgeDirection.UP, ForgeDirection.UNKNOWN, + ForgeDirection.UNKNOWN }, // EAST + }; + + private static ForgeDirection findNormal(ForgeDirection majorAxis, ForgeDirection minorAxis) { + return normals[majorAxis.ordinal()][minorAxis.ordinal()]; + } + + private static void renderRotorBladeConnection(RenderBlocks renderer, Block block, int metadata, + ForgeDirection rotorDir, ForgeDirection bladeDir, int x, int y, int z, boolean drawOuterRectangle) { + + // This is the dimension in which the blade expands + ForgeDirection normal = findNormal(rotorDir, bladeDir); + + // Used for proper calculation of the IJK coords + int rotorDirMultiplier = rotorDir.offsetX < 0 || rotorDir.offsetY < 0 || rotorDir.offsetZ < 0 ? -1 : 1; + int bladeDirMultiplier = bladeDir.offsetX < 0 || bladeDir.offsetY < 0 || bladeDir.offsetZ < 0 ? -1 : 1; + int normalDirMultiplier = normal.offsetX < 0 || normal.offsetY < 0 || normal.offsetZ < 0 ? -1 : 1; + + // Compute the 8 coordinates of the inner and outer rectangles in IJK space, which we'll re-orient later + // I = blade dir, J = rotor dir, K = normal dir + double rotorDirectionOffset = 0.05D; + double bladeInnerOffset = 0.2D; + double bladeOuterOffset = 0.5D; + double normalInnerOffset = 0.2D; + double normalOuterOffset = 0.4D; + + double rotorOffsets[] = new double[8]; + rotorOffsets[0] = rotorOffsets[3] = rotorOffsets[4] = rotorOffsets[7] = 0.5D + + (rotorDirMultiplier * rotorDirectionOffset); + rotorOffsets[1] = rotorOffsets[2] = rotorOffsets[5] = rotorOffsets[6] = 0.5D + - (rotorDirMultiplier * rotorDirectionOffset); + + double bladeOffsets[] = new double[8]; + bladeOffsets[0] = bladeOffsets[1] = bladeOffsets[2] = bladeOffsets[3] = 0.5D + + (bladeDirMultiplier * bladeInnerOffset); + bladeOffsets[4] = bladeOffsets[5] = bladeOffsets[6] = bladeOffsets[7] = 0.5D + + (bladeDirMultiplier * bladeOuterOffset); + + double normalOffsets[] = new double[8]; + normalOffsets[0] = normalOffsets[1] = 0.5D - (normalDirMultiplier * normalInnerOffset); + normalOffsets[2] = normalOffsets[3] = 0.5D + (normalDirMultiplier * normalInnerOffset); + normalOffsets[4] = normalOffsets[5] = 0.5D - (normalDirMultiplier * normalOuterOffset); + normalOffsets[6] = normalOffsets[7] = 0.5D + (normalDirMultiplier * normalOuterOffset); + + // Now calculate our 8 coordinates in XYZ space from IJK space + double[] xCoords = { 0D, 0D, 0D, 0D, 0D, 0D, 0D, 0D }; + double[] yCoords = { 0D, 0D, 0D, 0D, 0D, 0D, 0D, 0D }; + double[] zCoords = { 0D, 0D, 0D, 0D, 0D, 0D, 0D, 0D }; + + int xMagRotor = Math.abs(rotorDir.offsetX); + int xMagBlade = Math.abs(bladeDir.offsetX); + int xMagNormal = Math.abs(normal.offsetX); + int yMagRotor = Math.abs(rotorDir.offsetY); + int yMagBlade = Math.abs(bladeDir.offsetY); + int yMagNormal = Math.abs(normal.offsetY); + int zMagRotor = Math.abs(rotorDir.offsetZ); + int zMagBlade = Math.abs(bladeDir.offsetZ); + int zMagNormal = Math.abs(normal.offsetZ); + + for (int i = 0; i < 8; i++) { + xCoords[i] = rotorOffsets[i] * xMagRotor + bladeOffsets[i] * xMagBlade + normalOffsets[i] * xMagNormal; + yCoords[i] = rotorOffsets[i] * yMagRotor + bladeOffsets[i] * yMagBlade + normalOffsets[i] * yMagNormal; + zCoords[i] = rotorOffsets[i] * zMagRotor + bladeOffsets[i] * zMagBlade + normalOffsets[i] * zMagNormal; + } + + // Calculate UV coords for each face. + double[] u = { 0D, 0D, 16D, 16D }; + double[] v = { 0D, 16D, 16D, 0D }; + + IIcon IIcon = BigReactors.blockTurbineRotorPart.getRotorConnectorIcon(); + for (int i = 0; i < 4; i++) { + u[i] = IIcon.getInterpolatedU(u[i]); + v[i] = IIcon.getInterpolatedV(v[i]); + } + + // Element buffer, which of these do we draw? + int[][] quads; + if (rotorDir.offsetX != 0 || (bladeDir.offsetX != 0 && rotorDir.offsetY != 0)) { + quads = quadSet2; + } else { + quads = quadSet1; + } + + Tessellator tessellator = Tessellator.instance; + tessellator.addTranslation(x, y, z); + + for (int face = drawOuterRectangle ? 0 : 1; face < quads.length; face++) { + for (int vertex = 0; vertex < quads[face].length; vertex++) { + int idx = quads[face][vertex]; + tessellator.addVertexWithUV(xCoords[idx], yCoords[idx], zCoords[idx], u[vertex], v[vertex]); + } + } + + tessellator.addTranslation(-x, -y, -z); + renderer.setRenderBounds(0D, 0D, 0D, 1D, 1D, 1D); + } + + private static final int[][] quadSet1 = { { 4, 5, 6, 7 }, // Outer rectangular face of the rotor + { 7, 3, 0, 4 }, // "top" rhombus + { 6, 5, 1, 2 }, // "bottom" rhombus + { 0, 1, 5, 4 }, // "left" irregular rectangle + { 7, 6, 2, 3 }, // "right irregular rectangle + }; + + private static final int[][] quadSet2 = { { 7, 6, 5, 4 }, // Outer rectangular face of the rotor + { 4, 0, 3, 7 }, // "top" rhombus + { 2, 1, 5, 6 }, // "bottom" rhombus + { 4, 5, 1, 0 }, // "left" irregular rectangle + { 3, 2, 6, 7 }, // "right irregular rectangle + }; } diff --git a/src/main/java/erogenousbeef/bigreactors/client/renderer/RotorSpecialRenderer.java b/src/main/java/erogenousbeef/bigreactors/client/renderer/RotorSpecialRenderer.java index 2d1b9594..01c3ec5e 100644 --- a/src/main/java/erogenousbeef/bigreactors/client/renderer/RotorSpecialRenderer.java +++ b/src/main/java/erogenousbeef/bigreactors/client/renderer/RotorSpecialRenderer.java @@ -21,118 +21,134 @@ public class RotorSpecialRenderer extends TileEntitySpecialRenderer { - RenderBlocks renderBlocks = new RenderBlocks(); - - @Override - public void renderTileEntityAt(TileEntity tileentity, double x, double y, - double z, float f) { - TileEntityTurbineRotorBearing bearing = (TileEntityTurbineRotorBearing)tileentity; - - if(bearing == null || !bearing.isConnected()) { return; } - - MultiblockTurbine turbine = bearing.getTurbine(); - - if(!turbine.isAssembled() || !turbine.getActive() || !turbine.hasGlass()) { return; } - - Integer displayList = bearing.getDisplayList(); - ForgeDirection rotorDir = bearing.getOutwardsDir().getOpposite(); - - if(displayList == null) { - RotorInfo info = bearing.getRotorInfo(); - displayList = generateRotor(info); - bearing.setDisplayList(displayList); - } - - float angle = bearing.getAngle(); - long elapsedTime = Minecraft.getSystemTime() - ClientProxy.lastRenderTime; - - float speed = turbine.getRotorSpeed(); - if(speed > 0.001f) { - angle += speed * ((float)elapsedTime / 60000f) * 360f; // RPM * time in minutes * 360 degrees per rotation - angle = angle % 360f; - bearing.setAngle(angle); - } - - GL11.glPushMatrix(); - GL11.glPushAttrib(GL11.GL_ENABLE_BIT); - GL11.glEnable(GL11.GL_CULL_FACE); - GL11.glDisable(GL11.GL_LIGHTING); - - bindTexture(net.minecraft.client.renderer.texture.TextureMap.locationBlocksTexture); - - GL11.glTranslated(x + rotorDir.offsetX, y + rotorDir.offsetY, z + rotorDir.offsetZ); - if(rotorDir.offsetX != 0) { - GL11.glTranslated(0, 0.5, 0.5); - } - else if(rotorDir.offsetY != 0) { - GL11.glTranslated(0.5, 0, 0.5); - } - else if(rotorDir.offsetZ != 0) { - GL11.glTranslated(0.5, 0.5, 0); - } - - GL11.glRotatef(angle, rotorDir.offsetX, rotorDir.offsetY, rotorDir.offsetZ); - GL11.glColor3f(1f, 1f, 1f); - GL11.glCallList(displayList); - - GL11.glEnable(GL11.GL_LIGHTING); - GL11.glPopAttrib(); - GL11.glPopMatrix(); - } - - int generateRotor(RotorInfo rotorInfo) { - int list = GLAllocation.generateDisplayLists(1); - GL11.glNewList(list, GL11.GL_COMPILE); - - ForgeDirection rotorDir = rotorInfo.rotorDirection; - int rotorLen = rotorInfo.rotorLength; - CoordTriplet currentRotorCoord = new CoordTriplet(0,0,0); - - Tessellator tessellator = Tessellator.instance; - if(rotorDir.offsetX != 0) { - tessellator.setTranslation(0, -0.5, -0.5); - } - else if(rotorDir.offsetY != 0) { - tessellator.setTranslation(-0.5, 0, -0.5); - } - else { - tessellator.setTranslation(-0.5, -0.5, 0); - } - - tessellator.startDrawingQuads(); - tessellator.setBrightness(256); - tessellator.setColorOpaque(255, 255, 255); - - CoordTriplet bladeCoord = new CoordTriplet(0,0,0); - int rotorIdx = 0; - boolean[] hasBlades = new boolean[4]; - ForgeDirection[] bladeDirs = StaticUtils.neighborsBySide[rotorInfo.rotorDirection.ordinal()]; - - while(rotorIdx < rotorInfo.rotorLength) { - - for(int i = 0; i < hasBlades.length; i++) { - hasBlades[i] = rotorInfo.bladeLengths[rotorIdx][i] > 0; - } - - RotorSimpleRenderer.renderRotorShaft(BigReactors.blockTurbineRotorPart, renderBlocks, BlockTurbineRotorPart.METADATA_SHAFT, rotorDir, hasBlades, currentRotorCoord.x, currentRotorCoord.y, currentRotorCoord.z, false); - for(int bladeIdx = 0; bladeIdx < bladeDirs.length; bladeIdx++) { - bladeCoord.copy(currentRotorCoord); - int bladeLen = 0; - bladeCoord.translate(bladeDirs[bladeIdx]); - while(bladeLen < rotorInfo.bladeLengths[rotorIdx][bladeIdx]) { - RotorSimpleRenderer.renderBlade(renderBlocks, bladeCoord.x, bladeCoord.y, bladeCoord.z, BigReactors.blockTurbineRotorPart, BlockTurbineRotorPart.METADATA_BLADE, rotorInfo.rotorDirection); - bladeLen++; - bladeCoord.translate(bladeDirs[bladeIdx]); - } - } - rotorIdx++; - currentRotorCoord.translate(rotorDir); - } - tessellator.setTranslation(0, 0, 0); - tessellator.draw(); - - GL11.glEndList(); - return list; - } - + RenderBlocks renderBlocks = new RenderBlocks(); + + @Override + public void renderTileEntityAt(TileEntity tileentity, double x, double y, double z, float f) { + TileEntityTurbineRotorBearing bearing = (TileEntityTurbineRotorBearing) tileentity; + + if (bearing == null || !bearing.isConnected()) { + return; + } + + MultiblockTurbine turbine = bearing.getTurbine(); + + if (!turbine.isAssembled() || !turbine.getActive() || !turbine.hasGlass()) { + return; + } + + Integer displayList = bearing.getDisplayList(); + ForgeDirection rotorDir = bearing.getOutwardsDir() + .getOpposite(); + + if (displayList == null) { + RotorInfo info = bearing.getRotorInfo(); + displayList = generateRotor(info); + bearing.setDisplayList(displayList); + } + + float angle = bearing.getAngle(); + long elapsedTime = Minecraft.getSystemTime() - ClientProxy.lastRenderTime; + + float speed = turbine.getRotorSpeed(); + if (speed > 0.001f) { + angle += speed * ((float) elapsedTime / 60000f) * 360f; // RPM * time in minutes * 360 degrees per rotation + angle = angle % 360f; + bearing.setAngle(angle); + } + + GL11.glPushMatrix(); + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glEnable(GL11.GL_CULL_FACE); + GL11.glDisable(GL11.GL_LIGHTING); + + bindTexture(net.minecraft.client.renderer.texture.TextureMap.locationBlocksTexture); + + GL11.glTranslated(x + rotorDir.offsetX, y + rotorDir.offsetY, z + rotorDir.offsetZ); + if (rotorDir.offsetX != 0) { + GL11.glTranslated(0, 0.5, 0.5); + } else if (rotorDir.offsetY != 0) { + GL11.glTranslated(0.5, 0, 0.5); + } else if (rotorDir.offsetZ != 0) { + GL11.glTranslated(0.5, 0.5, 0); + } + + GL11.glRotatef(angle, rotorDir.offsetX, rotorDir.offsetY, rotorDir.offsetZ); + GL11.glColor3f(1f, 1f, 1f); + GL11.glCallList(displayList); + + GL11.glEnable(GL11.GL_LIGHTING); + GL11.glPopAttrib(); + GL11.glPopMatrix(); + } + + int generateRotor(RotorInfo rotorInfo) { + int list = GLAllocation.generateDisplayLists(1); + GL11.glNewList(list, GL11.GL_COMPILE); + + ForgeDirection rotorDir = rotorInfo.rotorDirection; + int rotorLen = rotorInfo.rotorLength; + CoordTriplet currentRotorCoord = new CoordTriplet(0, 0, 0); + + Tessellator tessellator = Tessellator.instance; + if (rotorDir.offsetX != 0) { + tessellator.setTranslation(0, -0.5, -0.5); + } else if (rotorDir.offsetY != 0) { + tessellator.setTranslation(-0.5, 0, -0.5); + } else { + tessellator.setTranslation(-0.5, -0.5, 0); + } + + tessellator.startDrawingQuads(); + tessellator.setBrightness(256); + tessellator.setColorOpaque(255, 255, 255); + + CoordTriplet bladeCoord = new CoordTriplet(0, 0, 0); + int rotorIdx = 0; + boolean[] hasBlades = new boolean[4]; + ForgeDirection[] bladeDirs = StaticUtils.neighborsBySide[rotorInfo.rotorDirection.ordinal()]; + + while (rotorIdx < rotorInfo.rotorLength) { + + for (int i = 0; i < hasBlades.length; i++) { + hasBlades[i] = rotorInfo.bladeLengths[rotorIdx][i] > 0; + } + + RotorSimpleRenderer.renderRotorShaft( + BigReactors.blockTurbineRotorPart, + renderBlocks, + BlockTurbineRotorPart.METADATA_SHAFT, + rotorDir, + hasBlades, + currentRotorCoord.x, + currentRotorCoord.y, + currentRotorCoord.z, + false); + for (int bladeIdx = 0; bladeIdx < bladeDirs.length; bladeIdx++) { + bladeCoord.copy(currentRotorCoord); + int bladeLen = 0; + bladeCoord.translate(bladeDirs[bladeIdx]); + while (bladeLen < rotorInfo.bladeLengths[rotorIdx][bladeIdx]) { + RotorSimpleRenderer.renderBlade( + renderBlocks, + bladeCoord.x, + bladeCoord.y, + bladeCoord.z, + BigReactors.blockTurbineRotorPart, + BlockTurbineRotorPart.METADATA_BLADE, + rotorInfo.rotorDirection); + bladeLen++; + bladeCoord.translate(bladeDirs[bladeIdx]); + } + } + rotorIdx++; + currentRotorCoord.translate(rotorDir); + } + tessellator.setTranslation(0, 0, 0); + tessellator.draw(); + + GL11.glEndList(); + return list; + } + } diff --git a/src/main/java/erogenousbeef/bigreactors/client/renderer/SimpleRendererFuelRod.java b/src/main/java/erogenousbeef/bigreactors/client/renderer/SimpleRendererFuelRod.java index 591dad0c..d314f252 100644 --- a/src/main/java/erogenousbeef/bigreactors/client/renderer/SimpleRendererFuelRod.java +++ b/src/main/java/erogenousbeef/bigreactors/client/renderer/SimpleRendererFuelRod.java @@ -20,16 +20,14 @@ public class SimpleRendererFuelRod implements ISimpleBlockRenderingHandler { - private static final float FLUID_RENDER_OFFSET_MAX = 0.05f; - private static final float FLUID_RENDER_OFFSET_MIN = 0.45f; - - public SimpleRendererFuelRod() { - } - - @Override - public void renderInventoryBlock(Block block, int metadata, int modelID, - RenderBlocks renderer) { - Tessellator tessellator = Tessellator.instance; + private static final float FLUID_RENDER_OFFSET_MAX = 0.05f; + private static final float FLUID_RENDER_OFFSET_MIN = 0.45f; + + public SimpleRendererFuelRod() {} + + @Override + public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer) { + Tessellator tessellator = Tessellator.instance; GL11.glTranslatef(-0.5F, -0.5F, -0.5F); tessellator.startDrawingQuads(); tessellator.setNormal(0.0F, -1.0F, 0.0F); @@ -56,12 +54,14 @@ public void renderInventoryBlock(Block block, int metadata, int modelID, renderer.renderFaceXPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 5, metadata)); tessellator.draw(); GL11.glTranslatef(0.5F, 0.5F, 0.5F); - } + } - @Override - public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, - Block block, int modelId, RenderBlocks renderer) { - if(!(block instanceof BlockFuelRod)) { return false; } + @Override + public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, + RenderBlocks renderer) { + if (!(block instanceof BlockFuelRod)) { + return false; + } Tessellator tessellator = Tessellator.instance; @@ -69,190 +69,184 @@ public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, boolean renderBottom = block.shouldSideBeRendered(world, x, y - 1, z, 0); boolean renderedFuelOnTop = false; boolean renderedFuelOnBottom = false; - - boolean[] renderSides = new boolean[] - { - block.shouldSideBeRendered(world, x, y, z - 1, 2), - block.shouldSideBeRendered(world, x, y, z + 1, 3), - block.shouldSideBeRendered(world, x - 1, y, z, 4), - block.shouldSideBeRendered(world, x + 1, y, z, 5) - }; - - if (!renderTop && !renderBottom && !renderSides[0] && !renderSides[1] && !renderSides[2] && !renderSides[3]) - { + + boolean[] renderSides = new boolean[] { block.shouldSideBeRendered(world, x, y, z - 1, 2), + block.shouldSideBeRendered(world, x, y, z + 1, 3), block.shouldSideBeRendered(world, x - 1, y, z, 4), + block.shouldSideBeRendered(world, x + 1, y, z, 5) }; + + if (!renderTop && !renderBottom && !renderSides[0] && !renderSides[1] && !renderSides[2] && !renderSides[3]) { return false; } boolean rendered = false; int blockMetadata = world.getBlockMetadata(x, y, z); - + // Render internal bits, if we can TileEntity te; te = world.getTileEntity(x, y, z); - if(te instanceof TileEntityReactorFuelRod) { - TileEntityReactorFuelRod fuelRod = (TileEntityReactorFuelRod)te; - if(fuelRod.isConnected()) { - MultiblockReactor reactor = (MultiblockReactor)fuelRod.getMultiblockController(); - int fuelAmount = reactor.getFuelAmount(); - int wasteAmount = reactor.getWasteAmount(); - int totalFluid = fuelAmount + wasteAmount; - int capacity = reactor.getCapacity(); - if(capacity > 0 && totalFluid > 0) { - // Okay, we're connected and have some kind of fluid inside. Let's do this. - float fluidColumnOffsetFromCenter = -1f; - float red, green, blue; - IIcon iconSide, iconBottom; - iconSide = iconBottom = null; - red = green = blue = 1f; - - iconSide = BigReactors.fluidFuelColumn.getFlowingIcon(); - iconBottom = BigReactors.fluidFuelColumn.getStillIcon(); - - ReactantData fuelData = Reactants.getReactant(reactor.getFuelType()); - ReactantData wasteData = Reactants.getReactant(reactor.getWasteType()); - - int fuelColor = fuelData != null ? fuelData.getColor() : StandardReactants.colorYellorium; - int wasteColor = wasteData != null ? wasteData.getColor() : StandardReactants.colorCyanite; - - if(fuelAmount == 0) { - red = unpackR(wasteColor); - green = unpackG(wasteColor); - blue = unpackB(wasteColor); - } - else if(fuelAmount >= totalFluid) { - red = unpackR(fuelColor); - green = unpackG(fuelColor); - blue = unpackB(fuelColor); - } - else { - // Blend the colors - float proportion = (float)fuelAmount / (float)totalFluid; - float fuelR, fuelG, fuelB; - float wasteR, wasteG, wasteB; - - fuelR = unpackR(fuelColor); - fuelG = unpackG(fuelColor); - fuelB = unpackB(fuelColor); - wasteR = unpackR(wasteColor); - wasteG = unpackG(wasteColor); - wasteB = unpackB(wasteColor); - - red = lerp(wasteR, fuelR, proportion); - green = lerp(wasteG, fuelG, proportion); - blue = lerp(wasteB, fuelB, proportion); - } - - float pctFilled = Math.min(1f, Math.max(0f, (float)totalFluid / (float)capacity)); - fluidColumnOffsetFromCenter = lerp(FLUID_RENDER_OFFSET_MIN, FLUID_RENDER_OFFSET_MAX, pctFilled); - - if(iconSide != null && iconBottom != null) { - // We've got fuel data! Let's do this thang. - - tessellator.setColorRGBA_F(red, green, blue, 0.75f); - tessellator.setBrightness(world.getLightBrightnessForSkyBlocks(x, y, z, 15)); - - renderer.setOverrideBlockTexture(iconBottom); - float xzMin = fluidColumnOffsetFromCenter; - float xzMax = 1f - fluidColumnOffsetFromCenter; - renderer.setRenderBounds(xzMin, 0.01f, xzMin, xzMax, 0.99f, xzMax); - - if(renderer.renderAllFaces || renderBottom) { - rendered = true; - renderer.renderFaceYNeg(block, x, y, z, iconBottom); - } - - if(renderer.renderAllFaces || renderTop) { - rendered = true; - renderer.renderFaceYPos(block, x, y, z, iconBottom); - } - - renderer.setOverrideBlockTexture(iconSide); - renderer.setRenderBounds(xzMin, 0f, xzMin, xzMax, 1f, xzMax); - - if(renderer.renderAllFaces || renderSides[0]) { - rendered = true; - renderer.renderFaceZNeg(block, x, y, z, iconSide); - } - if(renderer.renderAllFaces || renderSides[1]) { - rendered = true; - renderer.renderFaceZPos(block, x, y, z, iconSide); - } - if(renderer.renderAllFaces || renderSides[2]) { - rendered = true; - renderer.renderFaceXNeg(block, x, y, z, iconSide); - } - if(renderer.renderAllFaces || renderSides[3]) { - rendered = true; - renderer.renderFaceXPos(block, x, y, z, iconSide); - } - } - } - } + if (te instanceof TileEntityReactorFuelRod) { + TileEntityReactorFuelRod fuelRod = (TileEntityReactorFuelRod) te; + if (fuelRod.isConnected()) { + MultiblockReactor reactor = (MultiblockReactor) fuelRod.getMultiblockController(); + int fuelAmount = reactor.getFuelAmount(); + int wasteAmount = reactor.getWasteAmount(); + int totalFluid = fuelAmount + wasteAmount; + int capacity = reactor.getCapacity(); + if (capacity > 0 && totalFluid > 0) { + // Okay, we're connected and have some kind of fluid inside. Let's do this. + float fluidColumnOffsetFromCenter = -1f; + float red, green, blue; + IIcon iconSide, iconBottom; + iconSide = iconBottom = null; + red = green = blue = 1f; + + iconSide = BigReactors.fluidFuelColumn.getFlowingIcon(); + iconBottom = BigReactors.fluidFuelColumn.getStillIcon(); + + ReactantData fuelData = Reactants.getReactant(reactor.getFuelType()); + ReactantData wasteData = Reactants.getReactant(reactor.getWasteType()); + + int fuelColor = fuelData != null ? fuelData.getColor() : StandardReactants.colorYellorium; + int wasteColor = wasteData != null ? wasteData.getColor() : StandardReactants.colorCyanite; + + if (fuelAmount == 0) { + red = unpackR(wasteColor); + green = unpackG(wasteColor); + blue = unpackB(wasteColor); + } else if (fuelAmount >= totalFluid) { + red = unpackR(fuelColor); + green = unpackG(fuelColor); + blue = unpackB(fuelColor); + } else { + // Blend the colors + float proportion = (float) fuelAmount / (float) totalFluid; + float fuelR, fuelG, fuelB; + float wasteR, wasteG, wasteB; + + fuelR = unpackR(fuelColor); + fuelG = unpackG(fuelColor); + fuelB = unpackB(fuelColor); + wasteR = unpackR(wasteColor); + wasteG = unpackG(wasteColor); + wasteB = unpackB(wasteColor); + + red = lerp(wasteR, fuelR, proportion); + green = lerp(wasteG, fuelG, proportion); + blue = lerp(wasteB, fuelB, proportion); + } + + float pctFilled = Math.min(1f, Math.max(0f, (float) totalFluid / (float) capacity)); + fluidColumnOffsetFromCenter = lerp(FLUID_RENDER_OFFSET_MIN, FLUID_RENDER_OFFSET_MAX, pctFilled); + + if (iconSide != null && iconBottom != null) { + // We've got fuel data! Let's do this thang. + + tessellator.setColorRGBA_F(red, green, blue, 0.75f); + tessellator.setBrightness(world.getLightBrightnessForSkyBlocks(x, y, z, 15)); + + renderer.setOverrideBlockTexture(iconBottom); + float xzMin = fluidColumnOffsetFromCenter; + float xzMax = 1f - fluidColumnOffsetFromCenter; + renderer.setRenderBounds(xzMin, 0.01f, xzMin, xzMax, 0.99f, xzMax); + + if (renderer.renderAllFaces || renderBottom) { + rendered = true; + renderer.renderFaceYNeg(block, x, y, z, iconBottom); + } + + if (renderer.renderAllFaces || renderTop) { + rendered = true; + renderer.renderFaceYPos(block, x, y, z, iconBottom); + } + + renderer.setOverrideBlockTexture(iconSide); + renderer.setRenderBounds(xzMin, 0f, xzMin, xzMax, 1f, xzMax); + + if (renderer.renderAllFaces || renderSides[0]) { + rendered = true; + renderer.renderFaceZNeg(block, x, y, z, iconSide); + } + if (renderer.renderAllFaces || renderSides[1]) { + rendered = true; + renderer.renderFaceZPos(block, x, y, z, iconSide); + } + if (renderer.renderAllFaces || renderSides[2]) { + rendered = true; + renderer.renderFaceXNeg(block, x, y, z, iconSide); + } + if (renderer.renderAllFaces || renderSides[3]) { + rendered = true; + renderer.renderFaceXPos(block, x, y, z, iconSide); + } + } + } + } } - + // Then render external housing tessellator.setColorRGBA(255, 255, 255, 255); renderer.setRenderBoundsFromBlock(block); renderer.setOverrideBlockTexture(null); // First, render the regular block - if(!renderedFuelOnBottom && (renderer.renderAllFaces || renderBottom)) { - rendered = true; + if (!renderedFuelOnBottom && (renderer.renderAllFaces || renderBottom)) { + rendered = true; tessellator.setBrightness(block.getMixedBrightnessForBlock(world, x, y, z)); renderer.renderFaceYNeg(block, x, y, z, block.getIcon(0, blockMetadata)); } - if(renderer.renderAllFaces || renderTop) { - rendered = true; + if (renderer.renderAllFaces || renderTop) { + rendered = true; tessellator.setBrightness(block.getMixedBrightnessForBlock(world, x, y, z)); renderer.renderFaceYPos(block, x, y, z, block.getIcon(1, blockMetadata)); } - if(renderer.renderAllFaces || renderSides[0]) { - rendered = true; + if (renderer.renderAllFaces || renderSides[0]) { + rendered = true; tessellator.setBrightness(block.getMixedBrightnessForBlock(world, x, y, z)); renderer.renderFaceZNeg(block, x, y, z, block.getIcon(2, blockMetadata)); } - if(renderer.renderAllFaces || renderSides[1]) { - rendered = true; + if (renderer.renderAllFaces || renderSides[1]) { + rendered = true; tessellator.setBrightness(block.getMixedBrightnessForBlock(world, x, y, z)); renderer.renderFaceZPos(block, x, y, z, block.getIcon(3, blockMetadata)); } - if(renderer.renderAllFaces || renderSides[2]) { - rendered = true; + if (renderer.renderAllFaces || renderSides[2]) { + rendered = true; tessellator.setBrightness(block.getMixedBrightnessForBlock(world, x, y, z)); renderer.renderFaceXNeg(block, x, y, z, block.getIcon(4, blockMetadata)); } - if(renderer.renderAllFaces || renderSides[3]) { - rendered = true; + if (renderer.renderAllFaces || renderSides[3]) { + rendered = true; tessellator.setBrightness(block.getMixedBrightnessForBlock(world, x, y, z)); renderer.renderFaceXPos(block, x, y, z, block.getIcon(5, blockMetadata)); } - - return rendered; - } - - @Override - public boolean shouldRender3DInInventory(int modelID) { - return true; - } - - @Override - public int getRenderId() { - return BlockFuelRod.renderId; - } - - /// HELPERS /// - protected static float unpackR(int rgb) { - return (float)(rgb >> 16 & 255) / 255.0F; - } - - protected static float unpackG(int rgb) { - return (float)(rgb >> 8 & 255) / 255.0F; - } - - protected static float unpackB(int rgb) { - return (float)(rgb & 255) / 255.0F; - } - protected static float lerp(float min, float max, float value) { - return min + (max-min)*value; - } + + return rendered; + } + + @Override + public boolean shouldRender3DInInventory(int modelID) { + return true; + } + + @Override + public int getRenderId() { + return BlockFuelRod.renderId; + } + + /// HELPERS /// + protected static float unpackR(int rgb) { + return (float) (rgb >> 16 & 255) / 255.0F; + } + + protected static float unpackG(int rgb) { + return (float) (rgb >> 8 & 255) / 255.0F; + } + + protected static float unpackB(int rgb) { + return (float) (rgb & 255) / 255.0F; + } + + protected static float lerp(float min, float max, float value) { + return min + (max - min) * value; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/BRConfig.java b/src/main/java/erogenousbeef/bigreactors/common/BRConfig.java index e791c677..748bda79 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/BRConfig.java +++ b/src/main/java/erogenousbeef/bigreactors/common/BRConfig.java @@ -3,29 +3,34 @@ import java.io.File; import net.minecraftforge.common.config.Configuration; + import cpw.mods.fml.common.Loader; public class BRConfig { - /** - * The version of Big Reactors. - * These are replaced by Gradle when built. - */ - public static final String VERSION = "@VERSION@"; - public static final String MINECRAFT_VERSION = "[1.7.10]"; - - public static final int WORLDGEN_VERSION = 1; // Bump this when changing world generation so the world regens - - /** - * The Big Reactors configuration file. - */ - public static final Configuration CONFIGURATION = new Configuration(new File(Loader.instance().getConfigDir(), "BigReactors" + File.separator + "BigReactors.cfg")); - - static - { - /** - * Loads the configuration and sets all the values. - */ - CONFIGURATION.load(); - CONFIGURATION.save(); - } + + /** + * The version of Big Reactors. + * These are replaced by Gradle when built. + */ + public static final String VERSION = "@VERSION@"; + public static final String MINECRAFT_VERSION = "[1.7.10]"; + + public static final int WORLDGEN_VERSION = 1; // Bump this when changing world generation so the world regens + + /** + * The Big Reactors configuration file. + */ + public static final Configuration CONFIGURATION = new Configuration( + new File( + Loader.instance() + .getConfigDir(), + "BigReactors" + File.separator + "BigReactors.cfg")); + + static { + /** + * Loads the configuration and sets all the values. + */ + CONFIGURATION.load(); + CONFIGURATION.save(); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/BREventHandler.java b/src/main/java/erogenousbeef/bigreactors/common/BREventHandler.java index b0a6697d..0b9114d6 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/BREventHandler.java +++ b/src/main/java/erogenousbeef/bigreactors/common/BREventHandler.java @@ -3,39 +3,41 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.ChunkCoordIntPair; import net.minecraftforge.event.world.ChunkDataEvent; + import cpw.mods.fml.common.eventhandler.SubscribeEvent; import erogenousbeef.bigreactors.utils.StaticUtils; public class BREventHandler { - @SubscribeEvent - public void chunkSave(ChunkDataEvent.Save saveEvent) { - if(BigReactors.enableWorldGen) { - NBTTagCompound saveData = saveEvent.getData(); - - saveData.setInteger("BigReactorsWorldGen", BRConfig.WORLDGEN_VERSION); - saveData.setInteger("BigReactorsUserWorldGen", BigReactors.userWorldGenVersion); - } - } - - @SubscribeEvent - public void chunkLoad(ChunkDataEvent.Load loadEvent) { - if(!BigReactors.enableWorldRegeneration || !BigReactors.enableWorldGen) { - return; - } - - NBTTagCompound loadData = loadEvent.getData(); - if(loadData.getInteger("BigReactorsWorldGen") == BRConfig.WORLDGEN_VERSION && - loadData.getInteger("BigReactorsUserWorldGen") == BigReactors.userWorldGenVersion) { - return; - } - - if(!StaticUtils.WorldGen.shouldGenerateInDimension(loadEvent.world.provider.dimensionId)) { - return; - } - - ChunkCoordIntPair coordPair = loadEvent.getChunk().getChunkCoordIntPair(); - BigReactors.tickHandler.addRegenChunk(loadEvent.world.provider.dimensionId, coordPair); - } - + @SubscribeEvent + public void chunkSave(ChunkDataEvent.Save saveEvent) { + if (BigReactors.enableWorldGen) { + NBTTagCompound saveData = saveEvent.getData(); + + saveData.setInteger("BigReactorsWorldGen", BRConfig.WORLDGEN_VERSION); + saveData.setInteger("BigReactorsUserWorldGen", BigReactors.userWorldGenVersion); + } + } + + @SubscribeEvent + public void chunkLoad(ChunkDataEvent.Load loadEvent) { + if (!BigReactors.enableWorldRegeneration || !BigReactors.enableWorldGen) { + return; + } + + NBTTagCompound loadData = loadEvent.getData(); + if (loadData.getInteger("BigReactorsWorldGen") == BRConfig.WORLDGEN_VERSION + && loadData.getInteger("BigReactorsUserWorldGen") == BigReactors.userWorldGenVersion) { + return; + } + + if (!StaticUtils.WorldGen.shouldGenerateInDimension(loadEvent.world.provider.dimensionId)) { + return; + } + + ChunkCoordIntPair coordPair = loadEvent.getChunk() + .getChunkCoordIntPair(); + BigReactors.tickHandler.addRegenChunk(loadEvent.world.provider.dimensionId, coordPair); + } + } diff --git a/src/main/java/erogenousbeef/bigreactors/common/BRLoader.java b/src/main/java/erogenousbeef/bigreactors/common/BRLoader.java index ec0469aa..898baf96 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/BRLoader.java +++ b/src/main/java/erogenousbeef/bigreactors/common/BRLoader.java @@ -9,6 +9,7 @@ import net.minecraftforge.event.entity.player.FillBucketEvent; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; + import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.Mod.EventHandler; import cpw.mods.fml.common.Mod.Instance; @@ -23,92 +24,93 @@ import erogenousbeef.bigreactors.common.data.StandardReactants; import erogenousbeef.core.multiblock.MultiblockEventHandler; -@Mod(modid = BRLoader.MOD_ID, name = BigReactors.NAME, version = BRConfig.VERSION, acceptedMinecraftVersions = BRConfig.MINECRAFT_VERSION, dependencies = BRLoader.DEPENDENCIES) +@Mod( + modid = BRLoader.MOD_ID, + name = BigReactors.NAME, + version = BRConfig.VERSION, + acceptedMinecraftVersions = BRConfig.MINECRAFT_VERSION, + dependencies = BRLoader.DEPENDENCIES) public class BRLoader { - public static final String MOD_ID = BigReactors.MODID; + public static final String MOD_ID = BigReactors.MODID; public static final String DEPENDENCIES = "required-after:Forge@[10.13.2.1291,);required-after:CoFHCore;after:ThermalExpansion"; - - @Instance(MOD_ID) - public static BRLoader instance; - - @SidedProxy(clientSide = "erogenousbeef.bigreactors.client.ClientProxy", serverSide = "erogenousbeef.bigreactors.common.CommonProxy") - public static CommonProxy proxy; - - @Mod.Metadata(MOD_ID) - public static ModMetadata metadata; - - private MultiblockEventHandler multiblockEventHandler; - - @EventHandler - public void preInit(FMLPreInitializationEvent event) - { - BigReactors.registerOres(0, true); - BigReactors.registerIngots(0); - BigReactors.registerFuelRods(0, true); - BigReactors.registerReactorPartBlocks(0, true); - BigReactors.registerTurbineParts(); - BigReactors.registerDevices(0, true); - BigReactors.registerFluids(0, true); - BigReactors.registerCreativeParts(0, true); - BigReactors.registerItems(); - - StandardReactants.register(); - - BigReactors.eventHandler = new BREventHandler(); - MinecraftForge.EVENT_BUS.register(BigReactors.eventHandler); - MinecraftForge.EVENT_BUS.register(proxy); - - multiblockEventHandler = new MultiblockEventHandler(); - MinecraftForge.EVENT_BUS.register(multiblockEventHandler); - - proxy.preInit(); - - Fluid waterFluid = FluidRegistry.WATER; // Force-load water to prevent startup crashes - } - - @EventHandler - public void load(FMLInitializationEvent evt) - { - proxy.init(); - BigReactors.register(this); - } - - @EventHandler - public void postInit(FMLPostInitializationEvent evt) { - proxy.postInit(); - } - - @EventHandler - public void onIMCEvent(FMLInterModComms.IMCEvent event) { - // TODO - } - - // GAME EVENT HANDLERS - // FORGE EVENT HANDLERS - - // Handle bucketing of reactor fluids - @SubscribeEvent - public void onBucketFill(FillBucketEvent e) - { - if(e.current.getItem() != Items.bucket) - { + + @Instance(MOD_ID) + public static BRLoader instance; + + @SidedProxy( + clientSide = "erogenousbeef.bigreactors.client.ClientProxy", + serverSide = "erogenousbeef.bigreactors.common.CommonProxy") + public static CommonProxy proxy; + + @Mod.Metadata(MOD_ID) + public static ModMetadata metadata; + + private MultiblockEventHandler multiblockEventHandler; + + @EventHandler + public void preInit(FMLPreInitializationEvent event) { + BigReactors.registerOres(0, true); + BigReactors.registerIngots(0); + BigReactors.registerFuelRods(0, true); + BigReactors.registerReactorPartBlocks(0, true); + BigReactors.registerTurbineParts(); + BigReactors.registerDevices(0, true); + BigReactors.registerFluids(0, true); + BigReactors.registerCreativeParts(0, true); + BigReactors.registerItems(); + + StandardReactants.register(); + + BigReactors.eventHandler = new BREventHandler(); + MinecraftForge.EVENT_BUS.register(BigReactors.eventHandler); + MinecraftForge.EVENT_BUS.register(proxy); + + multiblockEventHandler = new MultiblockEventHandler(); + MinecraftForge.EVENT_BUS.register(multiblockEventHandler); + + proxy.preInit(); + + Fluid waterFluid = FluidRegistry.WATER; // Force-load water to prevent startup crashes + } + + @EventHandler + public void load(FMLInitializationEvent evt) { + proxy.init(); + BigReactors.register(this); + } + + @EventHandler + public void postInit(FMLPostInitializationEvent evt) { + proxy.postInit(); + } + + @EventHandler + public void onIMCEvent(FMLInterModComms.IMCEvent event) { + // TODO + } + + // GAME EVENT HANDLERS + // FORGE EVENT HANDLERS + + // Handle bucketing of reactor fluids + @SubscribeEvent + public void onBucketFill(FillBucketEvent e) { + if (e.current.getItem() != Items.bucket) { return; } ItemStack filledBucket = fillBucket(e.world, e.target); - if(filledBucket != null) - { + if (filledBucket != null) { e.world.setBlockToAir(e.target.blockX, e.target.blockY, e.target.blockZ); e.result = filledBucket; e.setResult(Result.ALLOW); } } - - private ItemStack fillBucket(World world, MovingObjectPosition mop) - { + + private ItemStack fillBucket(World world, MovingObjectPosition mop) { Block block = world.getBlock(mop.blockX, mop.blockY, mop.blockZ); - if(block == BigReactors.fluidCyaniteStill) return new ItemStack(BigReactors.fluidCyaniteBucketItem); - else if(block == BigReactors.fluidYelloriumStill) return new ItemStack(BigReactors.fluidYelloriumBucketItem); + if (block == BigReactors.fluidCyaniteStill) return new ItemStack(BigReactors.fluidCyaniteBucketItem); + else if (block == BigReactors.fluidYelloriumStill) return new ItemStack(BigReactors.fluidYelloriumBucketItem); else return null; } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/BRLog.java b/src/main/java/erogenousbeef/bigreactors/common/BRLog.java index 85f67733..38ab70c9 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/BRLog.java +++ b/src/main/java/erogenousbeef/bigreactors/common/BRLog.java @@ -6,40 +6,33 @@ public class BRLog { - private static final String LOGCHANNEL = "BigReactors"; - - public static void log(Level level, String format, Object... data) - { - FMLLog.log(LOGCHANNEL, level, format, data); + private static final String LOGCHANNEL = "BigReactors"; + + public static void log(Level level, String format, Object... data) { + FMLLog.log(LOGCHANNEL, level, format, data); } - public static void fatal(String format, Object... data) - { + public static void fatal(String format, Object... data) { log(Level.FATAL, format, data); } - public static void error(String format, Object... data) - { - log(Level.ERROR, format, data); + public static void error(String format, Object... data) { + log(Level.ERROR, format, data); } - public static void warning(String format, Object... data) - { + public static void warning(String format, Object... data) { log(Level.WARN, format, data); } - public static void info(String format, Object... data) - { + public static void info(String format, Object... data) { log(Level.INFO, format, data); } - public static void debug(String format, Object... data) - { + public static void debug(String format, Object... data) { log(Level.DEBUG, format, data); } - public static void trace(String format, Object... data) - { + public static void trace(String format, Object... data) { log(Level.TRACE, format, data); } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/BigReactors.java b/src/main/java/erogenousbeef/bigreactors/common/BigReactors.java index e28feee8..7f8735f2 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/BigReactors.java +++ b/src/main/java/erogenousbeef/bigreactors/common/BigReactors.java @@ -19,6 +19,7 @@ import net.minecraftforge.oredict.OreDictionary; import net.minecraftforge.oredict.ShapedOreRecipe; import net.minecraftforge.oredict.ShapelessOreRecipe; + import cofh.core.util.oredict.OreDictionaryArbiter; import cofh.lib.util.helpers.ItemHelper; import cpw.mods.fml.common.Loader; @@ -74,835 +75,1327 @@ public class BigReactors { - public static final String NAME = "Big Reactors"; - public static final String MODID = "BigReactors"; - public static final String CHANNEL = MODID.toLowerCase(); - public static final String RESOURCE_PATH = "/assets/bigreactors/"; - - public static final CreativeTabs TAB = new CreativeTabBR(MODID); - - public static final String TEXTURE_NAME_PREFIX = "bigreactors:"; - - public static final String TEXTURE_DIRECTORY = RESOURCE_PATH + "textures/"; - public static final String GUI_DIRECTORY = TEXTURE_NAME_PREFIX + "textures/gui/"; - public static final String BLOCK_TEXTURE_DIRECTORY = TEXTURE_DIRECTORY + "blocks/"; - public static final String ITEM_TEXTURE_DIRECTORY = TEXTURE_DIRECTORY + "items/"; - public static final String MODEL_TEXTURE_DIRECTORY = TEXTURE_DIRECTORY + "models/"; - - public static final String LANGUAGE_PATH = RESOURCE_PATH + "languages/"; - private static final String[] LANGUAGES_SUPPORTED = new String[] { "de_DE", "en_US", "es_SP", "nl_NL", "pl_PL", "pt_BR", "ru_RU", "sv_SE", "zh_CN" }; - - public static final int BLOCK_ID_PREFIX = 1750; - - public static Block blockYelloriteOre; - public static BlockBRMetal blockMetal; - public static Block blockYelloriumFuelRod; - public static BlockReactorPart blockReactorPart; - public static Block blockReactorRedstonePort; // UGH. Why does the redstone API not allow me to check metadata? :( - - public static BlockTurbinePart blockTurbinePart; - public static BlockTurbineRotorPart blockTurbineRotorPart; - - public static BlockMultiblockGlass blockMultiblockGlass; - public static BlockMBCreativePart blockMultiblockCreativePart; - - public static Block blockRadiothermalGen; - public static Block blockDevice; - - public static Block fluidYelloriumStill; - public static Block fluidCyaniteStill; - public static Block fluidFuelColumnStill; - - // Buckets for bucketing reactor fluids - public static Item fluidYelloriumBucketItem; - public static Item fluidCyaniteBucketItem; - - public static Fluid fluidYellorium; - public static Fluid fluidCyanite; - public static Fluid fluidFuelColumn; - - public static Fluid fluidSteam; - public static boolean registeredOwnSteam; - - public static final int defaultFluidColorFuel = 0xbcba50; - public static final int defaultFluidColorWaste = 0x4d92b5; - - public static final int ITEM_ID_PREFIX = 17750; - public static ItemIngot ingotGeneric; - - public static ItemBeefDebugTool itemDebugTool; - - public static BRSimpleOreGenerator yelloriteOreGeneration; - - public static boolean INITIALIZED = false; - public static boolean enableWorldGen = true; - public static boolean enableWorldGenInNegativeDimensions = false; - public static boolean enableWorldRegeneration = true; - public static int userWorldGenVersion = 0; - - public static BREventHandler eventHandler = null; - public static BigReactorsTickHandler tickHandler = null; - public static BRWorldGenerator worldGenerator = null; - public static HashSet dimensionWhitelist = new HashSet(); - - private static boolean registeredTileEntities = false; - public static int maximumReactorSize = MultiblockReactor.DIMENSION_UNBOUNDED; - public static int maximumReactorHeight = MultiblockReactor.DIMENSION_UNBOUNDED; - public static int ticksPerRedstoneUpdate = 20; // Once per second, roughly - - public static int maximumTurbineSize = 16; - public static int maximumTurbineHeight = 32; - - public static float powerProductionMultiplier = 1.0f; - public static float fuelUsageMultiplier = 1.0f; - - public static float reactorPowerProductionMultiplier = 1.0f; - public static float turbinePowerProductionMultiplier = 1.0f; - - public static float turbineCoilDragMultiplier = 1.0f; - public static float turbineAeroDragMultiplier = 1.0f; - public static float turbineMassDragMultiplier = 1.0f; - public static float turbineFluidPerBladeMultiplier = 1.0f; - - public static boolean isValentinesDay = false; // Easter Egg :) - - // Game Balance values - - protected static IIcon iconSteamStill; - protected static IIcon iconSteamFlowing; - protected static IIcon iconFuelColumnStill; - protected static IIcon iconFuelColumnFlowing; - - private static boolean registerYelloriteSmeltToUranium = true; - private static boolean registerYelloriumAsUranium = true; - - /** - * Call this function in your mod init stage. - */ - public static void register(Object modInstance) - { - - if (!INITIALIZED) - { - - // General config loading - BRConfig.CONFIGURATION.load(); - enableWorldGen = BRConfig.CONFIGURATION.get("WorldGen", "enableWorldGen", true, "If false, disables all world gen from Big Reactors; all other worldgen settings are automatically overridden").getBoolean(true); - enableWorldGenInNegativeDimensions = BRConfig.CONFIGURATION.get("WorldGen", "enableWorldGenInNegativeDims", false, "Run BR world generation in negative dimension IDs? (default: false) If you don't know what this is, leave it alone.").getBoolean(false); - enableWorldRegeneration = BRConfig.CONFIGURATION.get("WorldGen", "enableWorldRegeneration", false, "Run BR World Generation in chunks that have already been generated, but have not been modified by Big Reactors before. This is largely useful for worlds that existed before BigReactors was released.").getBoolean(false); - userWorldGenVersion = BRConfig.CONFIGURATION.get("WorldGen", "userWorldGenVersion", 0, "User-set world generation version. Increase this by 1 if you want Big Reactors to re-run world generation in your world.").getInt(); - int[] worldGenDimensionWhitelist = BRConfig.CONFIGURATION.get("WorldGen", "dimensionWhitelist", new int[] {}, "If enableWorldGenInNegativeDimensions is false, you may add negative dimensions to this whitelist to selectively enable worldgen in them.").getIntList(); - for(int i : worldGenDimensionWhitelist) { - dimensionWhitelist.add(i); - } - - boolean registerCoalFurnaceRecipe = BRConfig.CONFIGURATION.get("Recipes", "registerCoalForSmelting", true, "If set, coal will be smeltable into graphite bars. Disable this if other mods need to smelt coal into their own products. (Default: true)").getBoolean(true); - boolean registerCharcoalFurnaceRecipe = BRConfig.CONFIGURATION.get("Recipes", "registerCharcoalForSmelting", true, "If set, charcoal will be smeltable into graphite bars. Disable this if other mods need to smelt charcoal into their own products. (Default: true)").getBoolean(true); - boolean registerCoalCraftingRecipe = BRConfig.CONFIGURATION.get("Recipes", "registerGraphiteCoalCraftingRecipes", false, "If set, graphite bars can be crafted from 2 gravel, 1 coal. Use this if other mods interfere with the smelting recipe. (Default: false)").getBoolean(false); - boolean registerCharcoalCraftingRecipe = BRConfig.CONFIGURATION.get("Recipes", "registerGraphiteCharcoalCraftingRecipes", false, "If set, graphite bars can be crafted from 2 gravel, 1 charcoal. Use this if other mods interfere with the smelting recipe. (Default: false)").getBoolean(false); - registerYelloriteSmeltToUranium = BRConfig.CONFIGURATION.get("Recipes", "registerYelloriteSmeltToUranium", true, "If set, yellorite ore will smelt into whichever item is registered as ingotUranium in the ore dictionary. If false, it will smelt into ingotYellorium. (Default: true)").getBoolean(true); - - boolean useSteelForIron = BRConfig.CONFIGURATION.get("Recipes", "requireSteelInsteadOfIron", false, "If set, then all Big Reactors components will require steel ingots (ingotSteel) in place of iron ingots. Will be ignored if no other mod registers steel ingots. (default: false)").getBoolean(false); - boolean useExpensiveGlass = BRConfig.CONFIGURATION.get("Recipes", "requireObsidianGlass", false, "If set, then Big Reactors will require hardened or reinforced glass (blockGlassHardened or glassReinforced) instead of plain glass. Will be ignored if no other mod registers those glass types. (default: false)").getBoolean(false); - - boolean enableReactorPowerTapRecipe = BRConfig.CONFIGURATION.get("Recipes", "enableReactorPowerTapRecipe", true, "If set, reactor power taps can be crafted, allowing players to use passive-cooled reactors.").getBoolean(true); - boolean enableCyaniteFromYelloriumRecipe = BRConfig.CONFIGURATION.get("Recipes", "enableCyaniteFromYelloriumRecipe", true, "If set, cyanite will be craftable from yellorium ingots and sand.").getBoolean(true); - - maximumReactorSize = BRConfig.CONFIGURATION.get("General", "maxReactorSize", 32, "The maximum valid size of a reactor in the X/Z plane, in blocks. Lower this if your server's players are building ginormous reactors.").getInt(); - maximumReactorHeight = BRConfig.CONFIGURATION.get("General", "maxReactorHeight", 48, "The maximum valid size of a reactor in the Y dimension, in blocks. Lower this if your server's players are building ginormous reactors. Bigger Y sizes have far less performance impact than X/Z sizes.").getInt(); - ticksPerRedstoneUpdate = BRConfig.CONFIGURATION.get("General", "ticksPerRedstoneUpdate", 20, "Number of ticks between updates for redstone/rednet ports.").getInt(); - powerProductionMultiplier = (float)BRConfig.CONFIGURATION.get("General", "powerProductionMultiplier", 1.0f, "A multiplier for balancing overall power production from Big Reactors. Defaults to 1.").getDouble(1.0); - fuelUsageMultiplier = (float)BRConfig.CONFIGURATION.get("General", "fuelUsageMultiplier", 1.0f, "A multiplier for balancing fuel consumption. Defaults to 1.").getDouble(1.0); - - reactorPowerProductionMultiplier = (float)BRConfig.CONFIGURATION.get("General", "reactorPowerProductionMultiplier", 1.0f, "A multiplier for balancing reactor power production. Stacks with powerProductionMultiplier. Defaults to 1.").getDouble(1.0); - turbinePowerProductionMultiplier = (float)BRConfig.CONFIGURATION.get("General", "turbinePowerProductionMultiplier", 1.0f, "A multiplier for balancing turbine power production. Stacks with powerProductionMultiplier. Defaults to 1.").getDouble(1.0); - - maximumTurbineSize = BRConfig.CONFIGURATION.get("General", "maxTurbineSize", 16, "The maximum valid size of a turbine in the X/Z plane, in blocks. Lower this for smaller turbines, which means lower max output.").getInt(); - maximumTurbineHeight = BRConfig.CONFIGURATION.get("General", "maxTurbineHeight", 32, "The maximum valid height of a turbine (Y axis), in blocks. (Default: 32)").getInt(); - - turbineCoilDragMultiplier = (float)BRConfig.CONFIGURATION.get("General", "turbineCoilDragMultiplier", 1.0, "A multiplier for balancing coil size. Multiplies the amount of energy drawn per coil block per tick. (Default: 1)").getDouble(1.0); - turbineAeroDragMultiplier = (float)BRConfig.CONFIGURATION.get("General", "turbineAeroDragMultiplier", 1.0, "A multiplier for balancing rotor sizes. Multiplies the amount of energy lost to aerodynamic drag per tick. (Default: 1)").getDouble(1.0); - turbineMassDragMultiplier = (float)BRConfig.CONFIGURATION.get("General", "turbineMassDragMultiplier", 1.0, "A multiplier for balancing rotor sizes. Multiplies the amount of energy lost to friction per tick. (Default: 1)").getDouble(1.0); - turbineFluidPerBladeMultiplier = (float)BRConfig.CONFIGURATION.get("General", "turbineFluidPerBladeMultiplier", 1.0, "A multiplier for balancing coil size. Multiplies the amount of fluid each blade block can process (base of 25 will be multiplied, then rounded down to the nearest integer). (Default: 1)").getDouble(1.0); - - - - MultiblockTurbine.inputFluidPerBlade = (int) Math.floor(MultiblockTurbine.inputFluidPerBlade * turbineFluidPerBladeMultiplier); - MultiblockTurbine.inductorBaseDragCoefficient *= turbineCoilDragMultiplier; - - BRConfig.CONFIGURATION.save(); - - if(enableWorldGen) { - worldGenerator = new BRWorldGenerator(); - GameRegistry.registerWorldGenerator(worldGenerator, 0); - } - - // Patch up vanilla being stupid - most mods already do this, so it's usually a no-op - if(!ItemHelper.oreNameExists("ingotIron")) { - OreDictionary.registerOre("ingotIron", new ItemStack(Items.iron_ingot, 1)); - } - - if(!ItemHelper.oreNameExists("ingotGold")) { - OreDictionary.registerOre("ingotGold", new ItemStack(Items.gold_ingot, 1)); - } - - if(!ItemHelper.oreNameExists("blockSnow")) { - OreDictionary.registerOre("blockSnow", new ItemStack(Blocks.snow, 1)); - } - - if(!ItemHelper.oreNameExists("blockIce")) { - OreDictionary.registerOre("blockIce", new ItemStack(Blocks.ice, 1)); - } - - if(!ItemHelper.oreNameExists("blockGlassColorless")) { - OreDictionary.registerOre("blockGlassColorless", new ItemStack(Blocks.glass, 1)); - } - - // Use steel if the players are masochists and someone else has supplied steel. - String ironOrSteelIngot = "ingotIron"; - if(useSteelForIron) { - ironOrSteelIngot = "ingotSteel"; - } - - String yelloriumIngot = "ingotYellorium"; - String blutoniumIngot = "ingotBlutonium"; - if(registerYelloriumAsUranium) { - yelloriumIngot = "ingotUranium"; - blutoniumIngot = "ingotPlutonium"; - } - - /* - * Register Recipes - */ - // Recipe Registry - - // Yellorium - if (blockYelloriteOre != null) - { - ItemStack product; - - if(registerYelloriteSmeltToUranium) { - ArrayList candidateOres = OreDictionaryArbiter.getOres("ingotUranium"); - if(candidateOres == null || candidateOres.size() <= 0) { - BRLog.warning("Config value registerYelloriteSmeltToUranium is set to True, but there are no ores registered as ingotUranium in the ore dictionary! Falling back to using standard yellorium only."); - candidateOres = OreDictionaryArbiter.getOres("ingotYellorium"); - } - product = candidateOres.get(0).copy(); - } - else { - product = OreDictionaryArbiter.getOres("ingotYellorium").get(0).copy(); - } - - GameRegistry.addSmelting(blockYelloriteOre, product, 0.5f); - } - - - // Metal blocks - if(blockMetal != null && ingotGeneric != null) { - blockMetal.registerIngotRecipes(ingotGeneric); - } - - if(blockMetal != null) { - // Ludicrite block. Because. - GameRegistry.addRecipe(new ShapedOreRecipe(blockMetal.getItemStackForMaterial("Ludicrite"), "BPB", "ENE", "BPB", 'N', Items.nether_star, 'P', Items.ender_pearl, 'E', Blocks.emerald_block, 'B', blutoniumIngot)); - if(ItemHelper.getOre("blockEnderium") != null) { - // Ok, how about some ludicrous shit here. Enderium and blaze rods. Have fun, bucko. - GameRegistry.addRecipe(new ShapedOreRecipe(blockMetal.getItemStackForMaterial("Ludicrite"), "BRB", "E E", "BRB", 'B', blutoniumIngot, 'R', Items.blaze_rod, 'E', "blockEnderium")); - } - } - - if(ingotGeneric != null) { - // Map all dusts to ingots. - for(int i = 0; i < ItemIngot.MATERIALS.length; i++) { - ItemStack ingotStack = ingotGeneric.getIngotItem(ItemIngot.MATERIALS[i]); - ItemStack dustStack = ingotGeneric.getDustItem(ItemIngot.MATERIALS[i]); - GameRegistry.addSmelting(dustStack, ingotStack, 0f); - } - } - - ItemStack ingotGraphite = OreDictionaryArbiter.getOres("ingotGraphite").get(0).copy(); - ItemStack ingotCyanite = OreDictionaryArbiter.getOres("ingotCyanite").get(0).copy(); - - if(registerCoalFurnaceRecipe) { - // Coal -> Graphite - GameRegistry.addSmelting(Items.coal, ingotGraphite, 1); - } - - if(registerCharcoalFurnaceRecipe) { - // Charcoal -> Graphite - GameRegistry.addSmelting(new ItemStack(Items.coal, 1, 1), ingotGraphite, 1); - } - - if(registerCoalCraftingRecipe) { - GameRegistry.addRecipe(new ShapedOreRecipe(ingotGraphite, "GCG", 'G', Blocks.gravel, 'C', new ItemStack(Items.coal, 1, 0))); - } - - if(registerCharcoalCraftingRecipe) { - GameRegistry.addRecipe(new ShapedOreRecipe( ingotGraphite, "GCG", 'G', Blocks.gravel, 'C', new ItemStack(Items.coal, 1, 1))); - } - - if(enableCyaniteFromYelloriumRecipe) { - GameRegistry.addRecipe(new ShapelessOreRecipe(ingotCyanite, yelloriumIngot, Blocks.sand )); - } - - // Basic Parts: Reactor Casing, Fuel Rods - if(blockYelloriumFuelRod != null) { - GameRegistry.addRecipe(new ShapedOreRecipe( new ItemStack(blockYelloriumFuelRod, 1), "ICI", "IUI", "ICI", 'I', ironOrSteelIngot, 'C', "ingotGraphite", 'U', yelloriumIngot)); - } - - if(blockReactorPart != null) { - ItemStack reactorPartStack = BigReactors.blockReactorPart.getReactorCasingItemStack(); - reactorPartStack.stackSize = 4; - GameRegistry.addRecipe(new ShapedOreRecipe(reactorPartStack, "ICI", "CUC", "ICI", 'I', ironOrSteelIngot, 'C', "ingotGraphite", 'U', yelloriumIngot)); - } - - // Advanced Parts: Control Rod, Access Port, Power Tap, Controller - if(blockReactorPart != null) { - ItemStack reactorPartStack = BigReactors.blockReactorPart.getReactorControllerItemStack(); - - GameRegistry.addRecipe(new ShapedOreRecipe(reactorPartStack, "C C", "GDG", "CRC", 'D', Items.diamond, 'G', yelloriumIngot, 'C', "reactorCasing", 'R', Items.redstone)); - - if(enableReactorPowerTapRecipe) { - reactorPartStack = BigReactors.blockReactorPart.getReactorPowerTapItemStack(); - GameRegistry.addRecipe(new ShapedOreRecipe(reactorPartStack, "CRC", "R R", "CRC", 'C', "reactorCasing", 'R', Items.redstone)); - } - - reactorPartStack = BigReactors.blockReactorPart.getAccessPortItemStack(); - GameRegistry.addRecipe(new ShapedOreRecipe(reactorPartStack, "C C", " V ", "CPC", 'C', "reactorCasing", 'V', Blocks.chest, 'P', Blocks.piston)); - - reactorPartStack = BigReactors.blockReactorPart.getCoolantPortItemStack(); - GameRegistry.addRecipe(new ShapedOreRecipe(reactorPartStack, "C C", "IVI", "CPC", 'C', "reactorCasing", 'V', Items.bucket, 'P', Blocks.piston, 'I', ironOrSteelIngot)); - - reactorPartStack = BigReactors.blockReactorPart.getControlRodItemStack(); - GameRegistry.addRecipe(new ShapedOreRecipe(reactorPartStack, "CGC", "GRG", "CUC", 'G', "ingotGraphite", 'C', "reactorCasing", 'R', Items.redstone, 'U', yelloriumIngot)); - - if(Loader.isModLoaded("MineFactoryReloaded")) { - reactorPartStack = BigReactors.blockReactorPart.getRedNetPortItemStack(); - GameRegistry.addRecipe(new ShapedOreRecipe(reactorPartStack, "CRC", "RGR", "CRC", 'C', "reactorCasing", 'R', "cableRedNet", 'G', "ingotGold")); - } - - if(Loader.isModLoaded("ComputerCraft") || Loader.isModLoaded("OpenComputers")) { - reactorPartStack = BigReactors.blockReactorPart.getComputerPortItemStack(); - GameRegistry.addRecipe(new ShapedOreRecipe(reactorPartStack, "CRC", "GPG", "CRC", 'C', "reactorCasing", 'R', Items.redstone, 'G', "ingotGold", 'P', Items.repeater)); - } - } - - if(blockMultiblockGlass != null) { - ItemStack reactorGlassStack = blockMultiblockGlass.getItemStack("reactor"); - ItemStack turbineGlassStack = blockMultiblockGlass.getItemStack("turbine"); - - if(useExpensiveGlass && (ItemHelper.oreNameExists("glassReinforced") || ItemHelper.oreNameExists("blockGlassHardened"))) { - GameRegistry.addRecipe(new ShapedOreRecipe(reactorGlassStack, "GCG", 'G', "glassReinforced", 'C', "reactorCasing")); - GameRegistry.addRecipe(new ShapedOreRecipe(reactorGlassStack, "GCG", 'G', "blockGlassHardened", 'C', "reactorCasing")); - - GameRegistry.addRecipe(new ShapedOreRecipe(turbineGlassStack, "GCG", 'G', "glassReinforced", 'C', "turbineHousing")); - GameRegistry.addRecipe(new ShapedOreRecipe(turbineGlassStack, "GCG", 'G', "blockGlassHardened", 'C', "turbineHousing")); - } - else { - GameRegistry.addRecipe(new ShapedOreRecipe(reactorGlassStack, "GCG", 'G', "blockGlassColorless", 'C', "reactorCasing")); - GameRegistry.addRecipe(new ShapedOreRecipe(turbineGlassStack, "GCG", 'G', "blockGlassColorless", 'C', "turbineHousing")); - } - } - - if(blockDevice != null) { - ItemStack cyaniteReprocessorStack = ((BlockBRDevice)blockDevice).getCyaniteReprocessorItemStack(); - GameRegistry.addRecipe(new ShapedOreRecipe(cyaniteReprocessorStack, "CIC", "PFP", "CRC", 'C', "reactorCasing", 'I', ironOrSteelIngot, 'F', blockYelloriumFuelRod, 'P', Blocks.piston, 'R', Items.redstone)); - } - - if(blockReactorRedstonePort != null) { - ItemStack redstonePortStack = new ItemStack(BigReactors.blockReactorRedstonePort, 1); - GameRegistry.addRecipe(new ShapedOreRecipe(redstonePortStack, "CRC", "RGR", "CRC", 'C', "reactorCasing", 'R', Items.redstone, 'G', Items.gold_ingot)); - } - - if(blockTurbinePart != null) { - ItemStack turbineHousing = blockTurbinePart.getItemStack("housing"); - ItemStack turbineController = blockTurbinePart.getItemStack("controller"); - ItemStack turbinePowerTap = blockTurbinePart.getItemStack("powerTap"); - ItemStack turbineFluidPort = blockTurbinePart.getItemStack("fluidPort"); - ItemStack turbineBearing = blockTurbinePart.getItemStack("bearing"); - - turbineHousing.stackSize = 4; - GameRegistry.addRecipe(new ShapedOreRecipe(turbineHousing, "IGI", "QCQ", "IGI", 'C', "ingotCyanite", 'I', ironOrSteelIngot, 'Q', Items.quartz, 'G', "ingotGraphite")); - GameRegistry.addRecipe(new ShapedOreRecipe(turbineController, "H H", "BDB", "H H", 'H', "turbineHousing", 'D', Items.diamond, 'B', blutoniumIngot)); - GameRegistry.addRecipe(new ShapedOreRecipe(turbinePowerTap, "HRH", "R R", "HRH", 'H', "turbineHousing", 'R', Items.redstone)); - GameRegistry.addRecipe(new ShapedOreRecipe(turbineFluidPort, "H H", "IVI", "HPH", 'H', "turbineHousing", 'I', ironOrSteelIngot, 'V', Items.bucket, 'P', Blocks.piston)); - GameRegistry.addRecipe(new ShapedOreRecipe(turbineBearing, "HRH", "DDD", "HRH", 'H', "turbineHousing", 'D', Items.diamond, 'R', "turbineRotorShaft")); - - if(Loader.isModLoaded("ComputerCraft") || Loader.isModLoaded("OpenComputers")) { - ItemStack turbineComputerPort = blockTurbinePart.getItemStack("computerPort"); - GameRegistry.addRecipe(new ShapedOreRecipe(turbineComputerPort, "HRH", "GPG", "HRH", 'H', "turbineHousing", 'G', "ingotGold", 'R', "turbineRotorShaft")); - - } - } - - if(blockTurbineRotorPart != null) { - ItemStack rotorShaft = blockTurbineRotorPart.getItemStack("rotor"); - ItemStack rotorBlade = blockTurbineRotorPart.getItemStack("blade"); - - GameRegistry.addRecipe(new ShapedOreRecipe(rotorShaft, "ICI", 'C', "ingotCyanite", 'I', ironOrSteelIngot)); - GameRegistry.addRecipe(new ShapedOreRecipe(rotorBlade, "CII", 'C', "ingotCyanite", 'I', ironOrSteelIngot)); - } - - registerGameBalanceData(); - } - - INITIALIZED = true; - } - - - /** - * Call this to register Tile Entities - */ - public static void registerTileEntities() - { - if (!registeredTileEntities) - { - GameRegistry.registerTileEntity(TileEntityReactorPowerTap.class, "BRReactorPowerTap"); - GameRegistry.registerTileEntity(TileEntityReactorPart.class, "BRReactorPart"); - GameRegistry.registerTileEntity(TileEntityReactorAccessPort.class, "BRReactorAccessPort"); - GameRegistry.registerTileEntity(TileEntityReactorGlass.class, "BRReactorGlass"); - GameRegistry.registerTileEntity(TileEntityReactorFuelRod.class, "BRFuelRod"); - GameRegistry.registerTileEntity(TileEntityCyaniteReprocessor.class, "BRCyaniteReprocessor"); - - GameRegistry.registerTileEntity(TileEntityReactorControlRod.class, "BRReactorControlRod"); - GameRegistry.registerTileEntity(TileEntityReactorRedNetPort.class, "BRReactorRedNetPort"); - GameRegistry.registerTileEntity(TileEntityReactorRedstonePort.class,"BRReactorRedstonePort"); - GameRegistry.registerTileEntity(TileEntityReactorComputerPort.class, "BRReactorComputerPort"); - GameRegistry.registerTileEntity(TileEntityReactorCoolantPort.class, "BRReactorCoolantPort"); - GameRegistry.registerTileEntity(TileEntityReactorCreativeCoolantPort.class, "BRReactorCreativeCoolantPort"); - - GameRegistry.registerTileEntity(TileEntityTurbinePartStandard.class, "BRTurbinePart"); - GameRegistry.registerTileEntity(TileEntityTurbinePowerTap.class, "BRTurbinePowerTap"); - GameRegistry.registerTileEntity(TileEntityTurbineFluidPort.class, "BRTurbineFluidPort"); - GameRegistry.registerTileEntity(TileEntityTurbineComputerPort.class, "BRTurbineComputerPort"); - GameRegistry.registerTileEntity(TileEntityTurbinePartGlass.class, "BRTurbineGlass"); - GameRegistry.registerTileEntity(TileEntityTurbineRotorBearing.class, "BRTurbineRotorBearing"); - GameRegistry.registerTileEntity(TileEntityTurbineRotorPart.class, "BRTurbineRotorPart"); - GameRegistry.registerTileEntity(TileEntityTurbineCreativeSteamGenerator.class, "BRTurbineCreativeSteamGenerator"); - - registeredTileEntities = true; - } - } - - - public static ItemStack registerOres(int i, boolean b) { - BRConfig.CONFIGURATION.load(); - - if (blockYelloriteOre == null) { - blockYelloriteOre = new BlockBROre(); - GameRegistry.registerBlock(BigReactors.blockYelloriteOre, ItemBlockBigReactors.class, "YelloriteOre"); - ItemStack yelloriteStack = new ItemStack(blockYelloriteOre, 1); - OreDictionary.registerOre("oreYellorite", yelloriteStack); - OreDictionary.registerOre("oreYellorium", yelloriteStack); // For convenience of mods which fiddle with recipes - } - - if(blockMetal == null) { - blockMetal = new BlockBRMetal(); - GameRegistry.registerBlock(BigReactors.blockMetal, ItemBlockBigReactors.class, "BRMetalBlock"); - blockMetal.registerOreDictEntries(); - } - - boolean genYelloriteOre = BRConfig.CONFIGURATION.get("WorldGen", "GenerateYelloriteOre", true, "Add yellorite ore during world generation?").getBoolean(true); - if (yelloriteOreGeneration == null && genYelloriteOre) - { - // Magic number: 1 = stone - int clustersPerChunk; - int orePerCluster; - int maxY; - - clustersPerChunk = BRConfig.CONFIGURATION.get("WorldGen", "MaxYelloriteClustersPerChunk", 5, "Maximum number of clusters per chunk; will generate at least half this number, rounded down").getInt(); - orePerCluster = BRConfig.CONFIGURATION.get("WorldGen", "MaxYelloriteOrePerCluster", 10, "Maximum number of blocks to generate in each cluster; will usually generate at least half this number").getInt(); - maxY = BRConfig.CONFIGURATION.get("WorldGen", "YelloriteMaxY", 50, "Maximum height (Y coordinate) in the world to generate yellorite ore").getInt(); - int[] dimensionBlacklist = BRConfig.CONFIGURATION.get("WorldGen", "YelloriteDimensionBlacklist", new int[] {}, "Dimensions in which yellorite ore should not be generated; Nether/End automatically included").getIntList(); - - yelloriteOreGeneration = new BRSimpleOreGenerator(blockYelloriteOre, 0, Blocks.stone, - clustersPerChunk/2, clustersPerChunk, 4, maxY, orePerCluster); - - // Per KingLemming's request, bonus yellorite around y12. :) - BRSimpleOreGenerator yelloriteOreGeneration2 = new BRSimpleOreGenerator(blockYelloriteOre, 0, Blocks.stone, - 1, 2, 11, 13, orePerCluster); - - if(dimensionBlacklist != null) { - for(int dimension : dimensionBlacklist) { - yelloriteOreGeneration.blacklistDimension(dimension); - yelloriteOreGeneration2.blacklistDimension(dimension); - } - } - - BRWorldGenerator.addGenerator(BigReactors.yelloriteOreGeneration); - BRWorldGenerator.addGenerator(yelloriteOreGeneration2); - } - - BRConfig.CONFIGURATION.save(); - - return new ItemStack(blockYelloriteOre); - } - - - public static ItemStack registerIngots(int id) { - if (BigReactors.ingotGeneric == null) - { - BRConfig.CONFIGURATION.load(); - registerYelloriumAsUranium = BRConfig.CONFIGURATION.get("Recipes", "registerYelloriumAsUranium", true, "If set, yellorium will be registered in the ore dictionary as ingotUranium as well as ingotYellorium. Otherwise, it will only be registered as ingotYellorium. (Default: true)").getBoolean(true); - BigReactors.ingotGeneric = new ItemIngot(); + public static final String NAME = "Big Reactors"; + public static final String MODID = "BigReactors"; + public static final String CHANNEL = MODID.toLowerCase(); + public static final String RESOURCE_PATH = "/assets/bigreactors/"; + + public static final CreativeTabs TAB = new CreativeTabBR(MODID); + + public static final String TEXTURE_NAME_PREFIX = "bigreactors:"; + + public static final String TEXTURE_DIRECTORY = RESOURCE_PATH + "textures/"; + public static final String GUI_DIRECTORY = TEXTURE_NAME_PREFIX + "textures/gui/"; + public static final String BLOCK_TEXTURE_DIRECTORY = TEXTURE_DIRECTORY + "blocks/"; + public static final String ITEM_TEXTURE_DIRECTORY = TEXTURE_DIRECTORY + "items/"; + public static final String MODEL_TEXTURE_DIRECTORY = TEXTURE_DIRECTORY + "models/"; + + public static final String LANGUAGE_PATH = RESOURCE_PATH + "languages/"; + private static final String[] LANGUAGES_SUPPORTED = new String[] { "de_DE", "en_US", "es_SP", "nl_NL", "pl_PL", + "pt_BR", "ru_RU", "sv_SE", "zh_CN" }; + + public static final int BLOCK_ID_PREFIX = 1750; + + public static Block blockYelloriteOre; + public static BlockBRMetal blockMetal; + public static Block blockYelloriumFuelRod; + public static BlockReactorPart blockReactorPart; + public static Block blockReactorRedstonePort; // UGH. Why does the redstone API not allow me to check metadata? :( + + public static BlockTurbinePart blockTurbinePart; + public static BlockTurbineRotorPart blockTurbineRotorPart; + + public static BlockMultiblockGlass blockMultiblockGlass; + public static BlockMBCreativePart blockMultiblockCreativePart; + + public static Block blockRadiothermalGen; + public static Block blockDevice; + + public static Block fluidYelloriumStill; + public static Block fluidCyaniteStill; + public static Block fluidFuelColumnStill; + + // Buckets for bucketing reactor fluids + public static Item fluidYelloriumBucketItem; + public static Item fluidCyaniteBucketItem; + + public static Fluid fluidYellorium; + public static Fluid fluidCyanite; + public static Fluid fluidFuelColumn; + + public static Fluid fluidSteam; + public static boolean registeredOwnSteam; + + public static final int defaultFluidColorFuel = 0xbcba50; + public static final int defaultFluidColorWaste = 0x4d92b5; + + public static final int ITEM_ID_PREFIX = 17750; + public static ItemIngot ingotGeneric; + + public static ItemBeefDebugTool itemDebugTool; + + public static BRSimpleOreGenerator yelloriteOreGeneration; + + public static boolean INITIALIZED = false; + public static boolean enableWorldGen = true; + public static boolean enableWorldGenInNegativeDimensions = false; + public static boolean enableWorldRegeneration = true; + public static int userWorldGenVersion = 0; + + public static BREventHandler eventHandler = null; + public static BigReactorsTickHandler tickHandler = null; + public static BRWorldGenerator worldGenerator = null; + public static HashSet dimensionWhitelist = new HashSet(); + + private static boolean registeredTileEntities = false; + public static int maximumReactorSize = MultiblockReactor.DIMENSION_UNBOUNDED; + public static int maximumReactorHeight = MultiblockReactor.DIMENSION_UNBOUNDED; + public static int ticksPerRedstoneUpdate = 20; // Once per second, roughly + + public static int maximumTurbineSize = 16; + public static int maximumTurbineHeight = 32; + + public static float powerProductionMultiplier = 1.0f; + public static float fuelUsageMultiplier = 1.0f; + + public static float reactorPowerProductionMultiplier = 1.0f; + public static float turbinePowerProductionMultiplier = 1.0f; + + public static float turbineCoilDragMultiplier = 1.0f; + public static float turbineAeroDragMultiplier = 1.0f; + public static float turbineMassDragMultiplier = 1.0f; + public static float turbineFluidPerBladeMultiplier = 1.0f; + + public static boolean isValentinesDay = false; // Easter Egg :) + + // Game Balance values + + protected static IIcon iconSteamStill; + protected static IIcon iconSteamFlowing; + protected static IIcon iconFuelColumnStill; + protected static IIcon iconFuelColumnFlowing; + + private static boolean registerYelloriteSmeltToUranium = true; + private static boolean registerYelloriumAsUranium = true; + + /** + * Call this function in your mod init stage. + */ + public static void register(Object modInstance) { + + if (!INITIALIZED) { + + // General config loading + BRConfig.CONFIGURATION.load(); + enableWorldGen = BRConfig.CONFIGURATION.get( + "WorldGen", + "enableWorldGen", + true, + "If false, disables all world gen from Big Reactors; all other worldgen settings are automatically overridden") + .getBoolean(true); + enableWorldGenInNegativeDimensions = BRConfig.CONFIGURATION.get( + "WorldGen", + "enableWorldGenInNegativeDims", + false, + "Run BR world generation in negative dimension IDs? (default: false) If you don't know what this is, leave it alone.") + .getBoolean(false); + enableWorldRegeneration = BRConfig.CONFIGURATION.get( + "WorldGen", + "enableWorldRegeneration", + false, + "Run BR World Generation in chunks that have already been generated, but have not been modified by Big Reactors before. This is largely useful for worlds that existed before BigReactors was released.") + .getBoolean(false); + userWorldGenVersion = BRConfig.CONFIGURATION.get( + "WorldGen", + "userWorldGenVersion", + 0, + "User-set world generation version. Increase this by 1 if you want Big Reactors to re-run world generation in your world.") + .getInt(); + int[] worldGenDimensionWhitelist = BRConfig.CONFIGURATION.get( + "WorldGen", + "dimensionWhitelist", + new int[] {}, + "If enableWorldGenInNegativeDimensions is false, you may add negative dimensions to this whitelist to selectively enable worldgen in them.") + .getIntList(); + for (int i : worldGenDimensionWhitelist) { + dimensionWhitelist.add(i); + } + + boolean registerCoalFurnaceRecipe = BRConfig.CONFIGURATION.get( + "Recipes", + "registerCoalForSmelting", + true, + "If set, coal will be smeltable into graphite bars. Disable this if other mods need to smelt coal into their own products. (Default: true)") + .getBoolean(true); + boolean registerCharcoalFurnaceRecipe = BRConfig.CONFIGURATION.get( + "Recipes", + "registerCharcoalForSmelting", + true, + "If set, charcoal will be smeltable into graphite bars. Disable this if other mods need to smelt charcoal into their own products. (Default: true)") + .getBoolean(true); + boolean registerCoalCraftingRecipe = BRConfig.CONFIGURATION.get( + "Recipes", + "registerGraphiteCoalCraftingRecipes", + false, + "If set, graphite bars can be crafted from 2 gravel, 1 coal. Use this if other mods interfere with the smelting recipe. (Default: false)") + .getBoolean(false); + boolean registerCharcoalCraftingRecipe = BRConfig.CONFIGURATION.get( + "Recipes", + "registerGraphiteCharcoalCraftingRecipes", + false, + "If set, graphite bars can be crafted from 2 gravel, 1 charcoal. Use this if other mods interfere with the smelting recipe. (Default: false)") + .getBoolean(false); + registerYelloriteSmeltToUranium = BRConfig.CONFIGURATION.get( + "Recipes", + "registerYelloriteSmeltToUranium", + true, + "If set, yellorite ore will smelt into whichever item is registered as ingotUranium in the ore dictionary. If false, it will smelt into ingotYellorium. (Default: true)") + .getBoolean(true); + + boolean useSteelForIron = BRConfig.CONFIGURATION.get( + "Recipes", + "requireSteelInsteadOfIron", + false, + "If set, then all Big Reactors components will require steel ingots (ingotSteel) in place of iron ingots. Will be ignored if no other mod registers steel ingots. (default: false)") + .getBoolean(false); + boolean useExpensiveGlass = BRConfig.CONFIGURATION.get( + "Recipes", + "requireObsidianGlass", + false, + "If set, then Big Reactors will require hardened or reinforced glass (blockGlassHardened or glassReinforced) instead of plain glass. Will be ignored if no other mod registers those glass types. (default: false)") + .getBoolean(false); + + boolean enableReactorPowerTapRecipe = BRConfig.CONFIGURATION + .get( + "Recipes", + "enableReactorPowerTapRecipe", + true, + "If set, reactor power taps can be crafted, allowing players to use passive-cooled reactors.") + .getBoolean(true); + boolean enableCyaniteFromYelloriumRecipe = BRConfig.CONFIGURATION + .get( + "Recipes", + "enableCyaniteFromYelloriumRecipe", + true, + "If set, cyanite will be craftable from yellorium ingots and sand.") + .getBoolean(true); + + maximumReactorSize = BRConfig.CONFIGURATION.get( + "General", + "maxReactorSize", + 32, + "The maximum valid size of a reactor in the X/Z plane, in blocks. Lower this if your server's players are building ginormous reactors.") + .getInt(); + maximumReactorHeight = BRConfig.CONFIGURATION.get( + "General", + "maxReactorHeight", + 48, + "The maximum valid size of a reactor in the Y dimension, in blocks. Lower this if your server's players are building ginormous reactors. Bigger Y sizes have far less performance impact than X/Z sizes.") + .getInt(); + ticksPerRedstoneUpdate = BRConfig.CONFIGURATION + .get( + "General", + "ticksPerRedstoneUpdate", + 20, + "Number of ticks between updates for redstone/rednet ports.") + .getInt(); + powerProductionMultiplier = (float) BRConfig.CONFIGURATION + .get( + "General", + "powerProductionMultiplier", + 1.0f, + "A multiplier for balancing overall power production from Big Reactors. Defaults to 1.") + .getDouble(1.0); + fuelUsageMultiplier = (float) BRConfig.CONFIGURATION + .get( + "General", + "fuelUsageMultiplier", + 1.0f, + "A multiplier for balancing fuel consumption. Defaults to 1.") + .getDouble(1.0); + + reactorPowerProductionMultiplier = (float) BRConfig.CONFIGURATION.get( + "General", + "reactorPowerProductionMultiplier", + 1.0f, + "A multiplier for balancing reactor power production. Stacks with powerProductionMultiplier. Defaults to 1.") + .getDouble(1.0); + turbinePowerProductionMultiplier = (float) BRConfig.CONFIGURATION.get( + "General", + "turbinePowerProductionMultiplier", + 1.0f, + "A multiplier for balancing turbine power production. Stacks with powerProductionMultiplier. Defaults to 1.") + .getDouble(1.0); + + maximumTurbineSize = BRConfig.CONFIGURATION.get( + "General", + "maxTurbineSize", + 16, + "The maximum valid size of a turbine in the X/Z plane, in blocks. Lower this for smaller turbines, which means lower max output.") + .getInt(); + maximumTurbineHeight = BRConfig.CONFIGURATION + .get( + "General", + "maxTurbineHeight", + 32, + "The maximum valid height of a turbine (Y axis), in blocks. (Default: 32)") + .getInt(); + + turbineCoilDragMultiplier = (float) BRConfig.CONFIGURATION.get( + "General", + "turbineCoilDragMultiplier", + 1.0, + "A multiplier for balancing coil size. Multiplies the amount of energy drawn per coil block per tick. (Default: 1)") + .getDouble(1.0); + turbineAeroDragMultiplier = (float) BRConfig.CONFIGURATION.get( + "General", + "turbineAeroDragMultiplier", + 1.0, + "A multiplier for balancing rotor sizes. Multiplies the amount of energy lost to aerodynamic drag per tick. (Default: 1)") + .getDouble(1.0); + turbineMassDragMultiplier = (float) BRConfig.CONFIGURATION.get( + "General", + "turbineMassDragMultiplier", + 1.0, + "A multiplier for balancing rotor sizes. Multiplies the amount of energy lost to friction per tick. (Default: 1)") + .getDouble(1.0); + turbineFluidPerBladeMultiplier = (float) BRConfig.CONFIGURATION.get( + "General", + "turbineFluidPerBladeMultiplier", + 1.0, + "A multiplier for balancing coil size. Multiplies the amount of fluid each blade block can process (base of 25 will be multiplied, then rounded down to the nearest integer). (Default: 1)") + .getDouble(1.0); + + MultiblockTurbine.inputFluidPerBlade = (int) Math + .floor(MultiblockTurbine.inputFluidPerBlade * turbineFluidPerBladeMultiplier); + MultiblockTurbine.inductorBaseDragCoefficient *= turbineCoilDragMultiplier; + + BRConfig.CONFIGURATION.save(); + + if (enableWorldGen) { + worldGenerator = new BRWorldGenerator(); + GameRegistry.registerWorldGenerator(worldGenerator, 0); + } + + // Patch up vanilla being stupid - most mods already do this, so it's usually a no-op + if (!ItemHelper.oreNameExists("ingotIron")) { + OreDictionary.registerOre("ingotIron", new ItemStack(Items.iron_ingot, 1)); + } + + if (!ItemHelper.oreNameExists("ingotGold")) { + OreDictionary.registerOre("ingotGold", new ItemStack(Items.gold_ingot, 1)); + } + + if (!ItemHelper.oreNameExists("blockSnow")) { + OreDictionary.registerOre("blockSnow", new ItemStack(Blocks.snow, 1)); + } + + if (!ItemHelper.oreNameExists("blockIce")) { + OreDictionary.registerOre("blockIce", new ItemStack(Blocks.ice, 1)); + } + + if (!ItemHelper.oreNameExists("blockGlassColorless")) { + OreDictionary.registerOre("blockGlassColorless", new ItemStack(Blocks.glass, 1)); + } + + // Use steel if the players are masochists and someone else has supplied steel. + String ironOrSteelIngot = "ingotIron"; + if (useSteelForIron) { + ironOrSteelIngot = "ingotSteel"; + } + + String yelloriumIngot = "ingotYellorium"; + String blutoniumIngot = "ingotBlutonium"; + if (registerYelloriumAsUranium) { + yelloriumIngot = "ingotUranium"; + blutoniumIngot = "ingotPlutonium"; + } + + /* + * Register Recipes + */ + // Recipe Registry + + // Yellorium + if (blockYelloriteOre != null) { + ItemStack product; + + if (registerYelloriteSmeltToUranium) { + ArrayList candidateOres = OreDictionaryArbiter.getOres("ingotUranium"); + if (candidateOres == null || candidateOres.size() <= 0) { + BRLog.warning( + "Config value registerYelloriteSmeltToUranium is set to True, but there are no ores registered as ingotUranium in the ore dictionary! Falling back to using standard yellorium only."); + candidateOres = OreDictionaryArbiter.getOres("ingotYellorium"); + } + product = candidateOres.get(0) + .copy(); + } else { + product = OreDictionaryArbiter.getOres("ingotYellorium") + .get(0) + .copy(); + } + + GameRegistry.addSmelting(blockYelloriteOre, product, 0.5f); + } + + // Metal blocks + if (blockMetal != null && ingotGeneric != null) { + blockMetal.registerIngotRecipes(ingotGeneric); + } + + if (blockMetal != null) { + // Ludicrite block. Because. + GameRegistry.addRecipe( + new ShapedOreRecipe( + blockMetal.getItemStackForMaterial("Ludicrite"), + "BPB", + "ENE", + "BPB", + 'N', + Items.nether_star, + 'P', + Items.ender_pearl, + 'E', + Blocks.emerald_block, + 'B', + blutoniumIngot)); + if (ItemHelper.getOre("blockEnderium") != null) { + // Ok, how about some ludicrous shit here. Enderium and blaze rods. Have fun, bucko. + GameRegistry.addRecipe( + new ShapedOreRecipe( + blockMetal.getItemStackForMaterial("Ludicrite"), + "BRB", + "E E", + "BRB", + 'B', + blutoniumIngot, + 'R', + Items.blaze_rod, + 'E', + "blockEnderium")); + } + } + + if (ingotGeneric != null) { + // Map all dusts to ingots. + for (int i = 0; i < ItemIngot.MATERIALS.length; i++) { + ItemStack ingotStack = ingotGeneric.getIngotItem(ItemIngot.MATERIALS[i]); + ItemStack dustStack = ingotGeneric.getDustItem(ItemIngot.MATERIALS[i]); + GameRegistry.addSmelting(dustStack, ingotStack, 0f); + } + } + + ItemStack ingotGraphite = OreDictionaryArbiter.getOres("ingotGraphite") + .get(0) + .copy(); + ItemStack ingotCyanite = OreDictionaryArbiter.getOres("ingotCyanite") + .get(0) + .copy(); + + if (registerCoalFurnaceRecipe) { + // Coal -> Graphite + GameRegistry.addSmelting(Items.coal, ingotGraphite, 1); + } + + if (registerCharcoalFurnaceRecipe) { + // Charcoal -> Graphite + GameRegistry.addSmelting(new ItemStack(Items.coal, 1, 1), ingotGraphite, 1); + } + + if (registerCoalCraftingRecipe) { + GameRegistry.addRecipe( + new ShapedOreRecipe( + ingotGraphite, + "GCG", + 'G', + Blocks.gravel, + 'C', + new ItemStack(Items.coal, 1, 0))); + } + + if (registerCharcoalCraftingRecipe) { + GameRegistry.addRecipe( + new ShapedOreRecipe( + ingotGraphite, + "GCG", + 'G', + Blocks.gravel, + 'C', + new ItemStack(Items.coal, 1, 1))); + } + + if (enableCyaniteFromYelloriumRecipe) { + GameRegistry.addRecipe(new ShapelessOreRecipe(ingotCyanite, yelloriumIngot, Blocks.sand)); + } + + // Basic Parts: Reactor Casing, Fuel Rods + if (blockYelloriumFuelRod != null) { + GameRegistry.addRecipe( + new ShapedOreRecipe( + new ItemStack(blockYelloriumFuelRod, 1), + "ICI", + "IUI", + "ICI", + 'I', + ironOrSteelIngot, + 'C', + "ingotGraphite", + 'U', + yelloriumIngot)); + } + + if (blockReactorPart != null) { + ItemStack reactorPartStack = BigReactors.blockReactorPart.getReactorCasingItemStack(); + reactorPartStack.stackSize = 4; + GameRegistry.addRecipe( + new ShapedOreRecipe( + reactorPartStack, + "ICI", + "CUC", + "ICI", + 'I', + ironOrSteelIngot, + 'C', + "ingotGraphite", + 'U', + yelloriumIngot)); + } + + // Advanced Parts: Control Rod, Access Port, Power Tap, Controller + if (blockReactorPart != null) { + ItemStack reactorPartStack = BigReactors.blockReactorPart.getReactorControllerItemStack(); + + GameRegistry.addRecipe( + new ShapedOreRecipe( + reactorPartStack, + "C C", + "GDG", + "CRC", + 'D', + Items.diamond, + 'G', + yelloriumIngot, + 'C', + "reactorCasing", + 'R', + Items.redstone)); + + if (enableReactorPowerTapRecipe) { + reactorPartStack = BigReactors.blockReactorPart.getReactorPowerTapItemStack(); + GameRegistry.addRecipe( + new ShapedOreRecipe( + reactorPartStack, + "CRC", + "R R", + "CRC", + 'C', + "reactorCasing", + 'R', + Items.redstone)); + } + + reactorPartStack = BigReactors.blockReactorPart.getAccessPortItemStack(); + GameRegistry.addRecipe( + new ShapedOreRecipe( + reactorPartStack, + "C C", + " V ", + "CPC", + 'C', + "reactorCasing", + 'V', + Blocks.chest, + 'P', + Blocks.piston)); + + reactorPartStack = BigReactors.blockReactorPart.getCoolantPortItemStack(); + GameRegistry.addRecipe( + new ShapedOreRecipe( + reactorPartStack, + "C C", + "IVI", + "CPC", + 'C', + "reactorCasing", + 'V', + Items.bucket, + 'P', + Blocks.piston, + 'I', + ironOrSteelIngot)); + + reactorPartStack = BigReactors.blockReactorPart.getControlRodItemStack(); + GameRegistry.addRecipe( + new ShapedOreRecipe( + reactorPartStack, + "CGC", + "GRG", + "CUC", + 'G', + "ingotGraphite", + 'C', + "reactorCasing", + 'R', + Items.redstone, + 'U', + yelloriumIngot)); + + if (Loader.isModLoaded("MineFactoryReloaded")) { + reactorPartStack = BigReactors.blockReactorPart.getRedNetPortItemStack(); + GameRegistry.addRecipe( + new ShapedOreRecipe( + reactorPartStack, + "CRC", + "RGR", + "CRC", + 'C', + "reactorCasing", + 'R', + "cableRedNet", + 'G', + "ingotGold")); + } + + if (Loader.isModLoaded("ComputerCraft") || Loader.isModLoaded("OpenComputers")) { + reactorPartStack = BigReactors.blockReactorPart.getComputerPortItemStack(); + GameRegistry.addRecipe( + new ShapedOreRecipe( + reactorPartStack, + "CRC", + "GPG", + "CRC", + 'C', + "reactorCasing", + 'R', + Items.redstone, + 'G', + "ingotGold", + 'P', + Items.repeater)); + } + } + + if (blockMultiblockGlass != null) { + ItemStack reactorGlassStack = blockMultiblockGlass.getItemStack("reactor"); + ItemStack turbineGlassStack = blockMultiblockGlass.getItemStack("turbine"); + + if (useExpensiveGlass && (ItemHelper.oreNameExists("glassReinforced") + || ItemHelper.oreNameExists("blockGlassHardened"))) { + GameRegistry.addRecipe( + new ShapedOreRecipe(reactorGlassStack, "GCG", 'G', "glassReinforced", 'C', "reactorCasing")); + GameRegistry.addRecipe( + new ShapedOreRecipe(reactorGlassStack, "GCG", 'G', "blockGlassHardened", 'C', "reactorCasing")); + + GameRegistry.addRecipe( + new ShapedOreRecipe(turbineGlassStack, "GCG", 'G', "glassReinforced", 'C', "turbineHousing")); + GameRegistry.addRecipe( + new ShapedOreRecipe( + turbineGlassStack, + "GCG", + 'G', + "blockGlassHardened", + 'C', + "turbineHousing")); + } else { + GameRegistry.addRecipe( + new ShapedOreRecipe( + reactorGlassStack, + "GCG", + 'G', + "blockGlassColorless", + 'C', + "reactorCasing")); + GameRegistry.addRecipe( + new ShapedOreRecipe( + turbineGlassStack, + "GCG", + 'G', + "blockGlassColorless", + 'C', + "turbineHousing")); + } + } + + if (blockDevice != null) { + ItemStack cyaniteReprocessorStack = ((BlockBRDevice) blockDevice).getCyaniteReprocessorItemStack(); + GameRegistry.addRecipe( + new ShapedOreRecipe( + cyaniteReprocessorStack, + "CIC", + "PFP", + "CRC", + 'C', + "reactorCasing", + 'I', + ironOrSteelIngot, + 'F', + blockYelloriumFuelRod, + 'P', + Blocks.piston, + 'R', + Items.redstone)); + } + + if (blockReactorRedstonePort != null) { + ItemStack redstonePortStack = new ItemStack(BigReactors.blockReactorRedstonePort, 1); + GameRegistry.addRecipe( + new ShapedOreRecipe( + redstonePortStack, + "CRC", + "RGR", + "CRC", + 'C', + "reactorCasing", + 'R', + Items.redstone, + 'G', + Items.gold_ingot)); + } + + if (blockTurbinePart != null) { + ItemStack turbineHousing = blockTurbinePart.getItemStack("housing"); + ItemStack turbineController = blockTurbinePart.getItemStack("controller"); + ItemStack turbinePowerTap = blockTurbinePart.getItemStack("powerTap"); + ItemStack turbineFluidPort = blockTurbinePart.getItemStack("fluidPort"); + ItemStack turbineBearing = blockTurbinePart.getItemStack("bearing"); + + turbineHousing.stackSize = 4; + GameRegistry.addRecipe( + new ShapedOreRecipe( + turbineHousing, + "IGI", + "QCQ", + "IGI", + 'C', + "ingotCyanite", + 'I', + ironOrSteelIngot, + 'Q', + Items.quartz, + 'G', + "ingotGraphite")); + GameRegistry.addRecipe( + new ShapedOreRecipe( + turbineController, + "H H", + "BDB", + "H H", + 'H', + "turbineHousing", + 'D', + Items.diamond, + 'B', + blutoniumIngot)); + GameRegistry.addRecipe( + new ShapedOreRecipe( + turbinePowerTap, + "HRH", + "R R", + "HRH", + 'H', + "turbineHousing", + 'R', + Items.redstone)); + GameRegistry.addRecipe( + new ShapedOreRecipe( + turbineFluidPort, + "H H", + "IVI", + "HPH", + 'H', + "turbineHousing", + 'I', + ironOrSteelIngot, + 'V', + Items.bucket, + 'P', + Blocks.piston)); + GameRegistry.addRecipe( + new ShapedOreRecipe( + turbineBearing, + "HRH", + "DDD", + "HRH", + 'H', + "turbineHousing", + 'D', + Items.diamond, + 'R', + "turbineRotorShaft")); + + if (Loader.isModLoaded("ComputerCraft") || Loader.isModLoaded("OpenComputers")) { + ItemStack turbineComputerPort = blockTurbinePart.getItemStack("computerPort"); + GameRegistry.addRecipe( + new ShapedOreRecipe( + turbineComputerPort, + "HRH", + "GPG", + "HRH", + 'H', + "turbineHousing", + 'G', + "ingotGold", + 'R', + "turbineRotorShaft")); + + } + } + + if (blockTurbineRotorPart != null) { + ItemStack rotorShaft = blockTurbineRotorPart.getItemStack("rotor"); + ItemStack rotorBlade = blockTurbineRotorPart.getItemStack("blade"); + + GameRegistry + .addRecipe(new ShapedOreRecipe(rotorShaft, "ICI", 'C', "ingotCyanite", 'I', ironOrSteelIngot)); + GameRegistry + .addRecipe(new ShapedOreRecipe(rotorBlade, "CII", 'C', "ingotCyanite", 'I', ironOrSteelIngot)); + } + + registerGameBalanceData(); + } + + INITIALIZED = true; + } + + /** + * Call this to register Tile Entities + */ + public static void registerTileEntities() { + if (!registeredTileEntities) { + GameRegistry.registerTileEntity(TileEntityReactorPowerTap.class, "BRReactorPowerTap"); + GameRegistry.registerTileEntity(TileEntityReactorPart.class, "BRReactorPart"); + GameRegistry.registerTileEntity(TileEntityReactorAccessPort.class, "BRReactorAccessPort"); + GameRegistry.registerTileEntity(TileEntityReactorGlass.class, "BRReactorGlass"); + GameRegistry.registerTileEntity(TileEntityReactorFuelRod.class, "BRFuelRod"); + GameRegistry.registerTileEntity(TileEntityCyaniteReprocessor.class, "BRCyaniteReprocessor"); + + GameRegistry.registerTileEntity(TileEntityReactorControlRod.class, "BRReactorControlRod"); + GameRegistry.registerTileEntity(TileEntityReactorRedNetPort.class, "BRReactorRedNetPort"); + GameRegistry.registerTileEntity(TileEntityReactorRedstonePort.class, "BRReactorRedstonePort"); + GameRegistry.registerTileEntity(TileEntityReactorComputerPort.class, "BRReactorComputerPort"); + GameRegistry.registerTileEntity(TileEntityReactorCoolantPort.class, "BRReactorCoolantPort"); + GameRegistry.registerTileEntity(TileEntityReactorCreativeCoolantPort.class, "BRReactorCreativeCoolantPort"); + + GameRegistry.registerTileEntity(TileEntityTurbinePartStandard.class, "BRTurbinePart"); + GameRegistry.registerTileEntity(TileEntityTurbinePowerTap.class, "BRTurbinePowerTap"); + GameRegistry.registerTileEntity(TileEntityTurbineFluidPort.class, "BRTurbineFluidPort"); + GameRegistry.registerTileEntity(TileEntityTurbineComputerPort.class, "BRTurbineComputerPort"); + GameRegistry.registerTileEntity(TileEntityTurbinePartGlass.class, "BRTurbineGlass"); + GameRegistry.registerTileEntity(TileEntityTurbineRotorBearing.class, "BRTurbineRotorBearing"); + GameRegistry.registerTileEntity(TileEntityTurbineRotorPart.class, "BRTurbineRotorPart"); + GameRegistry + .registerTileEntity(TileEntityTurbineCreativeSteamGenerator.class, "BRTurbineCreativeSteamGenerator"); + + registeredTileEntities = true; + } + } + + public static ItemStack registerOres(int i, boolean b) { + BRConfig.CONFIGURATION.load(); + + if (blockYelloriteOre == null) { + blockYelloriteOre = new BlockBROre(); + GameRegistry.registerBlock(BigReactors.blockYelloriteOre, ItemBlockBigReactors.class, "YelloriteOre"); + ItemStack yelloriteStack = new ItemStack(blockYelloriteOre, 1); + OreDictionary.registerOre("oreUranium", yelloriteStack); + OreDictionary.registerOre("oreYellorite", yelloriteStack); + OreDictionary.registerOre("oreYellorium", yelloriteStack); // For convenience of mods which fiddle with + // recipes + } + + if (blockMetal == null) { + blockMetal = new BlockBRMetal(); + GameRegistry.registerBlock(BigReactors.blockMetal, ItemBlockBigReactors.class, "BRMetalBlock"); + blockMetal.registerOreDictEntries(); + } + + boolean genYelloriteOre = BRConfig.CONFIGURATION + .get("WorldGen", "GenerateYelloriteOre", true, "Add yellorite ore during world generation?") + .getBoolean(true); + if (yelloriteOreGeneration == null && genYelloriteOre) { + // Magic number: 1 = stone + int clustersPerChunk; + int orePerCluster; + int maxY; + + clustersPerChunk = BRConfig.CONFIGURATION + .get( + "WorldGen", + "MaxYelloriteClustersPerChunk", + 5, + "Maximum number of clusters per chunk; will generate at least half this number, rounded down") + .getInt(); + orePerCluster = BRConfig.CONFIGURATION.get( + "WorldGen", + "MaxYelloriteOrePerCluster", + 10, + "Maximum number of blocks to generate in each cluster; will usually generate at least half this number") + .getInt(); + maxY = BRConfig.CONFIGURATION + .get( + "WorldGen", + "YelloriteMaxY", + 50, + "Maximum height (Y coordinate) in the world to generate yellorite ore") + .getInt(); + int[] dimensionBlacklist = BRConfig.CONFIGURATION + .get( + "WorldGen", + "YelloriteDimensionBlacklist", + new int[] {}, + "Dimensions in which yellorite ore should not be generated; Nether/End automatically included") + .getIntList(); + + yelloriteOreGeneration = new BRSimpleOreGenerator( + blockYelloriteOre, + 0, + Blocks.stone, + clustersPerChunk / 2, + clustersPerChunk, + 4, + maxY, + orePerCluster); + + // Per KingLemming's request, bonus yellorite around y12. :) + BRSimpleOreGenerator yelloriteOreGeneration2 = new BRSimpleOreGenerator( + blockYelloriteOre, + 0, + Blocks.stone, + 1, + 2, + 11, + 13, + orePerCluster); + + if (dimensionBlacklist != null) { + for (int dimension : dimensionBlacklist) { + yelloriteOreGeneration.blacklistDimension(dimension); + yelloriteOreGeneration2.blacklistDimension(dimension); + } + } + + BRWorldGenerator.addGenerator(BigReactors.yelloriteOreGeneration); + BRWorldGenerator.addGenerator(yelloriteOreGeneration2); + } + + BRConfig.CONFIGURATION.save(); + + return new ItemStack(blockYelloriteOre); + } + + public static ItemStack registerIngots(int id) { + if (BigReactors.ingotGeneric == null) { + BRConfig.CONFIGURATION.load(); + registerYelloriumAsUranium = BRConfig.CONFIGURATION.get( + "Recipes", + "registerYelloriumAsUranium", + true, + "If set, yellorium will be registered in the ore dictionary as ingotUranium as well as ingotYellorium. Otherwise, it will only be registered as ingotYellorium. (Default: true)") + .getBoolean(true); + BigReactors.ingotGeneric = new ItemIngot(); GameRegistry.registerItem(ingotGeneric, "BRIngot"); - // Register all generic ingots & dusts - String itemName; - for(int i = 0; i < ItemIngot.TYPES.length; i++) { - itemName = ItemIngot.TYPES[i]; - OreDictionary.registerOre(itemName, ingotGeneric.getItemStackForType(itemName)); - } - - // Add aliases, if appropriate - if(registerYelloriumAsUranium) { - OreDictionary.registerOre("ingotUranium", ingotGeneric.getItemStackForType("ingotYellorium")); - OreDictionary.registerOre("ingotPlutonium", ingotGeneric.getItemStackForType("ingotBlutonium")); - OreDictionary.registerOre("dustUranium", ingotGeneric.getItemStackForType("dustYellorium")); - OreDictionary.registerOre("dustPlutonium", ingotGeneric.getItemStackForType("dustBlutonium")); - } - - BRConfig.CONFIGURATION.save(); - } - - return new ItemStack(ingotGeneric); - } - - - public static void registerFuelRods(int id, boolean require) { - if(BigReactors.blockYelloriumFuelRod == null) { - BRConfig.CONFIGURATION.load(); - BigReactors.blockYelloriumFuelRod = new BlockFuelRod(Material.iron); - GameRegistry.registerBlock(BigReactors.blockYelloriumFuelRod, ItemBlock.class, "YelloriumFuelRod"); - BRConfig.CONFIGURATION.save(); - } - } - - - public static void registerReactorPartBlocks(int id, boolean require) { - if(BigReactors.blockReactorPart == null) { - BRConfig.CONFIGURATION.load(); - BigReactors.blockReactorPart = new BlockReactorPart(Material.iron); - GameRegistry.registerBlock(BigReactors.blockReactorPart, ItemBlockBigReactors.class, "BRReactorPart"); - - OreDictionary.registerOre("reactorCasing", BigReactors.blockReactorPart.getReactorCasingItemStack()); - OreDictionary.registerOre("reactorController", BigReactors.blockReactorPart.getReactorControllerItemStack()); - OreDictionary.registerOre("reactorPowerTap", BigReactors.blockReactorPart.getReactorPowerTapItemStack()); - OreDictionary.registerOre("reactorRedNetPort", BigReactors.blockReactorPart.getRedNetPortItemStack()); - OreDictionary.registerOre("reactorComputerPort", BigReactors.blockReactorPart.getComputerPortItemStack()); - OreDictionary.registerOre("reactorCoolantPort", BigReactors.blockReactorPart.getCoolantPortItemStack()); - OreDictionary.registerOre("reactorControlRod", BigReactors.blockReactorPart.getControlRodItemStack()); - - BRConfig.CONFIGURATION.save(); - } - - if(BigReactors.blockMultiblockGlass == null) { - BRConfig.CONFIGURATION.load(); - - BigReactors.blockMultiblockGlass = new BlockMultiblockGlass(Material.glass); - GameRegistry.registerBlock(BigReactors.blockMultiblockGlass, ItemBlockBigReactors.class, "BRMultiblockGlass"); - - OreDictionary.registerOre("glassReactor", blockMultiblockGlass.getItemStack("reactor")); - OreDictionary.registerOre("glassTurbine", blockMultiblockGlass.getItemStack("turbine")); - - BRConfig.CONFIGURATION.save(); - } - - if(BigReactors.blockReactorRedstonePort == null) { - BRConfig.CONFIGURATION.load(); - - BigReactors.blockReactorRedstonePort = new BlockReactorRedstonePort(Material.iron); - GameRegistry.registerBlock(BigReactors.blockReactorRedstonePort, ItemBlock.class, "BRReactorRedstonePort"); - OreDictionary.registerOre("reactorRedstonePort", new ItemStack(blockReactorRedstonePort, 1)); - - BRConfig.CONFIGURATION.save(); - } - } - - public static void registerTurbineParts() { - if(BigReactors.blockTurbinePart == null) { - BRConfig.CONFIGURATION.load(); - BigReactors.blockTurbinePart = new BlockTurbinePart(Material.iron); - GameRegistry.registerBlock(BigReactors.blockTurbinePart, ItemBlockBigReactors.class, "BRTurbinePart"); - - OreDictionary.registerOre("turbineHousing", BigReactors.blockTurbinePart.getItemStack("housing")); - OreDictionary.registerOre("turbineController", BigReactors.blockTurbinePart.getItemStack("controller")); - OreDictionary.registerOre("turbinePowerTap", BigReactors.blockTurbinePart.getItemStack("powerTap")); - OreDictionary.registerOre("turbineFluidPort", BigReactors.blockTurbinePart.getItemStack("fluidPort")); - OreDictionary.registerOre("turbineBearing", BigReactors.blockTurbinePart.getItemStack("bearing")); - - BRConfig.CONFIGURATION.save(); - } - - if(BigReactors.blockTurbineRotorPart == null) { - BRConfig.CONFIGURATION.load(); - BigReactors.blockTurbineRotorPart = new BlockTurbineRotorPart(Material.iron); - GameRegistry.registerBlock(BigReactors.blockTurbineRotorPart, ItemBlockBigReactors.class, "BRTurbineRotorPart"); - - OreDictionary.registerOre("turbineRotorShaft", BigReactors.blockTurbineRotorPart.getItemStack("rotor")); - OreDictionary.registerOre("turbineRotorBlade", BigReactors.blockTurbineRotorPart.getItemStack("blade")); - - BRConfig.CONFIGURATION.save(); - } - } - - public static void registerDevices(int id, boolean require) { - if(BigReactors.blockDevice == null) { - BRConfig.CONFIGURATION.load(); - - BigReactors.blockDevice = new BlockBRDevice(Material.iron); - GameRegistry.registerBlock(BigReactors.blockDevice, ItemBlockBigReactors.class, "BRDevice"); - - OreDictionary.registerOre("brDeviceCyaniteProcessor", ((BlockBRDevice)BigReactors.blockDevice).getCyaniteReprocessorItemStack()); - - BRConfig.CONFIGURATION.save(); - } - } - - public static void registerCreativeParts(int id, boolean require) { - BRConfig.CONFIGURATION.load(); - - boolean regCreativeParts = BRConfig.CONFIGURATION.get("General", "registerCreativeMultiblockParts", true, "If true, creative parts for reactors, turbines and other multiblocks will be registered.").getBoolean(true); - if(regCreativeParts && BigReactors.blockMultiblockCreativePart == null) { - BigReactors.blockMultiblockCreativePart = new BlockMBCreativePart(Material.iron); - GameRegistry.registerBlock(BigReactors.blockMultiblockCreativePart, ItemBlockBigReactors.class, "BRMultiblockCreativePart"); - } - - BRConfig.CONFIGURATION.save(); - } - - public static void registerFluids(int id, boolean require) { - if(BigReactors.fluidYelloriumStill == null) { - BRConfig.CONFIGURATION.load(); - - BigReactors.fluidYellorium = FluidRegistry.getFluid("yellorium"); - if(fluidYellorium == null) { - fluidYellorium = new Fluid("yellorium"); - fluidYellorium.setDensity(100); - fluidYellorium.setGaseous(false); - fluidYellorium.setLuminosity(10); - fluidYellorium.setRarity(EnumRarity.uncommon); - fluidYellorium.setTemperature(295); - fluidYellorium.setViscosity(100); - fluidYellorium.setUnlocalizedName("bigreactors.yellorium.still"); - FluidRegistry.registerFluid(fluidYellorium); - } - - BlockBRGenericFluid liqY = new BlockBRGenericFluid(BigReactors.fluidYellorium, "yellorium"); - BigReactors.fluidYelloriumStill = liqY; - - GameRegistry.registerBlock(BigReactors.fluidYelloriumStill, ItemBlock.class, BigReactors.fluidYelloriumStill.getUnlocalizedName()); - - fluidYelloriumBucketItem = (new ItemBRBucket(liqY)).setUnlocalizedName("bucket.yellorium").setMaxStackSize(1).setContainerItem(Items.bucket); + // Register all generic ingots & dusts + String itemName; + for (int i = 0; i < ItemIngot.TYPES.length; i++) { + itemName = ItemIngot.TYPES[i]; + OreDictionary.registerOre(itemName, ingotGeneric.getItemStackForType(itemName)); + } + + // Add aliases, if appropriate + if (registerYelloriumAsUranium) { + OreDictionary.registerOre("ingotUranium", ingotGeneric.getItemStackForType("ingotYellorium")); + OreDictionary.registerOre("ingotPlutonium", ingotGeneric.getItemStackForType("ingotBlutonium")); + OreDictionary.registerOre("dustUranium", ingotGeneric.getItemStackForType("dustYellorium")); + OreDictionary.registerOre("dustPlutonium", ingotGeneric.getItemStackForType("dustBlutonium")); + } + + BRConfig.CONFIGURATION.save(); + } + + return new ItemStack(ingotGeneric); + } + + public static void registerFuelRods(int id, boolean require) { + if (BigReactors.blockYelloriumFuelRod == null) { + BRConfig.CONFIGURATION.load(); + BigReactors.blockYelloriumFuelRod = new BlockFuelRod(Material.iron); + GameRegistry.registerBlock(BigReactors.blockYelloriumFuelRod, ItemBlock.class, "YelloriumFuelRod"); + BRConfig.CONFIGURATION.save(); + } + } + + public static void registerReactorPartBlocks(int id, boolean require) { + if (BigReactors.blockReactorPart == null) { + BRConfig.CONFIGURATION.load(); + BigReactors.blockReactorPart = new BlockReactorPart(Material.iron); + GameRegistry.registerBlock(BigReactors.blockReactorPart, ItemBlockBigReactors.class, "BRReactorPart"); + + OreDictionary.registerOre("reactorCasing", BigReactors.blockReactorPart.getReactorCasingItemStack()); + OreDictionary + .registerOre("reactorController", BigReactors.blockReactorPart.getReactorControllerItemStack()); + OreDictionary.registerOre("reactorPowerTap", BigReactors.blockReactorPart.getReactorPowerTapItemStack()); + OreDictionary.registerOre("reactorRedNetPort", BigReactors.blockReactorPart.getRedNetPortItemStack()); + OreDictionary.registerOre("reactorComputerPort", BigReactors.blockReactorPart.getComputerPortItemStack()); + OreDictionary.registerOre("reactorCoolantPort", BigReactors.blockReactorPart.getCoolantPortItemStack()); + OreDictionary.registerOre("reactorControlRod", BigReactors.blockReactorPart.getControlRodItemStack()); + + BRConfig.CONFIGURATION.save(); + } + + if (BigReactors.blockMultiblockGlass == null) { + BRConfig.CONFIGURATION.load(); + + BigReactors.blockMultiblockGlass = new BlockMultiblockGlass(Material.glass); + GameRegistry + .registerBlock(BigReactors.blockMultiblockGlass, ItemBlockBigReactors.class, "BRMultiblockGlass"); + + OreDictionary.registerOre("glassReactor", blockMultiblockGlass.getItemStack("reactor")); + OreDictionary.registerOre("glassTurbine", blockMultiblockGlass.getItemStack("turbine")); + + BRConfig.CONFIGURATION.save(); + } + + if (BigReactors.blockReactorRedstonePort == null) { + BRConfig.CONFIGURATION.load(); + + BigReactors.blockReactorRedstonePort = new BlockReactorRedstonePort(Material.iron); + GameRegistry.registerBlock(BigReactors.blockReactorRedstonePort, ItemBlock.class, "BRReactorRedstonePort"); + OreDictionary.registerOre("reactorRedstonePort", new ItemStack(blockReactorRedstonePort, 1)); + + BRConfig.CONFIGURATION.save(); + } + } + + public static void registerTurbineParts() { + if (BigReactors.blockTurbinePart == null) { + BRConfig.CONFIGURATION.load(); + BigReactors.blockTurbinePart = new BlockTurbinePart(Material.iron); + GameRegistry.registerBlock(BigReactors.blockTurbinePart, ItemBlockBigReactors.class, "BRTurbinePart"); + + OreDictionary.registerOre("turbineHousing", BigReactors.blockTurbinePart.getItemStack("housing")); + OreDictionary.registerOre("turbineController", BigReactors.blockTurbinePart.getItemStack("controller")); + OreDictionary.registerOre("turbinePowerTap", BigReactors.blockTurbinePart.getItemStack("powerTap")); + OreDictionary.registerOre("turbineFluidPort", BigReactors.blockTurbinePart.getItemStack("fluidPort")); + OreDictionary.registerOre("turbineBearing", BigReactors.blockTurbinePart.getItemStack("bearing")); + + BRConfig.CONFIGURATION.save(); + } + + if (BigReactors.blockTurbineRotorPart == null) { + BRConfig.CONFIGURATION.load(); + BigReactors.blockTurbineRotorPart = new BlockTurbineRotorPart(Material.iron); + GameRegistry + .registerBlock(BigReactors.blockTurbineRotorPart, ItemBlockBigReactors.class, "BRTurbineRotorPart"); + + OreDictionary.registerOre("turbineRotorShaft", BigReactors.blockTurbineRotorPart.getItemStack("rotor")); + OreDictionary.registerOre("turbineRotorBlade", BigReactors.blockTurbineRotorPart.getItemStack("blade")); + + BRConfig.CONFIGURATION.save(); + } + } + + public static void registerDevices(int id, boolean require) { + if (BigReactors.blockDevice == null) { + BRConfig.CONFIGURATION.load(); + + BigReactors.blockDevice = new BlockBRDevice(Material.iron); + GameRegistry.registerBlock(BigReactors.blockDevice, ItemBlockBigReactors.class, "BRDevice"); + + OreDictionary.registerOre( + "brDeviceCyaniteProcessor", + ((BlockBRDevice) BigReactors.blockDevice).getCyaniteReprocessorItemStack()); + + BRConfig.CONFIGURATION.save(); + } + } + + public static void registerCreativeParts(int id, boolean require) { + BRConfig.CONFIGURATION.load(); + + boolean regCreativeParts = BRConfig.CONFIGURATION + .get( + "General", + "registerCreativeMultiblockParts", + true, + "If true, creative parts for reactors, turbines and other multiblocks will be registered.") + .getBoolean(true); + if (regCreativeParts && BigReactors.blockMultiblockCreativePart == null) { + BigReactors.blockMultiblockCreativePart = new BlockMBCreativePart(Material.iron); + GameRegistry.registerBlock( + BigReactors.blockMultiblockCreativePart, + ItemBlockBigReactors.class, + "BRMultiblockCreativePart"); + } + + BRConfig.CONFIGURATION.save(); + } + + public static void registerFluids(int id, boolean require) { + if (BigReactors.fluidYelloriumStill == null) { + BRConfig.CONFIGURATION.load(); + + BigReactors.fluidYellorium = FluidRegistry.getFluid("yellorium"); + if (fluidYellorium == null) { + fluidYellorium = new Fluid("yellorium"); + fluidYellorium.setDensity(100); + fluidYellorium.setGaseous(false); + fluidYellorium.setLuminosity(10); + fluidYellorium.setRarity(EnumRarity.uncommon); + fluidYellorium.setTemperature(295); + fluidYellorium.setViscosity(100); + fluidYellorium.setUnlocalizedName("bigreactors.yellorium.still"); + FluidRegistry.registerFluid(fluidYellorium); + } + + BlockBRGenericFluid liqY = new BlockBRGenericFluid(BigReactors.fluidYellorium, "yellorium"); + BigReactors.fluidYelloriumStill = liqY; + + GameRegistry.registerBlock( + BigReactors.fluidYelloriumStill, + ItemBlock.class, + BigReactors.fluidYelloriumStill.getUnlocalizedName()); + + fluidYelloriumBucketItem = (new ItemBRBucket(liqY)).setUnlocalizedName("bucket.yellorium") + .setMaxStackSize(1) + .setContainerItem(Items.bucket); GameRegistry.registerItem(fluidYelloriumBucketItem, "bucketYellorium"); - - BRConfig.CONFIGURATION.save(); - } - - if(BigReactors.fluidCyaniteStill == null) { - BRConfig.CONFIGURATION.load(); - - BigReactors.fluidCyanite = FluidRegistry.getFluid("cyanite"); - if(fluidCyanite == null) { - fluidCyanite = new Fluid("cyanite"); - fluidCyanite.setDensity(100); - fluidCyanite.setGaseous(false); - fluidCyanite.setLuminosity(6); - fluidCyanite.setRarity(EnumRarity.uncommon); - fluidCyanite.setTemperature(295); - fluidCyanite.setViscosity(100); - fluidCyanite.setUnlocalizedName("bigreactors.cyanite.still"); - FluidRegistry.registerFluid(fluidCyanite); - } - - BlockBRGenericFluid liqDY = new BlockBRGenericFluid(fluidCyanite, "cyanite"); - BigReactors.fluidCyaniteStill = liqDY; - GameRegistry.registerBlock(BigReactors.fluidCyaniteStill, ItemBlock.class, BigReactors.fluidCyaniteStill.getUnlocalizedName()); - - fluidCyaniteBucketItem = (new ItemBRBucket(liqDY)).setUnlocalizedName("bucket.cyanite").setMaxStackSize(1).setContainerItem(Items.bucket); + + BRConfig.CONFIGURATION.save(); + } + + if (BigReactors.fluidCyaniteStill == null) { + BRConfig.CONFIGURATION.load(); + + BigReactors.fluidCyanite = FluidRegistry.getFluid("cyanite"); + if (fluidCyanite == null) { + fluidCyanite = new Fluid("cyanite"); + fluidCyanite.setDensity(100); + fluidCyanite.setGaseous(false); + fluidCyanite.setLuminosity(6); + fluidCyanite.setRarity(EnumRarity.uncommon); + fluidCyanite.setTemperature(295); + fluidCyanite.setViscosity(100); + fluidCyanite.setUnlocalizedName("bigreactors.cyanite.still"); + FluidRegistry.registerFluid(fluidCyanite); + } + + BlockBRGenericFluid liqDY = new BlockBRGenericFluid(fluidCyanite, "cyanite"); + BigReactors.fluidCyaniteStill = liqDY; + GameRegistry.registerBlock( + BigReactors.fluidCyaniteStill, + ItemBlock.class, + BigReactors.fluidCyaniteStill.getUnlocalizedName()); + + fluidCyaniteBucketItem = (new ItemBRBucket(liqDY)).setUnlocalizedName("bucket.cyanite") + .setMaxStackSize(1) + .setContainerItem(Items.bucket); GameRegistry.registerItem(fluidCyaniteBucketItem, "bucketCyanite"); - - BRConfig.CONFIGURATION.save(); - } - - if(BigReactors.fluidFuelColumnStill == null) { - BRConfig.CONFIGURATION.load(); - - BigReactors.fluidFuelColumn = FluidRegistry.getFluid("fuelColumn"); - if(fluidFuelColumn == null) { - fluidFuelColumn = new Fluid("fuelColumn"); - fluidFuelColumn.setUnlocalizedName("bigreactors.fuelColumn.still"); - FluidRegistry.registerFluid(fluidFuelColumn); - } - - BRConfig.CONFIGURATION.save(); - } - - fluidSteam = FluidRegistry.getFluid("steam"); - registeredOwnSteam = false; - if(fluidSteam == null) { - // FINE THEN - BRConfig.CONFIGURATION.load(); - - fluidSteam = new Fluid("steam"); - fluidSteam.setUnlocalizedName("steam"); - fluidSteam.setTemperature(1000); // For consistency with TE - fluidSteam.setGaseous(true); - fluidSteam.setLuminosity(0); - fluidSteam.setRarity(EnumRarity.common); - fluidSteam.setDensity(6); - - registeredOwnSteam = true; - - FluidRegistry.registerFluid(fluidSteam); - - BRConfig.CONFIGURATION.save(); - } - - } - - // This must be done in init or later - protected static void registerGameBalanceData() { - // Register ingot & block => reactant mappings - StandardReactants.yelloriumMapping = Reactants.registerSolid("ingotYellorium", StandardReactants.yellorium); - StandardReactants.cyaniteMapping = Reactants.registerSolid("ingotCyanite", StandardReactants.cyanite); - - Reactants.registerSolid("ingotBlutonium", StandardReactants.blutonium); - - ItemStack blockYellorium = blockMetal.getItemStackForMaterial("Yellorium"); - Reactants.registerSolid(blockYellorium, StandardReactants.yellorium, Reactants.standardSolidReactantAmount * 9); - - ItemStack blockBlutonium = blockMetal.getItemStackForMaterial("Blutonium"); - Reactants.registerSolid(blockBlutonium, StandardReactants.blutonium, Reactants.standardSolidReactantAmount * 9); - - // Register fluid => reactant mappings - Reactants.registerFluid(fluidYellorium, StandardReactants.yellorium); - Reactants.registerFluid(fluidCyanite, StandardReactants.cyanite); - - // Register reactant => reactant conversions for making cyanite - ReactorConversions.register(StandardReactants.yellorium, StandardReactants.cyanite); - ReactorConversions.register(StandardReactants.blutonium, StandardReactants.cyanite); - - BRConfig.CONFIGURATION.load(); - boolean enableFantasyMetals = BRConfig.CONFIGURATION.get("General", "enableMetallurgyFantasyMetalsInTurbines", true, "If true, allows Metallurgy's fantasy metals to be used as part of turbine coils. Default: true").getBoolean(true); - boolean enableComedy = BRConfig.CONFIGURATION.get("General", "enableComedy", true, "If true, allows weird stuff inside reactors, like MFR sewage and pink slime. Default: true").getBoolean(true); - BRConfig.CONFIGURATION.save(); - - TurbineCoil.registerBlock("blockIron", 1f, 1f, 1f); - TurbineCoil.registerBlock("blockGold", 2f, 1f, 1.75f); - - TurbineCoil.registerBlock("blockCopper", 1.2f, 1f, 1.2f); // TE, lots of mods - TurbineCoil.registerBlock("blockOsmium", 1.2f, 1f, 1.2f); // Mekanism - TurbineCoil.registerBlock("blockZinc", 1.35f, 1f, 1.3f); - TurbineCoil.registerBlock("blockLead", 1.35f, 1.01f, 1.3f);// TE, Mekanism, some others - TurbineCoil.registerBlock("blockBrass", 1.4f, 1f, 1.2f); // Metallurgy - TurbineCoil.registerBlock("blockBronze", 1.4f, 1f, 1.2f); // Mekanism, many others - TurbineCoil.registerBlock("blockAluminum", 1.5f, 1f, 1.3f); // TiCo, couple others - TurbineCoil.registerBlock("blockSteel", 1.5f, 1f, 1.3f); // Metallurgy, Mek, etc. - TurbineCoil.registerBlock("blockInvar", 1.5f, 1f, 1.4f); // TE - TurbineCoil.registerBlock("blockSilver", 1.7f, 1f, 1.5f); // TE, lots of mods - TurbineCoil.registerBlock("blockElectrum", 2.5f, 1f, 2.0f); // TE, lots of mods - TurbineCoil.registerBlock("blockElectrumFlux",2.5f, 1.01f, 2.2f); // Redstone Arsenal, note small energy bonus (7% at 1000RF/t output) - TurbineCoil.registerBlock("blockPlatinum", 3.0f, 1f, 2.5f); // TE, lots of mods - TurbineCoil.registerBlock("blockShiny", 3.0f, 1f, 2.5f); // TE - TurbineCoil.registerBlock("blockTitanium", 3.1f, 1f, 2.7f); // Mariculture - TurbineCoil.registerBlock("blockEnderium", 3.0f, 1.02f, 3.0f); // TE, note tiny energy bonus! (14% at 1000RF/t output) - - TurbineCoil.registerBlock("blockLudicrite", 3.5f, 1.02f, 3.5f); - - if(enableFantasyMetals) { - // Metallurgy fantasy metals - TurbineCoil.registerBlock("blockMithril", 2.2f, 1f, 1.5f); - TurbineCoil.registerBlock("blockOrichalcum", 2.3f, 1f, 1.7f); - TurbineCoil.registerBlock("blockQuicksilver", 2.6f, 1f, 1.8f); - TurbineCoil.registerBlock("blockHaderoth", 3.0f, 1f, 2.0f); - TurbineCoil.registerBlock("blockCelenegil", 3.3f, 1f, 2.25f); - TurbineCoil.registerBlock("blockTartarite", 3.5f, 1f, 2.5f); - TurbineCoil.registerBlock("blockManyullyn", 3.5f, 1f, 2.5f); - } - - ReactorInterior.registerBlock("blockIron", 0.50f, 0.75f, 1.40f, IHeatEntity.conductivityIron); - ReactorInterior.registerBlock("blockGold", 0.52f, 0.80f, 1.45f, IHeatEntity.conductivityGold); - ReactorInterior.registerBlock("blockDiamond", 0.55f, 0.85f, 1.50f, IHeatEntity.conductivityDiamond); - ReactorInterior.registerBlock("blockEmerald", 0.55f, 0.85f, 1.50f, IHeatEntity.conductivityEmerald); - ReactorInterior.registerBlock("blockGraphite", 0.10f, 0.50f, 2.00f, IHeatEntity.conductivityGold); // Graphite: a great moderator! - ReactorInterior.registerBlock("blockGlassColorless", 0.20f, 0.25f, 1.10f, IHeatEntity.conductivityGlass); - ReactorInterior.registerBlock("blockIce", 0.33f, 0.33f, 1.15f, IHeatEntity.conductivityWater); - ReactorInterior.registerBlock("blockSnow", 0.15f, 0.33f, 1.05f, IHeatEntity.conductivityWater / 2f); - - // Mod blocks - ReactorInterior.registerBlock("blockCopper", 0.50f, 0.75f, 1.40f, IHeatEntity.conductivityCopper); - ReactorInterior.registerBlock("blockOsmium", 0.51f, 0.77f, 1.41f, IHeatEntity.conductivityCopper); - ReactorInterior.registerBlock("blockBrass", 0.51f, 0.77f, 1.41f, IHeatEntity.conductivityCopper); - ReactorInterior.registerBlock("blockBronze", 0.51f, 0.77f, 1.41f, IHeatEntity.conductivityCopper); - ReactorInterior.registerBlock("blockZinc", 0.51f, 0.77f, 1.41f, IHeatEntity.conductivityCopper); - ReactorInterior.registerBlock("blockAluminum", 0.50f, 0.78f, 1.42f, IHeatEntity.conductivityIron); - ReactorInterior.registerBlock("blockSteel", 0.50f, 0.78f, 1.42f, IHeatEntity.conductivityIron); - ReactorInterior.registerBlock("blockInvar", 0.50f, 0.79f, 1.43f, IHeatEntity.conductivityIron); - ReactorInterior.registerBlock("blockSilver", 0.51f, 0.79f, 1.43f, IHeatEntity.conductivitySilver); - ReactorInterior.registerBlock("blockLead", 0.75f, 0.75f, 1.75f, IHeatEntity.conductivitySilver); - ReactorInterior.registerBlock("blockElectrum", 0.53f, 0.82f, 1.47f, 2.2f); // Between gold and emerald - ReactorInterior.registerBlock("blockElectrumFlux",0.54f, 0.83f, 1.48f, 2.4f); // Between gold and emerald - ReactorInterior.registerBlock("blockPlatinum", 0.57f, 0.86f, 1.58f, IHeatEntity.conductivityEmerald); - ReactorInterior.registerBlock("blockShiny", 0.57f, 0.86f, 1.58f, IHeatEntity.conductivityEmerald); - ReactorInterior.registerBlock("blockTitanium", 0.58f, 0.87f, 1.59f, 2.7f); // Mariculture - ReactorInterior.registerBlock("blockEnderium", 0.60f, 0.88f, 1.60f, IHeatEntity.conductivityDiamond); - - if(enableFantasyMetals) { - ReactorInterior.registerBlock("blockMithril", 0.53f, 0.81f, 1.45f, IHeatEntity.conductivitySilver); - ReactorInterior.registerBlock("blockOrichalcum", 0.52f, 0.83f, 1.46f, 1.7f); // Between silver and gold - ReactorInterior.registerBlock("blockQuicksilver", 0.53f, 0.84f, 1.48f, IHeatEntity.conductivityGold); - ReactorInterior.registerBlock("blockHaderoth", 0.54f, 0.84f, 1.49f, IHeatEntity.conductivityEmerald); - ReactorInterior.registerBlock("blockCelenegil", 0.54f, 0.84f, 1.49f, IHeatEntity.conductivityDiamond); - ReactorInterior.registerBlock("blockTartarite", 0.65f, 0.90f, 1.62f, 4f); // Between diamond and graphene - ReactorInterior.registerBlock("blockManyullyn", 0.68f, 0.88f, 1.75f, 4.5f); - } - - //Water: 0.33f, 0.5f, 1.33f - ReactorInterior.registerFluid("water", RadiationHelper.waterData.absorption, RadiationHelper.waterData.heatEfficiency, RadiationHelper.waterData.moderation, IHeatEntity.conductivityWater); - ReactorInterior.registerFluid("redstone", 0.75f, 0.55f, 1.60f, IHeatEntity.conductivityEmerald); - ReactorInterior.registerFluid("glowstone", 0.20f, 0.60f, 1.75f, IHeatEntity.conductivityCopper); - ReactorInterior.registerFluid("cryotheum", 0.66f, 0.95f, 6.00f, IHeatEntity.conductivityDiamond); // Cryotheum: an amazing moderator! - ReactorInterior.registerFluid("ender", 0.90f, 0.75f, 2.00f, IHeatEntity.conductivityGold); - ReactorInterior.registerFluid("pyrotheum", 0.66f, 0.90f, 1.00f, IHeatEntity.conductivityIron); - - ReactorInterior.registerFluid("life essence", 0.70f, 0.55f, 1.75f, IHeatEntity.conductivityGold); // From Blood Magic - - if(enableComedy) { - ReactorInterior.registerBlock("blockMeat", 0.50f, 0.33f, 1.33f, IHeatEntity.conductivityStone); - ReactorInterior.registerBlock("blockMeatRaw", 0.40f, 0.50f, 1.50f, IHeatEntity.conductivityStone); - ReactorInterior.registerFluid("meat", 0.40f, 0.60f, 1.33f, IHeatEntity.conductivityStone); - ReactorInterior.registerFluid("pinkSlime", 0.45f, 0.70f, 1.50f, IHeatEntity.conductivityIron); - ReactorInterior.registerFluid("sewage", 0.50f, 0.65f, 1.44f, IHeatEntity.conductivityIron); - } - } - - public static void registerItems() { - if(itemDebugTool == null) { - itemDebugTool = new ItemBeefDebugTool(); - GameRegistry.registerItem(itemDebugTool, "BRDebugTool"); - } - } - - // Thanks KingLemming! - @SideOnly(Side.CLIENT) - public static void registerNonBlockFluidIcons(TextureMap map) { - iconFuelColumnStill = map.registerIcon(TEXTURE_NAME_PREFIX + "fluid.fuelColumn.still"); - iconFuelColumnFlowing = map.registerIcon(TEXTURE_NAME_PREFIX + "fluid.fuelColumn.flowing"); - - if(registeredOwnSteam) { - iconSteamStill = map.registerIcon(TEXTURE_NAME_PREFIX + "fluid.steam.still"); - iconSteamFlowing = map.registerIcon(TEXTURE_NAME_PREFIX + "fluid.steam.flowing"); - } - } - - - @SideOnly(Side.CLIENT) - public static void setNonBlockFluidIcons() { - fluidFuelColumn.setIcons(iconFuelColumnStill, iconFuelColumnFlowing); - - if(registeredOwnSteam) { - fluidSteam.setIcons(iconSteamStill, iconSteamFlowing); - } - } + + BRConfig.CONFIGURATION.save(); + } + + if (BigReactors.fluidFuelColumnStill == null) { + BRConfig.CONFIGURATION.load(); + + BigReactors.fluidFuelColumn = FluidRegistry.getFluid("fuelColumn"); + if (fluidFuelColumn == null) { + fluidFuelColumn = new Fluid("fuelColumn"); + fluidFuelColumn.setUnlocalizedName("bigreactors.fuelColumn.still"); + FluidRegistry.registerFluid(fluidFuelColumn); + } + + BRConfig.CONFIGURATION.save(); + } + + fluidSteam = FluidRegistry.getFluid("steam"); + registeredOwnSteam = false; + if (fluidSteam == null) { + // FINE THEN + BRConfig.CONFIGURATION.load(); + + fluidSteam = new Fluid("steam"); + fluidSteam.setUnlocalizedName("steam"); + fluidSteam.setTemperature(1000); // For consistency with TE + fluidSteam.setGaseous(true); + fluidSteam.setLuminosity(0); + fluidSteam.setRarity(EnumRarity.common); + fluidSteam.setDensity(6); + + registeredOwnSteam = true; + + FluidRegistry.registerFluid(fluidSteam); + + BRConfig.CONFIGURATION.save(); + } + + } + + // This must be done in init or later + protected static void registerGameBalanceData() { + // Register ingot & block => reactant mappings + StandardReactants.yelloriumMapping = Reactants.registerSolid("ingotYellorium", StandardReactants.yellorium); + StandardReactants.cyaniteMapping = Reactants.registerSolid("ingotCyanite", StandardReactants.cyanite); + + Reactants.registerSolid("ingotBlutonium", StandardReactants.blutonium); + + ItemStack blockYellorium = blockMetal.getItemStackForMaterial("Yellorium"); + Reactants.registerSolid(blockYellorium, StandardReactants.yellorium, Reactants.standardSolidReactantAmount * 9); + + ItemStack blockBlutonium = blockMetal.getItemStackForMaterial("Blutonium"); + Reactants.registerSolid(blockBlutonium, StandardReactants.blutonium, Reactants.standardSolidReactantAmount * 9); + + // Register fluid => reactant mappings + Reactants.registerFluid(fluidYellorium, StandardReactants.yellorium); + Reactants.registerFluid(fluidCyanite, StandardReactants.cyanite); + + // Register reactant => reactant conversions for making cyanite + ReactorConversions.register(StandardReactants.yellorium, StandardReactants.cyanite); + ReactorConversions.register(StandardReactants.blutonium, StandardReactants.cyanite); + + BRConfig.CONFIGURATION.load(); + boolean enableFantasyMetals = BRConfig.CONFIGURATION + .get( + "General", + "enableMetallurgyFantasyMetalsInTurbines", + true, + "If true, allows Metallurgy's fantasy metals to be used as part of turbine coils. Default: true") + .getBoolean(true); + boolean enableComedy = BRConfig.CONFIGURATION + .get( + "General", + "enableComedy", + true, + "If true, allows weird stuff inside reactors, like MFR sewage and pink slime. Default: true") + .getBoolean(true); + BRConfig.CONFIGURATION.save(); + + TurbineCoil.registerBlock("blockIron", 1f, 1f, 1f); + TurbineCoil.registerBlock("blockGold", 2f, 1f, 1.75f); + + TurbineCoil.registerBlock("blockCopper", 1.2f, 1f, 1.2f); // TE, lots of mods + TurbineCoil.registerBlock("blockOsmium", 1.2f, 1f, 1.2f); // Mekanism + TurbineCoil.registerBlock("blockZinc", 1.35f, 1f, 1.3f); + TurbineCoil.registerBlock("blockLead", 1.35f, 1.01f, 1.3f);// TE, Mekanism, some others + TurbineCoil.registerBlock("blockBrass", 1.4f, 1f, 1.2f); // Metallurgy + TurbineCoil.registerBlock("blockBronze", 1.4f, 1f, 1.2f); // Mekanism, many others + TurbineCoil.registerBlock("blockAluminum", 1.5f, 1f, 1.3f); // TiCo, couple others + TurbineCoil.registerBlock("blockSteel", 1.5f, 1f, 1.3f); // Metallurgy, Mek, etc. + TurbineCoil.registerBlock("blockInvar", 1.5f, 1f, 1.4f); // TE + TurbineCoil.registerBlock("blockSilver", 1.7f, 1f, 1.5f); // TE, lots of mods + TurbineCoil.registerBlock("blockElectrum", 2.5f, 1f, 2.0f); // TE, lots of mods + TurbineCoil.registerBlock("blockElectrumFlux", 2.5f, 1.01f, 2.2f); // Redstone Arsenal, note small energy bonus + // (7% at 1000RF/t output) + TurbineCoil.registerBlock("blockPlatinum", 3.0f, 1f, 2.5f); // TE, lots of mods + TurbineCoil.registerBlock("blockShiny", 3.0f, 1f, 2.5f); // TE + TurbineCoil.registerBlock("blockTitanium", 3.1f, 1f, 2.7f); // Mariculture + TurbineCoil.registerBlock("blockEnderium", 3.0f, 1.02f, 3.0f); // TE, note tiny energy bonus! (14% at 1000RF/t + // output) + + TurbineCoil.registerBlock("blockLudicrite", 3.5f, 1.02f, 3.5f); + + if (enableFantasyMetals) { + // Metallurgy fantasy metals + TurbineCoil.registerBlock("blockMithril", 2.2f, 1f, 1.5f); + TurbineCoil.registerBlock("blockOrichalcum", 2.3f, 1f, 1.7f); + TurbineCoil.registerBlock("blockQuicksilver", 2.6f, 1f, 1.8f); + TurbineCoil.registerBlock("blockHaderoth", 3.0f, 1f, 2.0f); + TurbineCoil.registerBlock("blockCelenegil", 3.3f, 1f, 2.25f); + TurbineCoil.registerBlock("blockTartarite", 3.5f, 1f, 2.5f); + TurbineCoil.registerBlock("blockManyullyn", 3.5f, 1f, 2.5f); + } + + ReactorInterior.registerBlock("blockIron", 0.50f, 0.75f, 1.40f, IHeatEntity.conductivityIron); + ReactorInterior.registerBlock("blockGold", 0.52f, 0.80f, 1.45f, IHeatEntity.conductivityGold); + ReactorInterior.registerBlock("blockDiamond", 0.55f, 0.85f, 1.50f, IHeatEntity.conductivityDiamond); + ReactorInterior.registerBlock("blockEmerald", 0.55f, 0.85f, 1.50f, IHeatEntity.conductivityEmerald); + ReactorInterior.registerBlock("blockGraphite", 0.10f, 0.50f, 2.00f, IHeatEntity.conductivityGold); // Graphite: + // a great + // moderator! + ReactorInterior.registerBlock("blockGlassColorless", 0.20f, 0.25f, 1.10f, IHeatEntity.conductivityGlass); + ReactorInterior.registerBlock("blockIce", 0.33f, 0.33f, 1.15f, IHeatEntity.conductivityWater); + ReactorInterior.registerBlock("blockSnow", 0.15f, 0.33f, 1.05f, IHeatEntity.conductivityWater / 2f); + + // Mod blocks + ReactorInterior.registerBlock("blockCopper", 0.50f, 0.75f, 1.40f, IHeatEntity.conductivityCopper); + ReactorInterior.registerBlock("blockOsmium", 0.51f, 0.77f, 1.41f, IHeatEntity.conductivityCopper); + ReactorInterior.registerBlock("blockBrass", 0.51f, 0.77f, 1.41f, IHeatEntity.conductivityCopper); + ReactorInterior.registerBlock("blockBronze", 0.51f, 0.77f, 1.41f, IHeatEntity.conductivityCopper); + ReactorInterior.registerBlock("blockZinc", 0.51f, 0.77f, 1.41f, IHeatEntity.conductivityCopper); + ReactorInterior.registerBlock("blockAluminum", 0.50f, 0.78f, 1.42f, IHeatEntity.conductivityIron); + ReactorInterior.registerBlock("blockSteel", 0.50f, 0.78f, 1.42f, IHeatEntity.conductivityIron); + ReactorInterior.registerBlock("blockInvar", 0.50f, 0.79f, 1.43f, IHeatEntity.conductivityIron); + ReactorInterior.registerBlock("blockSilver", 0.51f, 0.79f, 1.43f, IHeatEntity.conductivitySilver); + ReactorInterior.registerBlock("blockLead", 0.75f, 0.75f, 1.75f, IHeatEntity.conductivitySilver); + ReactorInterior.registerBlock("blockElectrum", 0.53f, 0.82f, 1.47f, 2.2f); // Between gold and emerald + ReactorInterior.registerBlock("blockElectrumFlux", 0.54f, 0.83f, 1.48f, 2.4f); // Between gold and emerald + ReactorInterior.registerBlock("blockPlatinum", 0.57f, 0.86f, 1.58f, IHeatEntity.conductivityEmerald); + ReactorInterior.registerBlock("blockShiny", 0.57f, 0.86f, 1.58f, IHeatEntity.conductivityEmerald); + ReactorInterior.registerBlock("blockTitanium", 0.58f, 0.87f, 1.59f, 2.7f); // Mariculture + ReactorInterior.registerBlock("blockEnderium", 0.60f, 0.88f, 1.60f, IHeatEntity.conductivityDiamond); + + if (enableFantasyMetals) { + ReactorInterior.registerBlock("blockMithril", 0.53f, 0.81f, 1.45f, IHeatEntity.conductivitySilver); + ReactorInterior.registerBlock("blockOrichalcum", 0.52f, 0.83f, 1.46f, 1.7f); // Between silver and gold + ReactorInterior.registerBlock("blockQuicksilver", 0.53f, 0.84f, 1.48f, IHeatEntity.conductivityGold); + ReactorInterior.registerBlock("blockHaderoth", 0.54f, 0.84f, 1.49f, IHeatEntity.conductivityEmerald); + ReactorInterior.registerBlock("blockCelenegil", 0.54f, 0.84f, 1.49f, IHeatEntity.conductivityDiamond); + ReactorInterior.registerBlock("blockTartarite", 0.65f, 0.90f, 1.62f, 4f); // Between diamond and graphene + ReactorInterior.registerBlock("blockManyullyn", 0.68f, 0.88f, 1.75f, 4.5f); + } + + // Water: 0.33f, 0.5f, 1.33f + ReactorInterior.registerFluid( + "water", + RadiationHelper.waterData.absorption, + RadiationHelper.waterData.heatEfficiency, + RadiationHelper.waterData.moderation, + IHeatEntity.conductivityWater); + ReactorInterior.registerFluid("redstone", 0.75f, 0.55f, 1.60f, IHeatEntity.conductivityEmerald); + ReactorInterior.registerFluid("glowstone", 0.20f, 0.60f, 1.75f, IHeatEntity.conductivityCopper); + ReactorInterior.registerFluid("cryotheum", 0.66f, 0.95f, 6.00f, IHeatEntity.conductivityDiamond); // Cryotheum: + // an amazing + // moderator! + ReactorInterior.registerFluid("ender", 0.90f, 0.75f, 2.00f, IHeatEntity.conductivityGold); + ReactorInterior.registerFluid("pyrotheum", 0.66f, 0.90f, 1.00f, IHeatEntity.conductivityIron); + + ReactorInterior.registerFluid("life essence", 0.70f, 0.55f, 1.75f, IHeatEntity.conductivityGold); // From Blood + // Magic + + if (enableComedy) { + ReactorInterior.registerBlock("blockMeat", 0.50f, 0.33f, 1.33f, IHeatEntity.conductivityStone); + ReactorInterior.registerBlock("blockMeatRaw", 0.40f, 0.50f, 1.50f, IHeatEntity.conductivityStone); + ReactorInterior.registerFluid("meat", 0.40f, 0.60f, 1.33f, IHeatEntity.conductivityStone); + ReactorInterior.registerFluid("pinkSlime", 0.45f, 0.70f, 1.50f, IHeatEntity.conductivityIron); + ReactorInterior.registerFluid("sewage", 0.50f, 0.65f, 1.44f, IHeatEntity.conductivityIron); + } + } + + public static void registerItems() { + if (itemDebugTool == null) { + itemDebugTool = new ItemBeefDebugTool(); + GameRegistry.registerItem(itemDebugTool, "BRDebugTool"); + } + } + + // Thanks KingLemming! + @SideOnly(Side.CLIENT) + public static void registerNonBlockFluidIcons(TextureMap map) { + iconFuelColumnStill = map.registerIcon(TEXTURE_NAME_PREFIX + "fluid.fuelColumn.still"); + iconFuelColumnFlowing = map.registerIcon(TEXTURE_NAME_PREFIX + "fluid.fuelColumn.flowing"); + + if (registeredOwnSteam) { + iconSteamStill = map.registerIcon(TEXTURE_NAME_PREFIX + "fluid.steam.still"); + iconSteamFlowing = map.registerIcon(TEXTURE_NAME_PREFIX + "fluid.steam.flowing"); + } + } + + @SideOnly(Side.CLIENT) + public static void setNonBlockFluidIcons() { + fluidFuelColumn.setIcons(iconFuelColumnStill, iconFuelColumnFlowing); + + if (registeredOwnSteam) { + fluidSteam.setIcons(iconSteamStill, iconSteamFlowing); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/BigReactorsTickHandler.java b/src/main/java/erogenousbeef/bigreactors/common/BigReactorsTickHandler.java index 9d86d8bf..8c329f06 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/BigReactorsTickHandler.java +++ b/src/main/java/erogenousbeef/bigreactors/common/BigReactorsTickHandler.java @@ -6,59 +6,69 @@ import java.util.Random; import net.minecraft.world.ChunkCoordIntPair; + import cpw.mods.fml.common.eventhandler.SubscribeEvent; import cpw.mods.fml.common.gameevent.TickEvent; import cpw.mods.fml.relauncher.Side; public class BigReactorsTickHandler { - protected HashMap> chunkRegenMap; - protected static final long maximumDeltaTimeNanoSecs = 16000000; // 16 milliseconds - - public void addRegenChunk(int dimensionId, ChunkCoordIntPair chunkCoord) { - if(chunkRegenMap == null) { - chunkRegenMap = new HashMap>(); - } - - if(!chunkRegenMap.containsKey(dimensionId)) { - LinkedList list = new LinkedList(); - list.add(chunkCoord); - chunkRegenMap.put(dimensionId, list); - } - else { - if(!chunkRegenMap.get(dimensionId).contains(chunkCoord)) { - chunkRegenMap.get(dimensionId).add(chunkCoord); - } - } - } + protected HashMap> chunkRegenMap; + protected static final long maximumDeltaTimeNanoSecs = 16000000; // 16 milliseconds + + public void addRegenChunk(int dimensionId, ChunkCoordIntPair chunkCoord) { + if (chunkRegenMap == null) { + chunkRegenMap = new HashMap>(); + } + + if (!chunkRegenMap.containsKey(dimensionId)) { + LinkedList list = new LinkedList(); + list.add(chunkCoord); + chunkRegenMap.put(dimensionId, list); + } else { + if (!chunkRegenMap.get(dimensionId) + .contains(chunkCoord)) { + chunkRegenMap.get(dimensionId) + .add(chunkCoord); + } + } + } @SubscribeEvent public void onWorldTick(TickEvent.WorldTickEvent event) { - if(event.side == Side.SERVER && event.phase == TickEvent.Phase.END) { - if(chunkRegenMap == null) { return; } + if (event.side == Side.SERVER && event.phase == TickEvent.Phase.END) { + if (chunkRegenMap == null) { + return; + } - if(event.world.isRemote) { return; } + if (event.world.isRemote) { + return; + } int dimensionId = event.world.provider.dimensionId; - if(chunkRegenMap.containsKey(dimensionId)) { + if (chunkRegenMap.containsKey(dimensionId)) { // Split up regen so it takes at most 16 millisec per frame to allow for ~55-60 FPS Queue chunksToGen = chunkRegenMap.get(dimensionId); long startTime = System.nanoTime(); - while(System.nanoTime() - startTime < maximumDeltaTimeNanoSecs && !chunksToGen.isEmpty()) { + while (System.nanoTime() - startTime < maximumDeltaTimeNanoSecs && !chunksToGen.isEmpty()) { // Regenerate chunk ChunkCoordIntPair nextChunk = chunksToGen.poll(); - if(nextChunk == null) { break; } + if (nextChunk == null) { + break; + } Random fmlRandom = new Random(event.world.getSeed()); long xSeed = fmlRandom.nextLong() >> 2 + 1L; long zSeed = fmlRandom.nextLong() >> 2 + 1L; - fmlRandom.setSeed((xSeed * nextChunk.chunkXPos + zSeed * nextChunk.chunkZPos) ^ event.world.getSeed()); + fmlRandom + .setSeed((xSeed * nextChunk.chunkXPos + zSeed * nextChunk.chunkZPos) ^ event.world.getSeed()); - BigReactors.worldGenerator.generateChunk(fmlRandom, nextChunk.chunkXPos, nextChunk.chunkZPos, event.world); + BigReactors.worldGenerator + .generateChunk(fmlRandom, nextChunk.chunkXPos, nextChunk.chunkZPos, event.world); } - if(chunksToGen.isEmpty()) { + if (chunksToGen.isEmpty()) { chunkRegenMap.remove(dimensionId); } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/CommonProxy.java b/src/main/java/erogenousbeef/bigreactors/common/CommonProxy.java index cdf2b449..c302f4e1 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/CommonProxy.java +++ b/src/main/java/erogenousbeef/bigreactors/common/CommonProxy.java @@ -5,6 +5,7 @@ import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraftforge.client.event.TextureStitchEvent; + import cofh.api.modhelpers.ThermalExpansionHelper; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.Loader; @@ -26,138 +27,150 @@ public class CommonProxy { - public void preInit() { - } - - public void init() { - BigReactors.registerTileEntities(); - - CommonPacketHandler.init(); - - NetworkRegistry.INSTANCE.registerGuiHandler(BRLoader.instance, new BigReactorsGUIHandler()); - BigReactors.tickHandler = new BigReactorsTickHandler(); - FMLCommonHandler.instance().bus().register(BigReactors.tickHandler); - FMLCommonHandler.instance().bus().register(new MultiblockServerTickHandler()); - - sendInterModAPIMessages(); - - if(Loader.isModLoaded("VersionChecker")) { - FMLInterModComms.sendRuntimeMessage(BRLoader.MOD_ID, "VersionChecker", "addVersionCheck", "http://big-reactors.com/version.json"); - } - } - - private void sendInterModAPIMessages() { - ItemIngot ingotGeneric = BigReactors.ingotGeneric; - ItemStack yelloriteOre = new ItemStack(BigReactors.blockYelloriteOre, 1); - - final int YELLORIUM = 0; - - String[] names = ItemIngot.MATERIALS; - ItemStack[] ingots = new ItemStack[names.length]; - ItemStack[] dusts = new ItemStack[names.length]; - - for(int i = 0; i < names.length; i++) { - ingots[i] = ingotGeneric.getIngotItem(names[i]); - dusts[i] = ingotGeneric.getDustItem(names[i]); - } - - ItemStack doubledYelloriumDust = null; - if(dusts[YELLORIUM] != null) { - doubledYelloriumDust = dusts[YELLORIUM].copy(); - doubledYelloriumDust.stackSize = 2; - } - - if(Loader.isModLoaded("ThermalExpansion")) { - ItemStack sandStack = new ItemStack(Blocks.sand, 1); - ItemStack doubleYellorium = ingots[YELLORIUM].copy(); - doubleYellorium.stackSize = 2; - - // TODO: Remove ThermalExpansionHelper once addSmelterRecipe and addPulverizerRecipe aren't broken - if(ingots[YELLORIUM] != null) { - ThermalExpansionHelper.addFurnaceRecipe(400, yelloriteOre, ingots[YELLORIUM]); - ThermalExpansionHelper.addSmelterRecipe(1600, yelloriteOre, sandStack, doubleYellorium); - } - - if(doubledYelloriumDust != null) { - ThermalExpansionHelper.addPulverizerRecipe(4000, yelloriteOre, doubledYelloriumDust); - ThermalExpansionHelper.addSmelterRecipe(200, doubledYelloriumDust, sandStack, doubleYellorium); - } - - for(int i = 0; i < ingots.length; i++) { - if(ingots[i] == null || dusts[i] == null) { continue; } - - ThermalExpansionHelper.addPulverizerRecipe(2400, ingots[i], dusts[i]); - ThermalExpansionHelper.addSmelterRecipe(200, doubledYelloriumDust, sandStack, doubleYellorium); - - ItemStack doubleDust = dusts[i].copy(); - doubleDust.stackSize = 2; - ItemStack doubleIngot = ingots[i].copy(); - doubleIngot.stackSize = 2; - - ThermalExpansionHelper.addSmelterRecipe(200, doubleDust, sandStack, doubleIngot); - } - } // END: IsModLoaded - ThermalExpansion - - if(Loader.isModLoaded("MineFactoryReloaded")) { - // Add yellorite to yellow focus list. - IMCHelper.MFR.addOreToMiningLaserFocus(yelloriteOre, 2); - + public void preInit() {} + + public void init() { + BigReactors.registerTileEntities(); + + CommonPacketHandler.init(); + + NetworkRegistry.INSTANCE.registerGuiHandler(BRLoader.instance, new BigReactorsGUIHandler()); + BigReactors.tickHandler = new BigReactorsTickHandler(); + FMLCommonHandler.instance() + .bus() + .register(BigReactors.tickHandler); + FMLCommonHandler.instance() + .bus() + .register(new MultiblockServerTickHandler()); + + sendInterModAPIMessages(); + + if (Loader.isModLoaded("VersionChecker")) { + FMLInterModComms.sendRuntimeMessage( + BRLoader.MOD_ID, + "VersionChecker", + "addVersionCheck", + "http://big-reactors.com/version.json"); + } + } + + private void sendInterModAPIMessages() { + ItemIngot ingotGeneric = BigReactors.ingotGeneric; + ItemStack yelloriteOre = new ItemStack(BigReactors.blockYelloriteOre, 1); + + final int YELLORIUM = 0; + + String[] names = ItemIngot.MATERIALS; + ItemStack[] ingots = new ItemStack[names.length]; + ItemStack[] dusts = new ItemStack[names.length]; + + for (int i = 0; i < names.length; i++) { + ingots[i] = ingotGeneric.getIngotItem(names[i]); + dusts[i] = ingotGeneric.getDustItem(names[i]); + } + + ItemStack doubledYelloriumDust = null; + if (dusts[YELLORIUM] != null) { + doubledYelloriumDust = dusts[YELLORIUM].copy(); + doubledYelloriumDust.stackSize = 2; + } + + if (Loader.isModLoaded("ThermalExpansion")) { + ItemStack sandStack = new ItemStack(Blocks.sand, 1); + ItemStack doubleYellorium = ingots[YELLORIUM].copy(); + doubleYellorium.stackSize = 2; + + // TODO: Remove ThermalExpansionHelper once addSmelterRecipe and addPulverizerRecipe aren't broken + if (ingots[YELLORIUM] != null) { + ThermalExpansionHelper.addFurnaceRecipe(400, yelloriteOre, ingots[YELLORIUM]); + ThermalExpansionHelper.addSmelterRecipe(1600, yelloriteOre, sandStack, doubleYellorium); + } + + if (doubledYelloriumDust != null) { + ThermalExpansionHelper.addPulverizerRecipe(4000, yelloriteOre, doubledYelloriumDust); + ThermalExpansionHelper.addSmelterRecipe(200, doubledYelloriumDust, sandStack, doubleYellorium); + } + + for (int i = 0; i < ingots.length; i++) { + if (ingots[i] == null || dusts[i] == null) { + continue; + } + + ThermalExpansionHelper.addPulverizerRecipe(2400, ingots[i], dusts[i]); + ThermalExpansionHelper.addSmelterRecipe(200, doubledYelloriumDust, sandStack, doubleYellorium); + + ItemStack doubleDust = dusts[i].copy(); + doubleDust.stackSize = 2; + ItemStack doubleIngot = ingots[i].copy(); + doubleIngot.stackSize = 2; + + ThermalExpansionHelper.addSmelterRecipe(200, doubleDust, sandStack, doubleIngot); + } + } // END: IsModLoaded - ThermalExpansion + + if (Loader.isModLoaded("MineFactoryReloaded")) { + // Add yellorite to yellow focus list. + IMCHelper.MFR.addOreToMiningLaserFocus(yelloriteOre, 2); + // Make Yellorite the 'preferred' ore for lime focus IMCHelper.MFR.setMiningLaserFocusPreferredOre(yelloriteOre, 9); - } // END: IsModLoaded - MineFactoryReloaded - - if(Loader.isModLoaded("appliedenergistics2")) { - if(doubledYelloriumDust != null) { - IMCHelper.AE2.addGrinderRecipe(yelloriteOre, doubledYelloriumDust, 4); - } - - for(int i = 0; i < ingots.length; i++) { - if(ingots[i] == null || dusts[i] == null) { continue; } - IMCHelper.AE2.addGrinderRecipe(ingots[i], dusts[i], 2); - } - } // END: IsModLoaded - AE2 - } - - public void postInit() { - BRConfig.CONFIGURATION.load(); - boolean autoAddUranium = BRConfig.CONFIGURATION.get("Compatibility", "autoAddUranium", - true, - "If true, automatically adds all " - +"unregistered ingots found as clones" - +"of standard yellorium fuel").getBoolean(true); - if(autoAddUranium) { - Reactants.registerSolid("ingotUranium", StandardReactants.yellorium); - } - - BRConfig.CONFIGURATION.save(); - - registerWithOtherMods(); - - // Easter Egg - Check if today is valentine's day. If so, change all particles to hearts. - Calendar calendar = Calendar.getInstance(); - BigReactors.isValentinesDay = (calendar.get(Calendar.MONTH) == 1 && calendar.get(Calendar.DAY_OF_MONTH) == 14); - } - - @SideOnly(Side.CLIENT) - @SubscribeEvent - public void registerIcons(TextureStitchEvent.Pre event) { - } - - @SideOnly(Side.CLIENT) - @SubscribeEvent - public void setIcons(TextureStitchEvent.Post event) { - } - - /// Mod Interoperability /// - void registerWithOtherMods() { - ModHelperBase modHelper; - - ModHelperBase.detectMods(); - - modHelper = new ModHelperComputerCraft(); - modHelper.register(); - - modHelper = new ModHelperMekanism(); - modHelper.register(); - } + } // END: IsModLoaded - MineFactoryReloaded + + if (Loader.isModLoaded("appliedenergistics2")) { + if (doubledYelloriumDust != null) { + IMCHelper.AE2.addGrinderRecipe(yelloriteOre, doubledYelloriumDust, 4); + } + + for (int i = 0; i < ingots.length; i++) { + if (ingots[i] == null || dusts[i] == null) { + continue; + } + IMCHelper.AE2.addGrinderRecipe(ingots[i], dusts[i], 2); + } + } // END: IsModLoaded - AE2 + } + + public void postInit() { + BRConfig.CONFIGURATION.load(); + boolean autoAddUranium = BRConfig.CONFIGURATION + .get( + "Compatibility", + "autoAddUranium", + true, + "If true, automatically adds all " + "unregistered ingots found as clones" + + "of standard yellorium fuel") + .getBoolean(true); + if (autoAddUranium) { + Reactants.registerSolid("ingotUranium", StandardReactants.yellorium); + } + + BRConfig.CONFIGURATION.save(); + + registerWithOtherMods(); + + // Easter Egg - Check if today is valentine's day. If so, change all particles to hearts. + Calendar calendar = Calendar.getInstance(); + BigReactors.isValentinesDay = (calendar.get(Calendar.MONTH) == 1 && calendar.get(Calendar.DAY_OF_MONTH) == 14); + } + + @SideOnly(Side.CLIENT) + @SubscribeEvent + public void registerIcons(TextureStitchEvent.Pre event) {} + + @SideOnly(Side.CLIENT) + @SubscribeEvent + public void setIcons(TextureStitchEvent.Post event) {} + + /// Mod Interoperability /// + void registerWithOtherMods() { + ModHelperBase modHelper; + + ModHelperBase.detectMods(); + + modHelper = new ModHelperComputerCraft(); + modHelper.register(); + + modHelper = new ModHelperMekanism(); + modHelper.register(); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/CreativeTabBR.java b/src/main/java/erogenousbeef/bigreactors/common/CreativeTabBR.java index 2ea85db3..45c9a121 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/CreativeTabBR.java +++ b/src/main/java/erogenousbeef/bigreactors/common/CreativeTabBR.java @@ -5,13 +5,11 @@ public class CreativeTabBR extends CreativeTabs { - public CreativeTabBR(String par2Str) - { - super(par2Str); - } + public CreativeTabBR(String par2Str) { + super(par2Str); + } - public Item getTabIconItem() - { - return Item.getItemFromBlock(BigReactors.blockYelloriteOre); - } + public Item getTabIconItem() { + return Item.getItemFromBlock(BigReactors.blockYelloriteOre); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/block/BlockBRDevice.java b/src/main/java/erogenousbeef/bigreactors/common/block/BlockBRDevice.java index a7100c74..bf011fb2 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/block/BlockBRDevice.java +++ b/src/main/java/erogenousbeef/bigreactors/common/block/BlockBRDevice.java @@ -3,8 +3,6 @@ import java.util.ArrayList; import java.util.List; -import org.apache.commons.lang3.exception.ExceptionUtils; - import net.minecraft.block.material.Material; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.creativetab.CreativeTabs; @@ -21,6 +19,7 @@ import net.minecraftforge.fluids.FluidContainerRegistry; import net.minecraftforge.fluids.FluidTankInfo; import net.minecraftforge.fluids.IFluidHandler; + import cofh.api.tileentity.IReconfigurableFacing; import cofh.core.block.BlockCoFHBase; import cofh.core.util.CoreUtils; @@ -37,211 +36,208 @@ public class BlockBRDevice extends BlockCoFHBase { - public static final int META_CYANITE_REPROCESSOR = 0; - - public static final String[] _subBlocks = { - "cyaniteReprocessor" - }; - - private IIcon[] _icons = new IIcon[_subBlocks.length]; - private IIcon[] _activeIcons = new IIcon[_subBlocks.length]; - - public BlockBRDevice(Material material) { - super(material); - setStepSound(soundTypeMetal); - setHardness(1.0f); - setBlockName("blockBRDevice"); - setBlockTextureName(BigReactors.TEXTURE_NAME_PREFIX + "blockBRDevice"); - setCreativeTab(BigReactors.TAB); - } - - public static final int SIDE_FRONT = ForgeDirection.NORTH.ordinal(); - - private IIcon safeGetIcon(IIcon[] list, int idx, int x, int y, int z) { - if(idx < 0 || idx >= list.length) { - BRLog.warning("Invalid metadata (%d) for block at %d, %d, %d!", idx, x, y, z); - return blockIcon; - } - else { - return list[idx]; - } - } - public IIcon getIconFromTileEntity(TileEntity te, int metadata, int side) { - if(metadata < 0) { return blockIcon; } - - // Tracks the actual index of the current side, after rotation - int front = -1; - - if(te instanceof IReconfigurableFacing) { - IReconfigurableFacing teFacing = (IReconfigurableFacing)te; - front = teFacing.getFacing(); - } - - if(side == front) { - if(te instanceof TileEntityBeefBase) { - TileEntityBeefBase beefTe = (TileEntityBeefBase)te; - if(beefTe.isActive()) { - return safeGetIcon(_activeIcons, metadata, te.xCoord, te.yCoord, te.zCoord); - } - } - return safeGetIcon(_icons, metadata, te.xCoord, te.yCoord, te.zCoord); - } - - if(te instanceof IBeefReconfigurableSides) { - IBeefReconfigurableSides teSides = (IBeefReconfigurableSides)te; - return teSides.getIconForSide(side); - } - - return blockIcon; - } - - @Override - public IIcon getIcon(IBlockAccess blockAccess, int x, int y, int z, int side) - { - TileEntity te = blockAccess.getTileEntity(x, y, z); - int metadata = blockAccess.getBlockMetadata(x, y, z); - return this.getIconFromTileEntity(te, metadata, side); - } - - @Override - public IIcon getIcon(int side, int metadata) - { - // This is used when rendering in-inventory. 4 == front here. - if(side == 4) { - return _icons[metadata]; - } - return this.blockIcon; - } - - @Override - @SideOnly(Side.CLIENT) - public void registerBlockIcons(IIconRegister par1IconRegister) - { - this.blockIcon = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName()); - - for(int i = 0; i < _subBlocks.length; ++i) { - _icons[i] = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + "." + _subBlocks[i]); - _activeIcons[i] = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + "." + _subBlocks[i] + ".active"); - } - } - - @Override - public TileEntity createNewTileEntity(World world, int metadata) { - switch(metadata) { - case META_CYANITE_REPROCESSOR: - return new TileEntityCyaniteReprocessor(); - default: - throw new IllegalArgumentException("Unknown metadata for tile entity"); - } - } - - public ItemStack getCyaniteReprocessorItemStack() { - return new ItemStack(this, 1, META_CYANITE_REPROCESSOR); - } - - @Override - public void getSubBlocks(Item par1, CreativeTabs par2CreativeTabs, List par3List) - { - par3List.add(this.getCyaniteReprocessorItemStack()); - } - - @Override - public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer entityPlayer, int side, float hitX, float hitY, float hitZ) { - TileEntity te = world.getTileEntity(x, y, z); - if(te == null) { return false; } - - if(entityPlayer.isSneaking()) { - - // Wrench + Sneak = Dismantle - if(StaticUtils.Inventory.isPlayerHoldingWrench(entityPlayer)) { - // Pass simulate == true on the client to prevent creation of "ghost" item stacks - dismantleBlock(entityPlayer, null, world, x, y, z, false, world.isRemote); - return true; - } - - return false; - } - - if(te instanceof IWrenchable && StaticUtils.Inventory.isPlayerHoldingWrench(entityPlayer)) { - return ((IWrenchable)te).onWrench(entityPlayer, side); - } - - // Handle buckets - if(te instanceof IFluidHandler) - { - if(FluidContainerRegistry.isEmptyContainer(entityPlayer.inventory.getCurrentItem())) { - IFluidHandler fluidHandler = (IFluidHandler)te; - FluidTankInfo[] infoz = fluidHandler.getTankInfo(ForgeDirection.UNKNOWN); - for(FluidTankInfo info : infoz) { - if(StaticUtils.Fluids.fillContainerFromTank(world, fluidHandler, entityPlayer, info.fluid)) { - return true; - } - } - } - else if(FluidContainerRegistry.isFilledContainer(entityPlayer.inventory.getCurrentItem())) - { - if(StaticUtils.Fluids.fillTankWithContainer(world, (IFluidHandler)te, entityPlayer)) { - return true; - } - } - } - - // Show GUI - if(te instanceof TileEntityBeefBase) { - if(!world.isRemote) { - entityPlayer.openGui(BRLoader.instance, 0, world, x, y, z); - } - return true; - } - - return false; - } - - // IDismantleable - @Override - public ArrayList dismantleBlock(EntityPlayer player, NBTTagCompound blockTag, - World world, int x, int y, int z, boolean returnDrops, boolean simulate) { - ArrayList stacks = new ArrayList(); - int metadata = world.getBlockMetadata(x, y, z); - stacks.add(new ItemStack(getItemDropped(metadata, world.rand, 0), 1, damageDropped(metadata))); - - if(returnDrops && !simulate) - { - TileEntity te = world.getTileEntity(x, y, z); - - if(te instanceof IInventory) { - IInventory invTe = (IInventory)te; - for(int i = 0; i < invTe.getSizeInventory(); i++) { - ItemStack stack = invTe.getStackInSlot(i); - if(stack != null) { - stacks.add(stack); - invTe.setInventorySlotContents(i, null); - } - } - } - } - - if(!simulate) { - world.setBlockToAir(x, y, z); - - if(!returnDrops) { - for(ItemStack stack: stacks) { - CoreUtils.dropItemStackIntoWorldWithVelocity(stack, world, x, y, z); - } - } - } - - return stacks; - } - - // IInitializer (unused) - @Override - public boolean initialize() { - return false; - } - - @Override - public boolean postInit() { - return false; - } + public static final int META_CYANITE_REPROCESSOR = 0; + + public static final String[] _subBlocks = { "cyaniteReprocessor" }; + + private IIcon[] _icons = new IIcon[_subBlocks.length]; + private IIcon[] _activeIcons = new IIcon[_subBlocks.length]; + + public BlockBRDevice(Material material) { + super(material); + setStepSound(soundTypeMetal); + setHardness(1.0f); + setBlockName("blockBRDevice"); + setBlockTextureName(BigReactors.TEXTURE_NAME_PREFIX + "blockBRDevice"); + setCreativeTab(BigReactors.TAB); + } + + public static final int SIDE_FRONT = ForgeDirection.NORTH.ordinal(); + + private IIcon safeGetIcon(IIcon[] list, int idx, int x, int y, int z) { + if (idx < 0 || idx >= list.length) { + BRLog.warning("Invalid metadata (%d) for block at %d, %d, %d!", idx, x, y, z); + return blockIcon; + } else { + return list[idx]; + } + } + + public IIcon getIconFromTileEntity(TileEntity te, int metadata, int side) { + if (metadata < 0) { + return blockIcon; + } + + // Tracks the actual index of the current side, after rotation + int front = -1; + + if (te instanceof IReconfigurableFacing) { + IReconfigurableFacing teFacing = (IReconfigurableFacing) te; + front = teFacing.getFacing(); + } + + if (side == front) { + if (te instanceof TileEntityBeefBase) { + TileEntityBeefBase beefTe = (TileEntityBeefBase) te; + if (beefTe.isActive()) { + return safeGetIcon(_activeIcons, metadata, te.xCoord, te.yCoord, te.zCoord); + } + } + return safeGetIcon(_icons, metadata, te.xCoord, te.yCoord, te.zCoord); + } + + if (te instanceof IBeefReconfigurableSides) { + IBeefReconfigurableSides teSides = (IBeefReconfigurableSides) te; + return teSides.getIconForSide(side); + } + + return blockIcon; + } + + @Override + public IIcon getIcon(IBlockAccess blockAccess, int x, int y, int z, int side) { + TileEntity te = blockAccess.getTileEntity(x, y, z); + int metadata = blockAccess.getBlockMetadata(x, y, z); + return this.getIconFromTileEntity(te, metadata, side); + } + + @Override + public IIcon getIcon(int side, int metadata) { + // This is used when rendering in-inventory. 4 == front here. + if (side == 4) { + return _icons[metadata]; + } + return this.blockIcon; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerBlockIcons(IIconRegister par1IconRegister) { + this.blockIcon = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName()); + + for (int i = 0; i < _subBlocks.length; ++i) { + _icons[i] = par1IconRegister + .registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + "." + _subBlocks[i]); + _activeIcons[i] = par1IconRegister + .registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + "." + _subBlocks[i] + ".active"); + } + } + + @Override + public TileEntity createNewTileEntity(World world, int metadata) { + switch (metadata) { + case META_CYANITE_REPROCESSOR: + return new TileEntityCyaniteReprocessor(); + default: + throw new IllegalArgumentException("Unknown metadata for tile entity"); + } + } + + public ItemStack getCyaniteReprocessorItemStack() { + return new ItemStack(this, 1, META_CYANITE_REPROCESSOR); + } + + @Override + public void getSubBlocks(Item par1, CreativeTabs par2CreativeTabs, List par3List) { + par3List.add(this.getCyaniteReprocessorItemStack()); + } + + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer entityPlayer, int side, float hitX, + float hitY, float hitZ) { + TileEntity te = world.getTileEntity(x, y, z); + if (te == null) { + return false; + } + + if (entityPlayer.isSneaking()) { + + // Wrench + Sneak = Dismantle + if (StaticUtils.Inventory.isPlayerHoldingWrench(entityPlayer)) { + // Pass simulate == true on the client to prevent creation of "ghost" item stacks + dismantleBlock(entityPlayer, null, world, x, y, z, false, world.isRemote); + return true; + } + + return false; + } + + if (te instanceof IWrenchable && StaticUtils.Inventory.isPlayerHoldingWrench(entityPlayer)) { + return ((IWrenchable) te).onWrench(entityPlayer, side); + } + + // Handle buckets + if (te instanceof IFluidHandler) { + if (FluidContainerRegistry.isEmptyContainer(entityPlayer.inventory.getCurrentItem())) { + IFluidHandler fluidHandler = (IFluidHandler) te; + FluidTankInfo[] infoz = fluidHandler.getTankInfo(ForgeDirection.UNKNOWN); + for (FluidTankInfo info : infoz) { + if (StaticUtils.Fluids.fillContainerFromTank(world, fluidHandler, entityPlayer, info.fluid)) { + return true; + } + } + } else if (FluidContainerRegistry.isFilledContainer(entityPlayer.inventory.getCurrentItem())) { + if (StaticUtils.Fluids.fillTankWithContainer(world, (IFluidHandler) te, entityPlayer)) { + return true; + } + } + } + + // Show GUI + if (te instanceof TileEntityBeefBase) { + if (!world.isRemote) { + entityPlayer.openGui(BRLoader.instance, 0, world, x, y, z); + } + return true; + } + + return false; + } + + // IDismantleable + @Override + public ArrayList dismantleBlock(EntityPlayer player, NBTTagCompound blockTag, World world, int x, int y, + int z, boolean returnDrops, boolean simulate) { + ArrayList stacks = new ArrayList(); + int metadata = world.getBlockMetadata(x, y, z); + stacks.add(new ItemStack(getItemDropped(metadata, world.rand, 0), 1, damageDropped(metadata))); + + if (returnDrops && !simulate) { + TileEntity te = world.getTileEntity(x, y, z); + + if (te instanceof IInventory) { + IInventory invTe = (IInventory) te; + for (int i = 0; i < invTe.getSizeInventory(); i++) { + ItemStack stack = invTe.getStackInSlot(i); + if (stack != null) { + stacks.add(stack); + invTe.setInventorySlotContents(i, null); + } + } + } + } + + if (!simulate) { + world.setBlockToAir(x, y, z); + + if (!returnDrops) { + for (ItemStack stack : stacks) { + CoreUtils.dropItemStackIntoWorldWithVelocity(stack, world, x, y, z); + } + } + } + + return stacks; + } + + // IInitializer (unused) + @Override + public boolean initialize() { + return false; + } + + @Override + public boolean postInit() { + return false; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/block/BlockBRGenericFluid.java b/src/main/java/erogenousbeef/bigreactors/common/block/BlockBRGenericFluid.java index fb1784c4..c3aefa0c 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/block/BlockBRGenericFluid.java +++ b/src/main/java/erogenousbeef/bigreactors/common/block/BlockBRGenericFluid.java @@ -5,33 +5,36 @@ import net.minecraft.util.IIcon; import net.minecraftforge.fluids.BlockFluidClassic; import net.minecraftforge.fluids.Fluid; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import erogenousbeef.bigreactors.common.BigReactors; public class BlockBRGenericFluid extends BlockFluidClassic { - private IIcon _iconFlowing; - private IIcon _iconStill; - - public BlockBRGenericFluid(Fluid fluid, String unlocalizedName) { - super(fluid, Material.water); - - setBlockName("fluid." + unlocalizedName + ".still"); - } - - @SideOnly(Side.CLIENT) - @Override - public void registerBlockIcons(IIconRegister iconRegistry) { - _iconStill = iconRegistry.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName()); - _iconFlowing = iconRegistry.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName().replace(".still", ".flowing")); - - this.stack.getFluid().setIcons(_iconStill, _iconFlowing); - } - - @SideOnly(Side.CLIENT) - @Override - public IIcon getIcon(int side, int metadata) { - return side <= 1 ? _iconStill : _iconFlowing; - } + private IIcon _iconFlowing; + private IIcon _iconStill; + + public BlockBRGenericFluid(Fluid fluid, String unlocalizedName) { + super(fluid, Material.water); + + setBlockName("fluid." + unlocalizedName + ".still"); + } + + @SideOnly(Side.CLIENT) + @Override + public void registerBlockIcons(IIconRegister iconRegistry) { + _iconStill = iconRegistry.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName()); + _iconFlowing = iconRegistry + .registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName().replace(".still", ".flowing")); + + this.stack.getFluid() + .setIcons(_iconStill, _iconFlowing); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(int side, int metadata) { + return side <= 1 ? _iconStill : _iconFlowing; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/block/BlockBRMetal.java b/src/main/java/erogenousbeef/bigreactors/common/block/BlockBRMetal.java index 75738bd7..3d53443d 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/block/BlockBRMetal.java +++ b/src/main/java/erogenousbeef/bigreactors/common/block/BlockBRMetal.java @@ -10,84 +10,84 @@ import net.minecraft.item.ItemStack; import net.minecraft.util.IIcon; import net.minecraftforge.oredict.OreDictionary; + import cpw.mods.fml.common.registry.GameRegistry; import erogenousbeef.bigreactors.common.BigReactors; import erogenousbeef.bigreactors.common.item.ItemIngot; public class BlockBRMetal extends Block { - public static final int METADATA_YELLORIUM = 0; - public static final int METADATA_CYANITE = 1; - public static final int METADATA_GRAPHITE = 2; - public static final int METADATA_BLUTONIUM = 3; - public static final int METADATA_LUDICRITE = 4; - - private static final String[] _subBlocks = new String[] { "blockYellorium", "blockCyanite", "blockGraphite", "blockBlutonium", "blockLudicrite" }; - private static final String[] _materials = new String[] { "Yellorium", "Cyanite", "Graphite", "Blutonium", "Ludicrite" }; - private IIcon[] _icons = new IIcon[_subBlocks.length]; - private static final int NUM_BLOCKS = _subBlocks.length; - - public BlockBRMetal() { - super(Material.iron); - this.setCreativeTab(BigReactors.TAB); - this.setBlockName("brMetal"); - this.setHardness(2f); - } - - @Override - public IIcon getIcon(int side, int metadata) - { - metadata = Math.max(0, Math.min(NUM_BLOCKS-1, metadata)); - return _icons[metadata]; - } - - @Override - public void registerBlockIcons(IIconRegister iconRegister) - { - for(int i = 0; i < NUM_BLOCKS; i++) { - _icons[i] = iconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + "." + _subBlocks[i]); - } - } - - @Override - public int damageDropped(int metadata) - { - return metadata; - } - - @Override - public void getSubBlocks(Item item, CreativeTabs par2CreativeTabs, List par3List) - { - for(int i = 0; i < NUM_BLOCKS; i++) { - par3List.add(new ItemStack(item, 1, i)); - } - } - - public ItemStack getItemStackForMaterial(String name) { - int i = 0; - - for(i = 0; i < NUM_BLOCKS; i++) { - if(name.equals(_materials[i])) { - break; - } - } - - return new ItemStack(this, 1, i); - } - - public void registerOreDictEntries() { - for(int i = 0; i < NUM_BLOCKS; i++) { - OreDictionary.registerOre(_subBlocks[i], new ItemStack(this, 1, i)); - } - } - - public void registerIngotRecipes(ItemIngot ingotItem) { - for(int i = 0; i < NUM_BLOCKS; i++) { - ItemStack block = new ItemStack(this, 1, i); - ItemStack ingot = ingotItem.getIngotItem(_materials[i]); - GameRegistry.addShapelessRecipe(block, ingot, ingot, ingot, ingot, ingot, ingot, ingot, ingot, ingot); - ingot.stackSize = 9; - GameRegistry.addShapelessRecipe(ingot, block); - } - } + public static final int METADATA_YELLORIUM = 0; + public static final int METADATA_CYANITE = 1; + public static final int METADATA_GRAPHITE = 2; + public static final int METADATA_BLUTONIUM = 3; + public static final int METADATA_LUDICRITE = 4; + + private static final String[] _subBlocks = new String[] { "blockYellorium", "blockCyanite", "blockGraphite", + "blockBlutonium", "blockLudicrite" }; + private static final String[] _materials = new String[] { "Yellorium", "Cyanite", "Graphite", "Blutonium", + "Ludicrite" }; + private IIcon[] _icons = new IIcon[_subBlocks.length]; + private static final int NUM_BLOCKS = _subBlocks.length; + + public BlockBRMetal() { + super(Material.iron); + this.setCreativeTab(BigReactors.TAB); + this.setBlockName("brMetal"); + this.setHardness(2f); + } + + @Override + public IIcon getIcon(int side, int metadata) { + metadata = Math.max(0, Math.min(NUM_BLOCKS - 1, metadata)); + return _icons[metadata]; + } + + @Override + public void registerBlockIcons(IIconRegister iconRegister) { + for (int i = 0; i < NUM_BLOCKS; i++) { + _icons[i] = iconRegister + .registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + "." + _subBlocks[i]); + } + } + + @Override + public int damageDropped(int metadata) { + return metadata; + } + + @Override + public void getSubBlocks(Item item, CreativeTabs par2CreativeTabs, List par3List) { + for (int i = 0; i < NUM_BLOCKS; i++) { + par3List.add(new ItemStack(item, 1, i)); + } + } + + public ItemStack getItemStackForMaterial(String name) { + int i = 0; + + for (i = 0; i < NUM_BLOCKS; i++) { + if (name.equals(_materials[i])) { + break; + } + } + + return new ItemStack(this, 1, i); + } + + public void registerOreDictEntries() { + for (int i = 0; i < NUM_BLOCKS; i++) { + OreDictionary.registerOre(_subBlocks[i], new ItemStack(this, 1, i)); + } + } + + public void registerIngotRecipes(ItemIngot ingotItem) { + for (int i = 0; i < NUM_BLOCKS; i++) { + ItemStack block = new ItemStack(this, 1, i); + ItemStack ingot = ingotItem.getIngotItem(_materials[i]); + GameRegistry.addShapelessRecipe(block, ingot, ingot, ingot, ingot, ingot, ingot, ingot, ingot, ingot); + ingot.stackSize = 9; + GameRegistry.addShapelessRecipe(ingot, block); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/block/BlockBROre.java b/src/main/java/erogenousbeef/bigreactors/common/block/BlockBROre.java index c3edb35a..d831ee3a 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/block/BlockBROre.java +++ b/src/main/java/erogenousbeef/bigreactors/common/block/BlockBROre.java @@ -9,41 +9,38 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.IIcon; + import erogenousbeef.bigreactors.common.BigReactors; public class BlockBROre extends Block { - private IIcon iconYellorite; - - public BlockBROre() - { - super(Material.rock); - this.setCreativeTab(BigReactors.TAB); - this.setBlockName("brOre"); - this.setBlockTextureName(BigReactors.TEXTURE_NAME_PREFIX + "oreYellorite"); - this.setHardness(2f); - } - - @Override - public IIcon getIcon(int side, int metadata) - { - return this.iconYellorite; - } - - @Override - public void registerBlockIcons(IIconRegister par1IconRegister) - { - this.iconYellorite = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + "oreYellorite"); - } - - @Override - public int damageDropped(int metadata) - { - return metadata; - } - - @Override - public void getSubBlocks(Item item, CreativeTabs par2CreativeTabs, List par3List) - { - par3List.add(new ItemStack(item, 1, 0)); - } + + private IIcon iconYellorite; + + public BlockBROre() { + super(Material.rock); + this.setCreativeTab(BigReactors.TAB); + this.setBlockName("brOre"); + this.setBlockTextureName(BigReactors.TEXTURE_NAME_PREFIX + "oreYellorite"); + this.setHardness(2f); + } + + @Override + public IIcon getIcon(int side, int metadata) { + return this.iconYellorite; + } + + @Override + public void registerBlockIcons(IIconRegister par1IconRegister) { + this.iconYellorite = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + "oreYellorite"); + } + + @Override + public int damageDropped(int metadata) { + return metadata; + } + + @Override + public void getSubBlocks(Item item, CreativeTabs par2CreativeTabs, List par3List) { + par3List.add(new ItemStack(item, 1, 0)); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/data/RadiationData.java b/src/main/java/erogenousbeef/bigreactors/common/data/RadiationData.java index e7b632cd..ac7e3862 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/data/RadiationData.java +++ b/src/main/java/erogenousbeef/bigreactors/common/data/RadiationData.java @@ -4,24 +4,24 @@ public class RadiationData { - public float fuelUsage = 0f; - public float environmentRfChange = 0f; // Amount of RF absorbed by the environment - public float fuelRfChange = 0f; // Amount of RF absorbed by the fuel - public float fuelAbsorbedRadiation = 0f; // in rad-units + public float fuelUsage = 0f; + public float environmentRfChange = 0f; // Amount of RF absorbed by the environment + public float fuelRfChange = 0f; // Amount of RF absorbed by the fuel + public float fuelAbsorbedRadiation = 0f; // in rad-units - public RadiationData() { - fuelUsage = 0f; - environmentRfChange = 0f; - fuelRfChange = 0f; - fuelAbsorbedRadiation = 0f; - } - - public float getEnvironmentHeatChange(int environmentVolume) { - return StaticUtils.Energy.getTempFromVolumeAndRF(environmentVolume, environmentRfChange); - } + public RadiationData() { + fuelUsage = 0f; + environmentRfChange = 0f; + fuelRfChange = 0f; + fuelAbsorbedRadiation = 0f; + } - public float getFuelHeatChange(int fuelVolume) { - return StaticUtils.Energy.getTempFromVolumeAndRF(fuelVolume, fuelRfChange); - - } + public float getEnvironmentHeatChange(int environmentVolume) { + return StaticUtils.Energy.getTempFromVolumeAndRF(environmentVolume, environmentRfChange); + } + + public float getFuelHeatChange(int fuelVolume) { + return StaticUtils.Energy.getTempFromVolumeAndRF(fuelVolume, fuelRfChange); + + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/data/RadiationPacket.java b/src/main/java/erogenousbeef/bigreactors/common/data/RadiationPacket.java index 2491cdba..9321b6f5 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/data/RadiationPacket.java +++ b/src/main/java/erogenousbeef/bigreactors/common/data/RadiationPacket.java @@ -1,6 +1,7 @@ package erogenousbeef.bigreactors.common.data; public class RadiationPacket { - public float hardness; - public float intensity; + + public float hardness; + public float intensity; } diff --git a/src/main/java/erogenousbeef/bigreactors/common/data/ReactantStack.java b/src/main/java/erogenousbeef/bigreactors/common/data/ReactantStack.java index 87119d9b..d46ac0c4 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/data/ReactantStack.java +++ b/src/main/java/erogenousbeef/bigreactors/common/data/ReactantStack.java @@ -1,98 +1,101 @@ package erogenousbeef.bigreactors.common.data; import net.minecraft.nbt.NBTTagCompound; + import erogenousbeef.bigreactors.common.BRLog; public class ReactantStack { - private String reactant; - public int amount; - - public ReactantStack(String name, int amount) { - assert(name != null); - reactant = name; - this.amount = amount; - } - - public ReactantStack(String name) { - assert(name != null); - reactant = name; - this.amount = 0; - } - - public static ReactantStack createFromNBT(NBTTagCompound tag) { - String name = null; - int amount = 0; - - if(tag.hasKey("name")) { - name = tag.getString("name"); - } - else { - return null; - } - - if(tag.hasKey("amount")) { - amount = tag.getInteger("amount"); - } - - return new ReactantStack(name, amount); - } - - public void readFromNBT(NBTTagCompound tag) { - if(tag.hasKey("name")) { - reactant = tag.getString("name"); - } - else { - BRLog.warning("ReactantStack::readFromNBT - Received a tag with no name!"); - } - - if(tag.hasKey("amount")) { - amount = tag.getInteger("amount"); - } - } - - public NBTTagCompound writeToNBT(NBTTagCompound tag) { - tag.setString("name", reactant); - tag.setInteger("amount", amount); - - return tag; - } - - public boolean isReactantEqual(String name) { - return reactant.equals(name); - } - - public boolean isReactantEqual(ReactantStack other) { - return reactant.equals(other.reactant); - } - - public String getName() { return reactant; } - - /** - * Split a reactant stack into two stacks. If the amount desired is greater than - * the current amount, returns the current item. Otherwise, returns a new stack - * with the desired amount and removes the desired amount from the current stack's - * amount. - * @param desiredAmount The amount of reactant desired. - * @return The - */ - public ReactantStack split(int desiredAmount) { - if(desiredAmount <= 0) { - throw new IllegalArgumentException("Cannot split a reactant into a stack of size zero"); - } - - if(desiredAmount >= amount) { return this; } - else { - ReactantStack newStack = new ReactantStack(reactant, desiredAmount); - amount -= desiredAmount; - return newStack; - } - } - - public String toString() { - if(reactant == null) { - return "UNKNOWN"; - } - return String.format("%s, %d mB", reactant, amount); - } + private String reactant; + public int amount; + + public ReactantStack(String name, int amount) { + assert (name != null); + reactant = name; + this.amount = amount; + } + + public ReactantStack(String name) { + assert (name != null); + reactant = name; + this.amount = 0; + } + + public static ReactantStack createFromNBT(NBTTagCompound tag) { + String name = null; + int amount = 0; + + if (tag.hasKey("name")) { + name = tag.getString("name"); + } else { + return null; + } + + if (tag.hasKey("amount")) { + amount = tag.getInteger("amount"); + } + + return new ReactantStack(name, amount); + } + + public void readFromNBT(NBTTagCompound tag) { + if (tag.hasKey("name")) { + reactant = tag.getString("name"); + } else { + BRLog.warning("ReactantStack::readFromNBT - Received a tag with no name!"); + } + + if (tag.hasKey("amount")) { + amount = tag.getInteger("amount"); + } + } + + public NBTTagCompound writeToNBT(NBTTagCompound tag) { + tag.setString("name", reactant); + tag.setInteger("amount", amount); + + return tag; + } + + public boolean isReactantEqual(String name) { + return reactant.equals(name); + } + + public boolean isReactantEqual(ReactantStack other) { + return reactant.equals(other.reactant); + } + + public String getName() { + return reactant; + } + + /** + * Split a reactant stack into two stacks. If the amount desired is greater than + * the current amount, returns the current item. Otherwise, returns a new stack + * with the desired amount and removes the desired amount from the current stack's + * amount. + * + * @param desiredAmount The amount of reactant desired. + * @return The + */ + public ReactantStack split(int desiredAmount) { + if (desiredAmount <= 0) { + throw new IllegalArgumentException("Cannot split a reactant into a stack of size zero"); + } + + if (desiredAmount >= amount) { + return this; + } else { + ReactantStack newStack = new ReactantStack(reactant, desiredAmount); + amount -= desiredAmount; + return newStack; + } + } + + public String toString() { + if (reactant == null) { + return "UNKNOWN"; + } + return String.format("%s, %d mB", reactant, amount); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/data/ReactorFuel.java b/src/main/java/erogenousbeef/bigreactors/common/data/ReactorFuel.java index 21458199..d726e5ae 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/data/ReactorFuel.java +++ b/src/main/java/erogenousbeef/bigreactors/common/data/ReactorFuel.java @@ -1,72 +1,74 @@ package erogenousbeef.bigreactors.common.data; import net.minecraftforge.fluids.Fluid; + import erogenousbeef.bigreactors.api.IReactorFuel; public class ReactorFuel implements IReactorFuel { - protected Fluid referenceFluid; - protected Fluid productFluid; - protected int color; - protected boolean isFuel; - protected boolean isWaste; - - public ReactorFuel(Fluid fluid, int color, boolean isFuel, boolean isWaste) { - this.referenceFluid = fluid; - this.color = color; - this.productFluid = null; - this.isFuel = isFuel; - this.isWaste = isWaste; - } - - public ReactorFuel(Fluid fluid, int color, boolean isFuel, boolean isWaste, Fluid productFluid) { - this(fluid, color, isFuel, isWaste); - this.productFluid = productFluid; - } - @Override - public boolean isFuelEqual(IReactorFuel otherFuel) { - return referenceFluid.getID() == otherFuel.getReferenceFluid().getID(); - } + protected Fluid referenceFluid; + protected Fluid productFluid; + protected int color; + protected boolean isFuel; + protected boolean isWaste; + + public ReactorFuel(Fluid fluid, int color, boolean isFuel, boolean isWaste) { + this.referenceFluid = fluid; + this.color = color; + this.productFluid = null; + this.isFuel = isFuel; + this.isWaste = isWaste; + } + + public ReactorFuel(Fluid fluid, int color, boolean isFuel, boolean isWaste, Fluid productFluid) { + this(fluid, color, isFuel, isWaste); + this.productFluid = productFluid; + } + + @Override + public boolean isFuelEqual(IReactorFuel otherFuel) { + return referenceFluid.getID() == otherFuel.getReferenceFluid() + .getID(); + } - @Override - public boolean isFuelEqual(Fluid fluid) { - return referenceFluid.getID() == fluid.getID(); - } + @Override + public boolean isFuelEqual(Fluid fluid) { + return referenceFluid.getID() == fluid.getID(); + } - @Override - public Fluid getReferenceFluid() { - return referenceFluid; - } + @Override + public Fluid getReferenceFluid() { + return referenceFluid; + } - @Override - public int getFuelColor() { - return color; - } + @Override + public int getFuelColor() { + return color; + } - @Override - public boolean equals(Object arg0) { - if(arg0 instanceof IReactorFuel) { - return isFuelEqual((IReactorFuel)arg0); - } - else if(arg0 instanceof Fluid) { - return isFuelEqual((Fluid)arg0); - } + @Override + public boolean equals(Object arg0) { + if (arg0 instanceof IReactorFuel) { + return isFuelEqual((IReactorFuel) arg0); + } else if (arg0 instanceof Fluid) { + return isFuelEqual((Fluid) arg0); + } - return false; - } + return false; + } - @Override - public Fluid getProductFluid() { - return productFluid; - } + @Override + public Fluid getProductFluid() { + return productFluid; + } - @Override - public boolean isFuel() { - return this.isFuel; - } + @Override + public boolean isFuel() { + return this.isFuel; + } - @Override - public boolean isWaste() { - return this.isWaste; - } + @Override + public boolean isWaste() { + return this.isWaste; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/data/ReactorSolidMapping.java b/src/main/java/erogenousbeef/bigreactors/common/data/ReactorSolidMapping.java index 7e40c63d..ee666ce1 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/data/ReactorSolidMapping.java +++ b/src/main/java/erogenousbeef/bigreactors/common/data/ReactorSolidMapping.java @@ -5,47 +5,44 @@ public class ReactorSolidMapping { - protected ItemStack referenceItem; - protected FluidStack referenceFluid; - - public ReactorSolidMapping(ItemStack item, FluidStack fluid) { - referenceItem = item.copy(); - referenceFluid = fluid; - } - - public ItemStack getReferenceItem() { - return referenceItem.copy(); - } - - public boolean isEqual(ReactorSolidMapping otherFuel) { - return isFluidEqual(otherFuel.getReferenceFluid()) && isItemEqual(otherFuel.getReferenceItem()); - } - - public boolean isItemEqual(ItemStack otherItem) { - return referenceItem.isItemEqual(otherItem); - } - - public boolean equals(Object other) { - if(other instanceof ReactorSolidMapping) { - return isEqual((ReactorSolidMapping)other); - } - else if(other instanceof FluidStack) { - return isFluidEqual((FluidStack)other); - } - else if(other instanceof ItemStack) { - return isItemEqual((ItemStack)other); - } - else { - // Standard IReactorFuels cannot be equal, as they do not contain solid data - return false; - } - } - - public FluidStack getReferenceFluid() { - return referenceFluid; - } - - public boolean isFluidEqual(FluidStack otherFluid) { - return referenceFluid.isFluidEqual(otherFluid); - } + protected ItemStack referenceItem; + protected FluidStack referenceFluid; + + public ReactorSolidMapping(ItemStack item, FluidStack fluid) { + referenceItem = item.copy(); + referenceFluid = fluid; + } + + public ItemStack getReferenceItem() { + return referenceItem.copy(); + } + + public boolean isEqual(ReactorSolidMapping otherFuel) { + return isFluidEqual(otherFuel.getReferenceFluid()) && isItemEqual(otherFuel.getReferenceItem()); + } + + public boolean isItemEqual(ItemStack otherItem) { + return referenceItem.isItemEqual(otherItem); + } + + public boolean equals(Object other) { + if (other instanceof ReactorSolidMapping) { + return isEqual((ReactorSolidMapping) other); + } else if (other instanceof FluidStack) { + return isFluidEqual((FluidStack) other); + } else if (other instanceof ItemStack) { + return isItemEqual((ItemStack) other); + } else { + // Standard IReactorFuels cannot be equal, as they do not contain solid data + return false; + } + } + + public FluidStack getReferenceFluid() { + return referenceFluid; + } + + public boolean isFluidEqual(FluidStack otherFluid) { + return referenceFluid.isFluidEqual(otherFluid); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/data/StandardReactants.java b/src/main/java/erogenousbeef/bigreactors/common/data/StandardReactants.java index 83d88fd4..851b5dfd 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/data/StandardReactants.java +++ b/src/main/java/erogenousbeef/bigreactors/common/data/StandardReactants.java @@ -6,21 +6,21 @@ public class StandardReactants { - public static final String yellorium = "yellorium"; - public static final String cyanite = "cyanite"; - public static final String blutonium = "blutonium"; - - public static final int colorYellorium = BigReactors.defaultFluidColorFuel; - public static final int colorCyanite = BigReactors.defaultFluidColorWaste; - - // These are used as fallbacks - public static SourceProductMapping yelloriumMapping; - public static SourceProductMapping cyaniteMapping; - - public static void register() { - Reactants.registerReactant(yellorium, 0, colorYellorium); - Reactants.registerReactant(cyanite, 1, colorCyanite); - Reactants.registerReactant(blutonium, 0, colorYellorium); - } - + public static final String yellorium = "yellorium"; + public static final String cyanite = "cyanite"; + public static final String blutonium = "blutonium"; + + public static final int colorYellorium = BigReactors.defaultFluidColorFuel; + public static final int colorCyanite = BigReactors.defaultFluidColorWaste; + + // These are used as fallbacks + public static SourceProductMapping yelloriumMapping; + public static SourceProductMapping cyaniteMapping; + + public static void register() { + Reactants.registerReactant(yellorium, 0, colorYellorium); + Reactants.registerReactant(cyanite, 1, colorCyanite); + Reactants.registerReactant(blutonium, 0, colorYellorium); + } + } diff --git a/src/main/java/erogenousbeef/bigreactors/common/interfaces/IBeefDebuggableTile.java b/src/main/java/erogenousbeef/bigreactors/common/interfaces/IBeefDebuggableTile.java index c71edbb6..0a22df82 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/interfaces/IBeefDebuggableTile.java +++ b/src/main/java/erogenousbeef/bigreactors/common/interfaces/IBeefDebuggableTile.java @@ -1,12 +1,12 @@ package erogenousbeef.bigreactors.common.interfaces; -import net.minecraft.entity.player.EntityPlayer; - /** * Implement this interface on tile entities which can be debugged via * the BeefDebugTool. + * * @author Erogenous Beef */ public interface IBeefDebuggableTile { - public String getDebugInfo(); + + public String getDebugInfo(); } diff --git a/src/main/java/erogenousbeef/bigreactors/common/interfaces/IBeefReconfigurableSides.java b/src/main/java/erogenousbeef/bigreactors/common/interfaces/IBeefReconfigurableSides.java index 43279025..b4ad6ef8 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/interfaces/IBeefReconfigurableSides.java +++ b/src/main/java/erogenousbeef/bigreactors/common/interfaces/IBeefReconfigurableSides.java @@ -1,14 +1,15 @@ package erogenousbeef.bigreactors.common.interfaces; import net.minecraft.util.IIcon; + import cofh.api.tileentity.IReconfigurableSides; public interface IBeefReconfigurableSides extends IReconfigurableSides { - /** - * Return the icon which should be used for a given side. - * Note: Passes the unrotated world side. - */ - public IIcon getIconForSide(int referenceSide); - + /** + * Return the icon which should be used for a given side. + * Note: Passes the unrotated world side. + */ + public IIcon getIconForSide(int referenceSide); + } diff --git a/src/main/java/erogenousbeef/bigreactors/common/interfaces/IMultipleFluidHandler.java b/src/main/java/erogenousbeef/bigreactors/common/interfaces/IMultipleFluidHandler.java index 3cad62d9..544c69a7 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/interfaces/IMultipleFluidHandler.java +++ b/src/main/java/erogenousbeef/bigreactors/common/interfaces/IMultipleFluidHandler.java @@ -4,9 +4,11 @@ /** * A subset of the Forge fluid interface, specifically made for GUI use. + * * @author Erogenous Beef * */ public interface IMultipleFluidHandler { - public FluidTankInfo[] getTankInfo(); + + public FluidTankInfo[] getTankInfo(); } diff --git a/src/main/java/erogenousbeef/bigreactors/common/interfaces/IReactorFuelInfo.java b/src/main/java/erogenousbeef/bigreactors/common/interfaces/IReactorFuelInfo.java index 0fe0dab0..8fd28123 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/interfaces/IReactorFuelInfo.java +++ b/src/main/java/erogenousbeef/bigreactors/common/interfaces/IReactorFuelInfo.java @@ -1,29 +1,29 @@ package erogenousbeef.bigreactors.common.interfaces; - /** * Implement on entities which expose their internal fueling state + * * @author Erogenous Beef */ public interface IReactorFuelInfo { - /** - * @return The amount of fuel contained in the entity. - */ - int getFuelAmount(); - - /** - * @return The amount of waste contained in the entity. - */ - int getWasteAmount(); + /** + * @return The amount of fuel contained in the entity. + */ + int getFuelAmount(); + + /** + * @return The amount of waste contained in the entity. + */ + int getWasteAmount(); + + /** + * @return An integer representing the maximum amount of fuel + waste, combined, the entity can contain. + */ + int getCapacity(); - /** - * @return An integer representing the maximum amount of fuel + waste, combined, the entity can contain. - */ - int getCapacity(); - - /** - * @return The number of fuel rods in this entity - */ - int getFuelRodCount(); + /** + * @return The number of fuel rods in this entity + */ + int getFuelRodCount(); } diff --git a/src/main/java/erogenousbeef/bigreactors/common/interfaces/IWrenchable.java b/src/main/java/erogenousbeef/bigreactors/common/interfaces/IWrenchable.java index 9a7e55dc..9748e909 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/interfaces/IWrenchable.java +++ b/src/main/java/erogenousbeef/bigreactors/common/interfaces/IWrenchable.java @@ -5,15 +5,17 @@ /** * Implement this class on tile entities which can be activated by a wrench or * hammer-type tool. + * * @author Erogenous Beef */ public interface IWrenchable { - /** - * Called when a player hits the machine with a wrench/hammer. - * - * @param player The player hitting the machine. - * @param hitSide The side on which the machine was hit. - * @return True if the machine handled the wrench hit, false otherwise. - */ - public boolean onWrench(EntityPlayer player, int hitSide); + + /** + * Called when a player hits the machine with a wrench/hammer. + * + * @param player The player hitting the machine. + * @param hitSide The side on which the machine was hit. + * @return True if the machine handled the wrench hit, false otherwise. + */ + public boolean onWrench(EntityPlayer player, int hitSide); } diff --git a/src/main/java/erogenousbeef/bigreactors/common/item/ItemBRBucket.java b/src/main/java/erogenousbeef/bigreactors/common/item/ItemBRBucket.java index fd5b276f..f772b46a 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/item/ItemBRBucket.java +++ b/src/main/java/erogenousbeef/bigreactors/common/item/ItemBRBucket.java @@ -9,42 +9,43 @@ import net.minecraft.item.ItemBucket; import net.minecraft.item.ItemStack; import net.minecraft.world.World; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import erogenousbeef.bigreactors.common.BigReactors; public class ItemBRBucket extends ItemBucket { - private Block _fluid; - - public ItemBRBucket(Block fluid) { - super(fluid); - setCreativeTab(BigReactors.TAB); - _fluid = fluid; - } - - @SideOnly(Side.CLIENT) - @Override - public void registerIcons(IIconRegister iconRegistry) { - this.itemIcon = iconRegistry.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName()); - } - - @Override - public boolean tryPlaceContainedLiquid(World world, int x, int y, int z) { - if(_fluid == null) { - return false; - } - else if(!world.isAirBlock(x, y, z) && world.getBlock(x, y, z).getMaterial().isSolid()) { - return false; - } - else { - world.setBlock(x, y, z, _fluid, 0, 3); - return true; - } - } - - @Override - public void getSubItems(Item item, CreativeTabs creativeTab, List subTypes) { - subTypes.add(new ItemStack(item, 1, 0)); - } + private Block _fluid; + + public ItemBRBucket(Block fluid) { + super(fluid); + setCreativeTab(BigReactors.TAB); + _fluid = fluid; + } + + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister iconRegistry) { + this.itemIcon = iconRegistry.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName()); + } + + @Override + public boolean tryPlaceContainedLiquid(World world, int x, int y, int z) { + if (_fluid == null) { + return false; + } else if (!world.isAirBlock(x, y, z) && world.getBlock(x, y, z) + .getMaterial() + .isSolid()) { + return false; + } else { + world.setBlock(x, y, z, _fluid, 0, 3); + return true; + } + } + + @Override + public void getSubItems(Item item, CreativeTabs creativeTab, List subTypes) { + subTypes.add(new ItemStack(item, 1, 0)); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/item/ItemBase.java b/src/main/java/erogenousbeef/bigreactors/common/item/ItemBase.java index 30f7ba30..c43a6897 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/item/ItemBase.java +++ b/src/main/java/erogenousbeef/bigreactors/common/item/ItemBase.java @@ -3,58 +3,57 @@ import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.item.Item; import net.minecraft.util.IIcon; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import erogenousbeef.bigreactors.common.BigReactors; public class ItemBase extends Item { - protected IIcon[] icons; - - public ItemBase(String name) - { - super(); - this.setUnlocalizedName(name); - this.setCreativeTab(BigReactors.TAB); - icons = new IIcon[getNumberOfSubItems()]; - } - - protected int getNumberOfSubItems() { - return 0; - } - - protected String[] getSubItemNames() { - return null; - } - - @Override - @SideOnly(Side.CLIENT) - public void registerIcons(IIconRegister iconRegister) - { - String[] subItemNames = getSubItemNames(); - if(subItemNames != null) { - for(int i = 0; i < subItemNames.length; i++) { - icons[i] = iconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + subItemNames[i]); - } - } - else - { - this.itemIcon = iconRegister.registerIcon(this.getUnlocalizedName().replace("item.", BigReactors.TEXTURE_NAME_PREFIX)); - } - } - - @Override - @SideOnly(Side.CLIENT) - public IIcon getIconFromDamage(int damage) - { - if(icons.length > damage && !this.isDamageable()) { - return icons[damage]; - } - - return super.getIconFromDamage(damage); - } - - @Override - public int getMetadata(int metadata) { - return metadata; - } + + protected IIcon[] icons; + + public ItemBase(String name) { + super(); + this.setUnlocalizedName(name); + this.setCreativeTab(BigReactors.TAB); + icons = new IIcon[getNumberOfSubItems()]; + } + + protected int getNumberOfSubItems() { + return 0; + } + + protected String[] getSubItemNames() { + return null; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IIconRegister iconRegister) { + String[] subItemNames = getSubItemNames(); + if (subItemNames != null) { + for (int i = 0; i < subItemNames.length; i++) { + icons[i] = iconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + subItemNames[i]); + } + } else { + this.itemIcon = iconRegister.registerIcon( + this.getUnlocalizedName() + .replace("item.", BigReactors.TEXTURE_NAME_PREFIX)); + } + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIconFromDamage(int damage) { + if (icons.length > damage && !this.isDamageable()) { + return icons[damage]; + } + + return super.getIconFromDamage(damage); + } + + @Override + public int getMetadata(int metadata) { + return metadata; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/item/ItemBeefDebugTool.java b/src/main/java/erogenousbeef/bigreactors/common/item/ItemBeefDebugTool.java index c536c924..9b147c67 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/item/ItemBeefDebugTool.java +++ b/src/main/java/erogenousbeef/bigreactors/common/item/ItemBeefDebugTool.java @@ -3,96 +3,103 @@ import java.util.ArrayList; import java.util.List; -import cofh.core.util.oredict.OreDictionaryArbiter; -import cofh.lib.util.helpers.ItemHelper; -import cpw.mods.fml.relauncher.Side; -import cpw.mods.fml.relauncher.SideOnly; -import erogenousbeef.bigreactors.common.BRLog; -import erogenousbeef.bigreactors.common.BigReactors; -import erogenousbeef.bigreactors.common.interfaces.IBeefDebuggableTile; import net.minecraft.block.Block; -import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ChatComponentText; import net.minecraft.util.EnumChatFormatting; import net.minecraft.world.World; +import cofh.core.util.oredict.OreDictionaryArbiter; +import cofh.lib.util.helpers.ItemHelper; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import erogenousbeef.bigreactors.common.interfaces.IBeefDebuggableTile; + public class ItemBeefDebugTool extends ItemBase { - public ItemBeefDebugTool() { - super("beefDebugTool"); - setMaxStackSize(1); - } + public ItemBeefDebugTool() { + super("beefDebugTool"); + setMaxStackSize(1); + } + + @Override + @SideOnly(Side.CLIENT) + public void addInformation(ItemStack stack, EntityPlayer player, List infoList, boolean advancedTooltips) { + super.addInformation(stack, player, infoList, advancedTooltips); + infoList.add("Rightclick a block to show debug info"); + infoList.add(""); + infoList.add(EnumChatFormatting.ITALIC + "Queries on server, by default."); + infoList.add( + EnumChatFormatting.GREEN + "Shift:" + + EnumChatFormatting.GRAY + + EnumChatFormatting.ITALIC + + " Query on client"); + } + + @Override + public boolean onItemUseFirst(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, + float hitX, float hitY, float hitZ) { + if (player.isSneaking() != world.isRemote) { + return false; + } - @Override - @SideOnly(Side.CLIENT) - public void addInformation(ItemStack stack, EntityPlayer player, List infoList, boolean advancedTooltips) { - super.addInformation(stack, player, infoList, advancedTooltips); - infoList.add("Rightclick a block to show debug info"); - infoList.add(""); - infoList.add(EnumChatFormatting.ITALIC + "Queries on server, by default."); - infoList.add(EnumChatFormatting.GREEN + "Shift:" + EnumChatFormatting.GRAY + EnumChatFormatting.ITALIC + " Query on client"); - } + String clientOrServer = world.isRemote ? "CLIENT" : "SERVER"; - @Override - public boolean onItemUseFirst(ItemStack stack, EntityPlayer player, World world, - int x, int y, int z, int side, float hitX, float hitY, float hitZ) { - if(player.isSneaking() != world.isRemote) { - return false; - } - - String clientOrServer = world.isRemote ? "CLIENT":"SERVER"; + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof IBeefDebuggableTile) { + String result = ((IBeefDebuggableTile) te).getDebugInfo(); + if (result != null && !result.isEmpty()) { + String[] results = result.split("\n"); + String initialMessage = String.format("[%s] Beef Debug Tool:", clientOrServer); + player.addChatMessage(new ChatComponentText(initialMessage)); + for (String r : results) { + player.addChatMessage(new ChatComponentText(r)); + } + return true; + } + } - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof IBeefDebuggableTile) { - String result = ((IBeefDebuggableTile)te).getDebugInfo(); - if(result != null && !result.isEmpty()) { - String[] results = result.split("\n"); - String initialMessage = String.format("[%s] Beef Debug Tool:", clientOrServer); - player.addChatMessage(new ChatComponentText(initialMessage)); - for(String r : results) { - player.addChatMessage(new ChatComponentText(r)); - } - return true; - } - } + Block b = world.getBlock(x, y, z); + if (b != null) { + ItemStack blockStack = new ItemStack(b, 1, world.getBlockMetadata(x, y, z)); + String oreName = ItemHelper.oreProxy.getOreName(blockStack); + player.addChatMessage( + new ChatComponentText( + String.format( + "[%s] Canonical ore name for %s: %s", + world.isRemote ? "CLIENT" : "SERVER", + b.getUnlocalizedName(), + oreName))); - Block b = world.getBlock(x, y, z); - if(b != null) { - ItemStack blockStack = new ItemStack(b, 1, world.getBlockMetadata(x,y,z)); - String oreName = ItemHelper.oreProxy.getOreName(blockStack); - player.addChatMessage(new ChatComponentText(String.format("[%s] Canonical ore name for %s: %s", world.isRemote?"CLIENT":"SERVER", b.getUnlocalizedName(), oreName))); + ArrayList allOreNames = OreDictionaryArbiter.getAllOreNames(blockStack); + if (allOreNames != null) { + player.addChatMessage( + new ChatComponentText( + String.format("[%s] All ore names (%d):", clientOrServer, allOreNames.size()))); + for (String on : allOreNames) { + player.addChatMessage(new ChatComponentText(on)); + } + } else { + player.addChatMessage(new ChatComponentText("getAllOreNames returned null")); + } + } - ArrayList allOreNames = OreDictionaryArbiter.getAllOreNames(blockStack); - if(allOreNames != null) { - player.addChatMessage(new ChatComponentText(String.format("[%s] All ore names (%d):", clientOrServer, allOreNames.size()))); - for(String on : allOreNames) { - player.addChatMessage(new ChatComponentText(on)); - } - } - else { - player.addChatMessage(new ChatComponentText("getAllOreNames returned null")); - } - } + // Consume clicks by default + return true; + } - // Consume clicks by default - return true; - } + @Override + public boolean doesSneakBypassUse(World world, int x, int y, int z, EntityPlayer player) { + return false; + } - @Override - public boolean doesSneakBypassUse(World world, int x, int y, int z, EntityPlayer player) - { - return false; - } - - /* - @Override - public boolean canHarvestBlock(Block block, ItemStack stack) - { - return false; - } - */ + /* + * @Override + * public boolean canHarvestBlock(Block block, ItemStack stack) + * { + * return false; + * } + */ } diff --git a/src/main/java/erogenousbeef/bigreactors/common/item/ItemBlockBigReactors.java b/src/main/java/erogenousbeef/bigreactors/common/item/ItemBlockBigReactors.java index daae6513..69605b4f 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/item/ItemBlockBigReactors.java +++ b/src/main/java/erogenousbeef/bigreactors/common/item/ItemBlockBigReactors.java @@ -18,21 +18,19 @@ public int getMetadata(int i) { @Override public String getUnlocalizedName(ItemStack itemStack) { - if(this.hasSubtypes) { + if (this.hasSubtypes) { int metadata = itemStack.getItemDamage(); return super.getUnlocalizedName(itemStack) + "." + Integer.toString(metadata); - } - else { + } else { return super.getUnlocalizedName(itemStack); } } @Override public String getUnlocalizedName() { - if(this.hasSubtypes) { + if (this.hasSubtypes) { return super.getUnlocalizedName() + ".0"; - } - else { + } else { return super.getUnlocalizedName(); } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/item/ItemIngot.java b/src/main/java/erogenousbeef/bigreactors/common/item/ItemIngot.java index a600ad22..2b1bf10c 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/item/ItemIngot.java +++ b/src/main/java/erogenousbeef/bigreactors/common/item/ItemIngot.java @@ -6,81 +6,75 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -public class ItemIngot extends ItemBase -{ - public static final String[] TYPES = { "ingotYellorium", "ingotCyanite", "ingotGraphite", "ingotBlutonium", - "dustYellorium", "dustCyanite", "dustGraphite", "dustBlutonium", - "ingotLudicrite", "dustLudicrite" }; - - public static final String[] MATERIALS = { "Yellorium", "Cyanite", "Graphite", "Blutonium", "Ludicrite" }; - - public ItemIngot() - { - super("ingot"); - this.setHasSubtypes(true); - this.setMaxDamage(0); - } - - @Override - protected int getNumberOfSubItems() { - return TYPES.length; - } - - @Override - protected String[] getSubItemNames() { - return TYPES; - } - - @Override - public int getMetadata(int damage) - { - return damage; - } - - @Override - public String getUnlocalizedName(ItemStack itemStack) - { - int idx = Math.min(TYPES.length-1, itemStack.getItemDamage()); - return "item." + TYPES[idx]; - } - - @Override - public void getSubItems(Item item, CreativeTabs creativeTabs, List list) - { - for (int i = 0; i < TYPES.length; i++) - { - list.add(new ItemStack(this, 1, i)); - } - } - - public static boolean isFuel(int itemDamage) { - return itemDamage == 0 || itemDamage == 3; - } - - public static boolean isWaste(int itemDamage) { - return itemDamage == 1; - } - - public static boolean isGraphite(int itemDamage) { - return itemDamage == 2; - } - - public ItemStack getItemStackForType(String typeName) { - for(int i = 0; i < TYPES.length; i++) { - if(TYPES[i].equals(typeName)) { - return new ItemStack(this, 1, i); - } - } - - return null; - } - - public ItemStack getIngotItem(String name) { - return getItemStackForType("ingot" + name); - } - - public ItemStack getDustItem(String name) { - return getItemStackForType("dust" + name); - } +public class ItemIngot extends ItemBase { + + public static final String[] TYPES = { "ingotYellorium", "ingotCyanite", "ingotGraphite", "ingotBlutonium", + "dustYellorium", "dustCyanite", "dustGraphite", "dustBlutonium", "ingotLudicrite", "dustLudicrite" }; + + public static final String[] MATERIALS = { "Yellorium", "Cyanite", "Graphite", "Blutonium", "Ludicrite" }; + + public ItemIngot() { + super("ingot"); + this.setHasSubtypes(true); + this.setMaxDamage(0); + } + + @Override + protected int getNumberOfSubItems() { + return TYPES.length; + } + + @Override + protected String[] getSubItemNames() { + return TYPES; + } + + @Override + public int getMetadata(int damage) { + return damage; + } + + @Override + public String getUnlocalizedName(ItemStack itemStack) { + int idx = Math.min(TYPES.length - 1, itemStack.getItemDamage()); + return "item." + TYPES[idx]; + } + + @Override + public void getSubItems(Item item, CreativeTabs creativeTabs, List list) { + for (int i = 0; i < TYPES.length; i++) { + list.add(new ItemStack(this, 1, i)); + } + } + + public static boolean isFuel(int itemDamage) { + return itemDamage == 0 || itemDamage == 3; + } + + public static boolean isWaste(int itemDamage) { + return itemDamage == 1; + } + + public static boolean isGraphite(int itemDamage) { + return itemDamage == 2; + } + + public ItemStack getItemStackForType(String typeName) { + for (int i = 0; i < TYPES.length; i++) { + if (TYPES[i].equals(typeName)) { + return new ItemStack(this, 1, i); + } + } + + return null; + } + + public ItemStack getIngotItem(String name) { + return getItemStackForType("ingot" + name); + } + + public ItemStack getDustItem(String name) { + return getItemStackForType("dust" + name); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/MultiblockReactor.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/MultiblockReactor.java index 90194cb6..6f337e61 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/MultiblockReactor.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/MultiblockReactor.java @@ -1,7 +1,5 @@ package erogenousbeef.bigreactors.common.multiblock; -import io.netty.buffer.ByteBuf; - import java.util.HashSet; import java.util.Iterator; import java.util.Set; @@ -21,6 +19,7 @@ import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTankInfo; import net.minecraftforge.fluids.IFluidBlock; + import cofh.api.energy.IEnergyProvider; import cofh.lib.util.helpers.ItemHelper; import cpw.mods.fml.common.network.simpleimpl.IMessage; @@ -55,1254 +54,1370 @@ import erogenousbeef.core.multiblock.MultiblockControllerBase; import erogenousbeef.core.multiblock.MultiblockValidationException; import erogenousbeef.core.multiblock.rectangular.RectangularMultiblockControllerBase; +import io.netty.buffer.ByteBuf; -public class MultiblockReactor extends RectangularMultiblockControllerBase implements IEnergyProvider, IReactorFuelInfo, IMultipleFluidHandler, IActivateable { - public static final int FuelCapacityPerFuelRod = 4 * Reactants.standardSolidReactantAmount; // 4 ingots per rod - - public static final int FLUID_SUPERHEATED = CoolantContainer.HOT; - public static final int FLUID_COOLANT = CoolantContainer.COLD; - - private static final float passiveCoolingPowerEfficiency = 0.5f; // 50% power penalty, so this comes out as about 1/3 a basic water-cooled reactor - private static final float passiveCoolingTransferEfficiency = 0.2f; // 20% of available heat transferred per tick when passively cooled - private static final float reactorHeatLossConductivity = 0.001f; // circa 1RF per tick per external surface block - - // Game stuff - stored - protected boolean active; - private float reactorHeat; - private float fuelHeat; - private WasteEjectionSetting wasteEjection; - private float energyStored; - protected FuelContainer fuelContainer; - protected RadiationHelper radiationHelper; - protected CoolantContainer coolantContainer; - - // Game stuff - derived at runtime - protected float fuelToReactorHeatTransferCoefficient; - protected float reactorToCoolantSystemHeatTransferCoefficient; - protected float reactorHeatLossCoefficient; - - protected Iterator currentFuelRod; - int reactorVolume; - - // UI stuff - private float energyGeneratedLastTick; - private float fuelConsumedLastTick; - - public enum WasteEjectionSetting { - kAutomatic, // Full auto, always remove waste - kManual, // Manual, only on button press - } - public static final WasteEjectionSetting[] s_EjectionSettings = WasteEjectionSetting.values(); - - // Lists of connected parts - private Set attachedPowerTaps; - private Set attachedTickables; - - private Set attachedControlRods; // Highest internal Y-coordinate in the fuel column - private Set attachedAccessPorts; - private Set attachedControllers; - - private Set attachedFuelRods; - private Set attachedCoolantPorts; - - private Set attachedGlass; - - // Updates - private Set updatePlayers; - private int ticksSinceLastUpdate; - private static final int ticksBetweenUpdates = 3; - private static final int maxEnergyStored = 10000000; - - public MultiblockReactor(World world) { - super(world); - - // Game stuff - active = false; - reactorHeat = 0f; - fuelHeat = 0f; - energyStored = 0f; - wasteEjection = WasteEjectionSetting.kAutomatic; - - // Derived stats - fuelToReactorHeatTransferCoefficient = 0f; - reactorToCoolantSystemHeatTransferCoefficient = 0f; - reactorHeatLossCoefficient = 0f; - - // UI and stats - energyGeneratedLastTick = 0f; - fuelConsumedLastTick = 0f; - - - attachedPowerTaps = new HashSet(); - attachedTickables = new HashSet(); - attachedControlRods = new HashSet(); - attachedAccessPorts = new HashSet(); - attachedControllers = new HashSet(); - attachedFuelRods = new HashSet(); - attachedCoolantPorts = new HashSet(); - attachedGlass = new HashSet(); - - currentFuelRod = null; - - updatePlayers = new HashSet(); - - ticksSinceLastUpdate = 0; - fuelContainer = new FuelContainer(); - radiationHelper = new RadiationHelper(); - coolantContainer = new CoolantContainer(); - - reactorVolume = 0; - } - - public void beginUpdatingPlayer(EntityPlayer playerToUpdate) { - updatePlayers.add(playerToUpdate); - sendIndividualUpdate(playerToUpdate); - } - - public void stopUpdatingPlayer(EntityPlayer playerToRemove) { - updatePlayers.remove(playerToRemove); - } - - @Override - protected void onBlockAdded(IMultiblockPart part) { - if(part instanceof TileEntityReactorAccessPort) { - attachedAccessPorts.add((TileEntityReactorAccessPort)part); - } - - if(part instanceof TileEntityReactorControlRod) { - TileEntityReactorControlRod controlRod = (TileEntityReactorControlRod)part; - attachedControlRods.add(controlRod); - } - - if(part instanceof TileEntityReactorPowerTap) { - attachedPowerTaps.add((TileEntityReactorPowerTap)part); - } - - if(part instanceof TileEntityReactorPart) { - TileEntityReactorPart reactorPart = (TileEntityReactorPart)part; - if(BlockReactorPart.isController(reactorPart.getBlockMetadata())) { - attachedControllers.add(reactorPart); - } - } - - if(part instanceof ITickableMultiblockPart) { - attachedTickables.add((ITickableMultiblockPart)part); - } - - if(part instanceof TileEntityReactorFuelRod) { - TileEntityReactorFuelRod fuelRod = (TileEntityReactorFuelRod)part; - attachedFuelRods.add(fuelRod); - - // Reset iterator - currentFuelRod = attachedFuelRods.iterator(); - - if(worldObj.isRemote) { - worldObj.markBlockForUpdate(fuelRod.xCoord, fuelRod.yCoord, fuelRod.zCoord); - } - } - - if(part instanceof TileEntityReactorCoolantPort) { - attachedCoolantPorts.add((TileEntityReactorCoolantPort) part); - } - - if(part instanceof TileEntityReactorGlass) { - attachedGlass.add((TileEntityReactorGlass)part); - } - } - - @Override - protected void onBlockRemoved(IMultiblockPart part) { - if(part instanceof TileEntityReactorAccessPort) { - attachedAccessPorts.remove((TileEntityReactorAccessPort)part); - } - - if(part instanceof TileEntityReactorControlRod) { - attachedControlRods.remove((TileEntityReactorControlRod)part); - } - - if(part instanceof TileEntityReactorPowerTap) { - attachedPowerTaps.remove((TileEntityReactorPowerTap)part); - } - - if(part instanceof TileEntityReactorPart) { - TileEntityReactorPart reactorPart = (TileEntityReactorPart)part; - if(BlockReactorPart.isController(reactorPart.getBlockMetadata())) { - attachedControllers.remove(reactorPart); - } - } - - if(part instanceof ITickableMultiblockPart) { - attachedTickables.remove((ITickableMultiblockPart)part); - } - - if(part instanceof TileEntityReactorFuelRod) { - attachedFuelRods.remove(part); - currentFuelRod = attachedFuelRods.iterator(); - } - - if(part instanceof TileEntityReactorCoolantPort) { - attachedCoolantPorts.remove((TileEntityReactorCoolantPort)part); - } - - if(part instanceof TileEntityReactorGlass) { - attachedGlass.remove((TileEntityReactorGlass)part); - } - } - - @Override - protected void isMachineWhole() throws MultiblockValidationException { - // Ensure that there is at least one controller and control rod attached. - if(attachedControlRods.size() < 1) { - throw new MultiblockValidationException("Not enough control rods. Reactors require at least 1."); - } - - if(attachedControllers.size() < 1) { - throw new MultiblockValidationException("Not enough controllers. Reactors require at least 1."); - } - - super.isMachineWhole(); - } - - @Override - public void updateClient() {} - - // Update loop. Only called when the machine is assembled. - @Override - public boolean updateServer() { - if(Float.isNaN(this.getReactorHeat())) { - this.setReactorHeat(0.0f); - } - - float oldHeat = this.getReactorHeat(); - float oldEnergy = this.getEnergyStored(); - energyGeneratedLastTick = 0f; - fuelConsumedLastTick = 0f; - - float newHeat = 0f; - - if(getActive()) { - // Select a control rod to radiate from. Reset the iterator and select a new Y-level if needed. - if(!currentFuelRod.hasNext()) { - currentFuelRod = attachedFuelRods.iterator(); - } - - // Radiate from that control rod - TileEntityReactorFuelRod source = currentFuelRod.next(); - TileEntityReactorControlRod sourceControlRod = (TileEntityReactorControlRod)worldObj.getTileEntity(source.xCoord, getMaximumCoord().y, source.zCoord); - if(sourceControlRod != null) - { - RadiationData radData = radiationHelper.radiate(worldObj, fuelContainer, source, sourceControlRod, getFuelHeat(), getReactorHeat(), attachedControlRods.size()); - - // Assimilate results of radiation - if(radData != null) { - addFuelHeat(radData.getFuelHeatChange(attachedFuelRods.size())); - addReactorHeat(radData.getEnvironmentHeatChange(getReactorVolume())); - fuelConsumedLastTick += radData.fuelUsage; - } - } - } - - // Allow radiation to decay even when reactor is off. - radiationHelper.tick(getActive()); - - // If we can, poop out waste and inject new fuel. - if(wasteEjection == WasteEjectionSetting.kAutomatic) { - ejectWaste(false, null); - } - - refuel(); - - // Heat Transfer: Fuel Pool <> Reactor Environment - float tempDiff = fuelHeat - reactorHeat; - if(tempDiff > 0.01f) { - float rfTransferred = tempDiff * fuelToReactorHeatTransferCoefficient; - float fuelRf = StaticUtils.Energy.getRFFromVolumeAndTemp(attachedFuelRods.size(), fuelHeat); - - fuelRf -= rfTransferred; - setFuelHeat(StaticUtils.Energy.getTempFromVolumeAndRF(attachedFuelRods.size(), fuelRf)); - - // Now see how much the reactor's temp has increased - float reactorRf = StaticUtils.Energy.getRFFromVolumeAndTemp(getReactorVolume(), getReactorHeat()); - reactorRf += rfTransferred; - setReactorHeat(StaticUtils.Energy.getTempFromVolumeAndRF(getReactorVolume(), reactorRf)); - } - - // If we have a temperature differential between environment and coolant system, move heat between them. - tempDiff = getReactorHeat() - getCoolantTemperature(); - if(tempDiff > 0.01f) { - float rfTransferred = tempDiff * reactorToCoolantSystemHeatTransferCoefficient; - float reactorRf = StaticUtils.Energy.getRFFromVolumeAndTemp(getReactorVolume(), getReactorHeat()); - - if(isPassivelyCooled()) { - rfTransferred *= passiveCoolingTransferEfficiency; - generateEnergy(rfTransferred * passiveCoolingPowerEfficiency); - } - else { - rfTransferred -= coolantContainer.onAbsorbHeat(rfTransferred); - energyGeneratedLastTick = coolantContainer.getFluidVaporizedLastTick(); // Piggyback so we don't have useless stuff in the update packet - } - - reactorRf -= rfTransferred; - setReactorHeat(StaticUtils.Energy.getTempFromVolumeAndRF(getReactorVolume(), reactorRf)); - } - - // Do passive heat loss - this is always versus external environment - tempDiff = getReactorHeat() - getPassiveCoolantTemperature(); - if(tempDiff > 0.000001f) { - float rfLost = Math.max(1f, tempDiff * reactorHeatLossCoefficient); // Lose at least 1RF/t - float reactorNewRf = Math.max(0f, StaticUtils.Energy.getRFFromVolumeAndTemp(getReactorVolume(), getReactorHeat()) - rfLost); - setReactorHeat(StaticUtils.Energy.getTempFromVolumeAndRF(getReactorVolume(), reactorNewRf)); - } - - // Prevent cryogenics - if(reactorHeat < 0f) { setReactorHeat(0f); } - if(fuelHeat < 0f) { setFuelHeat(0f); } - - // Distribute available power - int energyAvailable = (int)getEnergyStored(); - int energyRemaining = energyAvailable; - if(attachedPowerTaps.size() > 0 && energyRemaining > 0) { - // First, try to distribute fairly - int splitEnergy = energyRemaining / attachedPowerTaps.size(); - for(TileEntityReactorPowerTap powerTap : attachedPowerTaps) { - if(energyRemaining <= 0) { break; } - if(!powerTap.isConnected()) { continue; } - - energyRemaining -= splitEnergy - powerTap.onProvidePower(splitEnergy); - } - - // Next, just hose out whatever we can, if we have any left - if(energyRemaining > 0) { - for(TileEntityReactorPowerTap powerTap : attachedPowerTaps) { - if(energyRemaining <= 0) { break; } - if(!powerTap.isConnected()) { continue; } - - energyRemaining = powerTap.onProvidePower(energyRemaining); - } - } - } - - if(energyAvailable != energyRemaining) { - reduceStoredEnergy((energyAvailable - energyRemaining)); - } - - // Send updates periodically - ticksSinceLastUpdate++; - if(ticksSinceLastUpdate >= ticksBetweenUpdates) { - ticksSinceLastUpdate = 0; - sendTickUpdate(); - } - - // TODO: Overload/overheat - - // Update any connected tickables - for(ITickableMultiblockPart tickable : attachedTickables) { - tickable.onMultiblockServerTick(); - } - - if(attachedGlass.size() > 0 && fuelContainer.shouldUpdate()) { - markReferenceCoordForUpdate(); - } - - return (oldHeat != this.getReactorHeat() || oldEnergy != this.getEnergyStored()); - } - - public void setEnergyStored(float oldEnergy) { - energyStored = oldEnergy; - if(energyStored < 0.0 || Float.isNaN(energyStored)) { - energyStored = 0.0f; - } - else if(energyStored > maxEnergyStored) { - energyStored = maxEnergyStored; - } - } - - /** - * Generate energy, internally. Will be multiplied by the BR Setting powerProductionMultiplier - * @param newEnergy Base, unmultiplied energy to generate - */ - protected void generateEnergy(float newEnergy) { - newEnergy = newEnergy * BigReactors.powerProductionMultiplier * BigReactors.reactorPowerProductionMultiplier; - this.energyGeneratedLastTick += newEnergy; - this.addStoredEnergy(newEnergy); - } - - /** - * Add some energy to the internal storage buffer. - * Will not increase the buffer above the maximum or reduce it below 0. - * @param newEnergy - */ - protected void addStoredEnergy(float newEnergy) { - if(Float.isNaN(newEnergy)) { return; } - - energyStored += newEnergy; - if(energyStored > maxEnergyStored) { - energyStored = maxEnergyStored; - } - if(-0.00001f < energyStored && energyStored < 0.00001f) { - // Clamp to zero - energyStored = 0f; - } - } - - /** - * Remove some energy from the internal storage buffer. - * Will not reduce the buffer below 0. - * @param energy Amount by which the buffer should be reduced. - */ - protected void reduceStoredEnergy(float energy) { - this.addStoredEnergy(-1f * energy); - } - - public void setActive(boolean act) { - if(act == this.active) { return; } - this.active = act; - - for(IMultiblockPart part : connectedParts) { - if(this.active) { part.onMachineActivated(); } - else { part.onMachineDeactivated(); } - } - - if(worldObj.isRemote) { - // Force controllers to re-render on client - for(IMultiblockPart part : attachedControllers) { - worldObj.markBlockForUpdate(part.xCoord, part.yCoord, part.zCoord); - } - } - else { - this.markReferenceCoordForUpdate(); - } - } - - protected void addReactorHeat(float newCasingHeat) { - if(Float.isNaN(newCasingHeat)) { - return; - } - - reactorHeat += newCasingHeat; - // Clamp to zero to prevent floating point issues - if(-0.00001f < reactorHeat && reactorHeat < 0.00001f) { reactorHeat = 0.0f; } - } - - public float getReactorHeat() { - return reactorHeat; - } - - public void setReactorHeat(float newHeat) { - if(Float.isNaN(newHeat)) { - reactorHeat = 0.0f; - } - else { - reactorHeat = newHeat; - } - } - - protected void addFuelHeat(float additionalHeat) { - if(Float.isNaN(additionalHeat)) { return; } - - fuelHeat += additionalHeat; - if(-0.00001f < fuelHeat & fuelHeat < 0.00001f) { fuelHeat = 0f; } - } - - public float getFuelHeat() { return fuelHeat; } - - public void setFuelHeat(float newFuelHeat) { - if(Float.isNaN(newFuelHeat)) { fuelHeat = 0f; } - else { fuelHeat = newFuelHeat; } - } - - public int getFuelRodCount() { - return attachedControlRods.size(); - } - - // Static validation helpers - // Water, air, and metal blocks - @Override - protected void isBlockGoodForInterior(World world, int x, int y, int z) throws MultiblockValidationException { - if(world.isAirBlock(x, y, z)) { return; } // Air is OK - - Material material = world.getBlock(x, y, z).getMaterial(); - if(material == net.minecraft.block.material.MaterialLiquid.water) { - return; - } - - Block block = world.getBlock(x, y, z); - if(block == Blocks.iron_block || block == Blocks.gold_block || block == Blocks.diamond_block || block == Blocks.emerald_block) { - return; - } - - // Permit registered moderator blocks - int metadata = world.getBlockMetadata(x, y, z); - - if(ReactorInterior.getBlockData(ItemHelper.oreProxy.getOreName(new ItemStack(block, 1, metadata))) != null) { - return; - } - - // Permit TE fluids - if(block != null) { - if(block instanceof IFluidBlock) { - Fluid fluid = ((IFluidBlock)block).getFluid(); - String fluidName = fluid.getName(); - if(ReactorInterior.getFluidData(fluidName) != null) { return; } - - throw new MultiblockValidationException(String.format("%d, %d, %d - The fluid %s is not valid for the reactor's interior", x, y, z, fluidName)); - } - else { - throw new MultiblockValidationException(String.format("%d, %d, %d - %s is not valid for the reactor's interior", x, y, z, block.getLocalizedName())); - } - } - else { - throw new MultiblockValidationException(String.format("%d, %d, %d - Null block found, not valid for the reactor's interior", x, y, z)); - } - } - - @Override - public void writeToNBT(NBTTagCompound data) { - data.setBoolean("reactorActive", this.active); - data.setFloat("heat", this.reactorHeat); - data.setFloat("fuelHeat", fuelHeat); - data.setFloat("storedEnergy", this.energyStored); - data.setInteger("wasteEjection2", this.wasteEjection.ordinal()); - data.setTag("fuelContainer", fuelContainer.writeToNBT(new NBTTagCompound())); - data.setTag("radiation", radiationHelper.writeToNBT(new NBTTagCompound())); - data.setTag("coolantContainer", coolantContainer.writeToNBT(new NBTTagCompound())); - } - - @Override - public void readFromNBT(NBTTagCompound data) { - if(data.hasKey("reactorActive")) { - setActive(data.getBoolean("reactorActive")); - } - - if(data.hasKey("heat")) { - setReactorHeat(Math.max(getReactorHeat(), data.getFloat("heat"))); - } - - if(data.hasKey("storedEnergy")) { - setEnergyStored(Math.max(getEnergyStored(), data.getFloat("storedEnergy"))); - } - - if(data.hasKey("wasteEjection2")) { - this.wasteEjection = s_EjectionSettings[data.getInteger("wasteEjection2")]; - } - - if(data.hasKey("fuelHeat")) { - setFuelHeat(data.getFloat("fuelHeat")); - } - - if(data.hasKey("fuelContainer")) { - fuelContainer.readFromNBT(data.getCompoundTag("fuelContainer")); - } - - if(data.hasKey("radiation")) { - radiationHelper.readFromNBT(data.getCompoundTag("radiation")); - } - - if(data.hasKey("coolantContainer")) { - coolantContainer.readFromNBT(data.getCompoundTag("coolantContainer")); - } - } - - @Override - protected int getMinimumNumberOfBlocksForAssembledMachine() { - // Hollow cube. - return 26; - } - - @Override - public void formatDescriptionPacket(NBTTagCompound data) { - writeToNBT(data); - } - - @Override - public void decodeDescriptionPacket(NBTTagCompound data) { - readFromNBT(data); - onFuelStatusChanged(); - } - - // Network & Storage methods - /* - * Serialize a reactor into a given Byte buffer - * @param buf The byte buffer to serialize into - */ - public void serialize(ByteBuf buf) { - int fuelTypeID, wasteTypeID, coolantTypeID, vaporTypeID; - - // Marshal fluid types into integers - { - Fluid coolantType, vaporType; - coolantType = coolantContainer.getCoolantType(); - vaporType = coolantContainer.getVaporType(); - coolantTypeID = coolantType == null ? -1 : coolantType.getID(); - vaporTypeID = vaporType == null ? -1 : vaporType.getID(); - } - - // Basic data - buf.writeBoolean(active); - buf.writeFloat(reactorHeat); - buf.writeFloat(fuelHeat); - buf.writeFloat(energyStored); - buf.writeFloat(radiationHelper.getFertility()); - - // Statistics - buf.writeFloat(energyGeneratedLastTick); - buf.writeFloat(fuelConsumedLastTick); - - // Coolant data - buf.writeInt(coolantTypeID); - buf.writeInt(coolantContainer.getCoolantAmount()); - buf.writeInt(vaporTypeID); - buf.writeInt(coolantContainer.getVaporAmount()); - - fuelContainer.serialize(buf); - } - - /* - * Deserialize a reactor's data from a given Byte buffer - * @param buf The byte buffer containing reactor data - */ - public void deserialize(ByteBuf buf) { - // Basic data - setActive(buf.readBoolean()); - setReactorHeat(buf.readFloat()); - setFuelHeat(buf.readFloat()); - setEnergyStored(buf.readFloat()); - radiationHelper.setFertility(buf.readFloat()); - - // Statistics - setEnergyGeneratedLastTick(buf.readFloat()); - setFuelConsumedLastTick(buf.readFloat()); - - - // Coolant data - int coolantTypeID = buf.readInt(); - int coolantAmt = buf.readInt(); - int vaporTypeID = buf.readInt(); - int vaporAmt = buf.readInt(); - - // Fuel & waste data - fuelContainer.deserialize(buf); - - if(coolantTypeID == -1) { - coolantContainer.emptyCoolant(); - } - else { - coolantContainer.setCoolant(new FluidStack(FluidRegistry.getFluid(coolantTypeID), coolantAmt)); - } - - if(vaporTypeID == -1) { - coolantContainer.emptyVapor(); - } - else { - coolantContainer.setVapor(new FluidStack(FluidRegistry.getFluid(vaporTypeID), vaporAmt)); - } - - } - - protected IMessage getUpdatePacket() { +public class MultiblockReactor extends RectangularMultiblockControllerBase + implements IEnergyProvider, IReactorFuelInfo, IMultipleFluidHandler, IActivateable { + + public static final int FuelCapacityPerFuelRod = 4 * Reactants.standardSolidReactantAmount; // 4 ingots per rod + + public static final int FLUID_SUPERHEATED = CoolantContainer.HOT; + public static final int FLUID_COOLANT = CoolantContainer.COLD; + + private static final float passiveCoolingPowerEfficiency = 0.5f; // 50% power penalty, so this comes out as about + // 1/3 a basic water-cooled reactor + private static final float passiveCoolingTransferEfficiency = 0.2f; // 20% of available heat transferred per tick + // when passively cooled + private static final float reactorHeatLossConductivity = 0.001f; // circa 1RF per tick per external surface block + + // Game stuff - stored + protected boolean active; + private float reactorHeat; + private float fuelHeat; + private WasteEjectionSetting wasteEjection; + private float energyStored; + protected FuelContainer fuelContainer; + protected RadiationHelper radiationHelper; + protected CoolantContainer coolantContainer; + + // Game stuff - derived at runtime + protected float fuelToReactorHeatTransferCoefficient; + protected float reactorToCoolantSystemHeatTransferCoefficient; + protected float reactorHeatLossCoefficient; + + protected Iterator currentFuelRod; + int reactorVolume; + + // UI stuff + private float energyGeneratedLastTick; + private float fuelConsumedLastTick; + + public enum WasteEjectionSetting { + kAutomatic, // Full auto, always remove waste + kManual, // Manual, only on button press + } + + public static final WasteEjectionSetting[] s_EjectionSettings = WasteEjectionSetting.values(); + + // Lists of connected parts + private Set attachedPowerTaps; + private Set attachedTickables; + + private Set attachedControlRods; // Highest internal Y-coordinate in the fuel column + private Set attachedAccessPorts; + private Set attachedControllers; + + private Set attachedFuelRods; + private Set attachedCoolantPorts; + + private Set attachedGlass; + + // Updates + private Set updatePlayers; + private int ticksSinceLastUpdate; + private static final int ticksBetweenUpdates = 3; + private static final int maxEnergyStored = 10000000; + + public MultiblockReactor(World world) { + super(world); + + // Game stuff + active = false; + reactorHeat = 0f; + fuelHeat = 0f; + energyStored = 0f; + wasteEjection = WasteEjectionSetting.kAutomatic; + + // Derived stats + fuelToReactorHeatTransferCoefficient = 0f; + reactorToCoolantSystemHeatTransferCoefficient = 0f; + reactorHeatLossCoefficient = 0f; + + // UI and stats + energyGeneratedLastTick = 0f; + fuelConsumedLastTick = 0f; + + attachedPowerTaps = new HashSet(); + attachedTickables = new HashSet(); + attachedControlRods = new HashSet(); + attachedAccessPorts = new HashSet(); + attachedControllers = new HashSet(); + attachedFuelRods = new HashSet(); + attachedCoolantPorts = new HashSet(); + attachedGlass = new HashSet(); + + currentFuelRod = null; + + updatePlayers = new HashSet(); + + ticksSinceLastUpdate = 0; + fuelContainer = new FuelContainer(); + radiationHelper = new RadiationHelper(); + coolantContainer = new CoolantContainer(); + + reactorVolume = 0; + } + + public void beginUpdatingPlayer(EntityPlayer playerToUpdate) { + updatePlayers.add(playerToUpdate); + sendIndividualUpdate(playerToUpdate); + } + + public void stopUpdatingPlayer(EntityPlayer playerToRemove) { + updatePlayers.remove(playerToRemove); + } + + @Override + protected void onBlockAdded(IMultiblockPart part) { + if (part instanceof TileEntityReactorAccessPort) { + attachedAccessPorts.add((TileEntityReactorAccessPort) part); + } + + if (part instanceof TileEntityReactorControlRod) { + TileEntityReactorControlRod controlRod = (TileEntityReactorControlRod) part; + attachedControlRods.add(controlRod); + } + + if (part instanceof TileEntityReactorPowerTap) { + attachedPowerTaps.add((TileEntityReactorPowerTap) part); + } + + if (part instanceof TileEntityReactorPart) { + TileEntityReactorPart reactorPart = (TileEntityReactorPart) part; + if (BlockReactorPart.isController(reactorPart.getBlockMetadata())) { + attachedControllers.add(reactorPart); + } + } + + if (part instanceof ITickableMultiblockPart) { + attachedTickables.add((ITickableMultiblockPart) part); + } + + if (part instanceof TileEntityReactorFuelRod) { + TileEntityReactorFuelRod fuelRod = (TileEntityReactorFuelRod) part; + attachedFuelRods.add(fuelRod); + + // Reset iterator + currentFuelRod = attachedFuelRods.iterator(); + + if (worldObj.isRemote) { + worldObj.markBlockForUpdate(fuelRod.xCoord, fuelRod.yCoord, fuelRod.zCoord); + } + } + + if (part instanceof TileEntityReactorCoolantPort) { + attachedCoolantPorts.add((TileEntityReactorCoolantPort) part); + } + + if (part instanceof TileEntityReactorGlass) { + attachedGlass.add((TileEntityReactorGlass) part); + } + } + + @Override + protected void onBlockRemoved(IMultiblockPart part) { + if (part instanceof TileEntityReactorAccessPort) { + attachedAccessPorts.remove((TileEntityReactorAccessPort) part); + } + + if (part instanceof TileEntityReactorControlRod) { + attachedControlRods.remove((TileEntityReactorControlRod) part); + } + + if (part instanceof TileEntityReactorPowerTap) { + attachedPowerTaps.remove((TileEntityReactorPowerTap) part); + } + + if (part instanceof TileEntityReactorPart) { + TileEntityReactorPart reactorPart = (TileEntityReactorPart) part; + if (BlockReactorPart.isController(reactorPart.getBlockMetadata())) { + attachedControllers.remove(reactorPart); + } + } + + if (part instanceof ITickableMultiblockPart) { + attachedTickables.remove((ITickableMultiblockPart) part); + } + + if (part instanceof TileEntityReactorFuelRod) { + attachedFuelRods.remove(part); + currentFuelRod = attachedFuelRods.iterator(); + } + + if (part instanceof TileEntityReactorCoolantPort) { + attachedCoolantPorts.remove((TileEntityReactorCoolantPort) part); + } + + if (part instanceof TileEntityReactorGlass) { + attachedGlass.remove((TileEntityReactorGlass) part); + } + } + + @Override + protected void isMachineWhole() throws MultiblockValidationException { + // Ensure that there is at least one controller and control rod attached. + if (attachedControlRods.size() < 1) { + throw new MultiblockValidationException("Not enough control rods. Reactors require at least 1."); + } + + if (attachedControllers.size() < 1) { + throw new MultiblockValidationException("Not enough controllers. Reactors require at least 1."); + } + + super.isMachineWhole(); + } + + @Override + public void updateClient() {} + + // Update loop. Only called when the machine is assembled. + @Override + public boolean updateServer() { + if (Float.isNaN(this.getReactorHeat())) { + this.setReactorHeat(0.0f); + } + + float oldHeat = this.getReactorHeat(); + float oldEnergy = this.getEnergyStored(); + energyGeneratedLastTick = 0f; + fuelConsumedLastTick = 0f; + + float newHeat = 0f; + + if (getActive()) { + // Select a control rod to radiate from. Reset the iterator and select a new Y-level if needed. + if (!currentFuelRod.hasNext()) { + currentFuelRod = attachedFuelRods.iterator(); + } + + // Radiate from that control rod + TileEntityReactorFuelRod source = currentFuelRod.next(); + TileEntityReactorControlRod sourceControlRod = (TileEntityReactorControlRod) worldObj + .getTileEntity(source.xCoord, getMaximumCoord().y, source.zCoord); + if (sourceControlRod != null) { + RadiationData radData = radiationHelper.radiate( + worldObj, + fuelContainer, + source, + sourceControlRod, + getFuelHeat(), + getReactorHeat(), + attachedControlRods.size()); + + // Assimilate results of radiation + if (radData != null) { + addFuelHeat(radData.getFuelHeatChange(attachedFuelRods.size())); + addReactorHeat(radData.getEnvironmentHeatChange(getReactorVolume())); + fuelConsumedLastTick += radData.fuelUsage; + } + } + } + + // Allow radiation to decay even when reactor is off. + radiationHelper.tick(getActive()); + + // If we can, poop out waste and inject new fuel. + if (wasteEjection == WasteEjectionSetting.kAutomatic) { + ejectWaste(false, null); + } + + refuel(); + + // Heat Transfer: Fuel Pool <> Reactor Environment + float tempDiff = fuelHeat - reactorHeat; + if (tempDiff > 0.01f) { + float rfTransferred = tempDiff * fuelToReactorHeatTransferCoefficient; + float fuelRf = StaticUtils.Energy.getRFFromVolumeAndTemp(attachedFuelRods.size(), fuelHeat); + + fuelRf -= rfTransferred; + setFuelHeat(StaticUtils.Energy.getTempFromVolumeAndRF(attachedFuelRods.size(), fuelRf)); + + // Now see how much the reactor's temp has increased + float reactorRf = StaticUtils.Energy.getRFFromVolumeAndTemp(getReactorVolume(), getReactorHeat()); + reactorRf += rfTransferred; + setReactorHeat(StaticUtils.Energy.getTempFromVolumeAndRF(getReactorVolume(), reactorRf)); + } + + // If we have a temperature differential between environment and coolant system, move heat between them. + tempDiff = getReactorHeat() - getCoolantTemperature(); + if (tempDiff > 0.01f) { + float rfTransferred = tempDiff * reactorToCoolantSystemHeatTransferCoefficient; + float reactorRf = StaticUtils.Energy.getRFFromVolumeAndTemp(getReactorVolume(), getReactorHeat()); + + if (isPassivelyCooled()) { + rfTransferred *= passiveCoolingTransferEfficiency; + generateEnergy(rfTransferred * passiveCoolingPowerEfficiency); + } else { + rfTransferred -= coolantContainer.onAbsorbHeat(rfTransferred); + energyGeneratedLastTick = coolantContainer.getFluidVaporizedLastTick(); // Piggyback so we don't have + // useless stuff in the update + // packet + } + + reactorRf -= rfTransferred; + setReactorHeat(StaticUtils.Energy.getTempFromVolumeAndRF(getReactorVolume(), reactorRf)); + } + + // Do passive heat loss - this is always versus external environment + tempDiff = getReactorHeat() - getPassiveCoolantTemperature(); + if (tempDiff > 0.000001f) { + float rfLost = Math.max(1f, tempDiff * reactorHeatLossCoefficient); // Lose at least 1RF/t + float reactorNewRf = Math + .max(0f, StaticUtils.Energy.getRFFromVolumeAndTemp(getReactorVolume(), getReactorHeat()) - rfLost); + setReactorHeat(StaticUtils.Energy.getTempFromVolumeAndRF(getReactorVolume(), reactorNewRf)); + } + + // Prevent cryogenics + if (reactorHeat < 0f) { + setReactorHeat(0f); + } + if (fuelHeat < 0f) { + setFuelHeat(0f); + } + + // Distribute available power + int energyAvailable = (int) getEnergyStored(); + int energyRemaining = energyAvailable; + if (attachedPowerTaps.size() > 0 && energyRemaining > 0) { + // First, try to distribute fairly + int splitEnergy = energyRemaining / attachedPowerTaps.size(); + for (TileEntityReactorPowerTap powerTap : attachedPowerTaps) { + if (energyRemaining <= 0) { + break; + } + if (!powerTap.isConnected()) { + continue; + } + + energyRemaining -= splitEnergy - powerTap.onProvidePower(splitEnergy); + } + + // Next, just hose out whatever we can, if we have any left + if (energyRemaining > 0) { + for (TileEntityReactorPowerTap powerTap : attachedPowerTaps) { + if (energyRemaining <= 0) { + break; + } + if (!powerTap.isConnected()) { + continue; + } + + energyRemaining = powerTap.onProvidePower(energyRemaining); + } + } + } + + if (energyAvailable != energyRemaining) { + reduceStoredEnergy((energyAvailable - energyRemaining)); + } + + // Send updates periodically + ticksSinceLastUpdate++; + if (ticksSinceLastUpdate >= ticksBetweenUpdates) { + ticksSinceLastUpdate = 0; + sendTickUpdate(); + } + + // TODO: Overload/overheat + + // Update any connected tickables + for (ITickableMultiblockPart tickable : attachedTickables) { + tickable.onMultiblockServerTick(); + } + + if (attachedGlass.size() > 0 && fuelContainer.shouldUpdate()) { + markReferenceCoordForUpdate(); + } + + return (oldHeat != this.getReactorHeat() || oldEnergy != this.getEnergyStored()); + } + + public void setEnergyStored(float oldEnergy) { + energyStored = oldEnergy; + if (energyStored < 0.0 || Float.isNaN(energyStored)) { + energyStored = 0.0f; + } else if (energyStored > maxEnergyStored) { + energyStored = maxEnergyStored; + } + } + + /** + * Generate energy, internally. Will be multiplied by the BR Setting powerProductionMultiplier + * + * @param newEnergy Base, unmultiplied energy to generate + */ + protected void generateEnergy(float newEnergy) { + newEnergy = newEnergy * BigReactors.powerProductionMultiplier * BigReactors.reactorPowerProductionMultiplier; + this.energyGeneratedLastTick += newEnergy; + this.addStoredEnergy(newEnergy); + } + + /** + * Add some energy to the internal storage buffer. + * Will not increase the buffer above the maximum or reduce it below 0. + * + * @param newEnergy + */ + protected void addStoredEnergy(float newEnergy) { + if (Float.isNaN(newEnergy)) { + return; + } + + energyStored += newEnergy; + if (energyStored > maxEnergyStored) { + energyStored = maxEnergyStored; + } + if (-0.00001f < energyStored && energyStored < 0.00001f) { + // Clamp to zero + energyStored = 0f; + } + } + + /** + * Remove some energy from the internal storage buffer. + * Will not reduce the buffer below 0. + * + * @param energy Amount by which the buffer should be reduced. + */ + protected void reduceStoredEnergy(float energy) { + this.addStoredEnergy(-1f * energy); + } + + public void setActive(boolean act) { + if (act == this.active) { + return; + } + this.active = act; + + for (IMultiblockPart part : connectedParts) { + if (this.active) { + part.onMachineActivated(); + } else { + part.onMachineDeactivated(); + } + } + + if (worldObj.isRemote) { + // Force controllers to re-render on client + for (IMultiblockPart part : attachedControllers) { + worldObj.markBlockForUpdate(part.xCoord, part.yCoord, part.zCoord); + } + } else { + this.markReferenceCoordForUpdate(); + } + } + + protected void addReactorHeat(float newCasingHeat) { + if (Float.isNaN(newCasingHeat)) { + return; + } + + reactorHeat += newCasingHeat; + // Clamp to zero to prevent floating point issues + if (-0.00001f < reactorHeat && reactorHeat < 0.00001f) { + reactorHeat = 0.0f; + } + } + + public float getReactorHeat() { + return reactorHeat; + } + + public void setReactorHeat(float newHeat) { + if (Float.isNaN(newHeat)) { + reactorHeat = 0.0f; + } else { + reactorHeat = newHeat; + } + } + + protected void addFuelHeat(float additionalHeat) { + if (Float.isNaN(additionalHeat)) { + return; + } + + fuelHeat += additionalHeat; + if (-0.00001f < fuelHeat & fuelHeat < 0.00001f) { + fuelHeat = 0f; + } + } + + public float getFuelHeat() { + return fuelHeat; + } + + public void setFuelHeat(float newFuelHeat) { + if (Float.isNaN(newFuelHeat)) { + fuelHeat = 0f; + } else { + fuelHeat = newFuelHeat; + } + } + + public int getFuelRodCount() { + return attachedControlRods.size(); + } + + // Static validation helpers + // Water, air, and metal blocks + @Override + protected void isBlockGoodForInterior(World world, int x, int y, int z) throws MultiblockValidationException { + if (world.isAirBlock(x, y, z)) { + return; + } // Air is OK + + Material material = world.getBlock(x, y, z) + .getMaterial(); + if (material == net.minecraft.block.material.MaterialLiquid.water) { + return; + } + + Block block = world.getBlock(x, y, z); + if (block == Blocks.iron_block || block == Blocks.gold_block + || block == Blocks.diamond_block + || block == Blocks.emerald_block) { + return; + } + + // Permit registered moderator blocks + int metadata = world.getBlockMetadata(x, y, z); + + if (ReactorInterior.getBlockData(ItemHelper.oreProxy.getOreName(new ItemStack(block, 1, metadata))) != null) { + return; + } + + // Permit TE fluids + if (block != null) { + if (block instanceof IFluidBlock) { + Fluid fluid = ((IFluidBlock) block).getFluid(); + String fluidName = fluid.getName(); + if (ReactorInterior.getFluidData(fluidName) != null) { + return; + } + + throw new MultiblockValidationException( + String.format( + "%d, %d, %d - The fluid %s is not valid for the reactor's interior", + x, + y, + z, + fluidName)); + } else { + throw new MultiblockValidationException( + String.format( + "%d, %d, %d - %s is not valid for the reactor's interior", + x, + y, + z, + block.getLocalizedName())); + } + } else { + throw new MultiblockValidationException( + String.format("%d, %d, %d - Null block found, not valid for the reactor's interior", x, y, z)); + } + } + + @Override + public void writeToNBT(NBTTagCompound data) { + data.setBoolean("reactorActive", this.active); + data.setFloat("heat", this.reactorHeat); + data.setFloat("fuelHeat", fuelHeat); + data.setFloat("storedEnergy", this.energyStored); + data.setInteger("wasteEjection2", this.wasteEjection.ordinal()); + data.setTag("fuelContainer", fuelContainer.writeToNBT(new NBTTagCompound())); + data.setTag("radiation", radiationHelper.writeToNBT(new NBTTagCompound())); + data.setTag("coolantContainer", coolantContainer.writeToNBT(new NBTTagCompound())); + } + + @Override + public void readFromNBT(NBTTagCompound data) { + if (data.hasKey("reactorActive")) { + setActive(data.getBoolean("reactorActive")); + } + + if (data.hasKey("heat")) { + setReactorHeat(Math.max(getReactorHeat(), data.getFloat("heat"))); + } + + if (data.hasKey("storedEnergy")) { + setEnergyStored(Math.max(getEnergyStored(), data.getFloat("storedEnergy"))); + } + + if (data.hasKey("wasteEjection2")) { + this.wasteEjection = s_EjectionSettings[data.getInteger("wasteEjection2")]; + } + + if (data.hasKey("fuelHeat")) { + setFuelHeat(data.getFloat("fuelHeat")); + } + + if (data.hasKey("fuelContainer")) { + fuelContainer.readFromNBT(data.getCompoundTag("fuelContainer")); + } + + if (data.hasKey("radiation")) { + radiationHelper.readFromNBT(data.getCompoundTag("radiation")); + } + + if (data.hasKey("coolantContainer")) { + coolantContainer.readFromNBT(data.getCompoundTag("coolantContainer")); + } + } + + @Override + protected int getMinimumNumberOfBlocksForAssembledMachine() { + // Hollow cube. + return 26; + } + + @Override + public void formatDescriptionPacket(NBTTagCompound data) { + writeToNBT(data); + } + + @Override + public void decodeDescriptionPacket(NBTTagCompound data) { + readFromNBT(data); + onFuelStatusChanged(); + } + + // Network & Storage methods + /* + * Serialize a reactor into a given Byte buffer + * @param buf The byte buffer to serialize into + */ + public void serialize(ByteBuf buf) { + int fuelTypeID, wasteTypeID, coolantTypeID, vaporTypeID; + + // Marshal fluid types into integers + { + Fluid coolantType, vaporType; + coolantType = coolantContainer.getCoolantType(); + vaporType = coolantContainer.getVaporType(); + coolantTypeID = coolantType == null ? -1 : coolantType.getID(); + vaporTypeID = vaporType == null ? -1 : vaporType.getID(); + } + + // Basic data + buf.writeBoolean(active); + buf.writeFloat(reactorHeat); + buf.writeFloat(fuelHeat); + buf.writeFloat(energyStored); + buf.writeFloat(radiationHelper.getFertility()); + + // Statistics + buf.writeFloat(energyGeneratedLastTick); + buf.writeFloat(fuelConsumedLastTick); + + // Coolant data + buf.writeInt(coolantTypeID); + buf.writeInt(coolantContainer.getCoolantAmount()); + buf.writeInt(vaporTypeID); + buf.writeInt(coolantContainer.getVaporAmount()); + + fuelContainer.serialize(buf); + } + + /* + * Deserialize a reactor's data from a given Byte buffer + * @param buf The byte buffer containing reactor data + */ + public void deserialize(ByteBuf buf) { + // Basic data + setActive(buf.readBoolean()); + setReactorHeat(buf.readFloat()); + setFuelHeat(buf.readFloat()); + setEnergyStored(buf.readFloat()); + radiationHelper.setFertility(buf.readFloat()); + + // Statistics + setEnergyGeneratedLastTick(buf.readFloat()); + setFuelConsumedLastTick(buf.readFloat()); + + // Coolant data + int coolantTypeID = buf.readInt(); + int coolantAmt = buf.readInt(); + int vaporTypeID = buf.readInt(); + int vaporAmt = buf.readInt(); + + // Fuel & waste data + fuelContainer.deserialize(buf); + + if (coolantTypeID == -1) { + coolantContainer.emptyCoolant(); + } else { + coolantContainer.setCoolant(new FluidStack(FluidRegistry.getFluid(coolantTypeID), coolantAmt)); + } + + if (vaporTypeID == -1) { + coolantContainer.emptyVapor(); + } else { + coolantContainer.setVapor(new FluidStack(FluidRegistry.getFluid(vaporTypeID), vaporAmt)); + } + + } + + protected IMessage getUpdatePacket() { return new ReactorUpdateMessage(this); - } - - /** - * Sends a full state update to a player. - */ - protected void sendIndividualUpdate(EntityPlayer player) { - if(this.worldObj.isRemote) { return; } - - CommonPacketHandler.INSTANCE.sendTo(getUpdatePacket(), (EntityPlayerMP)player); - } - - /** - * Send an update to any clients with GUIs open - */ - protected void sendTickUpdate() { - if(this.worldObj.isRemote) { return; } - if(this.updatePlayers.size() <= 0) { return; } - - for(EntityPlayer player : updatePlayers) { - CommonPacketHandler.INSTANCE.sendTo(getUpdatePacket(), (EntityPlayerMP)player); - } - } - - /** - * Attempt to distribute a stack of ingots to a given access port, sensitive to the amount and type of ingots already in it. - * @param port The port to which we're distributing ingots. - * @param itemsToDistribute The stack of ingots to distribute. Will be modified during the operation and may be returned with stack size 0. - * @param distributeToInputs Should we try to send ingots to input ports? - * @return The number of waste items distributed, i.e. the differential in stack size for wasteToDistribute. - */ - private int tryDistributeItems(TileEntityReactorAccessPort port, ItemStack itemsToDistribute, boolean distributeToInputs) { - ItemStack existingStack = port.getStackInSlot(TileEntityReactorAccessPort.SLOT_OUTLET); - int initialWasteAmount = itemsToDistribute.stackSize; - if(!port.isInlet() || (distributeToInputs || attachedAccessPorts.size() < 2)) { - // Dump waste preferentially to outlets, unless we only have one access port - if(existingStack == null) { - if(itemsToDistribute.stackSize > port.getInventoryStackLimit()) { - ItemStack newStack = itemsToDistribute.splitStack(port.getInventoryStackLimit()); - port.setInventorySlotContents(TileEntityReactorAccessPort.SLOT_OUTLET, newStack); - } - else { - port.setInventorySlotContents(TileEntityReactorAccessPort.SLOT_OUTLET, itemsToDistribute.copy()); - itemsToDistribute.stackSize = 0; - } - } - else if(existingStack.isItemEqual(itemsToDistribute)) { - if(existingStack.stackSize + itemsToDistribute.stackSize <= existingStack.getMaxStackSize()) { - existingStack.stackSize += itemsToDistribute.stackSize; - itemsToDistribute.stackSize = 0; - } - else { - int amt = existingStack.getMaxStackSize() - existingStack.stackSize; - itemsToDistribute.stackSize -= existingStack.getMaxStackSize() - existingStack.stackSize; - existingStack.stackSize += amt; - } - } - - port.onItemsReceived(); - } - - return initialWasteAmount - itemsToDistribute.stackSize; - } - - @Override - protected void onAssimilated(MultiblockControllerBase otherMachine) { - this.attachedPowerTaps.clear(); - this.attachedTickables.clear(); - this.attachedAccessPorts.clear(); - this.attachedControllers.clear(); - this.attachedControlRods.clear(); - currentFuelRod = null; - } - - @Override - protected void onAssimilate(MultiblockControllerBase otherMachine) { - if(!(otherMachine instanceof MultiblockReactor)) { - BRLog.warning("[%s] Reactor @ %s is attempting to assimilate a non-Reactor machine! That machine's data will be lost!", worldObj.isRemote?"CLIENT":"SERVER", getReferenceCoord()); - return; - } - - MultiblockReactor otherReactor = (MultiblockReactor)otherMachine; - - if(otherReactor.reactorHeat > this.reactorHeat) { setReactorHeat(otherReactor.reactorHeat); } - if(otherReactor.fuelHeat > this.fuelHeat) { setFuelHeat(otherReactor.fuelHeat); } - - if(otherReactor.getEnergyStored() > this.getEnergyStored()) { this.setEnergyStored(otherReactor.getEnergyStored()); } - - fuelContainer.merge(otherReactor.fuelContainer); - radiationHelper.merge(otherReactor.radiationHelper); - coolantContainer.merge(otherReactor.coolantContainer); - } - - @Override - public void onAttachedPartWithMultiblockData(IMultiblockPart part, NBTTagCompound data) { - this.readFromNBT(data); - } - - public float getEnergyStored() { - return energyStored; - } - - /** - * Directly set the waste ejection setting. Will dispatch network updates - * from server to interested clients. - * @param newSetting The new waste ejection setting. - */ - public void setWasteEjection(WasteEjectionSetting newSetting) { - if(this.wasteEjection != newSetting) { - this.wasteEjection = newSetting; - - if(!this.worldObj.isRemote) { - markReferenceCoordDirty(); - - if(this.updatePlayers.size() > 0) { - for(EntityPlayer player : updatePlayers) { - CommonPacketHandler.INSTANCE.sendTo(new ReactorUpdateWasteEjectionMessage(this), (EntityPlayerMP)player); - } - } - } - } - } - - public WasteEjectionSetting getWasteEjection() { - return this.wasteEjection; - } - - protected void refuel() { - // For now, we only need to check fuel ports when we have more space than can accomodate 1 ingot - if(fuelContainer.getRemainingSpace() < Reactants.standardSolidReactantAmount) { - return; - } - - int amtAdded = 0; - - // Loop: Consume input reactants from all ports - for(TileEntityReactorAccessPort port : attachedAccessPorts) - { - if(fuelContainer.getRemainingSpace() <= 0) { break; } - - if(!port.isConnected()) { continue; } - - // See what type of reactant the port contains; if none, skip it. - String portReactantType = port.getInputReactantType(); - int portReactantAmount = port.getInputReactantAmount(); - if(portReactantType == null || portReactantAmount <= 0) { continue; } - - if(!Reactants.isFuel(portReactantType)) { continue; } // Skip nonfuels - - // HACK; TEMPORARY - // Alias blutonium to yellorium temporarily, until mixed fuels are implemented - if(portReactantType.equals(StandardReactants.blutonium)) { - portReactantType = StandardReactants.yellorium; - } - - // How much fuel can we actually add from this type of reactant? - int amountToAdd = fuelContainer.addFuel(portReactantType, portReactantAmount, false); - if(amountToAdd <= 0) { continue; } - - int portCanAdd = port.consumeReactantItem(amountToAdd); - if(portCanAdd <= 0) { continue; } - - amtAdded = fuelContainer.addFuel(portReactantType, portReactantAmount, true); - } - - if(amtAdded > 0) { - markReferenceCoordForUpdate(); - markReferenceCoordDirty(); - } - } - - /** - * Attempt to eject waste contained in the reactor - * @param dumpAll If true, any waste remaining after ejection will be discarded. - * @param destination If set, waste will only be ejected to ports with coordinates matching this one. - */ - public void ejectWaste(boolean dumpAll, CoordTriplet destination) - { - // For now, we can optimize by only running this when we have enough waste to product an ingot - int amtEjected = 0; - - String wasteReactantType = fuelContainer.getWasteType(); - if(wasteReactantType == null) { - return; - } - - int minimumReactantAmount = Reactants.getMinimumReactantToProduceSolid(wasteReactantType); - if(fuelContainer.getWasteAmount() >= minimumReactantAmount) { - - for(TileEntityReactorAccessPort port : attachedAccessPorts) { - if(fuelContainer.getWasteAmount() < minimumReactantAmount) { - continue; - } - - if(!port.isConnected()) { continue; } - if(destination != null && !destination.equals(port.xCoord, port.yCoord, port.zCoord)) { - continue; - } - - // First time through, we eject only to outlet ports - if(destination == null && !port.isInlet()) { - int reactantEjected = port.emitReactant(wasteReactantType, fuelContainer.getWasteAmount()); - fuelContainer.dumpWaste(reactantEjected); - amtEjected += reactantEjected; - } - } - - if(destination == null && fuelContainer.getWasteAmount() > minimumReactantAmount) { - // Loop a second time when destination is null and we still have waste - for(TileEntityReactorAccessPort port : attachedAccessPorts) { - if(fuelContainer.getWasteAmount() < minimumReactantAmount) { - continue; - } - - if(!port.isConnected()) { continue; } - int reactantEjected = port.emitReactant(wasteReactantType, fuelContainer.getWasteAmount()); - fuelContainer.dumpWaste(reactantEjected); - amtEjected += reactantEjected; - } - } - } - - if(dumpAll) - { - amtEjected += fuelContainer.getWasteAmount(); - fuelContainer.setWaste(null); - } - - if(amtEjected > 0) { - markReferenceCoordForUpdate(); - markReferenceCoordDirty(); - } - } - - /** - * Eject fuel contained in the reactor. - * @param dumpAll If true, any remaining fuel will simply be lost. - * @param destination If not null, then fuel will only be distributed to a port matching these coordinates. - */ - public void ejectFuel(boolean dumpAll, CoordTriplet destination) { - // For now, we can optimize by only running this when we have enough waste to product an ingot - int amtEjected = 0; - - String fuelReactantType = fuelContainer.getFuelType(); - if(fuelReactantType == null) { - return; - } - - int minimumReactantAmount = Reactants.getMinimumReactantToProduceSolid(fuelReactantType); - if(fuelContainer.getFuelAmount() >= minimumReactantAmount) { - - for(TileEntityReactorAccessPort port : attachedAccessPorts) { - if(fuelContainer.getFuelAmount() < minimumReactantAmount) { - continue; - } - - if(!port.isConnected()) { continue; } - if(destination != null && !destination.equals(port.xCoord, port.yCoord, port.zCoord)) { - continue; - } - - int reactantEjected = port.emitReactant(fuelReactantType, fuelContainer.getFuelAmount()); - fuelContainer.dumpFuel(reactantEjected); - amtEjected += reactantEjected; - } - } - - if(dumpAll) - { - amtEjected += fuelContainer.getFuelAmount(); - fuelContainer.setFuel(null); - } - - if(amtEjected > 0) { - markReferenceCoordForUpdate(); - markReferenceCoordDirty(); - } - } - - @Override - protected void onMachineAssembled() { - recalculateDerivedValues(); - } - - @Override - protected void onMachineRestored() { - recalculateDerivedValues(); - } - - @Override - protected void onMachinePaused() { - } - - @Override - protected void onMachineDisassembled() { - this.active = false; - } - - private void recalculateDerivedValues() { - // Recalculate size of fuel/waste tank via fuel rods - CoordTriplet minCoord, maxCoord; - minCoord = getMinimumCoord(); - maxCoord = getMaximumCoord(); - - fuelContainer.setCapacity(attachedFuelRods.size() * FuelCapacityPerFuelRod); - - // Calculate derived stats - - // Calculate heat transfer based on fuel rod environment - fuelToReactorHeatTransferCoefficient = 0f; - for(TileEntityReactorFuelRod fuelRod : attachedFuelRods) { - fuelToReactorHeatTransferCoefficient += fuelRod.getHeatTransferRate(); - } - - // Calculate heat transfer to coolant system based on reactor interior surface area. - // This is pretty simple to start with - surface area of the rectangular prism defining the interior. - int xSize = maxCoord.x - minCoord.x - 1; - int ySize = maxCoord.y - minCoord.y - 1; - int zSize = maxCoord.z - minCoord.z - 1; - - int surfaceArea = 2 * (xSize * ySize + xSize * zSize + ySize * zSize); - - reactorToCoolantSystemHeatTransferCoefficient = IHeatEntity.conductivityIron * surfaceArea; - - // Calculate passive heat loss. - // Get external surface area - xSize += 2; - ySize += 2; - zSize += 2; - - surfaceArea = 2 * (xSize * ySize + xSize * zSize + ySize * zSize); - reactorHeatLossCoefficient = reactorHeatLossConductivity * surfaceArea; - - if(worldObj.isRemote) { - // Make sure our fuel rods re-render - this.onFuelStatusChanged(); - } - else { - // Force an update of the client's multiblock information - markReferenceCoordForUpdate(); - } - - calculateReactorVolume(); - - if(attachedCoolantPorts.size() > 0) { - int outerVolume = StaticUtils.ExtraMath.Volume(minCoord, maxCoord) - reactorVolume; - coolantContainer.setCapacity(Math.max(0, Math.min(50000, outerVolume * 100))); - } - else { - coolantContainer.setCapacity(0); - } - } - - @Override - protected int getMaximumXSize() { - return BigReactors.maximumReactorSize; - } - - @Override - protected int getMaximumZSize() { - return BigReactors.maximumReactorSize; - } - - @Override - protected int getMaximumYSize() { - return BigReactors.maximumReactorHeight; - } - - /** - * Used to update the UI - */ - public void setEnergyGeneratedLastTick(float energyGeneratedLastTick) { - this.energyGeneratedLastTick = energyGeneratedLastTick; - } - - /** - * UI Helper - */ - public float getEnergyGeneratedLastTick() { - return this.energyGeneratedLastTick; - } - - /** - * Used to update the UI - */ - public void setFuelConsumedLastTick(float fuelConsumed) { - fuelConsumedLastTick = fuelConsumed; - } - - /** - * UI Helper - */ - public float getFuelConsumedLastTick() { - return fuelConsumedLastTick; - } - - /** - * UI Helper - * @return Percentile fuel richness (fuel/fuel+waste), or 0 if all control rods are empty - */ - public float getFuelRichness() { - int amtFuel, amtWaste; - amtFuel = fuelContainer.getFuelAmount(); - amtWaste = fuelContainer.getWasteAmount(); - - if(amtFuel + amtWaste <= 0f) { return 0f; } - else { return (float)amtFuel / (float)(amtFuel+amtWaste); } - } - - // IEnergyProvider - @Override - public int extractEnergy(ForgeDirection from, int maxExtract, - boolean simulate) { - int amtRemoved = (int)Math.min(maxExtract, this.energyStored); - if(!simulate) { - this.reduceStoredEnergy(amtRemoved); - } - return amtRemoved; - } - - @Override - public boolean canConnectEnergy(ForgeDirection from) { - return false; - } - - @Override - public int getEnergyStored(ForgeDirection from) { - return (int)energyStored; - } - - @Override - public int getMaxEnergyStored(ForgeDirection from) { - return maxEnergyStored; - } - - // Redstone helper - public void setAllControlRodInsertionValues(int newValue) { - if(this.assemblyState != AssemblyState.Assembled) { return; } - - for(TileEntityReactorControlRod cr : attachedControlRods) { - if(cr.isConnected()) { - cr.setControlRodInsertion((short)newValue); - } - } - } - - public void changeAllControlRodInsertionValues(short delta) { - if(this.assemblyState != AssemblyState.Assembled) { return; } - - for(TileEntityReactorControlRod cr : attachedControlRods) { - if(cr.isConnected()) { - cr.setControlRodInsertion( (short) (cr.getControlRodInsertion() + delta) ); - } - } - } - - public CoordTriplet[] getControlRodLocations() { - CoordTriplet[] coords = new CoordTriplet[this.attachedControlRods.size()]; - int i = 0; - for(TileEntityReactorControlRod cr : attachedControlRods) { - coords[i++] = cr.getWorldLocation(); - } - return coords; - } - - public int getFuelAmount() { - return fuelContainer.getFuelAmount(); - } - - public int getWasteAmount() { - return fuelContainer.getWasteAmount(); - } - - public String getFuelType() { - return fuelContainer.getFuelType(); - } - - public String getWasteType() { - return fuelContainer.getWasteType(); - } - - public int getEnergyStoredPercentage() { - return (int)(this.energyStored / (float)this.maxEnergyStored * 100f); - } - - @Override - public int getCapacity() { - if(worldObj.isRemote && assemblyState != AssemblyState.Assembled) { - // Estimate capacity - return attachedFuelRods.size() * FuelCapacityPerFuelRod; - } - - return fuelContainer.getCapacity(); - } - - public float getFuelFertility() { - return radiationHelper.getFertilityModifier(); - } - - // Coolant subsystem - public CoolantContainer getCoolantContainer() { - return coolantContainer; - } - - protected float getPassiveCoolantTemperature() { - return IHeatEntity.ambientHeat; - } - - protected float getCoolantTemperature() { - if(isPassivelyCooled()) { - return getPassiveCoolantTemperature(); - } - else { - return coolantContainer.getCoolantTemperature(getReactorHeat()); - } - } - - public boolean isPassivelyCooled() { - if(coolantContainer == null || coolantContainer.getCapacity() <= 0) { return true; } - else { return false; } - } - - protected int getReactorVolume() { - return reactorVolume; - } - - protected void calculateReactorVolume() { - CoordTriplet minInteriorCoord = getMinimumCoord(); - minInteriorCoord.x += 1; - minInteriorCoord.y += 1; - minInteriorCoord.z += 1; - - CoordTriplet maxInteriorCoord = getMaximumCoord(); - maxInteriorCoord.x -= 1; - maxInteriorCoord.y -= 1; - maxInteriorCoord.z -= 1; - - reactorVolume = StaticUtils.ExtraMath.Volume(minInteriorCoord, maxInteriorCoord); - } - - // Client-only - protected void onFuelStatusChanged() { - if(worldObj.isRemote) { - // On the client, re-render all the fuel rod blocks when the fuel status changes - for(TileEntityReactorFuelRod fuelRod : attachedFuelRods) { - worldObj.markBlockForUpdate(fuelRod.xCoord, fuelRod.yCoord, fuelRod.zCoord); - } - } - } - - private static final FluidTankInfo[] emptyTankInfo = new FluidTankInfo[0]; - - @Override - public FluidTankInfo[] getTankInfo() { - if(isPassivelyCooled()) { return emptyTankInfo; } - - return coolantContainer.getTankInfo(-1); - } - - protected void markReferenceCoordForUpdate() { - CoordTriplet rc = getReferenceCoord(); - if(worldObj != null && rc != null) { - worldObj.markBlockForUpdate(rc.x, rc.y, rc.z); - } - } - - protected void markReferenceCoordDirty() { - if(worldObj == null || worldObj.isRemote) { return; } - - CoordTriplet referenceCoord = getReferenceCoord(); - if(referenceCoord == null) { return; } - - TileEntity saveTe = worldObj.getTileEntity(referenceCoord.x, referenceCoord.y, referenceCoord.z); - worldObj.markTileEntityChunkModified(referenceCoord.x, referenceCoord.y, referenceCoord.z, saveTe); - } - - @Override - public boolean getActive() { - return this.active; - } - - public String getDebugInfo() { - StringBuilder sb = new StringBuilder(); - sb.append("Assembled: ").append(Boolean.toString(isAssembled())).append("\n"); - sb.append("Attached Blocks: ").append(Integer.toString(connectedParts.size())).append("\n"); - if(getLastValidationException() != null) { - sb.append("Validation Exception:\n").append(getLastValidationException().getMessage()).append("\n"); - } - - if(isAssembled()) { - sb.append("\nActive: ").append(Boolean.toString(getActive())); - sb.append("\nStored Energy: ").append(Float.toString(getEnergyStored())); - sb.append("\nCasing Heat: ").append(Float.toString(getReactorHeat())); - sb.append("\nFuel Heat: ").append(Float.toString(getFuelHeat())); - sb.append("\n\nReactant Tanks:\n"); - sb.append( fuelContainer.getDebugInfo() ); - sb.append("\n\nActively Cooled: ").append(Boolean.toString(!isPassivelyCooled())); - if(!isPassivelyCooled()) { - sb.append("\n\nCoolant Tanks:\n"); - sb.append( coolantContainer.getDebugInfo() ); - } - } - - return sb.toString(); - } + } + + /** + * Sends a full state update to a player. + */ + protected void sendIndividualUpdate(EntityPlayer player) { + if (this.worldObj.isRemote) { + return; + } + + CommonPacketHandler.INSTANCE.sendTo(getUpdatePacket(), (EntityPlayerMP) player); + } + + /** + * Send an update to any clients with GUIs open + */ + protected void sendTickUpdate() { + if (this.worldObj.isRemote) { + return; + } + if (this.updatePlayers.size() <= 0) { + return; + } + + for (EntityPlayer player : updatePlayers) { + CommonPacketHandler.INSTANCE.sendTo(getUpdatePacket(), (EntityPlayerMP) player); + } + } + + /** + * Attempt to distribute a stack of ingots to a given access port, sensitive to the amount and type of ingots + * already in it. + * + * @param port The port to which we're distributing ingots. + * @param itemsToDistribute The stack of ingots to distribute. Will be modified during the operation and may be + * returned with stack size 0. + * @param distributeToInputs Should we try to send ingots to input ports? + * @return The number of waste items distributed, i.e. the differential in stack size for wasteToDistribute. + */ + private int tryDistributeItems(TileEntityReactorAccessPort port, ItemStack itemsToDistribute, + boolean distributeToInputs) { + ItemStack existingStack = port.getStackInSlot(TileEntityReactorAccessPort.SLOT_OUTLET); + int initialWasteAmount = itemsToDistribute.stackSize; + if (!port.isInlet() || (distributeToInputs || attachedAccessPorts.size() < 2)) { + // Dump waste preferentially to outlets, unless we only have one access port + if (existingStack == null) { + if (itemsToDistribute.stackSize > port.getInventoryStackLimit()) { + ItemStack newStack = itemsToDistribute.splitStack(port.getInventoryStackLimit()); + port.setInventorySlotContents(TileEntityReactorAccessPort.SLOT_OUTLET, newStack); + } else { + port.setInventorySlotContents(TileEntityReactorAccessPort.SLOT_OUTLET, itemsToDistribute.copy()); + itemsToDistribute.stackSize = 0; + } + } else if (existingStack.isItemEqual(itemsToDistribute)) { + if (existingStack.stackSize + itemsToDistribute.stackSize <= existingStack.getMaxStackSize()) { + existingStack.stackSize += itemsToDistribute.stackSize; + itemsToDistribute.stackSize = 0; + } else { + int amt = existingStack.getMaxStackSize() - existingStack.stackSize; + itemsToDistribute.stackSize -= existingStack.getMaxStackSize() - existingStack.stackSize; + existingStack.stackSize += amt; + } + } + + port.onItemsReceived(); + } + + return initialWasteAmount - itemsToDistribute.stackSize; + } + + @Override + protected void onAssimilated(MultiblockControllerBase otherMachine) { + this.attachedPowerTaps.clear(); + this.attachedTickables.clear(); + this.attachedAccessPorts.clear(); + this.attachedControllers.clear(); + this.attachedControlRods.clear(); + currentFuelRod = null; + } + + @Override + protected void onAssimilate(MultiblockControllerBase otherMachine) { + if (!(otherMachine instanceof MultiblockReactor)) { + BRLog.warning( + "[%s] Reactor @ %s is attempting to assimilate a non-Reactor machine! That machine's data will be lost!", + worldObj.isRemote ? "CLIENT" : "SERVER", + getReferenceCoord()); + return; + } + + MultiblockReactor otherReactor = (MultiblockReactor) otherMachine; + + if (otherReactor.reactorHeat > this.reactorHeat) { + setReactorHeat(otherReactor.reactorHeat); + } + if (otherReactor.fuelHeat > this.fuelHeat) { + setFuelHeat(otherReactor.fuelHeat); + } + + if (otherReactor.getEnergyStored() > this.getEnergyStored()) { + this.setEnergyStored(otherReactor.getEnergyStored()); + } + + fuelContainer.merge(otherReactor.fuelContainer); + radiationHelper.merge(otherReactor.radiationHelper); + coolantContainer.merge(otherReactor.coolantContainer); + } + + @Override + public void onAttachedPartWithMultiblockData(IMultiblockPart part, NBTTagCompound data) { + this.readFromNBT(data); + } + + public float getEnergyStored() { + return energyStored; + } + + /** + * Directly set the waste ejection setting. Will dispatch network updates + * from server to interested clients. + * + * @param newSetting The new waste ejection setting. + */ + public void setWasteEjection(WasteEjectionSetting newSetting) { + if (this.wasteEjection != newSetting) { + this.wasteEjection = newSetting; + + if (!this.worldObj.isRemote) { + markReferenceCoordDirty(); + + if (this.updatePlayers.size() > 0) { + for (EntityPlayer player : updatePlayers) { + CommonPacketHandler.INSTANCE + .sendTo(new ReactorUpdateWasteEjectionMessage(this), (EntityPlayerMP) player); + } + } + } + } + } + + public WasteEjectionSetting getWasteEjection() { + return this.wasteEjection; + } + + protected void refuel() { + // For now, we only need to check fuel ports when we have more space than can accomodate 1 ingot + if (fuelContainer.getRemainingSpace() < Reactants.standardSolidReactantAmount) { + return; + } + + int amtAdded = 0; + + // Loop: Consume input reactants from all ports + for (TileEntityReactorAccessPort port : attachedAccessPorts) { + if (fuelContainer.getRemainingSpace() <= 0) { + break; + } + + if (!port.isConnected()) { + continue; + } + + // See what type of reactant the port contains; if none, skip it. + String portReactantType = port.getInputReactantType(); + int portReactantAmount = port.getInputReactantAmount(); + if (portReactantType == null || portReactantAmount <= 0) { + continue; + } + + if (!Reactants.isFuel(portReactantType)) { + continue; + } // Skip nonfuels + + // HACK; TEMPORARY + // Alias blutonium to yellorium temporarily, until mixed fuels are implemented + if (portReactantType.equals(StandardReactants.blutonium)) { + portReactantType = StandardReactants.yellorium; + } + + // How much fuel can we actually add from this type of reactant? + int amountToAdd = fuelContainer.addFuel(portReactantType, portReactantAmount, false); + if (amountToAdd <= 0) { + continue; + } + + int portCanAdd = port.consumeReactantItem(amountToAdd); + if (portCanAdd <= 0) { + continue; + } + + amtAdded = fuelContainer.addFuel(portReactantType, portReactantAmount, true); + } + + if (amtAdded > 0) { + markReferenceCoordForUpdate(); + markReferenceCoordDirty(); + } + } + + /** + * Attempt to eject waste contained in the reactor + * + * @param dumpAll If true, any waste remaining after ejection will be discarded. + * @param destination If set, waste will only be ejected to ports with coordinates matching this one. + */ + public void ejectWaste(boolean dumpAll, CoordTriplet destination) { + // For now, we can optimize by only running this when we have enough waste to product an ingot + int amtEjected = 0; + + String wasteReactantType = fuelContainer.getWasteType(); + if (wasteReactantType == null) { + return; + } + + int minimumReactantAmount = Reactants.getMinimumReactantToProduceSolid(wasteReactantType); + if (fuelContainer.getWasteAmount() >= minimumReactantAmount) { + + for (TileEntityReactorAccessPort port : attachedAccessPorts) { + if (fuelContainer.getWasteAmount() < minimumReactantAmount) { + continue; + } + + if (!port.isConnected()) { + continue; + } + if (destination != null && !destination.equals(port.xCoord, port.yCoord, port.zCoord)) { + continue; + } + + // First time through, we eject only to outlet ports + if (destination == null && !port.isInlet()) { + int reactantEjected = port.emitReactant(wasteReactantType, fuelContainer.getWasteAmount()); + fuelContainer.dumpWaste(reactantEjected); + amtEjected += reactantEjected; + } + } + + if (destination == null && fuelContainer.getWasteAmount() > minimumReactantAmount) { + // Loop a second time when destination is null and we still have waste + for (TileEntityReactorAccessPort port : attachedAccessPorts) { + if (fuelContainer.getWasteAmount() < minimumReactantAmount) { + continue; + } + + if (!port.isConnected()) { + continue; + } + int reactantEjected = port.emitReactant(wasteReactantType, fuelContainer.getWasteAmount()); + fuelContainer.dumpWaste(reactantEjected); + amtEjected += reactantEjected; + } + } + } + + if (dumpAll) { + amtEjected += fuelContainer.getWasteAmount(); + fuelContainer.setWaste(null); + } + + if (amtEjected > 0) { + markReferenceCoordForUpdate(); + markReferenceCoordDirty(); + } + } + + /** + * Eject fuel contained in the reactor. + * + * @param dumpAll If true, any remaining fuel will simply be lost. + * @param destination If not null, then fuel will only be distributed to a port matching these coordinates. + */ + public void ejectFuel(boolean dumpAll, CoordTriplet destination) { + // For now, we can optimize by only running this when we have enough waste to product an ingot + int amtEjected = 0; + + String fuelReactantType = fuelContainer.getFuelType(); + if (fuelReactantType == null) { + return; + } + + int minimumReactantAmount = Reactants.getMinimumReactantToProduceSolid(fuelReactantType); + if (fuelContainer.getFuelAmount() >= minimumReactantAmount) { + + for (TileEntityReactorAccessPort port : attachedAccessPorts) { + if (fuelContainer.getFuelAmount() < minimumReactantAmount) { + continue; + } + + if (!port.isConnected()) { + continue; + } + if (destination != null && !destination.equals(port.xCoord, port.yCoord, port.zCoord)) { + continue; + } + + int reactantEjected = port.emitReactant(fuelReactantType, fuelContainer.getFuelAmount()); + fuelContainer.dumpFuel(reactantEjected); + amtEjected += reactantEjected; + } + } + + if (dumpAll) { + amtEjected += fuelContainer.getFuelAmount(); + fuelContainer.setFuel(null); + } + + if (amtEjected > 0) { + markReferenceCoordForUpdate(); + markReferenceCoordDirty(); + } + } + + @Override + protected void onMachineAssembled() { + recalculateDerivedValues(); + } + + @Override + protected void onMachineRestored() { + recalculateDerivedValues(); + } + + @Override + protected void onMachinePaused() {} + + @Override + protected void onMachineDisassembled() { + this.active = false; + } + + private void recalculateDerivedValues() { + // Recalculate size of fuel/waste tank via fuel rods + CoordTriplet minCoord, maxCoord; + minCoord = getMinimumCoord(); + maxCoord = getMaximumCoord(); + + fuelContainer.setCapacity(attachedFuelRods.size() * FuelCapacityPerFuelRod); + + // Calculate derived stats + + // Calculate heat transfer based on fuel rod environment + fuelToReactorHeatTransferCoefficient = 0f; + for (TileEntityReactorFuelRod fuelRod : attachedFuelRods) { + fuelToReactorHeatTransferCoefficient += fuelRod.getHeatTransferRate(); + } + + // Calculate heat transfer to coolant system based on reactor interior surface area. + // This is pretty simple to start with - surface area of the rectangular prism defining the interior. + int xSize = maxCoord.x - minCoord.x - 1; + int ySize = maxCoord.y - minCoord.y - 1; + int zSize = maxCoord.z - minCoord.z - 1; + + int surfaceArea = 2 * (xSize * ySize + xSize * zSize + ySize * zSize); + + reactorToCoolantSystemHeatTransferCoefficient = IHeatEntity.conductivityIron * surfaceArea; + + // Calculate passive heat loss. + // Get external surface area + xSize += 2; + ySize += 2; + zSize += 2; + + surfaceArea = 2 * (xSize * ySize + xSize * zSize + ySize * zSize); + reactorHeatLossCoefficient = reactorHeatLossConductivity * surfaceArea; + + if (worldObj.isRemote) { + // Make sure our fuel rods re-render + this.onFuelStatusChanged(); + } else { + // Force an update of the client's multiblock information + markReferenceCoordForUpdate(); + } + + calculateReactorVolume(); + + if (attachedCoolantPorts.size() > 0) { + int outerVolume = StaticUtils.ExtraMath.Volume(minCoord, maxCoord) - reactorVolume; + coolantContainer.setCapacity(Math.max(0, Math.min(50000, outerVolume * 100))); + } else { + coolantContainer.setCapacity(0); + } + } + + @Override + protected int getMaximumXSize() { + return BigReactors.maximumReactorSize; + } + + @Override + protected int getMaximumZSize() { + return BigReactors.maximumReactorSize; + } + + @Override + protected int getMaximumYSize() { + return BigReactors.maximumReactorHeight; + } + + /** + * Used to update the UI + */ + public void setEnergyGeneratedLastTick(float energyGeneratedLastTick) { + this.energyGeneratedLastTick = energyGeneratedLastTick; + } + + /** + * UI Helper + */ + public float getEnergyGeneratedLastTick() { + return this.energyGeneratedLastTick; + } + + /** + * Used to update the UI + */ + public void setFuelConsumedLastTick(float fuelConsumed) { + fuelConsumedLastTick = fuelConsumed; + } + + /** + * UI Helper + */ + public float getFuelConsumedLastTick() { + return fuelConsumedLastTick; + } + + /** + * UI Helper + * + * @return Percentile fuel richness (fuel/fuel+waste), or 0 if all control rods are empty + */ + public float getFuelRichness() { + int amtFuel, amtWaste; + amtFuel = fuelContainer.getFuelAmount(); + amtWaste = fuelContainer.getWasteAmount(); + + if (amtFuel + amtWaste <= 0f) { + return 0f; + } else { + return (float) amtFuel / (float) (amtFuel + amtWaste); + } + } + + // IEnergyProvider + @Override + public int extractEnergy(ForgeDirection from, int maxExtract, boolean simulate) { + int amtRemoved = (int) Math.min(maxExtract, this.energyStored); + if (!simulate) { + this.reduceStoredEnergy(amtRemoved); + } + return amtRemoved; + } + + @Override + public boolean canConnectEnergy(ForgeDirection from) { + return false; + } + + @Override + public int getEnergyStored(ForgeDirection from) { + return (int) energyStored; + } + + @Override + public int getMaxEnergyStored(ForgeDirection from) { + return maxEnergyStored; + } + + // Redstone helper + public void setAllControlRodInsertionValues(int newValue) { + if (this.assemblyState != AssemblyState.Assembled) { + return; + } + + for (TileEntityReactorControlRod cr : attachedControlRods) { + if (cr.isConnected()) { + cr.setControlRodInsertion((short) newValue); + } + } + } + + public void changeAllControlRodInsertionValues(short delta) { + if (this.assemblyState != AssemblyState.Assembled) { + return; + } + + for (TileEntityReactorControlRod cr : attachedControlRods) { + if (cr.isConnected()) { + cr.setControlRodInsertion((short) (cr.getControlRodInsertion() + delta)); + } + } + } + + public CoordTriplet[] getControlRodLocations() { + CoordTriplet[] coords = new CoordTriplet[this.attachedControlRods.size()]; + int i = 0; + for (TileEntityReactorControlRod cr : attachedControlRods) { + coords[i++] = cr.getWorldLocation(); + } + return coords; + } + + public int getFuelAmount() { + return fuelContainer.getFuelAmount(); + } + + public int getWasteAmount() { + return fuelContainer.getWasteAmount(); + } + + public String getFuelType() { + return fuelContainer.getFuelType(); + } + + public String getWasteType() { + return fuelContainer.getWasteType(); + } + + public int getEnergyStoredPercentage() { + return (int) (this.energyStored / (float) this.maxEnergyStored * 100f); + } + + @Override + public int getCapacity() { + if (worldObj.isRemote && assemblyState != AssemblyState.Assembled) { + // Estimate capacity + return attachedFuelRods.size() * FuelCapacityPerFuelRod; + } + + return fuelContainer.getCapacity(); + } + + public float getFuelFertility() { + return radiationHelper.getFertilityModifier(); + } + + // Coolant subsystem + public CoolantContainer getCoolantContainer() { + return coolantContainer; + } + + protected float getPassiveCoolantTemperature() { + return IHeatEntity.ambientHeat; + } + + protected float getCoolantTemperature() { + if (isPassivelyCooled()) { + return getPassiveCoolantTemperature(); + } else { + return coolantContainer.getCoolantTemperature(getReactorHeat()); + } + } + + public boolean isPassivelyCooled() { + if (coolantContainer == null || coolantContainer.getCapacity() <= 0) { + return true; + } else { + return false; + } + } + + protected int getReactorVolume() { + return reactorVolume; + } + + protected void calculateReactorVolume() { + CoordTriplet minInteriorCoord = getMinimumCoord(); + minInteriorCoord.x += 1; + minInteriorCoord.y += 1; + minInteriorCoord.z += 1; + + CoordTriplet maxInteriorCoord = getMaximumCoord(); + maxInteriorCoord.x -= 1; + maxInteriorCoord.y -= 1; + maxInteriorCoord.z -= 1; + + reactorVolume = StaticUtils.ExtraMath.Volume(minInteriorCoord, maxInteriorCoord); + } + + // Client-only + protected void onFuelStatusChanged() { + if (worldObj.isRemote) { + // On the client, re-render all the fuel rod blocks when the fuel status changes + for (TileEntityReactorFuelRod fuelRod : attachedFuelRods) { + worldObj.markBlockForUpdate(fuelRod.xCoord, fuelRod.yCoord, fuelRod.zCoord); + } + } + } + + private static final FluidTankInfo[] emptyTankInfo = new FluidTankInfo[0]; + + @Override + public FluidTankInfo[] getTankInfo() { + if (isPassivelyCooled()) { + return emptyTankInfo; + } + + return coolantContainer.getTankInfo(-1); + } + + protected void markReferenceCoordForUpdate() { + CoordTriplet rc = getReferenceCoord(); + if (worldObj != null && rc != null) { + worldObj.markBlockForUpdate(rc.x, rc.y, rc.z); + } + } + + protected void markReferenceCoordDirty() { + if (worldObj == null || worldObj.isRemote) { + return; + } + + CoordTriplet referenceCoord = getReferenceCoord(); + if (referenceCoord == null) { + return; + } + + TileEntity saveTe = worldObj.getTileEntity(referenceCoord.x, referenceCoord.y, referenceCoord.z); + worldObj.markTileEntityChunkModified(referenceCoord.x, referenceCoord.y, referenceCoord.z, saveTe); + } + + @Override + public boolean getActive() { + return this.active; + } + + public String getDebugInfo() { + StringBuilder sb = new StringBuilder(); + sb.append("Assembled: ") + .append(Boolean.toString(isAssembled())) + .append("\n"); + sb.append("Attached Blocks: ") + .append(Integer.toString(connectedParts.size())) + .append("\n"); + if (getLastValidationException() != null) { + sb.append("Validation Exception:\n") + .append(getLastValidationException().getMessage()) + .append("\n"); + } + + if (isAssembled()) { + sb.append("\nActive: ") + .append(Boolean.toString(getActive())); + sb.append("\nStored Energy: ") + .append(Float.toString(getEnergyStored())); + sb.append("\nCasing Heat: ") + .append(Float.toString(getReactorHeat())); + sb.append("\nFuel Heat: ") + .append(Float.toString(getFuelHeat())); + sb.append("\n\nReactant Tanks:\n"); + sb.append(fuelContainer.getDebugInfo()); + sb.append("\n\nActively Cooled: ") + .append(Boolean.toString(!isPassivelyCooled())); + if (!isPassivelyCooled()) { + sb.append("\n\nCoolant Tanks:\n"); + sb.append(coolantContainer.getDebugInfo()); + } + } + + return sb.toString(); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/MultiblockTurbine.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/MultiblockTurbine.java index 37339adf..fc56a1a9 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/MultiblockTurbine.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/MultiblockTurbine.java @@ -1,7 +1,5 @@ package erogenousbeef.bigreactors.common.multiblock; -import io.netty.buffer.ByteBuf; - import java.util.HashSet; import java.util.Set; @@ -19,6 +17,7 @@ import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTank; import net.minecraftforge.fluids.FluidTankInfo; + import cofh.api.energy.IEnergyProvider; import cofh.lib.util.helpers.ItemHelper; import cpw.mods.fml.common.network.simpleimpl.IMessage; @@ -48,1152 +47,1287 @@ import erogenousbeef.core.multiblock.MultiblockControllerBase; import erogenousbeef.core.multiblock.MultiblockValidationException; import erogenousbeef.core.multiblock.rectangular.RectangularMultiblockControllerBase; +import io.netty.buffer.ByteBuf; + +public class MultiblockTurbine extends RectangularMultiblockControllerBase + implements IEnergyProvider, IMultipleFluidHandler, ISlotlessUpdater, IActivateable { + + public enum VentStatus { + VentOverflow, + VentAll, + DoNotVent + } + + public static final VentStatus[] s_VentStatuses = VentStatus.values(); + + // UI updates + private Set updatePlayers; + private int ticksSinceLastUpdate; + private static final int ticksBetweenUpdates = 3; + + // Fluid tanks. Input = Steam, Output = Water. + public static final int TANK_INPUT = 0; + public static final int TANK_OUTPUT = 1; + public static final int NUM_TANKS = 2; + public static final int FLUID_NONE = -1; + public static final int TANK_SIZE = 4000; + public static final int MAX_PERMITTED_FLOW = 2000; + + private FluidTank[] tanks; + + static final float maxEnergyStored = 1000000f; // 1 MegaRF + + // Persistent game data + float energyStored; + boolean active; + float rotorEnergy; + boolean inductorEngaged; + + // Player settings + VentStatus ventStatus; + int maxIntakeRate; + + // Derivable game data + int bladeSurfaceArea; // # of blocks that are blades + int rotorMass; // 10 = 1 standard block-weight + int coilSize; // number of blocks in the coils + + // Inductor dynamic constants - get from a table on assembly + float inductorDragCoefficient = inductorBaseDragCoefficient; + float inductionEfficiency = 0.5f; // Final energy rectification efficiency. Averaged based on coil material and + // shape. 0.25-0.5 = iron, 0.75-0.9 = diamond, 1 = perfect. + float inductionEnergyExponentBonus = 1f; // Exponential bonus to energy generation. Use this for very rare materials + // or special constructs. + + // Rotor dynamic constants - calculate on assembly + float rotorDragCoefficient = 0.01f; // RF/t lost to friction per unit of mass in the rotor. + float bladeDrag = 0.00025f; // RF/t lost to friction, multiplied by rotor speed squared. + float frictionalDrag = 0f; + + // Penalize suboptimal shapes with worse drag (i.e. increased drag without increasing lift) + // Suboptimal is defined as "not a christmas-tree shape". At worst, drag is increased 4x. + + // Game balance constants - some of these are modified by configs at startup + public static int inputFluidPerBlade = 25; // mB + public static float inductorBaseDragCoefficient = 0.1f; // RF/t extracted per coil block, multiplied by rotor speed + // squared. + public static final float baseBladeDragCoefficient = 0.00025f; // RF/t base lost to aero drag per blade block. + // Includes a 50% reduction to factor in constant + // parts of the drag equation + + float energyGeneratedLastTick; + int fluidConsumedLastTick; + float rotorEfficiencyLastTick; + + private Set attachedControllers; + private Set attachedRotorBearings; + + private Set attachedPowerTaps; + private Set attachedTickables; + + private Set attachedRotorShafts; + private Set attachedRotorBlades; + + private Set attachedGlass; + + // Data caches for validation + private Set foundCoils; + + private FloatUpdateTracker rpmUpdateTracker; + + private static final ForgeDirection[] RotorXBladeDirections = new ForgeDirection[] { ForgeDirection.UP, + ForgeDirection.SOUTH, ForgeDirection.DOWN, ForgeDirection.NORTH }; + private static final ForgeDirection[] RotorZBladeDirections = new ForgeDirection[] { ForgeDirection.UP, + ForgeDirection.EAST, ForgeDirection.DOWN, ForgeDirection.WEST }; + + public MultiblockTurbine(World world) { + super(world); + + updatePlayers = new HashSet(); + + ticksSinceLastUpdate = 0; + + tanks = new FluidTank[NUM_TANKS]; + for (int i = 0; i < NUM_TANKS; i++) tanks[i] = new FluidTank(TANK_SIZE); + + attachedControllers = new HashSet(); + attachedRotorBearings = new HashSet(); + attachedPowerTaps = new HashSet(); + attachedTickables = new HashSet(); + attachedRotorShafts = new HashSet(); + attachedRotorBlades = new HashSet(); + attachedGlass = new HashSet(); + + energyStored = 0f; + active = false; + inductorEngaged = true; + ventStatus = VentStatus.VentOverflow; + rotorEnergy = 0f; + maxIntakeRate = MAX_PERMITTED_FLOW; + + bladeSurfaceArea = 0; + rotorMass = 0; + coilSize = 0; + energyGeneratedLastTick = 0f; + fluidConsumedLastTick = 0; + rotorEfficiencyLastTick = 1f; -public class MultiblockTurbine extends RectangularMultiblockControllerBase implements IEnergyProvider, IMultipleFluidHandler, ISlotlessUpdater, IActivateable { - - public enum VentStatus { - VentOverflow, - VentAll, - DoNotVent - } - public static final VentStatus[] s_VentStatuses = VentStatus.values(); - - // UI updates - private Set updatePlayers; - private int ticksSinceLastUpdate; - private static final int ticksBetweenUpdates = 3; - - // Fluid tanks. Input = Steam, Output = Water. - public static final int TANK_INPUT = 0; - public static final int TANK_OUTPUT = 1; - public static final int NUM_TANKS = 2; - public static final int FLUID_NONE = -1; - public static final int TANK_SIZE = 4000; - public static final int MAX_PERMITTED_FLOW = 2000; - - private FluidTank[] tanks; - - static final float maxEnergyStored = 1000000f; // 1 MegaRF - - // Persistent game data - float energyStored; - boolean active; - float rotorEnergy; - boolean inductorEngaged; - - // Player settings - VentStatus ventStatus; - int maxIntakeRate; - - // Derivable game data - int bladeSurfaceArea; // # of blocks that are blades - int rotorMass; // 10 = 1 standard block-weight - int coilSize; // number of blocks in the coils - - // Inductor dynamic constants - get from a table on assembly - float inductorDragCoefficient = inductorBaseDragCoefficient; - float inductionEfficiency = 0.5f; // Final energy rectification efficiency. Averaged based on coil material and shape. 0.25-0.5 = iron, 0.75-0.9 = diamond, 1 = perfect. - float inductionEnergyExponentBonus = 1f; // Exponential bonus to energy generation. Use this for very rare materials or special constructs. - - // Rotor dynamic constants - calculate on assembly - float rotorDragCoefficient = 0.01f; // RF/t lost to friction per unit of mass in the rotor. - float bladeDrag = 0.00025f; // RF/t lost to friction, multiplied by rotor speed squared. - float frictionalDrag = 0f; - - // Penalize suboptimal shapes with worse drag (i.e. increased drag without increasing lift) - // Suboptimal is defined as "not a christmas-tree shape". At worst, drag is increased 4x. - - // Game balance constants - some of these are modified by configs at startup - public static int inputFluidPerBlade = 25; // mB - public static float inductorBaseDragCoefficient = 0.1f; // RF/t extracted per coil block, multiplied by rotor speed squared. - public static final float baseBladeDragCoefficient = 0.00025f; // RF/t base lost to aero drag per blade block. Includes a 50% reduction to factor in constant parts of the drag equation - - float energyGeneratedLastTick; - int fluidConsumedLastTick; - float rotorEfficiencyLastTick; - - private Set attachedControllers; - private Set attachedRotorBearings; - - private Set attachedPowerTaps; - private Set attachedTickables; - - private Set attachedRotorShafts; - private Set attachedRotorBlades; - - private Set attachedGlass; - - // Data caches for validation - private Set foundCoils; - - private FloatUpdateTracker rpmUpdateTracker; - - private static final ForgeDirection[] RotorXBladeDirections = new ForgeDirection[] { ForgeDirection.UP, ForgeDirection.SOUTH, ForgeDirection.DOWN, ForgeDirection.NORTH }; - private static final ForgeDirection[] RotorZBladeDirections = new ForgeDirection[] { ForgeDirection.UP, ForgeDirection.EAST, ForgeDirection.DOWN, ForgeDirection.WEST }; - - public MultiblockTurbine(World world) { - super(world); - - updatePlayers = new HashSet(); - - ticksSinceLastUpdate = 0; - - tanks = new FluidTank[NUM_TANKS]; - for(int i = 0; i < NUM_TANKS; i++) - tanks[i] = new FluidTank(TANK_SIZE); - - attachedControllers = new HashSet(); - attachedRotorBearings = new HashSet(); - attachedPowerTaps = new HashSet(); - attachedTickables = new HashSet(); - attachedRotorShafts = new HashSet(); - attachedRotorBlades = new HashSet(); - attachedGlass = new HashSet(); - - energyStored = 0f; - active = false; - inductorEngaged = true; - ventStatus = VentStatus.VentOverflow; - rotorEnergy = 0f; - maxIntakeRate = MAX_PERMITTED_FLOW; - - bladeSurfaceArea = 0; - rotorMass = 0; - coilSize = 0; - energyGeneratedLastTick = 0f; - fluidConsumedLastTick = 0; - rotorEfficiencyLastTick = 1f; - - foundCoils = new HashSet(); - - rpmUpdateTracker = new FloatUpdateTracker(100, 5, 10f, 100f); // Minimum 10RPM difference for slow updates, if change > 100 RPM, update every 5 ticks - } - - /** - * Sends a full state update to a player. - */ - protected void sendIndividualUpdate(EntityPlayer player) { - if(this.worldObj.isRemote) { return; } - - CommonPacketHandler.INSTANCE.sendTo(getUpdatePacket(), (EntityPlayerMP)player); - } - - protected IMessage getUpdatePacket() { + foundCoils = new HashSet(); + + rpmUpdateTracker = new FloatUpdateTracker(100, 5, 10f, 100f); // Minimum 10RPM difference for slow updates, if + // change > 100 RPM, update every 5 ticks + } + + /** + * Sends a full state update to a player. + */ + protected void sendIndividualUpdate(EntityPlayer player) { + if (this.worldObj.isRemote) { + return; + } + + CommonPacketHandler.INSTANCE.sendTo(getUpdatePacket(), (EntityPlayerMP) player); + } + + protected IMessage getUpdatePacket() { return new TurbineUpdateMessage(this); - } - - /** - * Send an update to any clients with GUIs open - */ - protected void sendTickUpdate() { - if(this.updatePlayers.size() <= 0) { return; } - - for(EntityPlayer player : updatePlayers) { - CommonPacketHandler.INSTANCE.sendTo(getUpdatePacket(), (EntityPlayerMP)player); - } - } - - // MultiblockControllerBase overrides - - @Override - public void onAttachedPartWithMultiblockData(IMultiblockPart part, NBTTagCompound data) { - readFromNBT(data); - } - - @Override - protected void onBlockAdded(IMultiblockPart newPart) { - if(newPart instanceof TileEntityTurbineRotorBearing) { - this.attachedRotorBearings.add((TileEntityTurbineRotorBearing)newPart); - } - - if(newPart instanceof TileEntityTurbinePowerTap) { - attachedPowerTaps.add((TileEntityTurbinePowerTap)newPart); - } - - if(newPart instanceof ITickableMultiblockPart) { - attachedTickables.add((ITickableMultiblockPart)newPart); - } - - if(newPart instanceof TileEntityTurbineRotorPart) { - TileEntityTurbineRotorPart turbinePart = (TileEntityTurbineRotorPart)newPart; - if(turbinePart.isRotorShaft()) { - attachedRotorShafts.add(turbinePart); - } - - if(turbinePart.isRotorBlade()) { - attachedRotorBlades.add(turbinePart); - } - } - - if(newPart instanceof TileEntityTurbinePartGlass) { - attachedGlass.add((TileEntityTurbinePartGlass)newPart); - } - - } - - @Override - protected void onBlockRemoved(IMultiblockPart oldPart) { - if(oldPart instanceof TileEntityTurbineRotorBearing) { - this.attachedRotorBearings.remove(oldPart); - } - - if(oldPart instanceof TileEntityTurbinePowerTap) { - attachedPowerTaps.remove((TileEntityTurbinePowerTap)oldPart); - } - - if(oldPart instanceof ITickableMultiblockPart) { - attachedTickables.remove((ITickableMultiblockPart)oldPart); - } - - if(oldPart instanceof TileEntityTurbineRotorPart) { - TileEntityTurbineRotorPart turbinePart = (TileEntityTurbineRotorPart)oldPart; - if(turbinePart.isRotorShaft()) { - attachedRotorShafts.remove(turbinePart); - } - - if(turbinePart.isRotorBlade()) { - attachedRotorBlades.remove(turbinePart); - } - } - - if(oldPart instanceof TileEntityTurbinePartGlass) { - attachedGlass.remove((TileEntityTurbinePartGlass)oldPart); - } - } - - @Override - protected void onMachineAssembled() { - recalculateDerivedStatistics(); - } - - @Override - protected void onMachineRestored() { - recalculateDerivedStatistics(); - } - - @Override - protected void onMachinePaused() { - } - - @Override - protected void onMachineDisassembled() { - rotorMass = 0; - bladeSurfaceArea = 0; - coilSize = 0; - - rotorEnergy = 0f; // Kill energy when machines get broken by players/explosions - rpmUpdateTracker.setValue(0f); - } - - // Validation code - @Override - protected void isMachineWhole() throws MultiblockValidationException { - if(attachedRotorBearings.size() != 1) { - throw new MultiblockValidationException("Turbines require exactly 1 rotor bearing"); - } - - // Set up validation caches - foundCoils.clear(); - - super.isMachineWhole(); - - // Now do additional validation based on the coils/blades/rotors that were found - - // Check that we have a rotor that goes all the way up the bearing - TileEntityTurbinePartBase rotorPart = attachedRotorBearings.iterator().next(); - - // Rotor bearing must calculate outwards dir, as this is normally only calculated in onMachineAssembled(). - rotorPart.recalculateOutwardsDirection(getMinimumCoord(), getMaximumCoord()); - - // Find out which way the rotor runs. Obv, this is inwards from the bearing. - ForgeDirection rotorDir = rotorPart.getOutwardsDir().getOpposite(); - CoordTriplet rotorCoord = rotorPart.getWorldLocation(); - - CoordTriplet minRotorCoord = getMinimumCoord(); - CoordTriplet maxRotorCoord = getMaximumCoord(); - - // Constrain min/max rotor coords to where the rotor bearing is and the block opposite it - if(rotorDir.offsetX == 0) { - minRotorCoord.x = maxRotorCoord.x = rotorCoord.x; - } - if(rotorDir.offsetY == 0) { - minRotorCoord.y = maxRotorCoord.y = rotorCoord.y; - } - if(rotorDir.offsetZ == 0) { - minRotorCoord.z = maxRotorCoord.z = rotorCoord.z; - } - - // Figure out where the rotor ends and which directions are normal to the rotor's 4 faces (this is where blades emit from) - CoordTriplet endRotorCoord = rotorCoord.equals(minRotorCoord) ? maxRotorCoord : minRotorCoord; - endRotorCoord.translate(rotorDir.getOpposite()); - - ForgeDirection[] bladeDirections; - if(rotorDir.offsetY != 0) { - bladeDirections = StaticUtils.CardinalDirections; - } - else if(rotorDir.offsetX != 0) { - bladeDirections = RotorXBladeDirections; - } - else { - bladeDirections = RotorZBladeDirections; - } - - Set rotorShafts = new HashSet(attachedRotorShafts.size()); - Set rotorBlades = new HashSet(attachedRotorBlades.size()); - - for(TileEntityTurbineRotorPart part : attachedRotorShafts) { - rotorShafts.add(part.getWorldLocation()); - } - - for(TileEntityTurbineRotorPart part : attachedRotorBlades) { - rotorBlades.add(part.getWorldLocation()); - } - - // Move along the length of the rotor, 1 block at a time - boolean encounteredCoils = false; - while(!rotorShafts.isEmpty() && !rotorCoord.equals(endRotorCoord)) { - rotorCoord.translate(rotorDir); - - // Ensure we find a rotor block along the length of the entire rotor - if(!rotorShafts.remove(rotorCoord)) { - throw new MultiblockValidationException(String.format("%s - This block must contain a rotor. The rotor must begin at the bearing and run the entire length of the turbine", rotorCoord)); - } - - // Now move out in the 4 rotor normals, looking for blades and coils - CoordTriplet checkCoord = rotorCoord.copy(); - boolean encounteredBlades = false; - for(ForgeDirection bladeDir : bladeDirections) { - checkCoord.copy(rotorCoord); - boolean foundABlade = false; - checkCoord.translate(bladeDir); - - // If we find 1 blade, we can keep moving along the normal to find more blades - while(rotorBlades.remove(checkCoord)) { - // We found a coil already?! NOT ALLOWED. - if(encounteredCoils) { - throw new MultiblockValidationException(String.format("%s - Rotor blades must be placed closer to the rotor bearing than all other parts inside a turbine", checkCoord)); - } - foundABlade = encounteredBlades = true; - checkCoord.translate(bladeDir); - } - - // If this block wasn't a blade, check to see if it was a coil - if(!foundABlade) { - if(foundCoils.remove(checkCoord)) { - encounteredCoils = true; - - // We cannot have blades and coils intermix. This prevents intermixing, depending on eval order. - if(encounteredBlades) { - throw new MultiblockValidationException(String.format("%s - Metal blocks must by placed further from the rotor bearing than all rotor blades", checkCoord)); - } - - // Check the two coil spots in the 'corners', which are permitted if they're connected to the main rotor coil somehow - CoordTriplet coilCheck = checkCoord.copy(); - coilCheck.translate(bladeDir.getRotation(rotorDir)); - foundCoils.remove(coilCheck); - coilCheck.copy(checkCoord); - coilCheck.translate(bladeDir.getRotation(rotorDir.getOpposite())); - foundCoils.remove(coilCheck); - } - // Else: It must have been air. - } - } - } - - if(!rotorCoord.equals(endRotorCoord)) { - throw new MultiblockValidationException("The rotor shaft must extend the entire length of the turbine interior."); - } - - // Ensure that we encountered all the rotor, blade and coil blocks. If not, there's loose stuff inside the turbine. - if(!rotorShafts.isEmpty()) { - throw new MultiblockValidationException(String.format("Found %d rotor blocks that are not attached to the main rotor. All rotor blocks must be in a column extending the entire length of the turbine, starting from the bearing.", rotorShafts.size())); - } - - if(!rotorBlades.isEmpty()) { - throw new MultiblockValidationException(String.format("Found %d rotor blades that are not attached to the rotor. All rotor blades must extend continuously from the rotor's shaft.", rotorBlades.size())); - } - - if(!foundCoils.isEmpty()) { - throw new MultiblockValidationException(String.format("Found %d metal blocks which were not in a ring around the rotor. All metal blocks must be in rings, or partial rings, around the rotor.", foundCoils.size())); - } - - // A-OK! - } - - @Override - protected void isBlockGoodForInterior(World world, int x, int y, int z) throws MultiblockValidationException { - // We only allow air and functional parts in turbines. - - // Air is ok - if(world.isAirBlock(x, y, z)) { return; } - - Block block = world.getBlock(x, y, z); - int metadata = world.getBlockMetadata(x,y,z); - - // Coil windings below here: - if(getCoilPartData(x, y, z, block, metadata) != null) { - foundCoils.add(new CoordTriplet(x,y,z)); - return; - } - - // Everything else, gtfo - throw new MultiblockValidationException(String.format("%d, %d, %d is invalid for a turbine interior. Only rotor parts, metal blocks and empty space are allowed.", x, y, z)); - } - - @Override - protected int getMinimumNumberOfBlocksForAssembledMachine() { - // Hollow 5x5x4 cube (100 - 18), interior minimum is 3x3x2 - return 82; - } - - @Override - protected int getMaximumXSize() { - return BigReactors.maximumTurbineSize; - } - - @Override - protected int getMaximumZSize() { - return BigReactors.maximumTurbineSize; - } - - @Override - protected int getMaximumYSize() { - return BigReactors.maximumTurbineHeight; - } - - @Override - protected int getMinimumXSize() { return 5; } - - @Override - protected int getMinimumYSize() { return 4; } - - @Override - protected int getMinimumZSize() { return 5; } - - - @Override - protected void onAssimilate(MultiblockControllerBase otherMachine) { - if(!(otherMachine instanceof MultiblockTurbine)) { - BRLog.warning("[%s] Turbine @ %s is attempting to assimilate a non-Turbine machine! That machine's data will be lost!", worldObj.isRemote?"CLIENT":"SERVER", getReferenceCoord()); - return; - } - - MultiblockTurbine otherTurbine = (MultiblockTurbine)otherMachine; - - setRotorEnergy(Math.max(rotorEnergy, otherTurbine.rotorEnergy)); - } - - @Override - protected void onAssimilated(MultiblockControllerBase assimilator) { - attachedControllers.clear(); - attachedRotorBearings.clear(); - attachedTickables.clear(); - attachedPowerTaps.clear(); - } - - @Override - protected boolean updateServer() { - energyGeneratedLastTick = 0f; - fluidConsumedLastTick = 0; - rotorEfficiencyLastTick = 1f; - - // Generate energy based on steam - int steamIn = 0; // mB. Based on water, actually. Probably higher for steam. Measure it. - - if(getActive()) { - // Spin up via steam inputs, convert some steam back into water. - // Use at most the user-configured max, or the amount in the tank, whichever is less. - steamIn = Math.min(maxIntakeRate, tanks[TANK_INPUT].getFluidAmount()); - - if(ventStatus == VentStatus.DoNotVent) { - // Cap steam used to available space, if not venting - int availableSpace = tanks[TANK_OUTPUT].getCapacity() - tanks[TANK_OUTPUT].getFluidAmount(); - steamIn = Math.min(steamIn, availableSpace); - } - } - - if(steamIn > 0 || rotorEnergy > 0) { - float rotorSpeed = getRotorSpeed(); - - // RFs lost to aerodynamic drag. - float aerodynamicDragTorque = (float)rotorSpeed * bladeDrag; - - float liftTorque = 0f; - if(steamIn > 0) { - // TODO: Lookup fluid parameters from a table - float fluidEnergyDensity = 10f; // RF per mB - - // Cap amount of steam we can fully extract energy from based on blade size - int steamToProcess = bladeSurfaceArea * inputFluidPerBlade; - steamToProcess = Math.min(steamToProcess, steamIn); - liftTorque = steamToProcess * fluidEnergyDensity; - - // Did we have excess steam for our blade size? - if(steamToProcess < steamIn) { - // Extract some percentage of the remaining steam's energy, based on how many blades are missing - steamToProcess = steamIn - steamToProcess; - float bladeEfficiency = 1f; - int neededBlades = steamIn / inputFluidPerBlade; // round in the player's favor - int missingBlades = neededBlades - bladeSurfaceArea; - bladeEfficiency = 1f - (float)missingBlades / (float)neededBlades; - liftTorque += steamToProcess * fluidEnergyDensity * bladeEfficiency; - - rotorEfficiencyLastTick = liftTorque / (steamIn * fluidEnergyDensity); - } - } - - // Yay for derivation. We're assuming delta-Time is always 1, as we're always calculating for 1 tick. - // RFs available to coils - float inductionTorque = inductorEngaged ? rotorSpeed * inductorDragCoefficient * coilSize : 0f; - float energyToGenerate = (float)Math.pow(inductionTorque, inductionEnergyExponentBonus) * inductionEfficiency; - if(energyToGenerate > 0f) { - // Efficiency curve. Rotors are 50% less efficient when not near 900/1800 RPMs. - float efficiency = (float)(0.25*Math.cos(rotorSpeed/(45.5*Math.PI))) + 0.75f; - if(rotorSpeed < 500) { - efficiency = Math.min(0.5f, efficiency); - } - - generateEnergy(energyToGenerate * efficiency); - } - - rotorEnergy += liftTorque + -1f*inductionTorque + -1f*aerodynamicDragTorque + -1f*frictionalDrag; - if(rotorEnergy < 0f) { rotorEnergy = 0f; } - - // And create some water - if(steamIn > 0) { - fluidConsumedLastTick = steamIn; - drain(TANK_INPUT, steamIn, true); - - if(ventStatus != VentStatus.VentAll) { - Fluid effluent = FluidRegistry.WATER; - FluidStack effluentStack = new FluidStack(effluent, steamIn); - fill(TANK_OUTPUT, effluentStack, true); - } - } - } - - int energyAvailable = (int)getEnergyStored(); - int energyRemaining = energyAvailable; - if(energyStored > 0 && attachedPowerTaps.size() > 0) { - // First, try to distribute fairly - int splitEnergy = energyRemaining / attachedPowerTaps.size(); - for(TileEntityTurbinePowerTap powerTap : attachedPowerTaps) { - if(energyRemaining <= 0) { break; } - if(powerTap == null || !powerTap.isConnected()) { continue; } - - energyRemaining -= splitEnergy - powerTap.onProvidePower(splitEnergy); - } - - // Next, just hose out whatever we can, if we have any left - if(energyRemaining > 0) { - for(TileEntityTurbinePowerTap powerTap : attachedPowerTaps) { - if(energyRemaining <= 0) { break; } - if(powerTap == null || !powerTap.isConnected()) { continue; } - - energyRemaining = powerTap.onProvidePower(energyRemaining); - } - } - } - - if(energyAvailable != energyRemaining) { - reduceStoredEnergy((energyAvailable - energyRemaining)); - } - - for(ITickableMultiblockPart part : attachedTickables) { - part.onMultiblockServerTick(); - } - - ticksSinceLastUpdate++; - if(ticksSinceLastUpdate >= ticksBetweenUpdates) { - sendTickUpdate(); - ticksSinceLastUpdate = 0; - } - - if(rpmUpdateTracker.shouldUpdate(getRotorSpeed())) { - markReferenceCoordDirty(); - } - - return energyGeneratedLastTick > 0 || fluidConsumedLastTick > 0; - } - - @Override - protected void updateClient() { - } - - @Override - public void writeToNBT(NBTTagCompound data) { - data.setTag("inputTank", tanks[TANK_INPUT].writeToNBT(new NBTTagCompound())); - data.setTag("outputTank", tanks[TANK_OUTPUT].writeToNBT(new NBTTagCompound())); - data.setBoolean("active", active); - data.setFloat("energy", energyStored); - data.setInteger("ventStatus", ventStatus.ordinal()); - data.setFloat("rotorEnergy", rotorEnergy); - data.setInteger("maxIntakeRate", maxIntakeRate); - data.setBoolean("inductorEngaged", inductorEngaged); - } - - @Override - public void readFromNBT(NBTTagCompound data) { - if(data.hasKey("inputTank")) { - tanks[TANK_INPUT].readFromNBT(data.getCompoundTag("inputTank")); - } - - if(data.hasKey("outputTank")) { - tanks[TANK_OUTPUT].readFromNBT(data.getCompoundTag("outputTank")); - } - - if(data.hasKey("active")) { - setActive(data.getBoolean("active")); - } - - if(data.hasKey("energy")) { - setEnergyStored(data.getFloat("energy")); - } - - if(data.hasKey("ventStatus")) { - setVentStatus(VentStatus.values()[data.getInteger("ventStatus")], false); - } - - if(data.hasKey("rotorEnergy")) { - setRotorEnergy(data.getFloat("rotorEnergy")); - - if(!worldObj.isRemote) { - rpmUpdateTracker.setValue(getRotorSpeed()); - } - } - - if(data.hasKey("maxIntakeRate")) { - maxIntakeRate = data.getInteger("maxIntakeRate"); - } - - if(data.hasKey("inductorEngaged")) { - setInductorEngaged(data.getBoolean("inductorEngaged"), false); - } - } - - @Override - public void formatDescriptionPacket(NBTTagCompound data) { - writeToNBT(data); - } - - @Override - public void decodeDescriptionPacket(NBTTagCompound data) { - readFromNBT(data); - } - - // Network Serialization - /** - * Used when dispatching update packets from the server. - * @param buf ByteBuf into which the turbine's full status should be written - */ - public void serialize(ByteBuf buf) { - // Capture compacted fluid data first - int inputFluidID, inputFluidAmt, outputFluidID, outputFluidAmt; - { - FluidStack inputFluid, outputFluid; - inputFluid = tanks[TANK_INPUT].getFluid(); - outputFluid = tanks[TANK_OUTPUT].getFluid(); - - if(inputFluid == null || inputFluid.amount <= 0) { - inputFluidID = FLUID_NONE; - inputFluidAmt = 0; - } - else { - inputFluidID = inputFluid.getFluid().getID(); - inputFluidAmt = inputFluid.amount; - } - - if(outputFluid == null || outputFluid.amount <= 0) { - outputFluidID = FLUID_NONE; - outputFluidAmt = 0; - } - else { - outputFluidID = outputFluid.getFluid().getID(); - outputFluidAmt = outputFluid.amount; - } - } - - // User settings - buf.writeBoolean(active); - buf.writeBoolean(inductorEngaged); - buf.writeInt(ventStatus.ordinal()); - buf.writeInt(maxIntakeRate); - - // Basic stats - buf.writeFloat(energyStored); - buf.writeFloat(rotorEnergy); - - // Reportage statistics - buf.writeFloat(energyGeneratedLastTick); - buf.writeInt(fluidConsumedLastTick); - buf.writeFloat(rotorEfficiencyLastTick); - - // Fluid data - buf.writeInt(inputFluidID); - buf.writeInt(inputFluidAmt); - buf.writeInt(outputFluidID); - buf.writeInt(outputFluidAmt); - } - - /** - * Used when a status packet arrives on the client. - * @param buf ByteBuf containing serialized turbine data - */ - public void deserialize(ByteBuf buf) { - // User settings - setActive(buf.readBoolean()); - setInductorEngaged(buf.readBoolean(), false); - setVentStatus(s_VentStatuses[buf.readInt()], false); - setMaxIntakeRate(buf.readInt()); - - // Basic data - setEnergyStored(buf.readFloat()); - setRotorEnergy(buf.readFloat()); - - // Reportage - energyGeneratedLastTick = buf.readFloat(); - fluidConsumedLastTick = buf.readInt(); - rotorEfficiencyLastTick = buf.readFloat(); - - // Fluid data - int inputFluidID = buf.readInt(); - int inputFluidAmt = buf.readInt(); - int outputFluidID = buf.readInt(); - int outputFluidAmt = buf.readInt(); - - if(inputFluidID == FLUID_NONE || inputFluidAmt <= 0) { - tanks[TANK_INPUT].setFluid(null); - } - else { - Fluid fluid = FluidRegistry.getFluid(inputFluidID); - if(fluid == null) { - BRLog.warning("[CLIENT] Multiblock Turbine received an unknown fluid of type %d, setting input tank to empty", inputFluidID); - tanks[TANK_INPUT].setFluid(null); - } - else { - tanks[TANK_INPUT].setFluid(new FluidStack(fluid, inputFluidAmt)); - } - } - - if(outputFluidID == FLUID_NONE || outputFluidAmt <= 0) { - tanks[TANK_OUTPUT].setFluid(null); - } - else { - Fluid fluid = FluidRegistry.getFluid(outputFluidID); - if(fluid == null) { - BRLog.warning("[CLIENT] Multiblock Turbine received an unknown fluid of type %d, setting output tank to empty", outputFluidID); - tanks[TANK_OUTPUT].setFluid(null); - } - else { - tanks[TANK_OUTPUT].setFluid(new FluidStack(fluid, outputFluidAmt)); - } - } - } - - // Nondirectional FluidHandler implementation, similar to IFluidHandler - public int fill(int tank, FluidStack resource, boolean doFill) { - if(!canFill(tank, resource.getFluid())) { - return 0; - } - - return tanks[tank].fill(resource, doFill); - } - - public FluidStack drain(int tank, FluidStack resource, boolean doDrain) { - if(canDrain(tank, resource.getFluid())) { - return tanks[tank].drain(resource.amount, doDrain); - } - - return null; - } - - public FluidStack drain(int tank, int maxDrain, boolean doDrain) { - if(tank < 0 || tank >= NUM_TANKS) { return null; } - - return tanks[tank].drain(maxDrain, doDrain); - } - - public boolean canFill(int tank, Fluid fluid) { - if(tank < 0 || tank >= NUM_TANKS) { return false; } - - FluidStack fluidStack = tanks[tank].getFluid(); - if(fluidStack != null) { - return fluidStack.getFluid().getID() == fluid.getID(); - } - else if(tank == TANK_INPUT) { - // TODO: Input tank can only be filled with compatible fluids from a registry - return fluid.getName().equals("steam"); - } - else { - // Output tank can be filled with anything. Don't be a dumb. - return true; - } - } - - public boolean canDrain(int tank, Fluid fluid) { - if(tank < 0 || tank >= NUM_TANKS) { return false; } - FluidStack fluidStack = tanks[tank].getFluid(); - if(fluidStack == null) { - return false; - } - - return fluidStack.getFluid().getID() == fluid.getID(); - } - - public FluidTankInfo[] getTankInfo() { - FluidTankInfo[] infos = new FluidTankInfo[NUM_TANKS]; - for(int i = 0; i < NUM_TANKS; i++) { - infos[i] = tanks[i].getInfo(); - } - - return infos; - } - - public FluidTankInfo getTankInfo(int tankIdx) { - return tanks[tankIdx].getInfo(); - } - - // IEnergyProvider - - @Override - public int extractEnergy(ForgeDirection from, int maxExtract, boolean simulate) { - int energyExtracted = Math.min((int)energyStored, maxExtract); - - if(!simulate) { - energyStored -= energyExtracted; - } - - return energyExtracted; - } - - @Override - public boolean canConnectEnergy(ForgeDirection from) { - return true; - } - - @Override - public int getEnergyStored(ForgeDirection from) { - return (int)energyStored; - } - - @Override - public int getMaxEnergyStored(ForgeDirection from) { - return (int)maxEnergyStored; - } - - private void setEnergyStored(float newEnergy) { - if(Float.isInfinite(newEnergy) || Float.isNaN(newEnergy)) { return; } - - energyStored = Math.max(0f, Math.min(maxEnergyStored, newEnergy)); - } - - // Energy Helpers - public float getEnergyStored() { - return energyStored; - } - - /** - * Remove some energy from the internal storage buffer. - * Will not reduce the buffer below 0. - * @param energy Amount by which the buffer should be reduced. - */ - protected void reduceStoredEnergy(float energy) { - addStoredEnergy(-1f * energy); - } - - /** - * Add some energy to the internal storage buffer. - * Will not increase the buffer above the maximum or reduce it below 0. - * @param newEnergy - */ - protected void addStoredEnergy(float newEnergy) { - if(Float.isNaN(newEnergy)) { return; } - - energyStored += newEnergy; - if(energyStored > maxEnergyStored) { - energyStored = maxEnergyStored; - } - if(-0.00001f < energyStored && energyStored < 0.00001f) { - // Clamp to zero - energyStored = 0f; - } - } - - public void setStoredEnergy(float oldEnergy) { - energyStored = oldEnergy; - if(energyStored < 0.0 || Float.isNaN(energyStored)) { - energyStored = 0.0f; - } - else if(energyStored > maxEnergyStored) { - energyStored = maxEnergyStored; - } - } - - /** - * Generate energy, internally. Will be multiplied by the BR Setting powerProductionMultiplier - * @param newEnergy Base, unmultiplied energy to generate - */ - protected void generateEnergy(float newEnergy) { - newEnergy = newEnergy * BigReactors.powerProductionMultiplier * BigReactors.turbinePowerProductionMultiplier; - energyGeneratedLastTick += newEnergy; - addStoredEnergy(newEnergy); - } - - // Activity state - public boolean getActive() { - return active; - } - - public void setActive(boolean newValue) { - if(newValue != active) { - this.active = newValue; - for(IMultiblockPart part : connectedParts) { - if(this.active) { part.onMachineActivated(); } - else { part.onMachineDeactivated(); } - } - - CoordTriplet referenceCoord = getReferenceCoord(); - worldObj.markBlockForUpdate(referenceCoord.x, referenceCoord.y, referenceCoord.z); - - markReferenceCoordDirty(); - } - - if(worldObj.isRemote) { - // Force controllers to re-render on client - for(IMultiblockPart part : attachedControllers) { - worldObj.markBlockForUpdate(part.xCoord, part.yCoord, part.zCoord); - } - - for(TileEntityTurbineRotorPart part : attachedRotorBlades) { - worldObj.markBlockForUpdate(part.xCoord, part.yCoord, part.zCoord); - } - - for(TileEntityTurbineRotorPart part : attachedRotorShafts) { - worldObj.markBlockForUpdate(part.xCoord, part.yCoord, part.zCoord); - } - } - } - - // Governor - public int getMaxIntakeRate() { return maxIntakeRate; } - - public void setMaxIntakeRate(int newRate) { - maxIntakeRate = Math.min(MAX_PERMITTED_FLOW, Math.max(0, newRate)); - markReferenceCoordDirty(); - } - - // for GUI use - public int getMaxIntakeRateMax() { return MAX_PERMITTED_FLOW; } - - // ISlotlessUpdater - @Override - public void beginUpdatingPlayer(EntityPlayer playerToUpdate) { - updatePlayers.add(playerToUpdate); - sendIndividualUpdate(playerToUpdate); - } - - @Override - public void stopUpdatingPlayer(EntityPlayer playerToRemove) { - updatePlayers.remove(playerToRemove); - } - - @Override - public boolean isUseableByPlayer(EntityPlayer player) { - return true; - } - - private CoilPartData getCoilPartData(int x, int y, int z, Block block, int metadata) { - // Allow vanilla iron and gold blocks - if(block == Blocks.iron_block) { return TurbineCoil.getBlockData("blockIron"); } - if(block == Blocks.gold_block) { return TurbineCoil.getBlockData("blockGold"); } - - if(block == BigReactors.blockMetal && metadata == BlockBRMetal.METADATA_LUDICRITE) { return TurbineCoil.getBlockData("blockLudicrite"); } - - // Check the oredict to see if it's copper, or a funky kind of gold/iron block - String oreName = ItemHelper.oreProxy.getOreName(new ItemStack(block, 1, metadata)); - return TurbineCoil.getBlockData(oreName); - } - - /** - * Recalculate rotor and coil parameters - */ - private void recalculateDerivedStatistics() { - CoordTriplet minInterior, maxInterior; - minInterior = getMinimumCoord(); - maxInterior = getMaximumCoord(); - minInterior.x++; minInterior.y++; minInterior.z++; - maxInterior.x--; maxInterior.y--; maxInterior.z--; - - rotorMass = 0; - bladeSurfaceArea = 0; - coilSize = 0; - float coilEfficiency = 0f; - float coilBonus = 0f; - float coilDragCoefficient = 0f; - - // Loop over interior space. Calculate mass and blade area of rotor and size of coils - for(int x = minInterior.x; x <= maxInterior.x; x++) { - for(int y = minInterior.y; y <= maxInterior.y; y++) { - for(int z = minInterior.z; z <= maxInterior.z; z++) { - Block block = worldObj.getBlock(x, y, z); - int metadata = worldObj.getBlockMetadata(x, y, z); - CoilPartData coilData = null; - - if(block == BigReactors.blockTurbineRotorPart) { - rotorMass += BigReactors.blockTurbineRotorPart.getRotorMass(block, metadata); - if(BlockTurbineRotorPart.isRotorBlade(metadata)) { - bladeSurfaceArea += 1; - } - } - - coilData = getCoilPartData(x, y, z, block, metadata); - if(coilData != null) { - coilEfficiency += coilData.efficiency; - coilBonus += coilData.bonus; - coilDragCoefficient += coilData.energyExtractionRate; - coilSize += 1; - } - } // end z - } // end y - } // end x loop - looping over interior - - // Precalculate some stuff now that we know how big the rotor and blades are - frictionalDrag = rotorMass * rotorDragCoefficient * BigReactors.turbineMassDragMultiplier; - bladeDrag = baseBladeDragCoefficient * bladeSurfaceArea * BigReactors.turbineAeroDragMultiplier; - - if(coilSize <= 0) - { - // Uh. No coil? Fine. - inductionEfficiency = 0f; - inductionEnergyExponentBonus = 1f; - inductorDragCoefficient = 0f; - } - else - { - inductionEfficiency = (coilEfficiency * 0.33f) / coilSize; - inductionEnergyExponentBonus = Math.max(1f, (coilBonus / coilSize)); - inductorDragCoefficient = (coilDragCoefficient / coilSize) * inductorBaseDragCoefficient; - } - } - - public float getRotorSpeed() { - if(attachedRotorBlades.size() <= 0 || rotorMass <= 0) { return 0f; } - return rotorEnergy / (attachedRotorBlades.size() * rotorMass); - } - - public float getEnergyGeneratedLastTick() { return energyGeneratedLastTick; } - public int getFluidConsumedLastTick() { return fluidConsumedLastTick; } - public int getNumRotorBlades() { return attachedRotorBlades.size(); } - public float getRotorEfficiencyLastTick() { return rotorEfficiencyLastTick; } - - public float getMaxRotorSpeed() { - return 2000f; - } - - public int getRotorMass() { - return rotorMass; - } - - public VentStatus getVentSetting() { - return ventStatus; - } - - public void setVentStatus(VentStatus newStatus, boolean markReferenceCoordDirty) { - ventStatus = newStatus; - if(markReferenceCoordDirty) - markReferenceCoordDirty(); - } - - public boolean getInductorEngaged() { - return inductorEngaged; - } - - public void setInductorEngaged(boolean engaged, boolean markReferenceCoordDirty) { - inductorEngaged = engaged; - if(markReferenceCoordDirty) - markReferenceCoordDirty(); - } - - - private void setRotorEnergy(float newEnergy) { - if(Float.isNaN(newEnergy) || Float.isInfinite(newEnergy)) { return; } - rotorEnergy = Math.max(0f, newEnergy); - } - - protected void markReferenceCoordDirty() { - if(worldObj == null || worldObj.isRemote) { return; } - - CoordTriplet referenceCoord = getReferenceCoord(); - if(referenceCoord == null) { return; } - - rpmUpdateTracker.onExternalUpdate(); - - TileEntity saveTe = worldObj.getTileEntity(referenceCoord.x, referenceCoord.y, referenceCoord.z); - worldObj.markTileEntityChunkModified(referenceCoord.x, referenceCoord.y, referenceCoord.z, saveTe); - worldObj.markBlockForUpdate(referenceCoord.x, referenceCoord.y, referenceCoord.z); - } - - // For client usage only - public ForgeDirection getRotorDirection() { - if(attachedRotorBearings.size() < 1) { - return ForgeDirection.UNKNOWN; - } - - if(!this.isAssembled()) { - return ForgeDirection.UNKNOWN; - } - - TileEntityTurbineRotorBearing rotorBearing = attachedRotorBearings.iterator().next(); - return rotorBearing.getOutwardsDir().getOpposite(); - } - - public boolean hasGlass() { return attachedGlass.size() > 0; } - - public String getDebugInfo() { - StringBuilder sb = new StringBuilder(); - sb.append("Assembled: ").append(Boolean.toString(isAssembled())).append("\n"); - sb.append("Attached Blocks: ").append(Integer.toString(connectedParts.size())).append("\n"); - if(getLastValidationException() != null) { - sb.append("Validation Exception:\n").append(getLastValidationException().getMessage()).append("\n"); - } - - if(isAssembled()) { - sb.append("\nActive: ").append(Boolean.toString(getActive())); - sb.append("\nStored Energy: ").append(Float.toString(getEnergyStored())); - sb.append("\nRotor Energy: ").append(Float.toString(rotorEnergy)); - sb.append("\nRotor Speed: ").append(Float.toString(getRotorSpeed())).append(" rpm"); - sb.append("\nInductor Engaged: ").append(Boolean.toString(inductorEngaged)); - sb.append("\nVent Status: ").append(ventStatus.toString()); - sb.append("\nMax Intake Rate: ").append(Integer.toString(maxIntakeRate)); - sb.append("\nCoil Size: ").append(Integer.toString(coilSize)); - sb.append("\nRotor Mass: ").append(Integer.toString(rotorMass)); - sb.append("\nBlade SurfArea: ").append(Integer.toString(bladeSurfaceArea)); - sb.append("\n# Blades: ").append(Integer.toString(attachedRotorBlades.size())); - sb.append("\n# Shafts: ").append(Integer.toString(attachedRotorShafts.size())); - sb.append("\nRotor Drag CoEff: ").append(Float.toString(rotorDragCoefficient)); - sb.append("\nBlade Drag: ").append(Float.toString(bladeDrag)); - sb.append("\nFrict Drag: ").append(Float.toString(frictionalDrag)); - sb.append("\n\nFluid Tanks:\n"); - for(int i = 0; i < tanks.length; i++) { - sb.append(String.format("[%d] %s ", i, i == TANK_OUTPUT ? "outlet":"inlet")); - if(tanks[i] == null || tanks[i].getFluid() == null) { - sb.append("empty"); - } - else { - FluidStack stack = tanks[i].getFluid(); - sb.append(String.format("%s, %d mB", stack.getFluid().getName(), stack.amount)); - } - sb.append("\n"); - } - } - - return sb.toString(); - } - - @SideOnly(Side.CLIENT) - public void resetCachedRotors() { - for(TileEntityTurbineRotorBearing bearing: attachedRotorBearings) { - bearing.clearDisplayList(); - } - } + } + + /** + * Send an update to any clients with GUIs open + */ + protected void sendTickUpdate() { + if (this.updatePlayers.size() <= 0) { + return; + } + + for (EntityPlayer player : updatePlayers) { + CommonPacketHandler.INSTANCE.sendTo(getUpdatePacket(), (EntityPlayerMP) player); + } + } + + // MultiblockControllerBase overrides + + @Override + public void onAttachedPartWithMultiblockData(IMultiblockPart part, NBTTagCompound data) { + readFromNBT(data); + } + + @Override + protected void onBlockAdded(IMultiblockPart newPart) { + if (newPart instanceof TileEntityTurbineRotorBearing) { + this.attachedRotorBearings.add((TileEntityTurbineRotorBearing) newPart); + } + + if (newPart instanceof TileEntityTurbinePowerTap) { + attachedPowerTaps.add((TileEntityTurbinePowerTap) newPart); + } + + if (newPart instanceof ITickableMultiblockPart) { + attachedTickables.add((ITickableMultiblockPart) newPart); + } + + if (newPart instanceof TileEntityTurbineRotorPart) { + TileEntityTurbineRotorPart turbinePart = (TileEntityTurbineRotorPart) newPart; + if (turbinePart.isRotorShaft()) { + attachedRotorShafts.add(turbinePart); + } + + if (turbinePart.isRotorBlade()) { + attachedRotorBlades.add(turbinePart); + } + } + + if (newPart instanceof TileEntityTurbinePartGlass) { + attachedGlass.add((TileEntityTurbinePartGlass) newPart); + } + + } + + @Override + protected void onBlockRemoved(IMultiblockPart oldPart) { + if (oldPart instanceof TileEntityTurbineRotorBearing) { + this.attachedRotorBearings.remove(oldPart); + } + + if (oldPart instanceof TileEntityTurbinePowerTap) { + attachedPowerTaps.remove((TileEntityTurbinePowerTap) oldPart); + } + + if (oldPart instanceof ITickableMultiblockPart) { + attachedTickables.remove((ITickableMultiblockPart) oldPart); + } + + if (oldPart instanceof TileEntityTurbineRotorPart) { + TileEntityTurbineRotorPart turbinePart = (TileEntityTurbineRotorPart) oldPart; + if (turbinePart.isRotorShaft()) { + attachedRotorShafts.remove(turbinePart); + } + + if (turbinePart.isRotorBlade()) { + attachedRotorBlades.remove(turbinePart); + } + } + + if (oldPart instanceof TileEntityTurbinePartGlass) { + attachedGlass.remove((TileEntityTurbinePartGlass) oldPart); + } + } + + @Override + protected void onMachineAssembled() { + recalculateDerivedStatistics(); + } + + @Override + protected void onMachineRestored() { + recalculateDerivedStatistics(); + } + + @Override + protected void onMachinePaused() {} + + @Override + protected void onMachineDisassembled() { + rotorMass = 0; + bladeSurfaceArea = 0; + coilSize = 0; + + rotorEnergy = 0f; // Kill energy when machines get broken by players/explosions + rpmUpdateTracker.setValue(0f); + } + + // Validation code + @Override + protected void isMachineWhole() throws MultiblockValidationException { + if (attachedRotorBearings.size() != 1) { + throw new MultiblockValidationException("Turbines require exactly 1 rotor bearing"); + } + + // Set up validation caches + foundCoils.clear(); + + super.isMachineWhole(); + + // Now do additional validation based on the coils/blades/rotors that were found + + // Check that we have a rotor that goes all the way up the bearing + TileEntityTurbinePartBase rotorPart = attachedRotorBearings.iterator() + .next(); + + // Rotor bearing must calculate outwards dir, as this is normally only calculated in onMachineAssembled(). + rotorPart.recalculateOutwardsDirection(getMinimumCoord(), getMaximumCoord()); + + // Find out which way the rotor runs. Obv, this is inwards from the bearing. + ForgeDirection rotorDir = rotorPart.getOutwardsDir() + .getOpposite(); + CoordTriplet rotorCoord = rotorPart.getWorldLocation(); + + CoordTriplet minRotorCoord = getMinimumCoord(); + CoordTriplet maxRotorCoord = getMaximumCoord(); + + // Constrain min/max rotor coords to where the rotor bearing is and the block opposite it + if (rotorDir.offsetX == 0) { + minRotorCoord.x = maxRotorCoord.x = rotorCoord.x; + } + if (rotorDir.offsetY == 0) { + minRotorCoord.y = maxRotorCoord.y = rotorCoord.y; + } + if (rotorDir.offsetZ == 0) { + minRotorCoord.z = maxRotorCoord.z = rotorCoord.z; + } + + // Figure out where the rotor ends and which directions are normal to the rotor's 4 faces (this is where blades + // emit from) + CoordTriplet endRotorCoord = rotorCoord.equals(minRotorCoord) ? maxRotorCoord : minRotorCoord; + endRotorCoord.translate(rotorDir.getOpposite()); + + ForgeDirection[] bladeDirections; + if (rotorDir.offsetY != 0) { + bladeDirections = StaticUtils.CardinalDirections; + } else if (rotorDir.offsetX != 0) { + bladeDirections = RotorXBladeDirections; + } else { + bladeDirections = RotorZBladeDirections; + } + + Set rotorShafts = new HashSet(attachedRotorShafts.size()); + Set rotorBlades = new HashSet(attachedRotorBlades.size()); + + for (TileEntityTurbineRotorPart part : attachedRotorShafts) { + rotorShafts.add(part.getWorldLocation()); + } + + for (TileEntityTurbineRotorPart part : attachedRotorBlades) { + rotorBlades.add(part.getWorldLocation()); + } + + // Move along the length of the rotor, 1 block at a time + boolean encounteredCoils = false; + while (!rotorShafts.isEmpty() && !rotorCoord.equals(endRotorCoord)) { + rotorCoord.translate(rotorDir); + + // Ensure we find a rotor block along the length of the entire rotor + if (!rotorShafts.remove(rotorCoord)) { + throw new MultiblockValidationException( + String.format( + "%s - This block must contain a rotor. The rotor must begin at the bearing and run the entire length of the turbine", + rotorCoord)); + } + + // Now move out in the 4 rotor normals, looking for blades and coils + CoordTriplet checkCoord = rotorCoord.copy(); + boolean encounteredBlades = false; + for (ForgeDirection bladeDir : bladeDirections) { + checkCoord.copy(rotorCoord); + boolean foundABlade = false; + checkCoord.translate(bladeDir); + + // If we find 1 blade, we can keep moving along the normal to find more blades + while (rotorBlades.remove(checkCoord)) { + // We found a coil already?! NOT ALLOWED. + if (encounteredCoils) { + throw new MultiblockValidationException( + String.format( + "%s - Rotor blades must be placed closer to the rotor bearing than all other parts inside a turbine", + checkCoord)); + } + foundABlade = encounteredBlades = true; + checkCoord.translate(bladeDir); + } + + // If this block wasn't a blade, check to see if it was a coil + if (!foundABlade) { + if (foundCoils.remove(checkCoord)) { + encounteredCoils = true; + + // We cannot have blades and coils intermix. This prevents intermixing, depending on eval order. + if (encounteredBlades) { + throw new MultiblockValidationException( + String.format( + "%s - Metal blocks must by placed further from the rotor bearing than all rotor blades", + checkCoord)); + } + + // Check the two coil spots in the 'corners', which are permitted if they're connected to the + // main rotor coil somehow + CoordTriplet coilCheck = checkCoord.copy(); + coilCheck.translate(bladeDir.getRotation(rotorDir)); + foundCoils.remove(coilCheck); + coilCheck.copy(checkCoord); + coilCheck.translate(bladeDir.getRotation(rotorDir.getOpposite())); + foundCoils.remove(coilCheck); + } + // Else: It must have been air. + } + } + } + + if (!rotorCoord.equals(endRotorCoord)) { + throw new MultiblockValidationException( + "The rotor shaft must extend the entire length of the turbine interior."); + } + + // Ensure that we encountered all the rotor, blade and coil blocks. If not, there's loose stuff inside the + // turbine. + if (!rotorShafts.isEmpty()) { + throw new MultiblockValidationException( + String.format( + "Found %d rotor blocks that are not attached to the main rotor. All rotor blocks must be in a column extending the entire length of the turbine, starting from the bearing.", + rotorShafts.size())); + } + + if (!rotorBlades.isEmpty()) { + throw new MultiblockValidationException( + String.format( + "Found %d rotor blades that are not attached to the rotor. All rotor blades must extend continuously from the rotor's shaft.", + rotorBlades.size())); + } + + if (!foundCoils.isEmpty()) { + throw new MultiblockValidationException( + String.format( + "Found %d metal blocks which were not in a ring around the rotor. All metal blocks must be in rings, or partial rings, around the rotor.", + foundCoils.size())); + } + + // A-OK! + } + + @Override + protected void isBlockGoodForInterior(World world, int x, int y, int z) throws MultiblockValidationException { + // We only allow air and functional parts in turbines. + + // Air is ok + if (world.isAirBlock(x, y, z)) { + return; + } + + Block block = world.getBlock(x, y, z); + int metadata = world.getBlockMetadata(x, y, z); + + // Coil windings below here: + if (getCoilPartData(x, y, z, block, metadata) != null) { + foundCoils.add(new CoordTriplet(x, y, z)); + return; + } + + // Everything else, gtfo + throw new MultiblockValidationException( + String.format( + "%d, %d, %d is invalid for a turbine interior. Only rotor parts, metal blocks and empty space are allowed.", + x, + y, + z)); + } + + @Override + protected int getMinimumNumberOfBlocksForAssembledMachine() { + // Hollow 5x5x4 cube (100 - 18), interior minimum is 3x3x2 + return 82; + } + + @Override + protected int getMaximumXSize() { + return BigReactors.maximumTurbineSize; + } + + @Override + protected int getMaximumZSize() { + return BigReactors.maximumTurbineSize; + } + + @Override + protected int getMaximumYSize() { + return BigReactors.maximumTurbineHeight; + } + + @Override + protected int getMinimumXSize() { + return 5; + } + + @Override + protected int getMinimumYSize() { + return 4; + } + + @Override + protected int getMinimumZSize() { + return 5; + } + + @Override + protected void onAssimilate(MultiblockControllerBase otherMachine) { + if (!(otherMachine instanceof MultiblockTurbine)) { + BRLog.warning( + "[%s] Turbine @ %s is attempting to assimilate a non-Turbine machine! That machine's data will be lost!", + worldObj.isRemote ? "CLIENT" : "SERVER", + getReferenceCoord()); + return; + } + + MultiblockTurbine otherTurbine = (MultiblockTurbine) otherMachine; + + setRotorEnergy(Math.max(rotorEnergy, otherTurbine.rotorEnergy)); + } + + @Override + protected void onAssimilated(MultiblockControllerBase assimilator) { + attachedControllers.clear(); + attachedRotorBearings.clear(); + attachedTickables.clear(); + attachedPowerTaps.clear(); + } + + @Override + protected boolean updateServer() { + energyGeneratedLastTick = 0f; + fluidConsumedLastTick = 0; + rotorEfficiencyLastTick = 1f; + + // Generate energy based on steam + int steamIn = 0; // mB. Based on water, actually. Probably higher for steam. Measure it. + + if (getActive()) { + // Spin up via steam inputs, convert some steam back into water. + // Use at most the user-configured max, or the amount in the tank, whichever is less. + steamIn = Math.min(maxIntakeRate, tanks[TANK_INPUT].getFluidAmount()); + + if (ventStatus == VentStatus.DoNotVent) { + // Cap steam used to available space, if not venting + int availableSpace = tanks[TANK_OUTPUT].getCapacity() - tanks[TANK_OUTPUT].getFluidAmount(); + steamIn = Math.min(steamIn, availableSpace); + } + } + + if (steamIn > 0 || rotorEnergy > 0) { + float rotorSpeed = getRotorSpeed(); + + // RFs lost to aerodynamic drag. + float aerodynamicDragTorque = (float) rotorSpeed * bladeDrag; + + float liftTorque = 0f; + if (steamIn > 0) { + // TODO: Lookup fluid parameters from a table + float fluidEnergyDensity = 10f; // RF per mB + + // Cap amount of steam we can fully extract energy from based on blade size + int steamToProcess = bladeSurfaceArea * inputFluidPerBlade; + steamToProcess = Math.min(steamToProcess, steamIn); + liftTorque = steamToProcess * fluidEnergyDensity; + + // Did we have excess steam for our blade size? + if (steamToProcess < steamIn) { + // Extract some percentage of the remaining steam's energy, based on how many blades are missing + steamToProcess = steamIn - steamToProcess; + float bladeEfficiency = 1f; + int neededBlades = steamIn / inputFluidPerBlade; // round in the player's favor + int missingBlades = neededBlades - bladeSurfaceArea; + bladeEfficiency = 1f - (float) missingBlades / (float) neededBlades; + liftTorque += steamToProcess * fluidEnergyDensity * bladeEfficiency; + + rotorEfficiencyLastTick = liftTorque / (steamIn * fluidEnergyDensity); + } + } + + // Yay for derivation. We're assuming delta-Time is always 1, as we're always calculating for 1 tick. + // RFs available to coils + float inductionTorque = inductorEngaged ? rotorSpeed * inductorDragCoefficient * coilSize : 0f; + float energyToGenerate = (float) Math.pow(inductionTorque, inductionEnergyExponentBonus) + * inductionEfficiency; + if (energyToGenerate > 0f) { + // Efficiency curve. Rotors are 50% less efficient when not near 900/1800 RPMs. + float efficiency = (float) (0.25 * Math.cos(rotorSpeed / (45.5 * Math.PI))) + 0.75f; + if (rotorSpeed < 500) { + efficiency = Math.min(0.5f, efficiency); + } + + generateEnergy(energyToGenerate * efficiency); + } + + rotorEnergy += liftTorque + -1f * inductionTorque + -1f * aerodynamicDragTorque + -1f * frictionalDrag; + if (rotorEnergy < 0f) { + rotorEnergy = 0f; + } + + // And create some water + if (steamIn > 0) { + fluidConsumedLastTick = steamIn; + drain(TANK_INPUT, steamIn, true); + + if (ventStatus != VentStatus.VentAll) { + Fluid effluent = FluidRegistry.WATER; + FluidStack effluentStack = new FluidStack(effluent, steamIn); + fill(TANK_OUTPUT, effluentStack, true); + } + } + } + + int energyAvailable = (int) getEnergyStored(); + int energyRemaining = energyAvailable; + if (energyStored > 0 && attachedPowerTaps.size() > 0) { + // First, try to distribute fairly + int splitEnergy = energyRemaining / attachedPowerTaps.size(); + for (TileEntityTurbinePowerTap powerTap : attachedPowerTaps) { + if (energyRemaining <= 0) { + break; + } + if (powerTap == null || !powerTap.isConnected()) { + continue; + } + + energyRemaining -= splitEnergy - powerTap.onProvidePower(splitEnergy); + } + + // Next, just hose out whatever we can, if we have any left + if (energyRemaining > 0) { + for (TileEntityTurbinePowerTap powerTap : attachedPowerTaps) { + if (energyRemaining <= 0) { + break; + } + if (powerTap == null || !powerTap.isConnected()) { + continue; + } + + energyRemaining = powerTap.onProvidePower(energyRemaining); + } + } + } + + if (energyAvailable != energyRemaining) { + reduceStoredEnergy((energyAvailable - energyRemaining)); + } + + for (ITickableMultiblockPart part : attachedTickables) { + part.onMultiblockServerTick(); + } + + ticksSinceLastUpdate++; + if (ticksSinceLastUpdate >= ticksBetweenUpdates) { + sendTickUpdate(); + ticksSinceLastUpdate = 0; + } + + if (rpmUpdateTracker.shouldUpdate(getRotorSpeed())) { + markReferenceCoordDirty(); + } + + return energyGeneratedLastTick > 0 || fluidConsumedLastTick > 0; + } + + @Override + protected void updateClient() {} + + @Override + public void writeToNBT(NBTTagCompound data) { + data.setTag("inputTank", tanks[TANK_INPUT].writeToNBT(new NBTTagCompound())); + data.setTag("outputTank", tanks[TANK_OUTPUT].writeToNBT(new NBTTagCompound())); + data.setBoolean("active", active); + data.setFloat("energy", energyStored); + data.setInteger("ventStatus", ventStatus.ordinal()); + data.setFloat("rotorEnergy", rotorEnergy); + data.setInteger("maxIntakeRate", maxIntakeRate); + data.setBoolean("inductorEngaged", inductorEngaged); + } + + @Override + public void readFromNBT(NBTTagCompound data) { + if (data.hasKey("inputTank")) { + tanks[TANK_INPUT].readFromNBT(data.getCompoundTag("inputTank")); + } + + if (data.hasKey("outputTank")) { + tanks[TANK_OUTPUT].readFromNBT(data.getCompoundTag("outputTank")); + } + + if (data.hasKey("active")) { + setActive(data.getBoolean("active")); + } + + if (data.hasKey("energy")) { + setEnergyStored(data.getFloat("energy")); + } + + if (data.hasKey("ventStatus")) { + setVentStatus(VentStatus.values()[data.getInteger("ventStatus")], false); + } + + if (data.hasKey("rotorEnergy")) { + setRotorEnergy(data.getFloat("rotorEnergy")); + + if (!worldObj.isRemote) { + rpmUpdateTracker.setValue(getRotorSpeed()); + } + } + + if (data.hasKey("maxIntakeRate")) { + maxIntakeRate = data.getInteger("maxIntakeRate"); + } + + if (data.hasKey("inductorEngaged")) { + setInductorEngaged(data.getBoolean("inductorEngaged"), false); + } + } + + @Override + public void formatDescriptionPacket(NBTTagCompound data) { + writeToNBT(data); + } + + @Override + public void decodeDescriptionPacket(NBTTagCompound data) { + readFromNBT(data); + } + + // Network Serialization + /** + * Used when dispatching update packets from the server. + * + * @param buf ByteBuf into which the turbine's full status should be written + */ + public void serialize(ByteBuf buf) { + // Capture compacted fluid data first + int inputFluidID, inputFluidAmt, outputFluidID, outputFluidAmt; + { + FluidStack inputFluid, outputFluid; + inputFluid = tanks[TANK_INPUT].getFluid(); + outputFluid = tanks[TANK_OUTPUT].getFluid(); + + if (inputFluid == null || inputFluid.amount <= 0) { + inputFluidID = FLUID_NONE; + inputFluidAmt = 0; + } else { + inputFluidID = inputFluid.getFluid() + .getID(); + inputFluidAmt = inputFluid.amount; + } + + if (outputFluid == null || outputFluid.amount <= 0) { + outputFluidID = FLUID_NONE; + outputFluidAmt = 0; + } else { + outputFluidID = outputFluid.getFluid() + .getID(); + outputFluidAmt = outputFluid.amount; + } + } + + // User settings + buf.writeBoolean(active); + buf.writeBoolean(inductorEngaged); + buf.writeInt(ventStatus.ordinal()); + buf.writeInt(maxIntakeRate); + + // Basic stats + buf.writeFloat(energyStored); + buf.writeFloat(rotorEnergy); + + // Reportage statistics + buf.writeFloat(energyGeneratedLastTick); + buf.writeInt(fluidConsumedLastTick); + buf.writeFloat(rotorEfficiencyLastTick); + + // Fluid data + buf.writeInt(inputFluidID); + buf.writeInt(inputFluidAmt); + buf.writeInt(outputFluidID); + buf.writeInt(outputFluidAmt); + } + + /** + * Used when a status packet arrives on the client. + * + * @param buf ByteBuf containing serialized turbine data + */ + public void deserialize(ByteBuf buf) { + // User settings + setActive(buf.readBoolean()); + setInductorEngaged(buf.readBoolean(), false); + setVentStatus(s_VentStatuses[buf.readInt()], false); + setMaxIntakeRate(buf.readInt()); + + // Basic data + setEnergyStored(buf.readFloat()); + setRotorEnergy(buf.readFloat()); + + // Reportage + energyGeneratedLastTick = buf.readFloat(); + fluidConsumedLastTick = buf.readInt(); + rotorEfficiencyLastTick = buf.readFloat(); + + // Fluid data + int inputFluidID = buf.readInt(); + int inputFluidAmt = buf.readInt(); + int outputFluidID = buf.readInt(); + int outputFluidAmt = buf.readInt(); + + if (inputFluidID == FLUID_NONE || inputFluidAmt <= 0) { + tanks[TANK_INPUT].setFluid(null); + } else { + Fluid fluid = FluidRegistry.getFluid(inputFluidID); + if (fluid == null) { + BRLog.warning( + "[CLIENT] Multiblock Turbine received an unknown fluid of type %d, setting input tank to empty", + inputFluidID); + tanks[TANK_INPUT].setFluid(null); + } else { + tanks[TANK_INPUT].setFluid(new FluidStack(fluid, inputFluidAmt)); + } + } + + if (outputFluidID == FLUID_NONE || outputFluidAmt <= 0) { + tanks[TANK_OUTPUT].setFluid(null); + } else { + Fluid fluid = FluidRegistry.getFluid(outputFluidID); + if (fluid == null) { + BRLog.warning( + "[CLIENT] Multiblock Turbine received an unknown fluid of type %d, setting output tank to empty", + outputFluidID); + tanks[TANK_OUTPUT].setFluid(null); + } else { + tanks[TANK_OUTPUT].setFluid(new FluidStack(fluid, outputFluidAmt)); + } + } + } + + // Nondirectional FluidHandler implementation, similar to IFluidHandler + public int fill(int tank, FluidStack resource, boolean doFill) { + if (!canFill(tank, resource.getFluid())) { + return 0; + } + + return tanks[tank].fill(resource, doFill); + } + + public FluidStack drain(int tank, FluidStack resource, boolean doDrain) { + if (canDrain(tank, resource.getFluid())) { + return tanks[tank].drain(resource.amount, doDrain); + } + + return null; + } + + public FluidStack drain(int tank, int maxDrain, boolean doDrain) { + if (tank < 0 || tank >= NUM_TANKS) { + return null; + } + + return tanks[tank].drain(maxDrain, doDrain); + } + + public boolean canFill(int tank, Fluid fluid) { + if (tank < 0 || tank >= NUM_TANKS) { + return false; + } + + FluidStack fluidStack = tanks[tank].getFluid(); + if (fluidStack != null) { + return fluidStack.getFluid() + .getID() == fluid.getID(); + } else if (tank == TANK_INPUT) { + // TODO: Input tank can only be filled with compatible fluids from a registry + return fluid.getName() + .equals("steam"); + } else { + // Output tank can be filled with anything. Don't be a dumb. + return true; + } + } + + public boolean canDrain(int tank, Fluid fluid) { + if (tank < 0 || tank >= NUM_TANKS) { + return false; + } + FluidStack fluidStack = tanks[tank].getFluid(); + if (fluidStack == null) { + return false; + } + + return fluidStack.getFluid() + .getID() == fluid.getID(); + } + + public FluidTankInfo[] getTankInfo() { + FluidTankInfo[] infos = new FluidTankInfo[NUM_TANKS]; + for (int i = 0; i < NUM_TANKS; i++) { + infos[i] = tanks[i].getInfo(); + } + + return infos; + } + + public FluidTankInfo getTankInfo(int tankIdx) { + return tanks[tankIdx].getInfo(); + } + + // IEnergyProvider + + @Override + public int extractEnergy(ForgeDirection from, int maxExtract, boolean simulate) { + int energyExtracted = Math.min((int) energyStored, maxExtract); + + if (!simulate) { + energyStored -= energyExtracted; + } + + return energyExtracted; + } + + @Override + public boolean canConnectEnergy(ForgeDirection from) { + return true; + } + + @Override + public int getEnergyStored(ForgeDirection from) { + return (int) energyStored; + } + + @Override + public int getMaxEnergyStored(ForgeDirection from) { + return (int) maxEnergyStored; + } + + private void setEnergyStored(float newEnergy) { + if (Float.isInfinite(newEnergy) || Float.isNaN(newEnergy)) { + return; + } + + energyStored = Math.max(0f, Math.min(maxEnergyStored, newEnergy)); + } + + // Energy Helpers + public float getEnergyStored() { + return energyStored; + } + + /** + * Remove some energy from the internal storage buffer. + * Will not reduce the buffer below 0. + * + * @param energy Amount by which the buffer should be reduced. + */ + protected void reduceStoredEnergy(float energy) { + addStoredEnergy(-1f * energy); + } + + /** + * Add some energy to the internal storage buffer. + * Will not increase the buffer above the maximum or reduce it below 0. + * + * @param newEnergy + */ + protected void addStoredEnergy(float newEnergy) { + if (Float.isNaN(newEnergy)) { + return; + } + + energyStored += newEnergy; + if (energyStored > maxEnergyStored) { + energyStored = maxEnergyStored; + } + if (-0.00001f < energyStored && energyStored < 0.00001f) { + // Clamp to zero + energyStored = 0f; + } + } + + public void setStoredEnergy(float oldEnergy) { + energyStored = oldEnergy; + if (energyStored < 0.0 || Float.isNaN(energyStored)) { + energyStored = 0.0f; + } else if (energyStored > maxEnergyStored) { + energyStored = maxEnergyStored; + } + } + + /** + * Generate energy, internally. Will be multiplied by the BR Setting powerProductionMultiplier + * + * @param newEnergy Base, unmultiplied energy to generate + */ + protected void generateEnergy(float newEnergy) { + newEnergy = newEnergy * BigReactors.powerProductionMultiplier * BigReactors.turbinePowerProductionMultiplier; + energyGeneratedLastTick += newEnergy; + addStoredEnergy(newEnergy); + } + + // Activity state + public boolean getActive() { + return active; + } + + public void setActive(boolean newValue) { + if (newValue != active) { + this.active = newValue; + for (IMultiblockPart part : connectedParts) { + if (this.active) { + part.onMachineActivated(); + } else { + part.onMachineDeactivated(); + } + } + + CoordTriplet referenceCoord = getReferenceCoord(); + worldObj.markBlockForUpdate(referenceCoord.x, referenceCoord.y, referenceCoord.z); + + markReferenceCoordDirty(); + } + + if (worldObj.isRemote) { + // Force controllers to re-render on client + for (IMultiblockPart part : attachedControllers) { + worldObj.markBlockForUpdate(part.xCoord, part.yCoord, part.zCoord); + } + + for (TileEntityTurbineRotorPart part : attachedRotorBlades) { + worldObj.markBlockForUpdate(part.xCoord, part.yCoord, part.zCoord); + } + + for (TileEntityTurbineRotorPart part : attachedRotorShafts) { + worldObj.markBlockForUpdate(part.xCoord, part.yCoord, part.zCoord); + } + } + } + + // Governor + public int getMaxIntakeRate() { + return maxIntakeRate; + } + + public void setMaxIntakeRate(int newRate) { + maxIntakeRate = Math.min(MAX_PERMITTED_FLOW, Math.max(0, newRate)); + markReferenceCoordDirty(); + } + + // for GUI use + public int getMaxIntakeRateMax() { + return MAX_PERMITTED_FLOW; + } + + // ISlotlessUpdater + @Override + public void beginUpdatingPlayer(EntityPlayer playerToUpdate) { + updatePlayers.add(playerToUpdate); + sendIndividualUpdate(playerToUpdate); + } + + @Override + public void stopUpdatingPlayer(EntityPlayer playerToRemove) { + updatePlayers.remove(playerToRemove); + } + + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return true; + } + + private CoilPartData getCoilPartData(int x, int y, int z, Block block, int metadata) { + // Allow vanilla iron and gold blocks + if (block == Blocks.iron_block) { + return TurbineCoil.getBlockData("blockIron"); + } + if (block == Blocks.gold_block) { + return TurbineCoil.getBlockData("blockGold"); + } + + if (block == BigReactors.blockMetal && metadata == BlockBRMetal.METADATA_LUDICRITE) { + return TurbineCoil.getBlockData("blockLudicrite"); + } + + // Check the oredict to see if it's copper, or a funky kind of gold/iron block + String oreName = ItemHelper.oreProxy.getOreName(new ItemStack(block, 1, metadata)); + return TurbineCoil.getBlockData(oreName); + } + + /** + * Recalculate rotor and coil parameters + */ + private void recalculateDerivedStatistics() { + CoordTriplet minInterior, maxInterior; + minInterior = getMinimumCoord(); + maxInterior = getMaximumCoord(); + minInterior.x++; + minInterior.y++; + minInterior.z++; + maxInterior.x--; + maxInterior.y--; + maxInterior.z--; + + rotorMass = 0; + bladeSurfaceArea = 0; + coilSize = 0; + float coilEfficiency = 0f; + float coilBonus = 0f; + float coilDragCoefficient = 0f; + + // Loop over interior space. Calculate mass and blade area of rotor and size of coils + for (int x = minInterior.x; x <= maxInterior.x; x++) { + for (int y = minInterior.y; y <= maxInterior.y; y++) { + for (int z = minInterior.z; z <= maxInterior.z; z++) { + Block block = worldObj.getBlock(x, y, z); + int metadata = worldObj.getBlockMetadata(x, y, z); + CoilPartData coilData = null; + + if (block == BigReactors.blockTurbineRotorPart) { + rotorMass += BigReactors.blockTurbineRotorPart.getRotorMass(block, metadata); + if (BlockTurbineRotorPart.isRotorBlade(metadata)) { + bladeSurfaceArea += 1; + } + } + + coilData = getCoilPartData(x, y, z, block, metadata); + if (coilData != null) { + coilEfficiency += coilData.efficiency; + coilBonus += coilData.bonus; + coilDragCoefficient += coilData.energyExtractionRate; + coilSize += 1; + } + } // end z + } // end y + } // end x loop - looping over interior + + // Precalculate some stuff now that we know how big the rotor and blades are + frictionalDrag = rotorMass * rotorDragCoefficient * BigReactors.turbineMassDragMultiplier; + bladeDrag = baseBladeDragCoefficient * bladeSurfaceArea * BigReactors.turbineAeroDragMultiplier; + + if (coilSize <= 0) { + // Uh. No coil? Fine. + inductionEfficiency = 0f; + inductionEnergyExponentBonus = 1f; + inductorDragCoefficient = 0f; + } else { + inductionEfficiency = (coilEfficiency * 0.33f) / coilSize; + inductionEnergyExponentBonus = Math.max(1f, (coilBonus / coilSize)); + inductorDragCoefficient = (coilDragCoefficient / coilSize) * inductorBaseDragCoefficient; + } + } + + public float getRotorSpeed() { + if (attachedRotorBlades.size() <= 0 || rotorMass <= 0) { + return 0f; + } + return rotorEnergy / (attachedRotorBlades.size() * rotorMass); + } + + public float getEnergyGeneratedLastTick() { + return energyGeneratedLastTick; + } + + public int getFluidConsumedLastTick() { + return fluidConsumedLastTick; + } + + public int getNumRotorBlades() { + return attachedRotorBlades.size(); + } + + public float getRotorEfficiencyLastTick() { + return rotorEfficiencyLastTick; + } + + public float getMaxRotorSpeed() { + return 2000f; + } + + public int getRotorMass() { + return rotorMass; + } + + public VentStatus getVentSetting() { + return ventStatus; + } + + public void setVentStatus(VentStatus newStatus, boolean markReferenceCoordDirty) { + ventStatus = newStatus; + if (markReferenceCoordDirty) markReferenceCoordDirty(); + } + + public boolean getInductorEngaged() { + return inductorEngaged; + } + + public void setInductorEngaged(boolean engaged, boolean markReferenceCoordDirty) { + inductorEngaged = engaged; + if (markReferenceCoordDirty) markReferenceCoordDirty(); + } + + private void setRotorEnergy(float newEnergy) { + if (Float.isNaN(newEnergy) || Float.isInfinite(newEnergy)) { + return; + } + rotorEnergy = Math.max(0f, newEnergy); + } + + protected void markReferenceCoordDirty() { + if (worldObj == null || worldObj.isRemote) { + return; + } + + CoordTriplet referenceCoord = getReferenceCoord(); + if (referenceCoord == null) { + return; + } + + rpmUpdateTracker.onExternalUpdate(); + + TileEntity saveTe = worldObj.getTileEntity(referenceCoord.x, referenceCoord.y, referenceCoord.z); + worldObj.markTileEntityChunkModified(referenceCoord.x, referenceCoord.y, referenceCoord.z, saveTe); + worldObj.markBlockForUpdate(referenceCoord.x, referenceCoord.y, referenceCoord.z); + } + + // For client usage only + public ForgeDirection getRotorDirection() { + if (attachedRotorBearings.size() < 1) { + return ForgeDirection.UNKNOWN; + } + + if (!this.isAssembled()) { + return ForgeDirection.UNKNOWN; + } + + TileEntityTurbineRotorBearing rotorBearing = attachedRotorBearings.iterator() + .next(); + return rotorBearing.getOutwardsDir() + .getOpposite(); + } + + public boolean hasGlass() { + return attachedGlass.size() > 0; + } + + public String getDebugInfo() { + StringBuilder sb = new StringBuilder(); + sb.append("Assembled: ") + .append(Boolean.toString(isAssembled())) + .append("\n"); + sb.append("Attached Blocks: ") + .append(Integer.toString(connectedParts.size())) + .append("\n"); + if (getLastValidationException() != null) { + sb.append("Validation Exception:\n") + .append(getLastValidationException().getMessage()) + .append("\n"); + } + + if (isAssembled()) { + sb.append("\nActive: ") + .append(Boolean.toString(getActive())); + sb.append("\nStored Energy: ") + .append(Float.toString(getEnergyStored())); + sb.append("\nRotor Energy: ") + .append(Float.toString(rotorEnergy)); + sb.append("\nRotor Speed: ") + .append(Float.toString(getRotorSpeed())) + .append(" rpm"); + sb.append("\nInductor Engaged: ") + .append(Boolean.toString(inductorEngaged)); + sb.append("\nVent Status: ") + .append(ventStatus.toString()); + sb.append("\nMax Intake Rate: ") + .append(Integer.toString(maxIntakeRate)); + sb.append("\nCoil Size: ") + .append(Integer.toString(coilSize)); + sb.append("\nRotor Mass: ") + .append(Integer.toString(rotorMass)); + sb.append("\nBlade SurfArea: ") + .append(Integer.toString(bladeSurfaceArea)); + sb.append("\n# Blades: ") + .append(Integer.toString(attachedRotorBlades.size())); + sb.append("\n# Shafts: ") + .append(Integer.toString(attachedRotorShafts.size())); + sb.append("\nRotor Drag CoEff: ") + .append(Float.toString(rotorDragCoefficient)); + sb.append("\nBlade Drag: ") + .append(Float.toString(bladeDrag)); + sb.append("\nFrict Drag: ") + .append(Float.toString(frictionalDrag)); + sb.append("\n\nFluid Tanks:\n"); + for (int i = 0; i < tanks.length; i++) { + sb.append(String.format("[%d] %s ", i, i == TANK_OUTPUT ? "outlet" : "inlet")); + if (tanks[i] == null || tanks[i].getFluid() == null) { + sb.append("empty"); + } else { + FluidStack stack = tanks[i].getFluid(); + sb.append( + String.format( + "%s, %d mB", + stack.getFluid() + .getName(), + stack.amount)); + } + sb.append("\n"); + } + } + + return sb.toString(); + } + + @SideOnly(Side.CLIENT) + public void resetCachedRotors() { + for (TileEntityTurbineRotorBearing bearing : attachedRotorBearings) { + bearing.clearDisplayList(); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockFuelRod.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockFuelRod.java index 1c2c65c0..5b7865bb 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockFuelRod.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockFuelRod.java @@ -8,6 +8,7 @@ import net.minecraft.util.IIcon; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import erogenousbeef.bigreactors.common.BigReactors; @@ -15,90 +16,94 @@ public class BlockFuelRod extends BlockContainer { - public static int renderId; - - @SideOnly(Side.CLIENT) - private IIcon iconFuelRodSide; - @SideOnly(Side.CLIENT) - private IIcon iconFuelRodTopBottom; - - public BlockFuelRod(Material material) { - super(material); - - setHardness(2f); - setLightLevel(0.9f); - setLightOpacity(1); - setCreativeTab(BigReactors.TAB); - setBlockName("yelloriumFuelRod"); - setBlockTextureName(BigReactors.TEXTURE_NAME_PREFIX + "yelloriumFuelRod"); - } - - @Override - public int getRenderType() { - return renderId; - } - - @SideOnly(Side.CLIENT) - @Override - public IIcon getIcon(int side, int metadata) - { - if(side == 0 || side == 1) { return this.iconFuelRodTopBottom; } - - return this.iconFuelRodSide; - } - - @SideOnly(Side.CLIENT) - @Override - public IIcon getIcon(IBlockAccess iblockaccess, int x, int y, int z, int side) { - if(side == 0 || side == 1) { return this.iconFuelRodTopBottom; } - else { return this.iconFuelRodSide; } - } - - @SideOnly(Side.CLIENT) - @Override - public void registerBlockIcons(IIconRegister par1IconRegister) - { - this.iconFuelRodSide = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + "fuelRod.side"); - this.iconFuelRodTopBottom = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + "fuelRod.end"); - } - - @Override - public boolean isOpaqueCube() { return false; } - - @Override - public TileEntity createNewTileEntity(World world, int metadata) { - return new TileEntityReactorFuelRod(); - } - - @Override - public boolean canCreatureSpawn(EnumCreatureType type, IBlockAccess world, int x, int y, int z) - { - return false; + public static int renderId; + + @SideOnly(Side.CLIENT) + private IIcon iconFuelRodSide; + @SideOnly(Side.CLIENT) + private IIcon iconFuelRodTopBottom; + + public BlockFuelRod(Material material) { + super(material); + + setHardness(2f); + setLightLevel(0.9f); + setLightOpacity(1); + setCreativeTab(BigReactors.TAB); + setBlockName("yelloriumFuelRod"); + setBlockTextureName(BigReactors.TEXTURE_NAME_PREFIX + "yelloriumFuelRod"); } - - /* - * TODO Have to make my own particle for this. :/ + + @Override + public int getRenderType() { + return renderId; + } + @SideOnly(Side.CLIENT) - public void randomDisplayTick(World world, int x, int y, int z, Random par5Random) - { - TileEntity te = world.getBlockTileEntity(x, y, z); - if(te instanceof TileEntityReactorFuelRod) { - TileEntityReactorFuelRod fuelRod = (TileEntityReactorFuelRod)te; - MultiblockReactor reactor = fuelRod.getReactorController(); - if(reactor != null && reactor.isActive() && reactor.getFuelConsumedLastTick() > 0) { - int numParticles = par5Random.nextInt(4) + 1; - while(numParticles > 0) { - world.spawnParticle(BigReactors.isValentinesDay ? "heart" : "crit", - fuelRod.xCoord + 0.5D, - fuelRod.yCoord + 0.5D, - fuelRod.zCoord + 0.5D, - par5Random.nextFloat() * 3f - 1.5f, - par5Random.nextFloat() * 3f - 1.5f, - par5Random.nextFloat() * 3f - 1.5f); - numParticles--; - } - } - } + @Override + public IIcon getIcon(int side, int metadata) { + if (side == 0 || side == 1) { + return this.iconFuelRodTopBottom; + } + + return this.iconFuelRodSide; } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(IBlockAccess iblockaccess, int x, int y, int z, int side) { + if (side == 0 || side == 1) { + return this.iconFuelRodTopBottom; + } else { + return this.iconFuelRodSide; + } + } + + @SideOnly(Side.CLIENT) + @Override + public void registerBlockIcons(IIconRegister par1IconRegister) { + this.iconFuelRodSide = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + "fuelRod.side"); + this.iconFuelRodTopBottom = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + "fuelRod.end"); + } + + @Override + public boolean isOpaqueCube() { + return false; + } + + @Override + public TileEntity createNewTileEntity(World world, int metadata) { + return new TileEntityReactorFuelRod(); + } + + @Override + public boolean canCreatureSpawn(EnumCreatureType type, IBlockAccess world, int x, int y, int z) { + return false; + } + + /* + * TODO Have to make my own particle for this. :/ + * @SideOnly(Side.CLIENT) + * public void randomDisplayTick(World world, int x, int y, int z, Random par5Random) + * { + * TileEntity te = world.getBlockTileEntity(x, y, z); + * if(te instanceof TileEntityReactorFuelRod) { + * TileEntityReactorFuelRod fuelRod = (TileEntityReactorFuelRod)te; + * MultiblockReactor reactor = fuelRod.getReactorController(); + * if(reactor != null && reactor.isActive() && reactor.getFuelConsumedLastTick() > 0) { + * int numParticles = par5Random.nextInt(4) + 1; + * while(numParticles > 0) { + * world.spawnParticle(BigReactors.isValentinesDay ? "heart" : "crit", + * fuelRod.xCoord + 0.5D, + * fuelRod.yCoord + 0.5D, + * fuelRod.zCoord + 0.5D, + * par5Random.nextFloat() * 3f - 1.5f, + * par5Random.nextFloat() * 3f - 1.5f, + * par5Random.nextFloat() * 3f - 1.5f); + * numParticles--; + * } + * } + * } + * } */ } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockMBCreativePart.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockMBCreativePart.java index 9c36b9fd..10fe08f7 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockMBCreativePart.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockMBCreativePart.java @@ -14,6 +14,7 @@ import net.minecraft.util.IIcon; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import erogenousbeef.bigreactors.common.BigReactors; @@ -25,138 +26,139 @@ public class BlockMBCreativePart extends BlockContainer { - public static final int REACTOR_CREATIVE_COOLANT_PORT = 0; - public static final int TURBINE_CREATIVE_FLUID_PORT = 1; - - private static String[] subBlocks = new String[] { "reactor.coolantPort", "turbine.fluidPort" }; - private static String[] subIconNames = new String[] { "reactor.coolantPort.outlet" }; - - private static final int SUBICON_CREATIVE_COOLANT_OUTLET = 0; - - private IIcon[] icons = new IIcon[subBlocks.length]; - private IIcon[] subIcons = new IIcon[subIconNames.length]; - - public BlockMBCreativePart(Material material) { - super(material); - - setStepSound(soundTypeMetal); - setHardness(1.0f); - setBlockName("blockMBCreativePart"); - this.setBlockTextureName(BigReactors.TEXTURE_NAME_PREFIX + "blockMBCreativePart"); - setCreativeTab(BigReactors.TAB); - } - - @Override + public static final int REACTOR_CREATIVE_COOLANT_PORT = 0; + public static final int TURBINE_CREATIVE_FLUID_PORT = 1; + + private static String[] subBlocks = new String[] { "reactor.coolantPort", "turbine.fluidPort" }; + private static String[] subIconNames = new String[] { "reactor.coolantPort.outlet" }; + + private static final int SUBICON_CREATIVE_COOLANT_OUTLET = 0; + + private IIcon[] icons = new IIcon[subBlocks.length]; + private IIcon[] subIcons = new IIcon[subIconNames.length]; + + public BlockMBCreativePart(Material material) { + super(material); + + setStepSound(soundTypeMetal); + setHardness(1.0f); + setBlockName("blockMBCreativePart"); + this.setBlockTextureName(BigReactors.TEXTURE_NAME_PREFIX + "blockMBCreativePart"); + setCreativeTab(BigReactors.TAB); + } + + @Override public IIcon getIcon(IBlockAccess blockAccess, int x, int y, int z, int side) { - int metadata = blockAccess.getBlockMetadata(x, y, z); - TileEntity te = blockAccess.getTileEntity(x, y, z); - - if(te instanceof RectangularMultiblockTileEntityBase) { - RectangularMultiblockTileEntityBase rte = (RectangularMultiblockTileEntityBase)te; - MultiblockControllerBase controller = rte.getMultiblockController(); - if(controller != null && controller.isAssembled()) { - if(rte.getOutwardsDir().ordinal() == side) { - return getIconFromTileEntity(rte, metadata); - } - } - } - - return getIcon(side, metadata); - } - - @Override - public IIcon getIcon(int side, int metadata) { - if(side == 0 || side == 1) { return blockIcon; } - metadata = metadata % icons.length; - return icons[metadata]; - } - - @Override - @SideOnly(Side.CLIENT) - public void registerBlockIcons(IIconRegister par1IconRegister) - { - this.blockIcon = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName()); - - for(int i = 0; i < subBlocks.length; ++i) { - icons[i] = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + "." + subBlocks[i]); - } - - for(int i = 0; i < subIconNames.length; ++i) { - subIcons[i] = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + "." + subIconNames[i]); - } - } - - @Override - public TileEntity createNewTileEntity(World world, int metadata) { - switch(metadata) { - case REACTOR_CREATIVE_COOLANT_PORT: - return new TileEntityReactorCreativeCoolantPort(); - case TURBINE_CREATIVE_FLUID_PORT: - return new TileEntityTurbineCreativeSteamGenerator(); - default: - return null; - } - } - - @Override - public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int par6, float par7, float par8, float par9) { - if(player.isSneaking()) { - return false; - } - - ItemStack currentEquippedItem = player.getCurrentEquippedItem(); - - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof TileEntityReactorCreativeCoolantPort) { - TileEntityReactorCreativeCoolantPort cp = (TileEntityReactorCreativeCoolantPort)te; - if(currentEquippedItem == null || StaticUtils.Inventory.isPlayerHoldingWrench(player)) { - // Use wrench to change inlet/outlet state - cp.setInlet(!cp.isInlet(), true); - } - else { - cp.forceAddWater(); - } - return true; - } - - return false; - } - - @Override - public int damageDropped(int metadata) - { - return metadata; - } - - public ItemStack getReactorCoolantPort() { - return new ItemStack(this, 1, REACTOR_CREATIVE_COOLANT_PORT); - } - - public ItemStack getTurbineFluidPort() { - return new ItemStack(this, 1, TURBINE_CREATIVE_FLUID_PORT); - } - - @Override - public void getSubBlocks(Item par1, CreativeTabs par2CreativeTabs, List par3List) - { - par3List.add(getReactorCoolantPort()); - par3List.add(getTurbineFluidPort()); - } - - private IIcon getIconFromTileEntity(RectangularMultiblockTileEntityBase rte, int metadata) { - if(rte instanceof TileEntityReactorCreativeCoolantPort) { - if(!((TileEntityReactorCreativeCoolantPort)rte).isInlet()) { - return subIcons[SUBICON_CREATIVE_COOLANT_OUTLET]; - } - } - - metadata = metadata % icons.length; - return icons[metadata]; - } - - @Override - public boolean canCreatureSpawn(EnumCreatureType type, IBlockAccess world, int x, int y, int z) - { - return false; + int metadata = blockAccess.getBlockMetadata(x, y, z); + TileEntity te = blockAccess.getTileEntity(x, y, z); + + if (te instanceof RectangularMultiblockTileEntityBase) { + RectangularMultiblockTileEntityBase rte = (RectangularMultiblockTileEntityBase) te; + MultiblockControllerBase controller = rte.getMultiblockController(); + if (controller != null && controller.isAssembled()) { + if (rte.getOutwardsDir() + .ordinal() == side) { + return getIconFromTileEntity(rte, metadata); + } + } + } + + return getIcon(side, metadata); + } + + @Override + public IIcon getIcon(int side, int metadata) { + if (side == 0 || side == 1) { + return blockIcon; + } + metadata = metadata % icons.length; + return icons[metadata]; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerBlockIcons(IIconRegister par1IconRegister) { + this.blockIcon = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName()); + + for (int i = 0; i < subBlocks.length; ++i) { + icons[i] = par1IconRegister + .registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + "." + subBlocks[i]); + } + + for (int i = 0; i < subIconNames.length; ++i) { + subIcons[i] = par1IconRegister + .registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + "." + subIconNames[i]); + } + } + + @Override + public TileEntity createNewTileEntity(World world, int metadata) { + switch (metadata) { + case REACTOR_CREATIVE_COOLANT_PORT: + return new TileEntityReactorCreativeCoolantPort(); + case TURBINE_CREATIVE_FLUID_PORT: + return new TileEntityTurbineCreativeSteamGenerator(); + default: + return null; + } + } + + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int par6, float par7, + float par8, float par9) { + if (player.isSneaking()) { + return false; + } + + ItemStack currentEquippedItem = player.getCurrentEquippedItem(); + + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof TileEntityReactorCreativeCoolantPort) { + TileEntityReactorCreativeCoolantPort cp = (TileEntityReactorCreativeCoolantPort) te; + if (currentEquippedItem == null || StaticUtils.Inventory.isPlayerHoldingWrench(player)) { + // Use wrench to change inlet/outlet state + cp.setInlet(!cp.isInlet(), true); + } else { + cp.forceAddWater(); + } + return true; + } + + return false; + } + + @Override + public int damageDropped(int metadata) { + return metadata; + } + + public ItemStack getReactorCoolantPort() { + return new ItemStack(this, 1, REACTOR_CREATIVE_COOLANT_PORT); + } + + public ItemStack getTurbineFluidPort() { + return new ItemStack(this, 1, TURBINE_CREATIVE_FLUID_PORT); + } + + @Override + public void getSubBlocks(Item par1, CreativeTabs par2CreativeTabs, List par3List) { + par3List.add(getReactorCoolantPort()); + par3List.add(getTurbineFluidPort()); + } + + private IIcon getIconFromTileEntity(RectangularMultiblockTileEntityBase rte, int metadata) { + if (rte instanceof TileEntityReactorCreativeCoolantPort) { + if (!((TileEntityReactorCreativeCoolantPort) rte).isInlet()) { + return subIcons[SUBICON_CREATIVE_COOLANT_OUTLET]; + } + } + + metadata = metadata % icons.length; + return icons[metadata]; + } + + @Override + public boolean canCreatureSpawn(EnumCreatureType type, IBlockAccess world, int x, int y, int z) { + return false; } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockMultiblockGlass.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockMultiblockGlass.java index b5bf1dab..c3723bd5 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockMultiblockGlass.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockMultiblockGlass.java @@ -17,6 +17,7 @@ import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import erogenousbeef.bigreactors.common.BigReactors; @@ -28,153 +29,159 @@ public class BlockMultiblockGlass extends BlockContainer { - public static final int METADATA_REACTOR = 0; - public static final int METADATA_TURBINE = 1; - - private static final String textureBaseName = "multiblockGlass"; - - private static String[] subBlocks = new String[] { "reactor", "turbine" }; - private IIcon[][] icons = new IIcon[subBlocks.length][16]; - private IIcon transparentIcon; - - public BlockMultiblockGlass(Material material) { - super(material); - - setStepSound(soundTypeGlass); - setHardness(2.0f); - setBlockName("brMultiblockGlass"); - this.setBlockTextureName(BigReactors.TEXTURE_NAME_PREFIX + textureBaseName); - setCreativeTab(BigReactors.TAB); - } - - @Override - public TileEntity createNewTileEntity(World world, int metadata) { - switch(metadata) { - case METADATA_REACTOR: - return new TileEntityReactorGlass(); - case METADATA_TURBINE: - return new TileEntityTurbinePartGlass(); - default: - throw new IllegalArgumentException("Unrecognized metadata"); - } - } - - @Override - @SideOnly(Side.CLIENT) - public void registerBlockIcons(IIconRegister par1IconRegister) - { - this.transparentIcon = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + "tile." + textureBaseName + ".transparent"); - - for(int metadata = 0; metadata < subBlocks.length; metadata++) { - for(int i = 0; i < 16; ++i) { - icons[metadata][i] = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + "tile." + textureBaseName + "." + subBlocks[metadata] + "." + Integer.toString(i)); - } - } - } - - @Override + public static final int METADATA_REACTOR = 0; + public static final int METADATA_TURBINE = 1; + + private static final String textureBaseName = "multiblockGlass"; + + private static String[] subBlocks = new String[] { "reactor", "turbine" }; + private IIcon[][] icons = new IIcon[subBlocks.length][16]; + private IIcon transparentIcon; + + public BlockMultiblockGlass(Material material) { + super(material); + + setStepSound(soundTypeGlass); + setHardness(2.0f); + setBlockName("brMultiblockGlass"); + this.setBlockTextureName(BigReactors.TEXTURE_NAME_PREFIX + textureBaseName); + setCreativeTab(BigReactors.TAB); + } + + @Override + public TileEntity createNewTileEntity(World world, int metadata) { + switch (metadata) { + case METADATA_REACTOR: + return new TileEntityReactorGlass(); + case METADATA_TURBINE: + return new TileEntityTurbinePartGlass(); + default: + throw new IllegalArgumentException("Unrecognized metadata"); + } + } + + @Override + @SideOnly(Side.CLIENT) + public void registerBlockIcons(IIconRegister par1IconRegister) { + this.transparentIcon = par1IconRegister + .registerIcon(BigReactors.TEXTURE_NAME_PREFIX + "tile." + textureBaseName + ".transparent"); + + for (int metadata = 0; metadata < subBlocks.length; metadata++) { + for (int i = 0; i < 16; ++i) { + icons[metadata][i] = par1IconRegister.registerIcon( + BigReactors.TEXTURE_NAME_PREFIX + "tile." + + textureBaseName + + "." + + subBlocks[metadata] + + "." + + Integer.toString(i)); + } + } + } + + @Override public IIcon getIcon(IBlockAccess blockAccess, int x, int y, int z, int side) { - ForgeDirection[] dirsToCheck = StaticUtils.neighborsBySide[side]; - ForgeDirection dir; - Block myBlock = blockAccess.getBlock(x, y, z); - int myBlockMetadata = blockAccess.getBlockMetadata(x, y, z); - - // First check if we have a block in front of us of the same type - if so, just be completely transparent on this side - ForgeDirection out = ForgeDirection.getOrientation(side); - if(blockAccess.getBlock(x + out.offsetX, y + out.offsetY, z + out.offsetZ) == myBlock && - blockAccess.getBlockMetadata(x + out.offsetX, y + out.offsetY, z + out.offsetZ) == myBlockMetadata) { - return transparentIcon; - } - - // Calculate icon index based on whether the blocks around this block match it - // Icons use a naming pattern so that the bits correspond to: - // 1 = Connected on top, 2 = connected on bottom, 4 = connected on left, 8 = connected on right - int iconIdx = 0; - for(int i = 0; i < dirsToCheck.length; i++) { - dir = dirsToCheck[i]; - // Same blockID and metadata on this side? - if(blockAccess.getBlock(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ) == myBlock && - blockAccess.getBlockMetadata(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ) == myBlockMetadata) { - // Connected! - iconIdx |= 1 << i; - } - } - - return icons[myBlockMetadata][iconIdx]; - } - - @Override - public IIcon getIcon(int side, int metadata) { - return icons[metadata][0]; - } - - @Override - public boolean isOpaqueCube() - { - return false; - } - - @Override - public int damageDropped(int metadata) - { - return metadata; - } - - public ItemStack getItemStack(String name) { - int metadata = -1; - for(int i = 0; i < subBlocks.length; i++) { - if(subBlocks[i].equals(name)) { - metadata = i; - break; - } - } - - if(metadata < 0) { - throw new IllegalArgumentException("Unable to find a block with the name " + name); - } - return new ItemStack(this, 1, metadata); - } - - @Override - public void getSubBlocks(Item par1, CreativeTabs par2CreativeTabs, List par3List) - { - for(int i = 0; i < subBlocks.length; i++) { - par3List.add(new ItemStack(this, 1, i)); - } - } - - @Override - public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int par6, float par7, float par8, float par9) { - if(player.isSneaking()) { - return false; - } - - // If the player's hands are empty and they rightclick on a multiblock, they get a - // multiblock-debugging message if the machine is not assembled. - if(!world.isRemote && player.getCurrentEquippedItem() == null) { - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof IMultiblockPart) { - MultiblockControllerBase controller = ((IMultiblockPart)te).getMultiblockController(); - - if(controller == null) { - player.addChatMessage(new ChatComponentText(String.format("SERIOUS ERROR - server part @ %d, %d, %d has no controller!", x, y, z))); //TODO Localize - } - else { - Exception e = controller.getLastValidationException(); - if(e != null) { - player.addChatMessage(new ChatComponentText(e.getMessage())); - return true; - } - } - } - } - - return false; - } - - @Override - public boolean canCreatureSpawn(EnumCreatureType type, IBlockAccess world, int x, int y, int z) - { - return false; + ForgeDirection[] dirsToCheck = StaticUtils.neighborsBySide[side]; + ForgeDirection dir; + Block myBlock = blockAccess.getBlock(x, y, z); + int myBlockMetadata = blockAccess.getBlockMetadata(x, y, z); + + // First check if we have a block in front of us of the same type - if so, just be completely transparent on + // this side + ForgeDirection out = ForgeDirection.getOrientation(side); + if (blockAccess.getBlock(x + out.offsetX, y + out.offsetY, z + out.offsetZ) == myBlock + && blockAccess.getBlockMetadata(x + out.offsetX, y + out.offsetY, z + out.offsetZ) == myBlockMetadata) { + return transparentIcon; + } + + // Calculate icon index based on whether the blocks around this block match it + // Icons use a naming pattern so that the bits correspond to: + // 1 = Connected on top, 2 = connected on bottom, 4 = connected on left, 8 = connected on right + int iconIdx = 0; + for (int i = 0; i < dirsToCheck.length; i++) { + dir = dirsToCheck[i]; + // Same blockID and metadata on this side? + if (blockAccess.getBlock(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ) == myBlock + && blockAccess.getBlockMetadata(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ) == myBlockMetadata) { + // Connected! + iconIdx |= 1 << i; + } + } + + return icons[myBlockMetadata][iconIdx]; + } + + @Override + public IIcon getIcon(int side, int metadata) { + return icons[metadata][0]; + } + + @Override + public boolean isOpaqueCube() { + return false; + } + + @Override + public int damageDropped(int metadata) { + return metadata; + } + + public ItemStack getItemStack(String name) { + int metadata = -1; + for (int i = 0; i < subBlocks.length; i++) { + if (subBlocks[i].equals(name)) { + metadata = i; + break; + } + } + + if (metadata < 0) { + throw new IllegalArgumentException("Unable to find a block with the name " + name); + } + return new ItemStack(this, 1, metadata); + } + + @Override + public void getSubBlocks(Item par1, CreativeTabs par2CreativeTabs, List par3List) { + for (int i = 0; i < subBlocks.length; i++) { + par3List.add(new ItemStack(this, 1, i)); + } + } + + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int par6, float par7, + float par8, float par9) { + if (player.isSneaking()) { + return false; + } + + // If the player's hands are empty and they rightclick on a multiblock, they get a + // multiblock-debugging message if the machine is not assembled. + if (!world.isRemote && player.getCurrentEquippedItem() == null) { + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof IMultiblockPart) { + MultiblockControllerBase controller = ((IMultiblockPart) te).getMultiblockController(); + + if (controller == null) { + player.addChatMessage( + new ChatComponentText( + String.format("SERIOUS ERROR - server part @ %d, %d, %d has no controller!", x, y, z))); // TODO + // Localize + } else { + Exception e = controller.getLastValidationException(); + if (e != null) { + player.addChatMessage(new ChatComponentText(e.getMessage())); + return true; + } + } + } + } + + return false; + } + + @Override + public boolean canCreatureSpawn(EnumCreatureType type, IBlockAccess world, int x, int y, int z) { + return false; } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockReactorPart.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockReactorPart.java index 8ab0a3e6..4e3b0a94 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockReactorPart.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockReactorPart.java @@ -19,8 +19,7 @@ import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; -import powercrystals.minefactoryreloaded.api.rednet.IRedNetOmniNode; -import powercrystals.minefactoryreloaded.api.rednet.connectivity.RedNetConnectionType; + import cpw.mods.fml.common.Optional; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -42,619 +41,622 @@ import erogenousbeef.core.multiblock.IMultiblockPart; import erogenousbeef.core.multiblock.MultiblockControllerBase; import erogenousbeef.core.multiblock.rectangular.PartPosition; +import powercrystals.minefactoryreloaded.api.rednet.IRedNetOmniNode; +import powercrystals.minefactoryreloaded.api.rednet.connectivity.RedNetConnectionType; @Optional.InterfaceList({ - @Optional.Interface(iface = "dan200.computercraft.api.peripheral.IPeripheralProvider", modid = "ComputerCraft"), - @Optional.Interface(iface = "powercrystals.minefactoryreloaded.api.rednet.IRedNetOmniNode", modid = "MineFactoryReloaded") -}) + @Optional.Interface(iface = "dan200.computercraft.api.peripheral.IPeripheralProvider", modid = "ComputerCraft"), + @Optional.Interface( + iface = "powercrystals.minefactoryreloaded.api.rednet.IRedNetOmniNode", + modid = "MineFactoryReloaded") }) public class BlockReactorPart extends BlockContainer implements IRedNetOmniNode, IPeripheralProvider { - - public static final int METADATA_CASING = 0; - public static final int METADATA_CONTROLLER = 1; - public static final int METADATA_CONTROLROD = 2; - public static final int METADATA_POWERTAP = 3; - public static final int METADATA_ACCESSPORT = 4; - public static final int METADATA_COOLANTPORT = 5; - public static final int METADATA_REDNETPORT = 6; - public static final int METADATA_COMPUTERPORT = 7; - - private static final int PORT_INLET = 0; - private static final int PORT_OUTLET = 1; - private static final int TAP_DISCONNECTED = 0; - private static final int TAP_CONNECTED = 1; - private static final int CONTROLLER_OFF = 0; - private static final int CONTROLLER_IDLE = 1; - private static final int CONTROLLER_ACTIVE = 2; - - private static String[] _subBlocks = new String[] { "casing", - "controller", - "controlRod", - "powerTap", - "accessPort", - "coolantPort", - "redNetPort", - "computerPort" }; - - - private static String[][] _states = new String[][] { - {"default", "face", "corner", "eastwest", "northsouth", "vertical"}, // Casing - {"off", "idle", "active"}, // Controller - {"top"}, // Control Rod - {"disconnected", "connected"}, // Power Tap - {"inlet", "outlet"}, // Access Port - {"inlet", "outlet"}, // Coolant Port - {"default"}, // RedNet Port - {"default"}, // Computer Port - }; - private IIcon[][] _icons = new IIcon[_states.length][]; - - private IIcon[] _redNetPortConfigIcons = new IIcon[TileEntityReactorRedNetPort.CircuitType.values().length - 1]; - - public static boolean isCasing(int metadata) { return metadata == METADATA_CASING; } - public static boolean isController(int metadata) { return metadata == METADATA_CONTROLLER; } - public static boolean isPowerTap(int metadata) { return metadata == METADATA_POWERTAP; } - public static boolean isAccessPort(int metadata) { return metadata == METADATA_ACCESSPORT; } - public static boolean isRedNetPort(int metadata) { return metadata == METADATA_REDNETPORT; } - public static boolean isComputerPort(int metadata) { return metadata == METADATA_COMPUTERPORT; } - public static boolean isCoolantPort(int metadata) { return metadata == METADATA_COOLANTPORT; } - public static boolean isControlRod(int metadata) { return metadata == METADATA_CONTROLROD; } - - public BlockReactorPart(Material material) { - super(material); - - setStepSound(soundTypeMetal); - setHardness(2.0f); - setBlockName("blockReactorPart"); - this.setBlockTextureName(BigReactors.TEXTURE_NAME_PREFIX + "blockReactorPart"); - setCreativeTab(BigReactors.TAB); - } - - @Override + + public static final int METADATA_CASING = 0; + public static final int METADATA_CONTROLLER = 1; + public static final int METADATA_CONTROLROD = 2; + public static final int METADATA_POWERTAP = 3; + public static final int METADATA_ACCESSPORT = 4; + public static final int METADATA_COOLANTPORT = 5; + public static final int METADATA_REDNETPORT = 6; + public static final int METADATA_COMPUTERPORT = 7; + + private static final int PORT_INLET = 0; + private static final int PORT_OUTLET = 1; + private static final int TAP_DISCONNECTED = 0; + private static final int TAP_CONNECTED = 1; + private static final int CONTROLLER_OFF = 0; + private static final int CONTROLLER_IDLE = 1; + private static final int CONTROLLER_ACTIVE = 2; + + private static String[] _subBlocks = new String[] { "casing", "controller", "controlRod", "powerTap", "accessPort", + "coolantPort", "redNetPort", "computerPort" }; + + private static String[][] _states = new String[][] { + { "default", "face", "corner", "eastwest", "northsouth", "vertical" }, // Casing + { "off", "idle", "active" }, // Controller + { "top" }, // Control Rod + { "disconnected", "connected" }, // Power Tap + { "inlet", "outlet" }, // Access Port + { "inlet", "outlet" }, // Coolant Port + { "default" }, // RedNet Port + { "default" }, // Computer Port + }; + private IIcon[][] _icons = new IIcon[_states.length][]; + + private IIcon[] _redNetPortConfigIcons = new IIcon[TileEntityReactorRedNetPort.CircuitType.values().length - 1]; + + public static boolean isCasing(int metadata) { + return metadata == METADATA_CASING; + } + + public static boolean isController(int metadata) { + return metadata == METADATA_CONTROLLER; + } + + public static boolean isPowerTap(int metadata) { + return metadata == METADATA_POWERTAP; + } + + public static boolean isAccessPort(int metadata) { + return metadata == METADATA_ACCESSPORT; + } + + public static boolean isRedNetPort(int metadata) { + return metadata == METADATA_REDNETPORT; + } + + public static boolean isComputerPort(int metadata) { + return metadata == METADATA_COMPUTERPORT; + } + + public static boolean isCoolantPort(int metadata) { + return metadata == METADATA_COOLANTPORT; + } + + public static boolean isControlRod(int metadata) { + return metadata == METADATA_CONTROLROD; + } + + public BlockReactorPart(Material material) { + super(material); + + setStepSound(soundTypeMetal); + setHardness(2.0f); + setBlockName("blockReactorPart"); + this.setBlockTextureName(BigReactors.TEXTURE_NAME_PREFIX + "blockReactorPart"); + setCreativeTab(BigReactors.TAB); + } + + @Override public IIcon getIcon(IBlockAccess blockAccess, int x, int y, int z, int side) { - IIcon icon = null; - int metadata = blockAccess.getBlockMetadata(x,y,z); - - if(metadata == METADATA_CONTROLROD) { - return getIcon(side, metadata); - } - - switch(metadata) { - case METADATA_CASING: - icon = getCasingIcon(blockAccess, x, y, z, side); - break; - case METADATA_CONTROLLER: - icon = getControllerIcon(blockAccess, x, y, z, side); - break; - case METADATA_POWERTAP: - icon = getPowerTapIcon(blockAccess, x, y, z, side); - break; - case METADATA_ACCESSPORT: - icon = getAccessPortIcon(blockAccess, x, y, z, side); - break; - case METADATA_COOLANTPORT: - icon = getCoolantPortIcon(blockAccess, x, y, z, side); - break; - case METADATA_REDNETPORT: - case METADATA_COMPUTERPORT: - icon = getFaceOrBlockIcon(blockAccess, x, y, z, side, metadata); - break; - } - - return icon != null ? icon : getIcon(side, metadata); - } - - @Override - public IIcon getIcon(int side, int metadata) - { - if(metadata == METADATA_CONTROLROD) { - if(side == 1) { - return _icons[metadata][0]; - } - } - else { - if(side > 1 && (metadata >= 0 && metadata < _icons.length)) { - return _icons[metadata][0]; - } - } - return blockIcon; - } - - @Override - @SideOnly(Side.CLIENT) - public void registerBlockIcons(IIconRegister par1IconRegister) - { - String prefix = BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + "."; - - for(int metadata = 0; metadata < _states.length; ++metadata) { - String[] blockStates = _states[metadata]; - _icons[metadata] = new IIcon[blockStates.length]; - - for(int state = 0; state < blockStates.length; state++) { - _icons[metadata][state] = par1IconRegister.registerIcon(prefix + _subBlocks[metadata] + "." + blockStates[state]); - } - } - - this.blockIcon = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName()); - - // We do this to skip DISABLED - TileEntityReactorRedNetPort.CircuitType[] circuitTypes = TileEntityReactorRedNetPort.CircuitType.values(); - String rednetPrefix = BigReactors.TEXTURE_NAME_PREFIX + "redNet/"; - - for(int i = 1; i < circuitTypes.length; ++i) { - _redNetPortConfigIcons[i - 1] = par1IconRegister.registerIcon(rednetPrefix + circuitTypes[i].name()); - } - } - - // We do this to skip DISABLED - @SideOnly(Side.CLIENT) - public IIcon getRedNetConfigIcon(TileEntityReactorRedNetPort.CircuitType circuitType) { - if(circuitType == TileEntityReactorRedNetPort.CircuitType.DISABLED) { return null; } - else { - return _redNetPortConfigIcons[circuitType.ordinal() - 1]; - } - } - - @Override - public TileEntity createNewTileEntity(World world, int metadata) { - switch(metadata) { - case METADATA_POWERTAP: - return new TileEntityReactorPowerTap(); - case METADATA_ACCESSPORT: - return new TileEntityReactorAccessPort(); - case METADATA_REDNETPORT: - return new TileEntityReactorRedNetPort(); - case METADATA_COMPUTERPORT: - return new TileEntityReactorComputerPort(); - case METADATA_COOLANTPORT: - return new TileEntityReactorCoolantPort(); - case METADATA_CONTROLROD: - return new TileEntityReactorControlRod(); - default: - return new TileEntityReactorPart(); - } - } - - @Override - public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock) { - TileEntity te = StaticUtils.TE.getTileEntityUnsafe(world, x, y, z); - - // Signal power taps when their neighbors change, etc. - if(te instanceof INeighborUpdatableEntity) { - ((INeighborUpdatableEntity)te).onNeighborBlockChange(world, x, y, z, neighborBlock); - } - } - - @Override - public void onNeighborChange(IBlockAccess world, int x, int y, int z, int neighborX, int neighborY, int neighborZ) { - TileEntity te = StaticUtils.TE.getTileEntityUnsafe(world, x, y, z); - - // Signal power taps when their neighbors change, etc. - if(te instanceof INeighborUpdatableEntity) { - ((INeighborUpdatableEntity)te).onNeighborTileChange(world, x, y, z, neighborX, neighborY, neighborZ); - } - } - - - @Override - public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int par6, float par7, float par8, float par9) { - if(player.isSneaking()) { - return false; - } - - int metadata = world.getBlockMetadata(x, y, z); - TileEntity te = world.getTileEntity(x, y, z); - IMultiblockPart part = null; - MultiblockControllerBase controller = null; - - if(te instanceof IMultiblockPart) { - part = (IMultiblockPart)te; - controller = part.getMultiblockController(); - } - - if(isCasing(metadata) || isPowerTap(metadata) || isComputerPort(metadata)) { - // If the player's hands are empty and they rightclick on a multiblock, they get a - // multiblock-debugging message if the machine is not assembled. - if(player.getCurrentEquippedItem() == null) { - if(controller != null) { - Exception e = controller.getLastValidationException(); - if(e != null) { - player.addChatMessage(new ChatComponentText(e.getMessage())); - return true; - } - } - else { - player.addChatMessage(new ChatComponentText("Block is not connected to a reactor. This could be due to lag, or a bug. If the problem persists, try breaking and re-placing the block.")); //TODO Localize - return true; - } - } - - // If nonempty, or there was no error, just fall through - return false; - } - - // Do toggly fiddly things for access/coolant ports - if(!world.isRemote && (isAccessPort(metadata) || isCoolantPort(metadata))) { - if(StaticUtils.Inventory.isPlayerHoldingWrench(player)) { - if(te instanceof TileEntityReactorCoolantPort) { - TileEntityReactorCoolantPort cp = (TileEntityReactorCoolantPort)te; - cp.setInlet(!cp.isInlet(), true); - return true; - } - else if(te instanceof TileEntityReactorAccessPort) { - TileEntityReactorAccessPort cp = (TileEntityReactorAccessPort)te; - cp.setInlet(!cp.isInlet()); - return true; - } - } - else if(isCoolantPort(metadata)) { - return false; - } - } - - // Don't open the controller GUI if the reactor isn't assembled - if(isController(metadata) && (controller == null || !controller.isAssembled())) { return false; } - - if(!world.isRemote) { - player.openGui(BRLoader.instance, 0, world, x, y, z); - } - return true; - } - - @Override - public boolean isOpaqueCube() - { - return true; - } - - @Override - public boolean renderAsNormalBlock() - { - return true; - } - - @Override - public int damageDropped(int metadata) - { - return metadata; - } - - public ItemStack getReactorCasingItemStack() { - return new ItemStack(this, 1, METADATA_CASING); - } - - public ItemStack getReactorControllerItemStack() { - return new ItemStack(this, 1, METADATA_CONTROLLER); - } - - public ItemStack getReactorPowerTapItemStack() { - return new ItemStack(this, 1, METADATA_POWERTAP); - } - - public ItemStack getAccessPortItemStack() { - return new ItemStack(this, 1, METADATA_ACCESSPORT); - } - - public ItemStack getRedNetPortItemStack() { - return new ItemStack(this, 1, METADATA_REDNETPORT); - } - - public ItemStack getComputerPortItemStack() { - return new ItemStack(this, 1, METADATA_COMPUTERPORT); - } - - public ItemStack getCoolantPortItemStack() { - return new ItemStack(this, 1, METADATA_COOLANTPORT); - } - - public ItemStack getControlRodItemStack() { - return new ItemStack(this, 1, METADATA_CONTROLROD); - } - - @Override - public void getSubBlocks(Item par1, CreativeTabs par2CreativeTabs, List par3List) - { - for(int metadata = 0; metadata < _subBlocks.length; metadata++) { - par3List.add(new ItemStack(this, 1, metadata)); - } - } - - @Override - public void breakBlock(World world, int x, int y, int z, Block block, int meta) - { - // Drop everything inside inventory blocks - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof IInventory) - { - IInventory inventory = ((IInventory)te); -inv: for(int i = 0; i < inventory.getSizeInventory(); i++) - { - ItemStack itemstack = inventory.getStackInSlot(i); - if(itemstack == null) - { - continue; - } - float xOffset = world.rand.nextFloat() * 0.8F + 0.1F; - float yOffset = world.rand.nextFloat() * 0.8F + 0.1F; - float zOffset = world.rand.nextFloat() * 0.8F + 0.1F; - do - { - if(itemstack.stackSize <= 0) - { - continue inv; - } - int amountToDrop = world.rand.nextInt(21) + 10; - if(amountToDrop > itemstack.stackSize) - { - amountToDrop = itemstack.stackSize; - } - itemstack.stackSize -= amountToDrop; - EntityItem entityitem = new EntityItem(world, (float)x + xOffset, (float)y + yOffset, (float)z + zOffset, new ItemStack(itemstack.getItem(), amountToDrop, itemstack.getItemDamage())); - if(itemstack.getTagCompound() != null) - { - entityitem.getEntityItem().setTagCompound(itemstack.getTagCompound()); - } - float motionMultiplier = 0.05F; - entityitem.motionX = (float)world.rand.nextGaussian() * motionMultiplier; - entityitem.motionY = (float)world.rand.nextGaussian() * motionMultiplier + 0.2F; - entityitem.motionZ = (float)world.rand.nextGaussian() * motionMultiplier; - world.spawnEntityInWorld(entityitem); - } while(true); - } - } - - super.breakBlock(world, x, y, z, block, meta); - } - - @Override - public boolean canCreatureSpawn(EnumCreatureType type, IBlockAccess world, int x, int y, int z) - { - return false; - } - - // IConnectableRedNet - @Optional.Method(modid = "MineFactoryReloaded") - @Override - public RedNetConnectionType getConnectionType(World world, int x, int y, - int z, ForgeDirection side) { - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof TileEntityReactorRedNetPort) { - return RedNetConnectionType.CableAll; - } - - return RedNetConnectionType.None; - } - - @Optional.Method(modid = "MineFactoryReloaded") - @Override - public int[] getOutputValues(World world, int x, int y, int z, - ForgeDirection side) { - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof TileEntityReactorRedNetPort) { - return ((TileEntityReactorRedNetPort)te).getOutputValues(); - } - else { - int[] values = new int[16]; - for(int i = 0; i < 16; i++) { - values[i] = 0; - } - return values; - } - } - - // Never used. we're always in "all" mode. - @Optional.Method(modid = "MineFactoryReloaded") - @Override - public int getOutputValue(World world, int x, int y, int z, - ForgeDirection side, int subnet) { - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof TileEntityReactorRedNetPort) { - return ((TileEntityReactorRedNetPort)te).getValueForChannel(subnet); - } - return 0; - } - - - @Optional.Method(modid = "MineFactoryReloaded") - @Override - public void onInputsChanged(World world, int x, int y, int z, - ForgeDirection side, int[] inputValues) { - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof TileEntityReactorRedNetPort) { - ((TileEntityReactorRedNetPort)te).onInputValuesChanged(inputValues); - } - } - - // Never used, we're always in "all" mode. - @Optional.Method(modid = "MineFactoryReloaded") - @Override - public void onInputChanged(World world, int x, int y, int z, - ForgeDirection side, int inputValue) { - return; - } - - // IPeripheralProvider - @Optional.Method(modid ="ComputerCraft") - @Override - public IPeripheral getPeripheral(World world, int x, int y, int z, int side) { - TileEntity te = world.getTileEntity(x, y, z); - - if(te instanceof TileEntityReactorComputerPort) - return (IPeripheral)te; - - return null; - } - - //// UGLY UI CODE HERE //// - private IIcon getCoolantPortIcon(IBlockAccess blockAccess, int x, int y, - int z, int side) { - TileEntity te = blockAccess.getTileEntity(x, y, z); - if(te instanceof TileEntityReactorCoolantPort) { - TileEntityReactorCoolantPort port = (TileEntityReactorCoolantPort)te; - - if(!isReactorAssembled(port) || isOutwardsSide(port, side)) { - if(port.isInlet()) { - return _icons[METADATA_COOLANTPORT][PORT_INLET]; - } - else { - return _icons[METADATA_COOLANTPORT][PORT_OUTLET]; - } - } - } - return blockIcon; - } - - private IIcon getAccessPortIcon(IBlockAccess blockAccess, int x, int y, - int z, int side) { - TileEntity te = blockAccess.getTileEntity(x, y, z); - if(te instanceof TileEntityReactorAccessPort) { - TileEntityReactorAccessPort port = (TileEntityReactorAccessPort)te; - - if(!isReactorAssembled(port) || isOutwardsSide(port, side)) { - if(port.isInlet()) { - return _icons[METADATA_ACCESSPORT][PORT_INLET]; - } - else { - return _icons[METADATA_ACCESSPORT][PORT_OUTLET]; - } - } - } - return blockIcon; - } - - private IIcon getPowerTapIcon(IBlockAccess blockAccess, int x, int y, int z, int side) { - TileEntity te = blockAccess.getTileEntity(x, y, z); - if(te instanceof TileEntityReactorPowerTap) { - TileEntityReactorPowerTap tap = (TileEntityReactorPowerTap)te; - - if(!isReactorAssembled(tap) || isOutwardsSide(tap, side)) { - if(tap.hasEnergyConnection()) { - return _icons[METADATA_POWERTAP][TAP_CONNECTED]; - } - else { - return _icons[METADATA_POWERTAP][TAP_DISCONNECTED]; - } - } - } - return blockIcon; - } - - private IIcon getControllerIcon(IBlockAccess blockAccess, int x, int y, - int z, int side) { - TileEntity te = blockAccess.getTileEntity(x, y, z); - if(te instanceof TileEntityReactorPart) { - TileEntityReactorPart controller = (TileEntityReactorPart)te; - MultiblockReactor reactor = controller.getReactorController(); - - if(reactor == null || !reactor.isAssembled()) { - return _icons[METADATA_CONTROLLER][CONTROLLER_OFF]; - } - else if(!isOutwardsSide(controller, side)) { - return blockIcon; - } - else if(reactor.getActive()) { - return _icons[METADATA_CONTROLLER][CONTROLLER_ACTIVE]; - } - else { - return _icons[METADATA_CONTROLLER][CONTROLLER_IDLE]; - } - } - return blockIcon; - } - - private static final int DEFAULT = 0; - private static final int FACE = 1; - private static final int CORNER = 2; - private static final int EASTWEST = 3; - private static final int NORTHSOUTH = 4; - private static final int VERTICAL = 5; - - private IIcon getCasingIcon(IBlockAccess blockAccess, int x, int y, int z, int side) { - TileEntity te = blockAccess.getTileEntity(x, y, z); - if(te instanceof TileEntityReactorPart) { - TileEntityReactorPart part = (TileEntityReactorPart)te; - PartPosition position = part.getPartPosition(); - MultiblockReactor reactor = part.getReactorController(); - if(reactor == null || !reactor.isAssembled()) { - return _icons[METADATA_CASING][DEFAULT]; - } - - switch(position) { - case BottomFace: - case TopFace: - case EastFace: - case WestFace: - case NorthFace: - case SouthFace: - return _icons[METADATA_CASING][FACE]; - case FrameCorner: - return _icons[METADATA_CASING][CORNER]; - case Frame: - return getCasingEdgeIcon(part, reactor, side); - case Interior: - case Unknown: - default: - return _icons[METADATA_CASING][DEFAULT]; - } - } - return _icons[METADATA_CASING][DEFAULT]; - } - - private IIcon getCasingEdgeIcon(TileEntityReactorPart part, MultiblockReactor reactor, int side) { - if(reactor == null || !reactor.isAssembled()) { return _icons[METADATA_CASING][DEFAULT]; } - - CoordTriplet minCoord = reactor.getMinimumCoord(); - CoordTriplet maxCoord = reactor.getMaximumCoord(); - - boolean xExtreme, yExtreme, zExtreme; - xExtreme = yExtreme = zExtreme = false; - - if(part.xCoord == minCoord.x || part.xCoord == maxCoord.x) { xExtreme = true; } - if(part.yCoord == minCoord.y || part.yCoord == maxCoord.y) { yExtreme = true; } - if(part.zCoord == minCoord.z || part.zCoord == maxCoord.z) { zExtreme = true; } - - int idx = DEFAULT; - if(!xExtreme) { - if(side < 4) { idx = EASTWEST; } - } - else if(!yExtreme) { - if(side > 1) { - idx = VERTICAL; - } - } - else { // !zExtreme - if(side < 2) { - idx = NORTHSOUTH; - } - else if(side > 3) { - idx = EASTWEST; - } - } - return _icons[METADATA_CASING][idx]; - } - - private IIcon getFaceOrBlockIcon(IBlockAccess blockAccess, int x, int y, int z, int side, int metadata) { - TileEntity te = blockAccess.getTileEntity(x, y, z); - if(te instanceof TileEntityReactorPart) { - TileEntityReactorPart part = (TileEntityReactorPart)te; - if(!isReactorAssembled(part) || isOutwardsSide(part, side)) { - return _icons[metadata][0]; - } - } - return this.blockIcon; - } - - /** - * @param part The part whose sides we're checking - * @param side The side to compare to the part - * @return True if `side` is the outwards-facing face of `part` - */ - private boolean isOutwardsSide(TileEntityReactorPart part, int side) { - ForgeDirection outDir = part.getOutwardsDir(); - return outDir.ordinal() == side; - } - - private boolean isReactorAssembled(TileEntityReactorPart part) { - MultiblockReactor reactor = part.getReactorController(); - return reactor != null && reactor.isAssembled(); - } + IIcon icon = null; + int metadata = blockAccess.getBlockMetadata(x, y, z); + + if (metadata == METADATA_CONTROLROD) { + return getIcon(side, metadata); + } + + switch (metadata) { + case METADATA_CASING: + icon = getCasingIcon(blockAccess, x, y, z, side); + break; + case METADATA_CONTROLLER: + icon = getControllerIcon(blockAccess, x, y, z, side); + break; + case METADATA_POWERTAP: + icon = getPowerTapIcon(blockAccess, x, y, z, side); + break; + case METADATA_ACCESSPORT: + icon = getAccessPortIcon(blockAccess, x, y, z, side); + break; + case METADATA_COOLANTPORT: + icon = getCoolantPortIcon(blockAccess, x, y, z, side); + break; + case METADATA_REDNETPORT: + case METADATA_COMPUTERPORT: + icon = getFaceOrBlockIcon(blockAccess, x, y, z, side, metadata); + break; + } + + return icon != null ? icon : getIcon(side, metadata); + } + + @Override + public IIcon getIcon(int side, int metadata) { + if (metadata == METADATA_CONTROLROD) { + if (side == 1) { + return _icons[metadata][0]; + } + } else { + if (side > 1 && (metadata >= 0 && metadata < _icons.length)) { + return _icons[metadata][0]; + } + } + return blockIcon; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerBlockIcons(IIconRegister par1IconRegister) { + String prefix = BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + "."; + + for (int metadata = 0; metadata < _states.length; ++metadata) { + String[] blockStates = _states[metadata]; + _icons[metadata] = new IIcon[blockStates.length]; + + for (int state = 0; state < blockStates.length; state++) { + _icons[metadata][state] = par1IconRegister + .registerIcon(prefix + _subBlocks[metadata] + "." + blockStates[state]); + } + } + + this.blockIcon = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName()); + + // We do this to skip DISABLED + TileEntityReactorRedNetPort.CircuitType[] circuitTypes = TileEntityReactorRedNetPort.CircuitType.values(); + String rednetPrefix = BigReactors.TEXTURE_NAME_PREFIX + "redNet/"; + + for (int i = 1; i < circuitTypes.length; ++i) { + _redNetPortConfigIcons[i - 1] = par1IconRegister.registerIcon(rednetPrefix + circuitTypes[i].name()); + } + } + + // We do this to skip DISABLED + @SideOnly(Side.CLIENT) + public IIcon getRedNetConfigIcon(TileEntityReactorRedNetPort.CircuitType circuitType) { + if (circuitType == TileEntityReactorRedNetPort.CircuitType.DISABLED) { + return null; + } else { + return _redNetPortConfigIcons[circuitType.ordinal() - 1]; + } + } + + @Override + public TileEntity createNewTileEntity(World world, int metadata) { + switch (metadata) { + case METADATA_POWERTAP: + return new TileEntityReactorPowerTap(); + case METADATA_ACCESSPORT: + return new TileEntityReactorAccessPort(); + case METADATA_REDNETPORT: + return new TileEntityReactorRedNetPort(); + case METADATA_COMPUTERPORT: + return new TileEntityReactorComputerPort(); + case METADATA_COOLANTPORT: + return new TileEntityReactorCoolantPort(); + case METADATA_CONTROLROD: + return new TileEntityReactorControlRod(); + default: + return new TileEntityReactorPart(); + } + } + + @Override + public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock) { + TileEntity te = StaticUtils.TE.getTileEntityUnsafe(world, x, y, z); + + // Signal power taps when their neighbors change, etc. + if (te instanceof INeighborUpdatableEntity) { + ((INeighborUpdatableEntity) te).onNeighborBlockChange(world, x, y, z, neighborBlock); + } + } + + @Override + public void onNeighborChange(IBlockAccess world, int x, int y, int z, int neighborX, int neighborY, int neighborZ) { + TileEntity te = StaticUtils.TE.getTileEntityUnsafe(world, x, y, z); + + // Signal power taps when their neighbors change, etc. + if (te instanceof INeighborUpdatableEntity) { + ((INeighborUpdatableEntity) te).onNeighborTileChange(world, x, y, z, neighborX, neighborY, neighborZ); + } + } + + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int par6, float par7, + float par8, float par9) { + if (player.isSneaking()) { + return false; + } + + int metadata = world.getBlockMetadata(x, y, z); + TileEntity te = world.getTileEntity(x, y, z); + IMultiblockPart part = null; + MultiblockControllerBase controller = null; + + if (te instanceof IMultiblockPart) { + part = (IMultiblockPart) te; + controller = part.getMultiblockController(); + } + + if (isCasing(metadata) || isPowerTap(metadata) || isComputerPort(metadata)) { + // If the player's hands are empty and they rightclick on a multiblock, they get a + // multiblock-debugging message if the machine is not assembled. + if (player.getCurrentEquippedItem() == null) { + if (controller != null) { + Exception e = controller.getLastValidationException(); + if (e != null) { + player.addChatMessage(new ChatComponentText(e.getMessage())); + return true; + } + } else { + player.addChatMessage( + new ChatComponentText( + "Block is not connected to a reactor. This could be due to lag, or a bug. If the problem persists, try breaking and re-placing the block.")); // TODO + // Localize + return true; + } + } + + // If nonempty, or there was no error, just fall through + return false; + } + + // Do toggly fiddly things for access/coolant ports + if (!world.isRemote && (isAccessPort(metadata) || isCoolantPort(metadata))) { + if (StaticUtils.Inventory.isPlayerHoldingWrench(player)) { + if (te instanceof TileEntityReactorCoolantPort) { + TileEntityReactorCoolantPort cp = (TileEntityReactorCoolantPort) te; + cp.setInlet(!cp.isInlet(), true); + return true; + } else if (te instanceof TileEntityReactorAccessPort) { + TileEntityReactorAccessPort cp = (TileEntityReactorAccessPort) te; + cp.setInlet(!cp.isInlet()); + return true; + } + } else if (isCoolantPort(metadata)) { + return false; + } + } + + // Don't open the controller GUI if the reactor isn't assembled + if (isController(metadata) && (controller == null || !controller.isAssembled())) { + return false; + } + + if (!world.isRemote) { + player.openGui(BRLoader.instance, 0, world, x, y, z); + } + return true; + } + + @Override + public boolean isOpaqueCube() { + return true; + } + + @Override + public boolean renderAsNormalBlock() { + return true; + } + + @Override + public int damageDropped(int metadata) { + return metadata; + } + + public ItemStack getReactorCasingItemStack() { + return new ItemStack(this, 1, METADATA_CASING); + } + + public ItemStack getReactorControllerItemStack() { + return new ItemStack(this, 1, METADATA_CONTROLLER); + } + + public ItemStack getReactorPowerTapItemStack() { + return new ItemStack(this, 1, METADATA_POWERTAP); + } + + public ItemStack getAccessPortItemStack() { + return new ItemStack(this, 1, METADATA_ACCESSPORT); + } + + public ItemStack getRedNetPortItemStack() { + return new ItemStack(this, 1, METADATA_REDNETPORT); + } + + public ItemStack getComputerPortItemStack() { + return new ItemStack(this, 1, METADATA_COMPUTERPORT); + } + + public ItemStack getCoolantPortItemStack() { + return new ItemStack(this, 1, METADATA_COOLANTPORT); + } + + public ItemStack getControlRodItemStack() { + return new ItemStack(this, 1, METADATA_CONTROLROD); + } + + @Override + public void getSubBlocks(Item par1, CreativeTabs par2CreativeTabs, List par3List) { + for (int metadata = 0; metadata < _subBlocks.length; metadata++) { + par3List.add(new ItemStack(this, 1, metadata)); + } + } + + @Override + public void breakBlock(World world, int x, int y, int z, Block block, int meta) { + // Drop everything inside inventory blocks + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof IInventory) { + IInventory inventory = ((IInventory) te); + inv: for (int i = 0; i < inventory.getSizeInventory(); i++) { + ItemStack itemstack = inventory.getStackInSlot(i); + if (itemstack == null) { + continue; + } + float xOffset = world.rand.nextFloat() * 0.8F + 0.1F; + float yOffset = world.rand.nextFloat() * 0.8F + 0.1F; + float zOffset = world.rand.nextFloat() * 0.8F + 0.1F; + do { + if (itemstack.stackSize <= 0) { + continue inv; + } + int amountToDrop = world.rand.nextInt(21) + 10; + if (amountToDrop > itemstack.stackSize) { + amountToDrop = itemstack.stackSize; + } + itemstack.stackSize -= amountToDrop; + EntityItem entityitem = new EntityItem( + world, + (float) x + xOffset, + (float) y + yOffset, + (float) z + zOffset, + new ItemStack(itemstack.getItem(), amountToDrop, itemstack.getItemDamage())); + if (itemstack.getTagCompound() != null) { + entityitem.getEntityItem() + .setTagCompound(itemstack.getTagCompound()); + } + float motionMultiplier = 0.05F; + entityitem.motionX = (float) world.rand.nextGaussian() * motionMultiplier; + entityitem.motionY = (float) world.rand.nextGaussian() * motionMultiplier + 0.2F; + entityitem.motionZ = (float) world.rand.nextGaussian() * motionMultiplier; + world.spawnEntityInWorld(entityitem); + } while (true); + } + } + + super.breakBlock(world, x, y, z, block, meta); + } + + @Override + public boolean canCreatureSpawn(EnumCreatureType type, IBlockAccess world, int x, int y, int z) { + return false; + } + + // IConnectableRedNet + @Optional.Method(modid = "MineFactoryReloaded") + @Override + public RedNetConnectionType getConnectionType(World world, int x, int y, int z, ForgeDirection side) { + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof TileEntityReactorRedNetPort) { + return RedNetConnectionType.CableAll; + } + + return RedNetConnectionType.None; + } + + @Optional.Method(modid = "MineFactoryReloaded") + @Override + public int[] getOutputValues(World world, int x, int y, int z, ForgeDirection side) { + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof TileEntityReactorRedNetPort) { + return ((TileEntityReactorRedNetPort) te).getOutputValues(); + } else { + int[] values = new int[16]; + for (int i = 0; i < 16; i++) { + values[i] = 0; + } + return values; + } + } + + // Never used. we're always in "all" mode. + @Optional.Method(modid = "MineFactoryReloaded") + @Override + public int getOutputValue(World world, int x, int y, int z, ForgeDirection side, int subnet) { + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof TileEntityReactorRedNetPort) { + return ((TileEntityReactorRedNetPort) te).getValueForChannel(subnet); + } + return 0; + } + + @Optional.Method(modid = "MineFactoryReloaded") + @Override + public void onInputsChanged(World world, int x, int y, int z, ForgeDirection side, int[] inputValues) { + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof TileEntityReactorRedNetPort) { + ((TileEntityReactorRedNetPort) te).onInputValuesChanged(inputValues); + } + } + + // Never used, we're always in "all" mode. + @Optional.Method(modid = "MineFactoryReloaded") + @Override + public void onInputChanged(World world, int x, int y, int z, ForgeDirection side, int inputValue) { + return; + } + + // IPeripheralProvider + @Optional.Method(modid = "ComputerCraft") + @Override + public IPeripheral getPeripheral(World world, int x, int y, int z, int side) { + TileEntity te = world.getTileEntity(x, y, z); + + if (te instanceof TileEntityReactorComputerPort) return (IPeripheral) te; + + return null; + } + + //// UGLY UI CODE HERE //// + private IIcon getCoolantPortIcon(IBlockAccess blockAccess, int x, int y, int z, int side) { + TileEntity te = blockAccess.getTileEntity(x, y, z); + if (te instanceof TileEntityReactorCoolantPort) { + TileEntityReactorCoolantPort port = (TileEntityReactorCoolantPort) te; + + if (!isReactorAssembled(port) || isOutwardsSide(port, side)) { + if (port.isInlet()) { + return _icons[METADATA_COOLANTPORT][PORT_INLET]; + } else { + return _icons[METADATA_COOLANTPORT][PORT_OUTLET]; + } + } + } + return blockIcon; + } + + private IIcon getAccessPortIcon(IBlockAccess blockAccess, int x, int y, int z, int side) { + TileEntity te = blockAccess.getTileEntity(x, y, z); + if (te instanceof TileEntityReactorAccessPort) { + TileEntityReactorAccessPort port = (TileEntityReactorAccessPort) te; + + if (!isReactorAssembled(port) || isOutwardsSide(port, side)) { + if (port.isInlet()) { + return _icons[METADATA_ACCESSPORT][PORT_INLET]; + } else { + return _icons[METADATA_ACCESSPORT][PORT_OUTLET]; + } + } + } + return blockIcon; + } + + private IIcon getPowerTapIcon(IBlockAccess blockAccess, int x, int y, int z, int side) { + TileEntity te = blockAccess.getTileEntity(x, y, z); + if (te instanceof TileEntityReactorPowerTap) { + TileEntityReactorPowerTap tap = (TileEntityReactorPowerTap) te; + + if (!isReactorAssembled(tap) || isOutwardsSide(tap, side)) { + if (tap.hasEnergyConnection()) { + return _icons[METADATA_POWERTAP][TAP_CONNECTED]; + } else { + return _icons[METADATA_POWERTAP][TAP_DISCONNECTED]; + } + } + } + return blockIcon; + } + + private IIcon getControllerIcon(IBlockAccess blockAccess, int x, int y, int z, int side) { + TileEntity te = blockAccess.getTileEntity(x, y, z); + if (te instanceof TileEntityReactorPart) { + TileEntityReactorPart controller = (TileEntityReactorPart) te; + MultiblockReactor reactor = controller.getReactorController(); + + if (reactor == null || !reactor.isAssembled()) { + return _icons[METADATA_CONTROLLER][CONTROLLER_OFF]; + } else if (!isOutwardsSide(controller, side)) { + return blockIcon; + } else if (reactor.getActive()) { + return _icons[METADATA_CONTROLLER][CONTROLLER_ACTIVE]; + } else { + return _icons[METADATA_CONTROLLER][CONTROLLER_IDLE]; + } + } + return blockIcon; + } + + private static final int DEFAULT = 0; + private static final int FACE = 1; + private static final int CORNER = 2; + private static final int EASTWEST = 3; + private static final int NORTHSOUTH = 4; + private static final int VERTICAL = 5; + + private IIcon getCasingIcon(IBlockAccess blockAccess, int x, int y, int z, int side) { + TileEntity te = blockAccess.getTileEntity(x, y, z); + if (te instanceof TileEntityReactorPart) { + TileEntityReactorPart part = (TileEntityReactorPart) te; + PartPosition position = part.getPartPosition(); + MultiblockReactor reactor = part.getReactorController(); + if (reactor == null || !reactor.isAssembled()) { + return _icons[METADATA_CASING][DEFAULT]; + } + + switch (position) { + case BottomFace: + case TopFace: + case EastFace: + case WestFace: + case NorthFace: + case SouthFace: + return _icons[METADATA_CASING][FACE]; + case FrameCorner: + return _icons[METADATA_CASING][CORNER]; + case Frame: + return getCasingEdgeIcon(part, reactor, side); + case Interior: + case Unknown: + default: + return _icons[METADATA_CASING][DEFAULT]; + } + } + return _icons[METADATA_CASING][DEFAULT]; + } + + private IIcon getCasingEdgeIcon(TileEntityReactorPart part, MultiblockReactor reactor, int side) { + if (reactor == null || !reactor.isAssembled()) { + return _icons[METADATA_CASING][DEFAULT]; + } + + CoordTriplet minCoord = reactor.getMinimumCoord(); + CoordTriplet maxCoord = reactor.getMaximumCoord(); + + boolean xExtreme, yExtreme, zExtreme; + xExtreme = yExtreme = zExtreme = false; + + if (part.xCoord == minCoord.x || part.xCoord == maxCoord.x) { + xExtreme = true; + } + if (part.yCoord == minCoord.y || part.yCoord == maxCoord.y) { + yExtreme = true; + } + if (part.zCoord == minCoord.z || part.zCoord == maxCoord.z) { + zExtreme = true; + } + + int idx = DEFAULT; + if (!xExtreme) { + if (side < 4) { + idx = EASTWEST; + } + } else if (!yExtreme) { + if (side > 1) { + idx = VERTICAL; + } + } else { // !zExtreme + if (side < 2) { + idx = NORTHSOUTH; + } else if (side > 3) { + idx = EASTWEST; + } + } + return _icons[METADATA_CASING][idx]; + } + + private IIcon getFaceOrBlockIcon(IBlockAccess blockAccess, int x, int y, int z, int side, int metadata) { + TileEntity te = blockAccess.getTileEntity(x, y, z); + if (te instanceof TileEntityReactorPart) { + TileEntityReactorPart part = (TileEntityReactorPart) te; + if (!isReactorAssembled(part) || isOutwardsSide(part, side)) { + return _icons[metadata][0]; + } + } + return this.blockIcon; + } + + /** + * @param part The part whose sides we're checking + * @param side The side to compare to the part + * @return True if `side` is the outwards-facing face of `part` + */ + private boolean isOutwardsSide(TileEntityReactorPart part, int side) { + ForgeDirection outDir = part.getOutwardsDir(); + return outDir.ordinal() == side; + } + + private boolean isReactorAssembled(TileEntityReactorPart part) { + MultiblockReactor reactor = part.getReactorController(); + return reactor != null && reactor.isAssembled(); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockReactorRedstonePort.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockReactorRedstonePort.java index ed6cda78..376ce85a 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockReactorRedstonePort.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockReactorRedstonePort.java @@ -13,209 +13,210 @@ import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; -import powercrystals.minefactoryreloaded.api.rednet.IRedNetOmniNode; -import powercrystals.minefactoryreloaded.api.rednet.connectivity.RedNetConnectionType; + import cpw.mods.fml.common.Optional; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import erogenousbeef.bigreactors.common.BRLoader; import erogenousbeef.bigreactors.common.BigReactors; import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorRedstonePort; +import powercrystals.minefactoryreloaded.api.rednet.IRedNetOmniNode; +import powercrystals.minefactoryreloaded.api.rednet.connectivity.RedNetConnectionType; -@Optional.InterfaceList({ - @Optional.Interface(iface = "powercrystals.minefactoryreloaded.api.rednet.IRedNetOmniNode", modid = "MineFactoryReloaded") -}) +@Optional.InterfaceList({ @Optional.Interface( + iface = "powercrystals.minefactoryreloaded.api.rednet.IRedNetOmniNode", + modid = "MineFactoryReloaded") }) public class BlockReactorRedstonePort extends BlockContainer implements IRedNetOmniNode { - protected IIcon blockIconLit; - - public static final int META_REDSTONE_LIT = 1; - public static final int META_REDSTONE_UNLIT = 0; - - protected final static int REDSTONE_VALUE_OFF = 0; // corresponds to no power - protected final static int REDSTONE_VALUE_ON = 15; // corresponds to strong power - - public BlockReactorRedstonePort(Material material) { - super(material); - - setStepSound(soundTypeMetal); - setHardness(2.0f); - setBlockName("blockReactorRedstonePort"); - this.setBlockTextureName(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName()); - setCreativeTab(BigReactors.TAB); - } - - @Override - public TileEntity createNewTileEntity(World world, int metadata) { - return new TileEntityReactorRedstonePort(); - } - - @Override - public IIcon getIcon(int side, int metadata) - { - if(side == 0 || side == 1) { return BigReactors.blockReactorPart.getIcon(side, BlockReactorPart.METADATA_CASING); } - - if(metadata == META_REDSTONE_LIT) { return blockIconLit; } - else { - return blockIcon; - } - } - - @Override - @SideOnly(Side.CLIENT) - public void registerBlockIcons(IIconRegister par1IconRegister) - { - this.blockIcon = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + ".unlit"); - this.blockIconLit = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + ".lit"); - } - - - @Override - public int damageDropped(int metadata) - { - return META_REDSTONE_UNLIT; - } - - @Override - public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int par6, float par7, float par8, float par9) { - if(player.isSneaking()) { - return false; - } - - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof TileEntityReactorRedstonePort) { - if(!((TileEntityReactorRedstonePort)te).isConnected()) { return false; } - - if(!world.isRemote) - ((TileEntityReactorRedstonePort)te).sendRedstoneUpdate(); - - if(!world.isRemote) { - player.openGui(BRLoader.instance, 0, world, x, y, z); - } - return true; - } - - return false; - } - + protected IIcon blockIconLit; + + public static final int META_REDSTONE_LIT = 1; + public static final int META_REDSTONE_UNLIT = 0; + + protected final static int REDSTONE_VALUE_OFF = 0; // corresponds to no power + protected final static int REDSTONE_VALUE_ON = 15; // corresponds to strong power + + public BlockReactorRedstonePort(Material material) { + super(material); + + setStepSound(soundTypeMetal); + setHardness(2.0f); + setBlockName("blockReactorRedstonePort"); + this.setBlockTextureName(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName()); + setCreativeTab(BigReactors.TAB); + } + + @Override + public TileEntity createNewTileEntity(World world, int metadata) { + return new TileEntityReactorRedstonePort(); + } + + @Override + public IIcon getIcon(int side, int metadata) { + if (side == 0 || side == 1) { + return BigReactors.blockReactorPart.getIcon(side, BlockReactorPart.METADATA_CASING); + } + + if (metadata == META_REDSTONE_LIT) { + return blockIconLit; + } else { + return blockIcon; + } + } + + @Override + @SideOnly(Side.CLIENT) + public void registerBlockIcons(IIconRegister par1IconRegister) { + this.blockIcon = par1IconRegister + .registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + ".unlit"); + this.blockIconLit = par1IconRegister + .registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + ".lit"); + } + + @Override + public int damageDropped(int metadata) { + return META_REDSTONE_UNLIT; + } + + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int par6, float par7, + float par8, float par9) { + if (player.isSneaking()) { + return false; + } + + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof TileEntityReactorRedstonePort) { + if (!((TileEntityReactorRedstonePort) te).isConnected()) { + return false; + } + + if (!world.isRemote) ((TileEntityReactorRedstonePort) te).sendRedstoneUpdate(); + + if (!world.isRemote) { + player.openGui(BRLoader.instance, 0, world, x, y, z); + } + return true; + } + + return false; + } + /** * A randomly called display update to be able to add particles or other items for display */ @SideOnly(Side.CLIENT) - public void randomDisplayTick(World world, int x, int y, int z, Random par5Random) - { - TileEntity te = world.getTileEntity(x, y, z); - if (te instanceof TileEntityReactorRedstonePort) - { - TileEntityReactorRedstonePort port = (TileEntityReactorRedstonePort)te; - if(port.isRedstoneActive()) { + public void randomDisplayTick(World world, int x, int y, int z, Random par5Random) { + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof TileEntityReactorRedstonePort) { + TileEntityReactorRedstonePort port = (TileEntityReactorRedstonePort) te; + if (port.isRedstoneActive()) { ForgeDirection out = port.getOutwardsDir(); - - if(out != ForgeDirection.UNKNOWN) { + + if (out != ForgeDirection.UNKNOWN) { double particleX, particleY, particleZ; particleY = y + 0.45D + par5Random.nextFloat() * 0.1D; - if(out.offsetX > 0) - particleX = x + par5Random.nextFloat() * 0.1D + 1.1D; - else - particleX = x + 0.45D + par5Random.nextFloat() * 0.1D; - - if(out.offsetZ > 0) - particleZ = z + par5Random.nextFloat() * 0.1D + 1.1D; - else - particleZ = z + 0.45D + par5Random.nextFloat() * 0.1D; - - world.spawnParticle("reddust", particleX, particleY, particleZ, 0.0D, par5Random.nextFloat() * 0.1D, 0.0D); + if (out.offsetX > 0) particleX = x + par5Random.nextFloat() * 0.1D + 1.1D; + else particleX = x + 0.45D + par5Random.nextFloat() * 0.1D; + + if (out.offsetZ > 0) particleZ = z + par5Random.nextFloat() * 0.1D + 1.1D; + else particleZ = z + 0.45D + par5Random.nextFloat() * 0.1D; + + world.spawnParticle( + "reddust", + particleX, + particleY, + particleZ, + 0.0D, + par5Random.nextFloat() * 0.1D, + 0.0D); } - } + } + } + } + + @Override + public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock) { + super.onNeighborBlockChange(world, x, y, z, neighborBlock); + + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof TileEntityReactorRedstonePort) { + ((TileEntityReactorRedstonePort) te).onNeighborBlockChange(x, y, z, neighborBlock); } } - + + // Redstone API + @Override + public boolean canProvidePower() { + return true; + } + + @Override + public int isProvidingStrongPower(IBlockAccess world, int x, int y, int z, int side) { + return isProvidingWeakPower(world, x, y, z, side); + } + + @Override + public int isProvidingWeakPower(IBlockAccess world, int x, int y, int z, int side) { + if (side == 0 || side == 1) { + return REDSTONE_VALUE_OFF; + } + + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof TileEntityReactorRedstonePort) { + TileEntityReactorRedstonePort port = (TileEntityReactorRedstonePort) te; + if (port.isOutput()) return port.isRedstoneActive() ? REDSTONE_VALUE_ON : REDSTONE_VALUE_OFF; + else return REDSTONE_VALUE_OFF; + } + + return REDSTONE_VALUE_OFF; + } + + // IRedNetOmniNode - for pretty cable connections + @Optional.Method(modid = "MineFactoryReloaded") + @Override + public RedNetConnectionType getConnectionType(World world, int x, int y, int z, ForgeDirection side) { + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof TileEntityReactorRedstonePort) { + TileEntityReactorRedstonePort port = (TileEntityReactorRedstonePort) te; + if (port.isConnected()) { + return RedNetConnectionType.CableSingle; + } + } + return RedNetConnectionType.None; + } + + @Optional.Method(modid = "MineFactoryReloaded") + @Override + public int[] getOutputValues(World world, int x, int y, int z, ForgeDirection side) { + return null; + } + + @Optional.Method(modid = "MineFactoryReloaded") + @Override + public int getOutputValue(World world, int x, int y, int z, ForgeDirection side, int subnet) { + return isProvidingWeakPower(world, x, y, z, side.ordinal()); + } + + @Optional.Method(modid = "MineFactoryReloaded") + @Override + public void onInputsChanged(World world, int x, int y, int z, ForgeDirection side, int[] inputValues) { + // Not used + } + + @Optional.Method(modid = "MineFactoryReloaded") + @Override + public void onInputChanged(World world, int x, int y, int z, ForgeDirection side, int inputValue) { + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof TileEntityReactorRedstonePort) { + TileEntityReactorRedstonePort port = (TileEntityReactorRedstonePort) te; + port.onRedNetUpdate(inputValue); + } + } + @Override - public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock) { - super.onNeighborBlockChange(world, x, y,z, neighborBlock); - - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof TileEntityReactorRedstonePort) { - ((TileEntityReactorRedstonePort)te).onNeighborBlockChange(x, y, z, neighborBlock); - } - } - - // Redstone API - @Override - public boolean canProvidePower() { return true; } - - @Override - public int isProvidingStrongPower(IBlockAccess world, int x, int y, int z, int side) { - return isProvidingWeakPower(world, x, y, z, side); - } - - @Override - public int isProvidingWeakPower(IBlockAccess world, int x, int y, int z, int side) { - if(side == 0 || side == 1) { return REDSTONE_VALUE_OFF; } - - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof TileEntityReactorRedstonePort) { - TileEntityReactorRedstonePort port = (TileEntityReactorRedstonePort)te; - if(port.isOutput()) - return port.isRedstoneActive() ? REDSTONE_VALUE_ON : REDSTONE_VALUE_OFF; - else - return REDSTONE_VALUE_OFF; - } - - return REDSTONE_VALUE_OFF; - } - - // IRedNetOmniNode - for pretty cable connections - @Optional.Method(modid = "MineFactoryReloaded") - @Override - public RedNetConnectionType getConnectionType(World world, int x, int y, - int z, ForgeDirection side) { - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof TileEntityReactorRedstonePort) { - TileEntityReactorRedstonePort port = (TileEntityReactorRedstonePort)te; - if(port.isConnected()) { - return RedNetConnectionType.CableSingle; - } - } - return RedNetConnectionType.None; - } - - @Optional.Method(modid = "MineFactoryReloaded") - @Override - public int[] getOutputValues(World world, int x, int y, int z, - ForgeDirection side) { - return null; - } - - @Optional.Method(modid = "MineFactoryReloaded") - @Override - public int getOutputValue(World world, int x, int y, int z, - ForgeDirection side, int subnet) { - return isProvidingWeakPower(world, x, y, z, side.ordinal()); - } - - @Optional.Method(modid = "MineFactoryReloaded") - @Override - public void onInputsChanged(World world, int x, int y, int z, - ForgeDirection side, int[] inputValues) { - // Not used - } - - @Optional.Method(modid = "MineFactoryReloaded") - @Override - public void onInputChanged(World world, int x, int y, int z, - ForgeDirection side, int inputValue) { - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof TileEntityReactorRedstonePort) { - TileEntityReactorRedstonePort port = (TileEntityReactorRedstonePort)te; - port.onRedNetUpdate(inputValue); - } - } - - @Override - public boolean canCreatureSpawn(EnumCreatureType type, IBlockAccess world, int x, int y, int z) - { - return false; + public boolean canCreatureSpawn(EnumCreatureType type, IBlockAccess world, int x, int y, int z) { + return false; } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockTurbinePart.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockTurbinePart.java index 436e3e60..827ca2e3 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockTurbinePart.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockTurbinePart.java @@ -21,6 +21,7 @@ import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; + import cpw.mods.fml.common.Optional; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -41,475 +42,481 @@ import erogenousbeef.core.common.CoordTriplet; import erogenousbeef.core.multiblock.IMultiblockPart; import erogenousbeef.core.multiblock.MultiblockControllerBase; + @Optional.InterfaceList({ - @Optional.Interface(iface = "dan200.computercraft.api.peripheral.IPeripheralProvider", modid = "ComputerCraft"), -}) + @Optional.Interface(iface = "dan200.computercraft.api.peripheral.IPeripheralProvider", modid = "ComputerCraft"), }) public class BlockTurbinePart extends BlockContainer implements IPeripheralProvider { - public static final int METADATA_HOUSING = 0; - public static final int METADATA_CONTROLLER = 1; - public static final int METADATA_POWERTAP = 2; - public static final int METADATA_FLUIDPORT = 3; - public static final int METADATA_BEARING = 4; - public static final int METADATA_COMPUTERPORT = 5; - - private static final String[] _subBlocks = new String[] { "housing", - "controller", - "powerTap", - "fluidPort", - "bearing", - "computerPort" }; - - // Additional non-metadata-based icons - private static final int SUBICON_NONE = -1; - private static final int SUBICON_HOUSING_FRAME_TOP = 0; - private static final int SUBICON_HOUSING_FRAME_BOTTOM = 1; - private static final int SUBICON_HOUSING_FRAME_LEFT = 2; - private static final int SUBICON_HOUSING_FRAME_RIGHT = 3; - private static final int SUBICON_HOUSING_FACE = 4; - private static final int SUBICON_HOUSING_CORNER = 5; - private static final int SUBICON_CONTROLLER_IDLE = 6; - private static final int SUBICON_CONTROLLER_ACTIVE = 7; - private static final int SUBICON_POWERTAP_ACTIVE = 8; - private static final int SUBICON_FLUIDPORT_OUTPUT = 9; - - private static final String[] _subIconNames = new String[] { - "housing.edge.0", - "housing.edge.1", - "housing.edge.2", - "housing.edge.3", - "housing.face", - "housing.corner", - "controller.idle", - "controller.active", - "powerTap.connected", - "fluidPort.outlet" - }; - - private IIcon[] _icons = new IIcon[_subBlocks.length]; - private IIcon[] _subIcons = new IIcon[_subIconNames.length]; - - public BlockTurbinePart(Material material) { - super(material); - - setStepSound(soundTypeMetal); - setHardness(2.0f); - setBlockName("blockTurbinePart"); - this.setBlockTextureName(BigReactors.TEXTURE_NAME_PREFIX + "blockTurbinePart"); - setCreativeTab(BigReactors.TAB); - } - - @Override - @SideOnly(Side.CLIENT) - public void registerBlockIcons(IIconRegister par1IconRegister) - { - // Base icons - for(int i = 0; i < _subBlocks.length; ++i) { - _icons[i] = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + "." + _subBlocks[i]); - } - - for(int i = 0; i < _subIcons.length; i++) { - _subIcons[i] = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + "." + _subIconNames[i]); - } - - this.blockIcon = _icons[0]; - } - - @Override + public static final int METADATA_HOUSING = 0; + public static final int METADATA_CONTROLLER = 1; + public static final int METADATA_POWERTAP = 2; + public static final int METADATA_FLUIDPORT = 3; + public static final int METADATA_BEARING = 4; + public static final int METADATA_COMPUTERPORT = 5; + + private static final String[] _subBlocks = new String[] { "housing", "controller", "powerTap", "fluidPort", + "bearing", "computerPort" }; + + // Additional non-metadata-based icons + private static final int SUBICON_NONE = -1; + private static final int SUBICON_HOUSING_FRAME_TOP = 0; + private static final int SUBICON_HOUSING_FRAME_BOTTOM = 1; + private static final int SUBICON_HOUSING_FRAME_LEFT = 2; + private static final int SUBICON_HOUSING_FRAME_RIGHT = 3; + private static final int SUBICON_HOUSING_FACE = 4; + private static final int SUBICON_HOUSING_CORNER = 5; + private static final int SUBICON_CONTROLLER_IDLE = 6; + private static final int SUBICON_CONTROLLER_ACTIVE = 7; + private static final int SUBICON_POWERTAP_ACTIVE = 8; + private static final int SUBICON_FLUIDPORT_OUTPUT = 9; + + private static final String[] _subIconNames = new String[] { "housing.edge.0", "housing.edge.1", "housing.edge.2", + "housing.edge.3", "housing.face", "housing.corner", "controller.idle", "controller.active", + "powerTap.connected", "fluidPort.outlet" }; + + private IIcon[] _icons = new IIcon[_subBlocks.length]; + private IIcon[] _subIcons = new IIcon[_subIconNames.length]; + + public BlockTurbinePart(Material material) { + super(material); + + setStepSound(soundTypeMetal); + setHardness(2.0f); + setBlockName("blockTurbinePart"); + this.setBlockTextureName(BigReactors.TEXTURE_NAME_PREFIX + "blockTurbinePart"); + setCreativeTab(BigReactors.TAB); + } + + @Override + @SideOnly(Side.CLIENT) + public void registerBlockIcons(IIconRegister par1IconRegister) { + // Base icons + for (int i = 0; i < _subBlocks.length; ++i) { + _icons[i] = par1IconRegister + .registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + "." + _subBlocks[i]); + } + + for (int i = 0; i < _subIcons.length; i++) { + _subIcons[i] = par1IconRegister + .registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + "." + _subIconNames[i]); + } + + this.blockIcon = _icons[0]; + } + + @Override public IIcon getIcon(IBlockAccess blockAccess, int x, int y, int z, int side) { - TileEntity te = blockAccess.getTileEntity(x, y, z); - int metadata = blockAccess.getBlockMetadata(x,y,z); - - if(te instanceof TileEntityTurbinePartBase) { - TileEntityTurbinePartBase part = (TileEntityTurbinePartBase)te; - MultiblockTurbine turbine = part.getTurbine(); - - if(metadata == METADATA_FLUIDPORT) { - if(te instanceof TileEntityTurbineFluidPort) { - if(turbine == null || !turbine.isAssembled() || part.getOutwardsDir().ordinal() == side) - { - if(((TileEntityTurbineFluidPort)te).getFlowDirection() == FluidFlow.Out) - return _subIcons[SUBICON_FLUIDPORT_OUTPUT]; - else - return _icons[METADATA_FLUIDPORT]; - } - else if(turbine.isAssembled() && part.getOutwardsDir().ordinal() != side) - return _subIcons[SUBICON_HOUSING_FACE]; - } - return getIcon(side, metadata); - } - else if(!part.isConnected() || turbine == null || !turbine.isAssembled()) { - return getIcon(side, metadata); - } - else { - int subIcon = SUBICON_NONE; - if(metadata == METADATA_HOUSING) { - subIcon = getSubIconForHousing(blockAccess, x, y, z, turbine, side); - } - else if(part.getOutwardsDir().ordinal() == side) { - // Only put the fancy icon on one side of the machine. Other parts will use the base. - if(metadata == METADATA_CONTROLLER) { - if(turbine.getActive()) { - subIcon = SUBICON_CONTROLLER_ACTIVE; - } - else { - subIcon = SUBICON_CONTROLLER_IDLE; - } - } - else if(metadata == METADATA_POWERTAP) { - if(te instanceof TileEntityTurbinePowerTap && ((TileEntityTurbinePowerTap)te).isAttachedToPowerNetwork()) { - subIcon = SUBICON_POWERTAP_ACTIVE; - } - } - } - else { - // Assembled non-housing parts use the face texture so it's all smooth on the inside - subIcon = SUBICON_HOUSING_FACE; - } - - if(subIcon == SUBICON_NONE) { - return getIcon(side, metadata); - } - else { - return _subIcons[subIcon]; - } - } - } - - // Not a "proper" TE, so just pass through - return getIcon(side, metadata); - } - - private int getSubIconForHousing(IBlockAccess blockAccess, int x, int y, int z, MultiblockTurbine turbine, int side) { - CoordTriplet minCoord, maxCoord; - minCoord = turbine.getMinimumCoord(); - maxCoord = turbine.getMaximumCoord(); - - if(minCoord == null || maxCoord == null) { - return SUBICON_NONE; - } - - int extremes = 0; - boolean xExtreme, yExtreme, zExtreme; - xExtreme = yExtreme = zExtreme = false; - - if(x == minCoord.x) { extremes++; xExtreme = true; } - if(y == minCoord.y) { extremes++; yExtreme = true; } - if(z == minCoord.z) { extremes++; zExtreme = true; } - - if(x == maxCoord.x) { extremes++; xExtreme = true; } - if(y == maxCoord.y) { extremes++; yExtreme = true; } - if(z == maxCoord.z) { extremes++; zExtreme = true; } - - if(extremes >= 3) { - return SUBICON_HOUSING_CORNER; - } - else if(extremes <= 0) { - return SUBICON_NONE; - } - else if(extremes == 1) { - return SUBICON_HOUSING_FACE; - } - else { - ForgeDirection[] dirsToCheck = StaticUtils.neighborsBySide[side]; - ForgeDirection dir; - - Block myBlock = blockAccess.getBlock(x, y, z); - int iconIdx = -1; - - for(int i = 0; i < dirsToCheck.length; i++) { - dir = dirsToCheck[i]; - - Block neighborBlock = blockAccess.getBlock(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ); - // See if we're a turbine part - if(neighborBlock != myBlock && neighborBlock != BigReactors.blockMultiblockGlass - && (BigReactors.blockMultiblockCreativePart != null && neighborBlock != BigReactors.blockMultiblockCreativePart)) { - // One of these things is not like the others... - iconIdx = i; - break; - } - } - - return iconIdx + SUBICON_HOUSING_FRAME_TOP; - } - } - - @Override - public IIcon getIcon(int side, int metadata) { - metadata = Math.max(0, Math.min(metadata, _subBlocks.length-1)); - return _icons[metadata]; - } - - @Override - public TileEntity createNewTileEntity(World world, int metadata) { - if(metadata == METADATA_POWERTAP) { - return new TileEntityTurbinePowerTap(); - } - else if(metadata == METADATA_FLUIDPORT) { - return new TileEntityTurbineFluidPort(); - } - else if(metadata == METADATA_BEARING) { - // Does jack-all different except for store display lists on the client - return new TileEntityTurbineRotorBearing(); - } - else if(metadata == METADATA_COMPUTERPORT) { - return new TileEntityTurbineComputerPort(); - } - else { - return new TileEntityTurbinePartStandard(); - } - } - - @Override - public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock) { - TileEntity te = StaticUtils.TE.getTileEntityUnsafe(world, x, y, z); - - // Signal power taps when their neighbors change, etc. - if(te instanceof INeighborUpdatableEntity) { - ((INeighborUpdatableEntity)te).onNeighborBlockChange(world, x, y, z, neighborBlock); - } - } - - @Override - public void onNeighborChange(IBlockAccess world, int x, int y, int z, int neighborX, int neighborY, int neighborZ) { - TileEntity te = StaticUtils.TE.getTileEntityUnsafe(world, x, y, z); - - // Signal power taps when their neighbors change, etc. - if(te instanceof INeighborUpdatableEntity) { - ((INeighborUpdatableEntity)te).onNeighborTileChange(world, x, y, z, neighborX, neighborY, neighborZ); - } - } - - - @Override - public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int par6, float par7, float par8, float par9) { - if(player.isSneaking()) { - return false; - } - - int metadata = world.getBlockMetadata(x, y, z); - - if(metadata == METADATA_FLUIDPORT && StaticUtils.Inventory.isPlayerHoldingWrench(player)) { - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof TileEntityTurbineFluidPort) { - TileEntityTurbineFluidPort fluidPort = (TileEntityTurbineFluidPort)te; - FluidFlow flow = fluidPort.getFlowDirection(); - fluidPort.setFluidFlowDirection(flow == FluidFlow.In ? FluidFlow.Out : FluidFlow.In, true); - return true; - } - } - - if(world.isRemote) { - return true; - } - - // If the player's hands are empty and they rightclick on a multiblock, they get a - // multiblock-debugging message if the machine is not assembled. - if(player.getCurrentEquippedItem() == null) { - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof IMultiblockPart) { - MultiblockControllerBase controller = ((IMultiblockPart)te).getMultiblockController(); - - if(controller == null) { - player.addChatMessage(new ChatComponentText(String.format("SERIOUS ERROR - server part @ %d, %d, %d has no controller!", x, y, z))); //TODO Localize - } - else { - Exception e = controller.getLastValidationException(); - if(e != null) { - player.addChatMessage(new ChatComponentText(e.getMessage() + " - controller " + Integer.toString(controller.hashCode()))); //Would it be worth it to localize one word? - return true; - } - } - } - } - - // Does this machine even have a GUI? - if(metadata != METADATA_CONTROLLER) { return false; } - - // Check to see if machine is assembled - TileEntity te = world.getTileEntity(x, y, z); - if(!(te instanceof IMultiblockPart)) { - return false; - } - - IMultiblockPart part = (IMultiblockPart)te; - if(!part.isConnected() || !part.getMultiblockController().isAssembled()) { - return false; - } - - player.openGui(BRLoader.instance, 0, world, x, y, z); - return true; - } - - @Override - public boolean isOpaqueCube() - { - return true; - } - - @Override - public boolean renderAsNormalBlock() - { - return true; - } - - @Override - public int damageDropped(int metadata) - { - return metadata; - } - - public ItemStack getItemStack(String name) { - int metadata = -1; - for(int i = 0; i < _subBlocks.length; i++) { - if(_subBlocks[i].equals(name)) { - metadata = i; - break; - } - } - - if(metadata < 0) { - throw new IllegalArgumentException("Unable to find a block with the name " + name); - } - - return new ItemStack(this, 1, metadata); - } - - @Override - public void getSubBlocks(Item par1, CreativeTabs par2CreativeTabs, List par3List) - { - for(int i = 0; i < _subBlocks.length; i++) { - par3List.add(new ItemStack(this, 1, i)); - } - } - - @Override - public void breakBlock(World world, int x, int y, int z, Block block, int meta) - { - // Drop everything inside inventory blocks - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof IInventory) - { - IInventory inventory = ((IInventory)te); -inv: for(int i = 0; i < inventory.getSizeInventory(); i++) - { - ItemStack itemstack = inventory.getStackInSlot(i); - if(itemstack == null) - { - continue; - } - float xOffset = world.rand.nextFloat() * 0.8F + 0.1F; - float yOffset = world.rand.nextFloat() * 0.8F + 0.1F; - float zOffset = world.rand.nextFloat() * 0.8F + 0.1F; - do - { - if(itemstack.stackSize <= 0) - { - continue inv; - } - int amountToDrop = world.rand.nextInt(21) + 10; - if(amountToDrop > itemstack.stackSize) - { - amountToDrop = itemstack.stackSize; - } - itemstack.stackSize -= amountToDrop; - EntityItem entityitem = new EntityItem(world, (float)x + xOffset, (float)y + yOffset, (float)z + zOffset, new ItemStack(itemstack.getItem(), amountToDrop, itemstack.getItemDamage())); - if(itemstack.getTagCompound() != null) - { - entityitem.getEntityItem().setTagCompound(itemstack.getTagCompound()); - } - float motionMultiplier = 0.05F; - entityitem.motionX = (float)world.rand.nextGaussian() * motionMultiplier; - entityitem.motionY = (float)world.rand.nextGaussian() * motionMultiplier + 0.2F; - entityitem.motionZ = (float)world.rand.nextGaussian() * motionMultiplier; - world.spawnEntityInWorld(entityitem); - } while(true); - } - } - - super.breakBlock(world, x, y, z, block, meta); - } - + TileEntity te = blockAccess.getTileEntity(x, y, z); + int metadata = blockAccess.getBlockMetadata(x, y, z); + + if (te instanceof TileEntityTurbinePartBase) { + TileEntityTurbinePartBase part = (TileEntityTurbinePartBase) te; + MultiblockTurbine turbine = part.getTurbine(); + + if (metadata == METADATA_FLUIDPORT) { + if (te instanceof TileEntityTurbineFluidPort) { + if (turbine == null || !turbine.isAssembled() + || part.getOutwardsDir() + .ordinal() == side) { + if (((TileEntityTurbineFluidPort) te).getFlowDirection() == FluidFlow.Out) + return _subIcons[SUBICON_FLUIDPORT_OUTPUT]; + else return _icons[METADATA_FLUIDPORT]; + } else if (turbine.isAssembled() && part.getOutwardsDir() + .ordinal() != side) return _subIcons[SUBICON_HOUSING_FACE]; + } + return getIcon(side, metadata); + } else if (!part.isConnected() || turbine == null || !turbine.isAssembled()) { + return getIcon(side, metadata); + } else { + int subIcon = SUBICON_NONE; + if (metadata == METADATA_HOUSING) { + subIcon = getSubIconForHousing(blockAccess, x, y, z, turbine, side); + } else if (part.getOutwardsDir() + .ordinal() == side) { + // Only put the fancy icon on one side of the machine. Other parts will use the base. + if (metadata == METADATA_CONTROLLER) { + if (turbine.getActive()) { + subIcon = SUBICON_CONTROLLER_ACTIVE; + } else { + subIcon = SUBICON_CONTROLLER_IDLE; + } + } else if (metadata == METADATA_POWERTAP) { + if (te instanceof TileEntityTurbinePowerTap + && ((TileEntityTurbinePowerTap) te).isAttachedToPowerNetwork()) { + subIcon = SUBICON_POWERTAP_ACTIVE; + } + } + } else { + // Assembled non-housing parts use the face texture so it's all smooth on the inside + subIcon = SUBICON_HOUSING_FACE; + } + + if (subIcon == SUBICON_NONE) { + return getIcon(side, metadata); + } else { + return _subIcons[subIcon]; + } + } + } + + // Not a "proper" TE, so just pass through + return getIcon(side, metadata); + } + + private int getSubIconForHousing(IBlockAccess blockAccess, int x, int y, int z, MultiblockTurbine turbine, + int side) { + CoordTriplet minCoord, maxCoord; + minCoord = turbine.getMinimumCoord(); + maxCoord = turbine.getMaximumCoord(); + + if (minCoord == null || maxCoord == null) { + return SUBICON_NONE; + } + + int extremes = 0; + boolean xExtreme, yExtreme, zExtreme; + xExtreme = yExtreme = zExtreme = false; + + if (x == minCoord.x) { + extremes++; + xExtreme = true; + } + if (y == minCoord.y) { + extremes++; + yExtreme = true; + } + if (z == minCoord.z) { + extremes++; + zExtreme = true; + } + + if (x == maxCoord.x) { + extremes++; + xExtreme = true; + } + if (y == maxCoord.y) { + extremes++; + yExtreme = true; + } + if (z == maxCoord.z) { + extremes++; + zExtreme = true; + } + + if (extremes >= 3) { + return SUBICON_HOUSING_CORNER; + } else if (extremes <= 0) { + return SUBICON_NONE; + } else if (extremes == 1) { + return SUBICON_HOUSING_FACE; + } else { + ForgeDirection[] dirsToCheck = StaticUtils.neighborsBySide[side]; + ForgeDirection dir; + + Block myBlock = blockAccess.getBlock(x, y, z); + int iconIdx = -1; + + for (int i = 0; i < dirsToCheck.length; i++) { + dir = dirsToCheck[i]; + + Block neighborBlock = blockAccess.getBlock(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ); + // See if we're a turbine part + if (neighborBlock != myBlock && neighborBlock != BigReactors.blockMultiblockGlass + && (BigReactors.blockMultiblockCreativePart != null + && neighborBlock != BigReactors.blockMultiblockCreativePart)) { + // One of these things is not like the others... + iconIdx = i; + break; + } + } + + return iconIdx + SUBICON_HOUSING_FRAME_TOP; + } + } + + @Override + public IIcon getIcon(int side, int metadata) { + metadata = Math.max(0, Math.min(metadata, _subBlocks.length - 1)); + return _icons[metadata]; + } + + @Override + public TileEntity createNewTileEntity(World world, int metadata) { + if (metadata == METADATA_POWERTAP) { + return new TileEntityTurbinePowerTap(); + } else if (metadata == METADATA_FLUIDPORT) { + return new TileEntityTurbineFluidPort(); + } else if (metadata == METADATA_BEARING) { + // Does jack-all different except for store display lists on the client + return new TileEntityTurbineRotorBearing(); + } else if (metadata == METADATA_COMPUTERPORT) { + return new TileEntityTurbineComputerPort(); + } else { + return new TileEntityTurbinePartStandard(); + } + } + + @Override + public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock) { + TileEntity te = StaticUtils.TE.getTileEntityUnsafe(world, x, y, z); + + // Signal power taps when their neighbors change, etc. + if (te instanceof INeighborUpdatableEntity) { + ((INeighborUpdatableEntity) te).onNeighborBlockChange(world, x, y, z, neighborBlock); + } + } + + @Override + public void onNeighborChange(IBlockAccess world, int x, int y, int z, int neighborX, int neighborY, int neighborZ) { + TileEntity te = StaticUtils.TE.getTileEntityUnsafe(world, x, y, z); + + // Signal power taps when their neighbors change, etc. + if (te instanceof INeighborUpdatableEntity) { + ((INeighborUpdatableEntity) te).onNeighborTileChange(world, x, y, z, neighborX, neighborY, neighborZ); + } + } + + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int par6, float par7, + float par8, float par9) { + if (player.isSneaking()) { + return false; + } + + int metadata = world.getBlockMetadata(x, y, z); + + if (metadata == METADATA_FLUIDPORT && StaticUtils.Inventory.isPlayerHoldingWrench(player)) { + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof TileEntityTurbineFluidPort) { + TileEntityTurbineFluidPort fluidPort = (TileEntityTurbineFluidPort) te; + FluidFlow flow = fluidPort.getFlowDirection(); + fluidPort.setFluidFlowDirection(flow == FluidFlow.In ? FluidFlow.Out : FluidFlow.In, true); + return true; + } + } + + if (world.isRemote) { + return true; + } + + // If the player's hands are empty and they rightclick on a multiblock, they get a + // multiblock-debugging message if the machine is not assembled. + if (player.getCurrentEquippedItem() == null) { + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof IMultiblockPart) { + MultiblockControllerBase controller = ((IMultiblockPart) te).getMultiblockController(); + + if (controller == null) { + player.addChatMessage( + new ChatComponentText( + String.format("SERIOUS ERROR - server part @ %d, %d, %d has no controller!", x, y, z))); // TODO + // Localize + } else { + Exception e = controller.getLastValidationException(); + if (e != null) { + player.addChatMessage( + new ChatComponentText( + e.getMessage() + " - controller " + Integer.toString(controller.hashCode()))); // Would + // it be + // worth + // it to + // localize + // one + // word? + return true; + } + } + } + } + + // Does this machine even have a GUI? + if (metadata != METADATA_CONTROLLER) { + return false; + } + + // Check to see if machine is assembled + TileEntity te = world.getTileEntity(x, y, z); + if (!(te instanceof IMultiblockPart)) { + return false; + } + + IMultiblockPart part = (IMultiblockPart) te; + if (!part.isConnected() || !part.getMultiblockController() + .isAssembled()) { + return false; + } + + player.openGui(BRLoader.instance, 0, world, x, y, z); + return true; + } + + @Override + public boolean isOpaqueCube() { + return true; + } + + @Override + public boolean renderAsNormalBlock() { + return true; + } + + @Override + public int damageDropped(int metadata) { + return metadata; + } + + public ItemStack getItemStack(String name) { + int metadata = -1; + for (int i = 0; i < _subBlocks.length; i++) { + if (_subBlocks[i].equals(name)) { + metadata = i; + break; + } + } + + if (metadata < 0) { + throw new IllegalArgumentException("Unable to find a block with the name " + name); + } + + return new ItemStack(this, 1, metadata); + } + + @Override + public void getSubBlocks(Item par1, CreativeTabs par2CreativeTabs, List par3List) { + for (int i = 0; i < _subBlocks.length; i++) { + par3List.add(new ItemStack(this, 1, i)); + } + } + + @Override + public void breakBlock(World world, int x, int y, int z, Block block, int meta) { + // Drop everything inside inventory blocks + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof IInventory) { + IInventory inventory = ((IInventory) te); + inv: for (int i = 0; i < inventory.getSizeInventory(); i++) { + ItemStack itemstack = inventory.getStackInSlot(i); + if (itemstack == null) { + continue; + } + float xOffset = world.rand.nextFloat() * 0.8F + 0.1F; + float yOffset = world.rand.nextFloat() * 0.8F + 0.1F; + float zOffset = world.rand.nextFloat() * 0.8F + 0.1F; + do { + if (itemstack.stackSize <= 0) { + continue inv; + } + int amountToDrop = world.rand.nextInt(21) + 10; + if (amountToDrop > itemstack.stackSize) { + amountToDrop = itemstack.stackSize; + } + itemstack.stackSize -= amountToDrop; + EntityItem entityitem = new EntityItem( + world, + (float) x + xOffset, + (float) y + yOffset, + (float) z + zOffset, + new ItemStack(itemstack.getItem(), amountToDrop, itemstack.getItemDamage())); + if (itemstack.getTagCompound() != null) { + entityitem.getEntityItem() + .setTagCompound(itemstack.getTagCompound()); + } + float motionMultiplier = 0.05F; + entityitem.motionX = (float) world.rand.nextGaussian() * motionMultiplier; + entityitem.motionY = (float) world.rand.nextGaussian() * motionMultiplier + 0.2F; + entityitem.motionZ = (float) world.rand.nextGaussian() * motionMultiplier; + world.spawnEntityInWorld(entityitem); + } while (true); + } + } + + super.breakBlock(world, x, y, z, block, meta); + } + /** * A randomly called display update to be able to add particles or other items for display */ @SideOnly(Side.CLIENT) - public void randomDisplayTick(World world, int x, int y, int z, Random par5Random) - { - int metadata = world.getBlockMetadata(x, y, z); - if(metadata == METADATA_BEARING) { - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof TileEntityTurbinePartStandard) { - // Rotor bearing found! - TileEntityTurbinePartStandard bearing = (TileEntityTurbinePartStandard)te; - MultiblockTurbine turbine = bearing.getTurbine(); - if(turbine != null && turbine.getActive()) { - // Spawn particles! - int numParticles = Math.min(20, Math.max(1, turbine.getFluidConsumedLastTick() / 40)); - ForgeDirection inwardsDir = bearing.getOutwardsDir().getOpposite(); - CoordTriplet minCoord, maxCoord; - minCoord = turbine.getMinimumCoord(); - maxCoord = turbine.getMaximumCoord(); - minCoord.x++; minCoord.y++; minCoord.z++; - maxCoord.x--; maxCoord.y--; maxCoord.z--; - if(inwardsDir.offsetX != 0) { - minCoord.x = maxCoord.x = bearing.xCoord + inwardsDir.offsetX; - } - else if(inwardsDir.offsetY != 0) { - minCoord.y = maxCoord.y = bearing.yCoord + inwardsDir.offsetY; - } - else { - minCoord.z = maxCoord.z = bearing.zCoord + inwardsDir.offsetZ; - } - + public void randomDisplayTick(World world, int x, int y, int z, Random par5Random) { + int metadata = world.getBlockMetadata(x, y, z); + if (metadata == METADATA_BEARING) { + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof TileEntityTurbinePartStandard) { + // Rotor bearing found! + TileEntityTurbinePartStandard bearing = (TileEntityTurbinePartStandard) te; + MultiblockTurbine turbine = bearing.getTurbine(); + if (turbine != null && turbine.getActive()) { + // Spawn particles! + int numParticles = Math.min(20, Math.max(1, turbine.getFluidConsumedLastTick() / 40)); + ForgeDirection inwardsDir = bearing.getOutwardsDir() + .getOpposite(); + CoordTriplet minCoord, maxCoord; + minCoord = turbine.getMinimumCoord(); + maxCoord = turbine.getMaximumCoord(); + minCoord.x++; + minCoord.y++; + minCoord.z++; + maxCoord.x--; + maxCoord.y--; + maxCoord.z--; + if (inwardsDir.offsetX != 0) { + minCoord.x = maxCoord.x = bearing.xCoord + inwardsDir.offsetX; + } else if (inwardsDir.offsetY != 0) { + minCoord.y = maxCoord.y = bearing.yCoord + inwardsDir.offsetY; + } else { + minCoord.z = maxCoord.z = bearing.zCoord + inwardsDir.offsetZ; + } + double particleX, particleY, particleZ; - for(int i = 0; i < numParticles; i++) { - particleX = minCoord.x + par5Random.nextFloat() * (maxCoord.x - minCoord.x + 1); - particleY = minCoord.y + par5Random.nextFloat() * (maxCoord.y - minCoord.y + 1); - particleZ = minCoord.z + par5Random.nextFloat() * (maxCoord.z - minCoord.z + 1); - world.spawnParticle(BigReactors.isValentinesDay ? "heart" : "cloud", particleX, particleY, particleZ, - par5Random.nextFloat() * inwardsDir.offsetX, - par5Random.nextFloat() * inwardsDir.offsetY, - par5Random.nextFloat() * inwardsDir.offsetZ); - } - } - } - } + for (int i = 0; i < numParticles; i++) { + particleX = minCoord.x + par5Random.nextFloat() * (maxCoord.x - minCoord.x + 1); + particleY = minCoord.y + par5Random.nextFloat() * (maxCoord.y - minCoord.y + 1); + particleZ = minCoord.z + par5Random.nextFloat() * (maxCoord.z - minCoord.z + 1); + world.spawnParticle( + BigReactors.isValentinesDay ? "heart" : "cloud", + particleX, + particleY, + particleZ, + par5Random.nextFloat() * inwardsDir.offsetX, + par5Random.nextFloat() * inwardsDir.offsetY, + par5Random.nextFloat() * inwardsDir.offsetZ); + } + } + } + } } - + @Override - public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int x, int y, int z) - { - int metadata = world.getBlockMetadata(x, y, z); - if(metadata == METADATA_BEARING) { - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof TileEntityTurbineRotorBearing) { - TileEntityTurbineRotorBearing bearing = (TileEntityTurbineRotorBearing)te; - if(bearing.isConnected() && bearing.getTurbine().getActive()) { - return bearing.getAABB(); - } - } - } - - return super.getCollisionBoundingBoxFromPool(world, x, y, z); + public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int x, int y, int z) { + int metadata = world.getBlockMetadata(x, y, z); + if (metadata == METADATA_BEARING) { + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof TileEntityTurbineRotorBearing) { + TileEntityTurbineRotorBearing bearing = (TileEntityTurbineRotorBearing) te; + if (bearing.isConnected() && bearing.getTurbine() + .getActive()) { + return bearing.getAABB(); + } + } + } + + return super.getCollisionBoundingBoxFromPool(world, x, y, z); } - @Override - public boolean canCreatureSpawn(EnumCreatureType type, IBlockAccess world, int x, int y, int z) - { - return false; + @Override + public boolean canCreatureSpawn(EnumCreatureType type, IBlockAccess world, int x, int y, int z) { + return false; } // IPeripheralProvider - @Optional.Method(modid = "ComputerCraft") - @Override - public IPeripheral getPeripheral(World world, int x, int y, int z, int side) { - TileEntity te = world.getTileEntity(x, y, z); - - if(te instanceof TileEntityTurbineComputerPort) - return (IPeripheral)te; - - return null; - } - + @Optional.Method(modid = "ComputerCraft") + @Override + public IPeripheral getPeripheral(World world, int x, int y, int z, int side) { + TileEntity te = world.getTileEntity(x, y, z); + + if (te instanceof TileEntityTurbineComputerPort) return (IPeripheral) te; + + return null; + } + } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockTurbineRotorPart.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockTurbineRotorPart.java index 17a517d1..7850f48a 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockTurbineRotorPart.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/block/BlockTurbineRotorPart.java @@ -14,6 +14,7 @@ import net.minecraft.util.IIcon; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import erogenousbeef.bigreactors.common.BigReactors; @@ -21,125 +22,118 @@ public class BlockTurbineRotorPart extends BlockContainer { - public static final int METADATA_SHAFT = 0; - public static final int METADATA_BLADE = 1; - public static int renderId; - - private static final String[] _subBlocks = new String[] { "rotor", - "blade", - }; - - private IIcon[] _icons = new IIcon[_subBlocks.length]; - private IIcon[] _subIcons = new IIcon[1]; - - public BlockTurbineRotorPart(Material material) { - super(material); - - setStepSound(soundTypeMetal); - setLightLevel(0.9f); - setHardness(2.0f); - setBlockName("blockTurbineRotorPart"); - this.setBlockTextureName(BigReactors.TEXTURE_NAME_PREFIX + "blockTurbineRotorPart"); - setCreativeTab(BigReactors.TAB); - } - - - @Override - public int getRenderType() { - return renderId; - } - - @Override - @SideOnly(Side.CLIENT) - public void registerBlockIcons(IIconRegister par1IconRegister) - { - // Base icons - for(int i = 0; i < _subBlocks.length; ++i) { - _icons[i] = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + "." + _subBlocks[i]); - } - - _subIcons[0] = par1IconRegister.registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + ".rotor.connector"); - } - - @Override - public IIcon getIcon(int side, int metadata) { - return _icons[metadata]; - } - - public IIcon getRotorConnectorIcon() { - return _subIcons[0]; - } - - @Override - public TileEntity createNewTileEntity(World world, int metadata) { - return new TileEntityTurbineRotorPart(); - } - - @Override - public boolean isOpaqueCube() - { - return false; - } - - @Override - public boolean renderAsNormalBlock() - { - return false; - } - - @Override - public int damageDropped(int metadata) - { - return metadata; - } - - public ItemStack getItemStack(String name) { - int metadata = -1; - for(int i = 0; i < _subBlocks.length; i++) { - if(_subBlocks[i].equals(name)) { - metadata = i; - break; - } - } - - if(metadata < 0) { - throw new IllegalArgumentException("Unable to find a block with the name " + name); - } - - return new ItemStack(this, 1, metadata); - } - - @Override - public void getSubBlocks(Item par1, CreativeTabs par2CreativeTabs, List par3List) - { - for(int i = 0; i < _subBlocks.length; i++) { - par3List.add(new ItemStack(this, 1, i)); - } - } - - public int getRotorMass(Block block, int metadata) { - if(this == block) { - switch(metadata) { - // TODO: add masses when you add non-standard turbine parts - default: - return 10; - } - } - - return 0; - } - - public static boolean isRotorBlade(int metadata) { - return metadata == METADATA_BLADE; - } - - public static boolean isRotorShaft(int metadata) { - return metadata == METADATA_SHAFT; - } - - @Override - public boolean canCreatureSpawn(EnumCreatureType type, IBlockAccess world, int x, int y, int z) - { - return false; + public static final int METADATA_SHAFT = 0; + public static final int METADATA_BLADE = 1; + public static int renderId; + + private static final String[] _subBlocks = new String[] { "rotor", "blade", }; + + private IIcon[] _icons = new IIcon[_subBlocks.length]; + private IIcon[] _subIcons = new IIcon[1]; + + public BlockTurbineRotorPart(Material material) { + super(material); + + setStepSound(soundTypeMetal); + setLightLevel(0.9f); + setHardness(2.0f); + setBlockName("blockTurbineRotorPart"); + this.setBlockTextureName(BigReactors.TEXTURE_NAME_PREFIX + "blockTurbineRotorPart"); + setCreativeTab(BigReactors.TAB); + } + + @Override + public int getRenderType() { + return renderId; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerBlockIcons(IIconRegister par1IconRegister) { + // Base icons + for (int i = 0; i < _subBlocks.length; ++i) { + _icons[i] = par1IconRegister + .registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + "." + _subBlocks[i]); + } + + _subIcons[0] = par1IconRegister + .registerIcon(BigReactors.TEXTURE_NAME_PREFIX + getUnlocalizedName() + ".rotor.connector"); + } + + @Override + public IIcon getIcon(int side, int metadata) { + return _icons[metadata]; + } + + public IIcon getRotorConnectorIcon() { + return _subIcons[0]; + } + + @Override + public TileEntity createNewTileEntity(World world, int metadata) { + return new TileEntityTurbineRotorPart(); + } + + @Override + public boolean isOpaqueCube() { + return false; + } + + @Override + public boolean renderAsNormalBlock() { + return false; + } + + @Override + public int damageDropped(int metadata) { + return metadata; + } + + public ItemStack getItemStack(String name) { + int metadata = -1; + for (int i = 0; i < _subBlocks.length; i++) { + if (_subBlocks[i].equals(name)) { + metadata = i; + break; + } + } + + if (metadata < 0) { + throw new IllegalArgumentException("Unable to find a block with the name " + name); + } + + return new ItemStack(this, 1, metadata); + } + + @Override + public void getSubBlocks(Item par1, CreativeTabs par2CreativeTabs, List par3List) { + for (int i = 0; i < _subBlocks.length; i++) { + par3List.add(new ItemStack(this, 1, i)); + } + } + + public int getRotorMass(Block block, int metadata) { + if (this == block) { + switch (metadata) { + // TODO: add masses when you add non-standard turbine parts + default: + return 10; + } + } + + return 0; + } + + public static boolean isRotorBlade(int metadata) { + return metadata == METADATA_BLADE; + } + + public static boolean isRotorShaft(int metadata) { + return metadata == METADATA_SHAFT; + } + + @Override + public boolean canCreatureSpawn(EnumCreatureType type, IBlockAccess world, int x, int y, int z) { + return false; } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/CoolantContainer.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/CoolantContainer.java index 3c67033c..caf41b34 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/CoolantContainer.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/CoolantContainer.java @@ -4,194 +4,212 @@ import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; + import erogenousbeef.bigreactors.common.BRLog; import erogenousbeef.bigreactors.common.BigReactors; public class CoolantContainer extends FluidHelper { - public static final int HOT = 0; - public static final int COLD = 1; - - private static final String[] tankNames = { "hot", "cold" }; - - private int fluidVaporizedLastTick; - - public CoolantContainer() { - super(true); - fluidVaporizedLastTick = 0; - } - - @Override - public int getNumberOfFluidTanks() { - return 2; - } - - @Override - protected String[] getNBTTankNames() { - return tankNames; - } - - public boolean isAcceptedCoolant(Fluid fluid) { - if(fluid == null) { return false; } - - // TODO: Lookup - return fluid.getID() == FluidRegistry.WATER.getID(); - } - - public int addCoolant(FluidStack incoming) { - if(incoming == null) { return 0; } - return fill(COLD, incoming, true); - } - - public int drainCoolant(int amount) { - return drainFluidFromStack(COLD, amount); - } - - public Fluid getCoolantType() { - return getFluidType(COLD); - } - - public int getCoolantAmount() { - return getFluidAmount(COLD); - } - - public Fluid getVaporType() { - return getFluidType(HOT); - } - - public int getVaporAmount() { - return getFluidAmount(HOT); - } - - public NBTTagCompound writeToNBT(NBTTagCompound destination) { - super.writeToNBT(destination); - - return destination; - } - - public void readFromNBT(NBTTagCompound data) { - super.readFromNBT(data); - } - - public void emptyCoolant() { - setFluid(COLD, null); - } - - public void emptyVapor() { - setFluid(HOT, null); - } - - public void setCoolant(FluidStack newFuel) { - setFluid(COLD, newFuel); - } - - public void setVapor(FluidStack newWaste) { - setFluid(HOT, newWaste); - } - - public void merge(CoolantContainer other) { - super.merge(other); - } - - public float getCoolantTemperature(float reactorTemperature) { - Fluid coolantType = getCoolantType(); - if(coolantType == null || getFluidAmount(COLD) <= 0) { return reactorTemperature; } - - return Math.min(reactorTemperature, getBoilingPoint(coolantType)); - } - - /** - * Attempt to transfer some heat (in RF) into the coolant system. - * This method assumes you've already checked the coolant temperature, above, - * and scaled the energy absorbed into the coolant based on surface area. - * - * @param rfAbsorbed RF to transfer into the coolant system. - * @return RF remaining after absorption. - */ - public float onAbsorbHeat(float rfAbsorbed) { - if(getFluidAmount(COLD) <= 0 || rfAbsorbed <= 0) { return rfAbsorbed; } - - Fluid coolantType = getCoolantType(); - int coolantAmt = getFluidAmount(COLD); - - float heatOfVaporization = getHeatOfVaporization(coolantType); - - int mbVaporized = Math.min(coolantAmt, (int)(rfAbsorbed / heatOfVaporization)); - - // Cap by the available space in the vapor chamber - mbVaporized = Math.min(mbVaporized, getRemainingSpaceForFluid(HOT)); - - // We don't do partial vaporization. Just return all the heat. - if(mbVaporized < 1) { return rfAbsorbed; } - - // Make sure we either have an empty vapor chamber or the vapor types match - Fluid newVaporType = getVaporizedCoolantFluid(coolantType); - if(newVaporType == null) { - BRLog.warning("Coolant in tank (%s) has no registered vapor type!", coolantType.getName()); - return rfAbsorbed; - } - - Fluid existingVaporType = getVaporType(); - if(existingVaporType != null && !newVaporType.getName().equals(existingVaporType.getName())) { - // Can't vaporize anything with incompatible vapor in the vapor tank - return rfAbsorbed; - } - - // Vaporize! -- POINT OF NO RETURN - fluidVaporizedLastTick = mbVaporized; - this.drainCoolant(mbVaporized); - - if(existingVaporType != null) { - addFluidToStack(HOT, mbVaporized); - } - else { - fill(HOT, new FluidStack(newVaporType, mbVaporized), true); - } - - // Calculate how much we actually absorbed via vaporization - float energyConsumed = (float)mbVaporized * heatOfVaporization; - - // And return energy remaining after absorption - return Math.max(0f, rfAbsorbed - energyConsumed); - } - - private float getBoilingPoint(Fluid fluid) { - if(fluid == null) { throw new IllegalArgumentException("Cannot pass a null fluid to getBoilingPoint"); } // just in case - - // TODO: Lookup - return 100f; - } - - /** - * Returns the amount of heat (in RF) needed to convert 1mB of liquid into 1mB of vapor. - * @return - */ - private float getHeatOfVaporization(Fluid fluid) { - if(fluid == null) { throw new IllegalArgumentException("Cannot pass a null fluid to getHeatOfVaporization"); } // just in case - - // TODO: Make a registry for this, do a lookup - return 4f; // TE converts 1mB steam into 2 RF of work in a steam turbine, so we assume it's 50% efficient. - } - - private Fluid getVaporizedCoolantFluid(Fluid fluid) { - if(fluid == null) { throw new IllegalArgumentException("Cannot pass a null fluid to getVaporizedCoolantFluid"); } // just in case - - return BigReactors.fluidSteam; - } - - @Override - protected boolean isFluidValidForStack(int stackIdx, Fluid fluid) { - switch(stackIdx) { - case COLD: - return isAcceptedCoolant(fluid); - case HOT: - return true; - default: - return false; - } - } - - public int getFluidVaporizedLastTick() { - return fluidVaporizedLastTick; - } + public static final int HOT = 0; + public static final int COLD = 1; + + private static final String[] tankNames = { "hot", "cold" }; + + private int fluidVaporizedLastTick; + + public CoolantContainer() { + super(true); + fluidVaporizedLastTick = 0; + } + + @Override + public int getNumberOfFluidTanks() { + return 2; + } + + @Override + protected String[] getNBTTankNames() { + return tankNames; + } + + public boolean isAcceptedCoolant(Fluid fluid) { + if (fluid == null) { + return false; + } + + // TODO: Lookup + return fluid.getID() == FluidRegistry.WATER.getID(); + } + + public int addCoolant(FluidStack incoming) { + if (incoming == null) { + return 0; + } + return fill(COLD, incoming, true); + } + + public int drainCoolant(int amount) { + return drainFluidFromStack(COLD, amount); + } + + public Fluid getCoolantType() { + return getFluidType(COLD); + } + + public int getCoolantAmount() { + return getFluidAmount(COLD); + } + + public Fluid getVaporType() { + return getFluidType(HOT); + } + + public int getVaporAmount() { + return getFluidAmount(HOT); + } + + public NBTTagCompound writeToNBT(NBTTagCompound destination) { + super.writeToNBT(destination); + + return destination; + } + + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + } + + public void emptyCoolant() { + setFluid(COLD, null); + } + + public void emptyVapor() { + setFluid(HOT, null); + } + + public void setCoolant(FluidStack newFuel) { + setFluid(COLD, newFuel); + } + + public void setVapor(FluidStack newWaste) { + setFluid(HOT, newWaste); + } + + public void merge(CoolantContainer other) { + super.merge(other); + } + + public float getCoolantTemperature(float reactorTemperature) { + Fluid coolantType = getCoolantType(); + if (coolantType == null || getFluidAmount(COLD) <= 0) { + return reactorTemperature; + } + + return Math.min(reactorTemperature, getBoilingPoint(coolantType)); + } + + /** + * Attempt to transfer some heat (in RF) into the coolant system. + * This method assumes you've already checked the coolant temperature, above, + * and scaled the energy absorbed into the coolant based on surface area. + * + * @param rfAbsorbed RF to transfer into the coolant system. + * @return RF remaining after absorption. + */ + public float onAbsorbHeat(float rfAbsorbed) { + if (getFluidAmount(COLD) <= 0 || rfAbsorbed <= 0) { + return rfAbsorbed; + } + + Fluid coolantType = getCoolantType(); + int coolantAmt = getFluidAmount(COLD); + + float heatOfVaporization = getHeatOfVaporization(coolantType); + + int mbVaporized = Math.min(coolantAmt, (int) (rfAbsorbed / heatOfVaporization)); + + // Cap by the available space in the vapor chamber + mbVaporized = Math.min(mbVaporized, getRemainingSpaceForFluid(HOT)); + + // We don't do partial vaporization. Just return all the heat. + if (mbVaporized < 1) { + return rfAbsorbed; + } + + // Make sure we either have an empty vapor chamber or the vapor types match + Fluid newVaporType = getVaporizedCoolantFluid(coolantType); + if (newVaporType == null) { + BRLog.warning("Coolant in tank (%s) has no registered vapor type!", coolantType.getName()); + return rfAbsorbed; + } + + Fluid existingVaporType = getVaporType(); + if (existingVaporType != null && !newVaporType.getName() + .equals(existingVaporType.getName())) { + // Can't vaporize anything with incompatible vapor in the vapor tank + return rfAbsorbed; + } + + // Vaporize! -- POINT OF NO RETURN + fluidVaporizedLastTick = mbVaporized; + this.drainCoolant(mbVaporized); + + if (existingVaporType != null) { + addFluidToStack(HOT, mbVaporized); + } else { + fill(HOT, new FluidStack(newVaporType, mbVaporized), true); + } + + // Calculate how much we actually absorbed via vaporization + float energyConsumed = (float) mbVaporized * heatOfVaporization; + + // And return energy remaining after absorption + return Math.max(0f, rfAbsorbed - energyConsumed); + } + + private float getBoilingPoint(Fluid fluid) { + if (fluid == null) { + throw new IllegalArgumentException("Cannot pass a null fluid to getBoilingPoint"); + } // just in case + + // TODO: Lookup + return 100f; + } + + /** + * Returns the amount of heat (in RF) needed to convert 1mB of liquid into 1mB of vapor. + * + * @return + */ + private float getHeatOfVaporization(Fluid fluid) { + if (fluid == null) { + throw new IllegalArgumentException("Cannot pass a null fluid to getHeatOfVaporization"); + } // just in case + + // TODO: Make a registry for this, do a lookup + return 4f; // TE converts 1mB steam into 2 RF of work in a steam turbine, so we assume it's 50% efficient. + } + + private Fluid getVaporizedCoolantFluid(Fluid fluid) { + if (fluid == null) { + throw new IllegalArgumentException("Cannot pass a null fluid to getVaporizedCoolantFluid"); + } // just in case + + return BigReactors.fluidSteam; + } + + @Override + protected boolean isFluidValidForStack(int stackIdx, Fluid fluid) { + switch (stackIdx) { + case COLD: + return isAcceptedCoolant(fluid); + case HOT: + return true; + default: + return false; + } + } + + public int getFluidVaporizedLastTick() { + return fluidVaporizedLastTick; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/FloatUpdateTracker.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/FloatUpdateTracker.java index eac36bf9..ae5cdf6d 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/FloatUpdateTracker.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/FloatUpdateTracker.java @@ -2,55 +2,57 @@ public class FloatUpdateTracker { - int ticksSinceLastUpdate; - int ticksBetweenUpdates; - int ticksBetweenUrgentUpdates; - float value; - float minimumDifference; - float maximumDifference; - - public FloatUpdateTracker(int minimumTicksBetweenUpdates, int minimumTicksBetweenUrgentUpdates, float minimumSpreadForUpdate, float maximumSpreadForUpdate) { - ticksSinceLastUpdate = 0; - value = 0f; - ticksBetweenUpdates = minimumTicksBetweenUpdates; - ticksBetweenUrgentUpdates = Math.min(ticksBetweenUpdates, minimumTicksBetweenUrgentUpdates); - minimumDifference = minimumSpreadForUpdate; - maximumDifference = Math.max(minimumDifference, maximumSpreadForUpdate); - } - - public void setValue(float v) { - value = v; - ticksSinceLastUpdate = 0; - } - - public void onExternalUpdate() { ticksSinceLastUpdate = 0; } - - public boolean shouldUpdate(float currentValue) { - ticksSinceLastUpdate++; - - if(ticksSinceLastUpdate < ticksBetweenUrgentUpdates) { - return false; - } - - float spread = Math.abs(currentValue - value); - if(spread >= maximumDifference) { - ticksSinceLastUpdate = 0; - value = currentValue; - return true; - } - - if(ticksSinceLastUpdate < ticksBetweenUpdates) { - return false; - } - - if(spread >= minimumDifference) { - ticksSinceLastUpdate = 0; - value = currentValue; - return true; - } - else { - ticksSinceLastUpdate = ticksBetweenUpdates; - return false; - } - } + int ticksSinceLastUpdate; + int ticksBetweenUpdates; + int ticksBetweenUrgentUpdates; + float value; + float minimumDifference; + float maximumDifference; + + public FloatUpdateTracker(int minimumTicksBetweenUpdates, int minimumTicksBetweenUrgentUpdates, + float minimumSpreadForUpdate, float maximumSpreadForUpdate) { + ticksSinceLastUpdate = 0; + value = 0f; + ticksBetweenUpdates = minimumTicksBetweenUpdates; + ticksBetweenUrgentUpdates = Math.min(ticksBetweenUpdates, minimumTicksBetweenUrgentUpdates); + minimumDifference = minimumSpreadForUpdate; + maximumDifference = Math.max(minimumDifference, maximumSpreadForUpdate); + } + + public void setValue(float v) { + value = v; + ticksSinceLastUpdate = 0; + } + + public void onExternalUpdate() { + ticksSinceLastUpdate = 0; + } + + public boolean shouldUpdate(float currentValue) { + ticksSinceLastUpdate++; + + if (ticksSinceLastUpdate < ticksBetweenUrgentUpdates) { + return false; + } + + float spread = Math.abs(currentValue - value); + if (spread >= maximumDifference) { + ticksSinceLastUpdate = 0; + value = currentValue; + return true; + } + + if (ticksSinceLastUpdate < ticksBetweenUpdates) { + return false; + } + + if (spread >= minimumDifference) { + ticksSinceLastUpdate = 0; + value = currentValue; + return true; + } else { + ticksSinceLastUpdate = ticksBetweenUpdates; + return false; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/FluidHelper.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/FluidHelper.java index 460e802f..f583dca7 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/FluidHelper.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/FluidHelper.java @@ -4,383 +4,433 @@ import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTankInfo; + import erogenousbeef.bigreactors.common.multiblock.interfaces.IConditionalUpdater; public abstract class FluidHelper implements IConditionalUpdater { - private FluidStack[] fluids; - private int capacity; - - private int ticksSinceLastUpdate; - private static final int minimumTicksBetweenUpdates = 60; - private static final int minimumDevianceForUpdate = 50; // at least 50mB difference before we send a fueling update to the client - - int[] fluidLevelAtLastUpdate; - - private static final int FORCE_UPDATE = -1000; - private int numberOfFluids; - - private boolean separateChambers; - - /** - * @param separate True if capacity is applied to each fluid separately, false if they should be treated like a single tank with multiple fluids inside. - */ - public FluidHelper(boolean separate) { - numberOfFluids = getNumberOfFluidTanks(); - - fluids = new FluidStack[numberOfFluids]; - fluidLevelAtLastUpdate = new int[numberOfFluids]; - - for(int i = 0; i < numberOfFluids; i++) { - fluids[i] = null; - fluidLevelAtLastUpdate[i] = FORCE_UPDATE; - } - - capacity = 0; - separateChambers = separate; - } - - public abstract int getNumberOfFluidTanks(); - protected abstract String[] getNBTTankNames(); - - // Implementation: IConditionalUpdater - public boolean shouldUpdate() { - ticksSinceLastUpdate++; - if(minimumTicksBetweenUpdates < ticksSinceLastUpdate) { - int dev = 0; - boolean shouldUpdate = false; - for(int i = 0; i < numberOfFluids && !shouldUpdate; i++) { - - if(fluids[i] == null && fluidLevelAtLastUpdate[i] > 0) { - shouldUpdate = true; - } - else if(fluids[i] != null) { - if(fluidLevelAtLastUpdate[i] == FORCE_UPDATE) { - shouldUpdate = true; - } - else { - dev += Math.abs(fluids[i].amount - fluidLevelAtLastUpdate[i]); - } - } - // else, both levels are zero, no-op - - if(dev >= minimumDevianceForUpdate) { - shouldUpdate = true; - } - } - - if(shouldUpdate) { - resetLastSeenFluidLevels(); - } - - ticksSinceLastUpdate = 0; - return shouldUpdate; - } - - return false; - } - - public int getCapacity() { return capacity; } - - public void setCapacity(int newCapacity) { - int oldCapacity = capacity; - capacity = newCapacity; - - clampContentsToCapacity(); - } - - protected void merge(FluidHelper other) { - if(other.capacity > capacity) { - capacity = other.capacity; - fluids = other.fluids; - } - } - - /** - * @return Total amount of stuff contained, across all fluid tanks - */ - public int getTotalAmount() { - int amt = 0; - for(int i = 0; i < fluids.length; i++) { - amt += getFluidAmount(i); - } - return amt; - } - - protected NBTTagCompound writeToNBT(NBTTagCompound destination) { - String[] tankNames = getNBTTankNames(); - - if(tankNames.length != fluids.length) { throw new IllegalArgumentException("getNBTTankNames must return the same number of strings as there are fluid stacks"); } - - FluidStack stack; - for(int i = 0; i < tankNames.length; i++) { - stack = fluids[i]; - if(stack != null) { - destination.setTag(tankNames[i], stack.writeToNBT(new NBTTagCompound())); - } - } - - return destination; - } - - protected void readFromNBT(NBTTagCompound data) { - String[] tankNames = getNBTTankNames(); - - if(tankNames.length != fluids.length) { throw new IllegalArgumentException("getNBTTankNames must return the same number of strings as there are fluid stacks"); } - - for(int i = 0; i < tankNames.length; i++) { - if(data.hasKey(tankNames[i])) { - fluids[i] = FluidStack.loadFluidStackFromNBT(data.getCompoundTag(tankNames[i])); - fluidLevelAtLastUpdate[i] = fluids[i].amount; - } - else { - fluids[i] = null; - fluidLevelAtLastUpdate[i] = 0; - } - } - } - - ////// FLUID HELPERS ////// - protected void setFluid(int idx, FluidStack newFluid) { - fluids[idx] = newFluid; - } - - protected int getFluidAmount(int idx) { - if(fluids[idx] == null) { return 0; } - else { return fluids[idx].amount; } - - } - - protected Fluid getFluidType(int idx) { - if(fluids[idx] == null) { return null; } - else { return fluids[idx].getFluid(); } - } - - protected abstract boolean isFluidValidForStack(int stackIdx, Fluid fluid); - - protected boolean canAddToStack(int idx, Fluid incoming) { - if(idx < 0 || idx >= fluids.length || incoming == null) { return false; } - else if(fluids[idx] == null) { return isFluidValidForStack(idx, incoming); } - return fluids[idx].getFluid().getID() == incoming.getID(); - } - - protected boolean canAddToStack(int idx, FluidStack incoming) { - if(idx < 0 || idx >= fluids.length || incoming == null) { return false; } - else if(fluids[idx] == null) {return isFluidValidForStack(idx, incoming.getFluid()); } - return fluids[idx].isFluidEqual(incoming); - } - - protected int addFluidToStack(int idx, int fluidAmount) { - if(fluids[idx] == null || fluids[idx].getFluid() == null) { - throw new IllegalArgumentException("Cannot add fluid with only an integer when tank is empty!"); - } - - int amtToAdd = Math.min(fluidAmount, getRemainingSpaceForFluid(idx)); - - fluids[idx].amount += amtToAdd; - return amtToAdd; - } - - /** - * Drain some fluid from a given stack - * @param idx Index of the stack (FUEL or WASTE) - * @param amount Nominal amount to drain - * @return Amount actually drained - */ - protected int drainFluidFromStack(int idx, Fluid fluid, int amount) { - if(fluids[idx] == null) { return 0; } - - if(fluids[idx].getFluid().getID() != fluid.getID()) { return 0; } - - return drainFluidFromStack(idx, amount); - } - - /** - * Drain fluid from a given stack, without caring what type it is. - * @param idx Index of the stack - * @param amount Amount to drain - * @return - */ - protected int drainFluidFromStack(int idx, int amount) { - if(fluids[idx] == null) { return 0; } - - if(fluids[idx].amount <= amount) { - amount = fluids[idx].amount; - fluids[idx] = null; - } - else { - fluids[idx].amount -= amount; - } - return amount; - } - - protected void clampContentsToCapacity() { - if(separateChambers) { - // Clamp each tank to capacity - for(int i = 0; i < fluids.length; i++) { - if(fluids[i] != null) { - fluids[i].amount = Math.min(getCapacity(), fluids[i].amount); - } - } - } - else { - if(getTotalAmount() > capacity) { - int diff = getTotalAmount() - capacity; - - // Reduce stuff in the tanks. Start with waste, to be nice to players. - for(int i = fluids.length - 1; i >= 0 && diff > 0; i--) { - if(fluids[i] != null) { - if(diff > fluids[i].amount) { - diff -= fluids[i].amount; - fluids[i] = null; - } - else { - fluids[i].amount -= diff; - diff = 0; - } - } - } - } - // Else: nothing to do, no need to clamp - } - } - - protected void resetLastSeenFluidLevels() { - for(int i = 0; i < numberOfFluids; i++) { - if(fluids[i] == null) { - fluidLevelAtLastUpdate[i] = 0; - } - else { - fluidLevelAtLastUpdate[i] = fluids[i].amount; - } - } - } - - protected int getRemainingSpaceForFluid(int idx) { - int containedFluidAmt; - if(separateChambers) { - containedFluidAmt = getFluidAmount(idx); - } - else { - containedFluidAmt = getTotalAmount(); - } - - return getCapacity() - containedFluidAmt; - } - - // IFluidHandler analogue - public int fill(int idx, FluidStack incoming, boolean doFill) { - if(incoming == null || idx < 0 || idx >= fluids.length) { return 0; } - - if(!canAddToStack(idx, incoming)) { - return 0; - } - - int amtToAdd = Math.min(incoming.amount, getRemainingSpaceForFluid(idx)); - - if(amtToAdd <= 0) { - return 0; - } - - if(!doFill) { return amtToAdd; } - - if(fluids[idx] == null) { - fluids[idx] = incoming.copy(); - fluids[idx].amount = amtToAdd; - } - else { - fluids[idx].amount += amtToAdd; - } - - return amtToAdd; - } - - public FluidStack drain(int idx, FluidStack resource, - boolean doDrain) { - if(resource == null || resource.amount <= 0 || idx < 0 || idx >= fluids.length) { return null; } - - Fluid existingFluid = getFluidType(idx); - if(existingFluid == null || existingFluid.getID() != resource.getFluid().getID()) { return null; } - - FluidStack drained = resource.copy(); - if(!doDrain) { - drained.amount = Math.min(resource.amount, getFluidAmount(idx)); - } - else { - drained.amount = drainFluidFromStack(idx, resource.amount); - } - - return drained; - } - - public FluidStack drain(int idx, int maxDrain, boolean doDrain) { - if(maxDrain <= 0 || idx < 0 || idx >= fluids.length) { return null; } - - if(getFluidType(idx) == null) { return null; } - - FluidStack drained = new FluidStack(getFluidType(idx), 0); - - if(!doDrain) { - drained.amount = Math.min(getFluidAmount(idx), maxDrain); - } - else { - drained.amount = drainFluidFromStack(idx, maxDrain); - } - - return drained; - } - - public boolean canFill(int idx, Fluid fluid) { - return canAddToStack(idx, fluid); - } - - public boolean canDrain(int idx, Fluid fluid) { - if(fluid == null || idx < 0 || idx >= fluids.length) { return false; } - - if(fluids[idx] == null) { return false; } - - return fluids[idx].getFluid().getID() == fluid.getID(); - } - - private static FluidTankInfo[] emptyTankArray = new FluidTankInfo[0]; - - public FluidTankInfo[] getTankInfo(int idx) { - if(idx >= fluids.length) { return emptyTankArray; } - - FluidTankInfo[] info; - - if(idx < 0) { - // All tanks - info = new FluidTankInfo[fluids.length]; - for(int i = 0; i < fluids.length; i++) { - info[i] = new FluidTankInfo(fluids[i] == null ? null : fluids[i].copy(), getCapacity()); - } - - return info; - } - else { - info = new FluidTankInfo[1]; - info[0] = new FluidTankInfo(fluids[idx] == null ? null : fluids[idx].copy(), getCapacity()); - } - - return info; - } - - public String getDebugInfo() { - StringBuilder sb = new StringBuilder(); - sb.append("Capacity (per): ").append(Integer.toString(getCapacity())); - String[] tankNames = getNBTTankNames(); - for(int i = 0; i < fluids.length; i++) { - sb.append("[").append(Integer.toString(i)).append("] ").append(tankNames[i]).append(": "); - if(fluids[i] == null) { - sb.append("NULL"); - } - else { - FluidStack stack = fluids[i]; - sb.append(stack.getFluid().getName()).append(", ").append(Integer.toString(stack.amount)).append(" mB"); - } - sb.append("\n"); - } - return sb.toString(); - } + private FluidStack[] fluids; + private int capacity; + + private int ticksSinceLastUpdate; + private static final int minimumTicksBetweenUpdates = 60; + private static final int minimumDevianceForUpdate = 50; // at least 50mB difference before we send a fueling update + // to the client + + int[] fluidLevelAtLastUpdate; + + private static final int FORCE_UPDATE = -1000; + private int numberOfFluids; + + private boolean separateChambers; + + /** + * @param separate True if capacity is applied to each fluid separately, false if they should be treated like a + * single tank with multiple fluids inside. + */ + public FluidHelper(boolean separate) { + numberOfFluids = getNumberOfFluidTanks(); + + fluids = new FluidStack[numberOfFluids]; + fluidLevelAtLastUpdate = new int[numberOfFluids]; + + for (int i = 0; i < numberOfFluids; i++) { + fluids[i] = null; + fluidLevelAtLastUpdate[i] = FORCE_UPDATE; + } + + capacity = 0; + separateChambers = separate; + } + + public abstract int getNumberOfFluidTanks(); + + protected abstract String[] getNBTTankNames(); + + // Implementation: IConditionalUpdater + public boolean shouldUpdate() { + ticksSinceLastUpdate++; + if (minimumTicksBetweenUpdates < ticksSinceLastUpdate) { + int dev = 0; + boolean shouldUpdate = false; + for (int i = 0; i < numberOfFluids && !shouldUpdate; i++) { + + if (fluids[i] == null && fluidLevelAtLastUpdate[i] > 0) { + shouldUpdate = true; + } else if (fluids[i] != null) { + if (fluidLevelAtLastUpdate[i] == FORCE_UPDATE) { + shouldUpdate = true; + } else { + dev += Math.abs(fluids[i].amount - fluidLevelAtLastUpdate[i]); + } + } + // else, both levels are zero, no-op + + if (dev >= minimumDevianceForUpdate) { + shouldUpdate = true; + } + } + + if (shouldUpdate) { + resetLastSeenFluidLevels(); + } + + ticksSinceLastUpdate = 0; + return shouldUpdate; + } + + return false; + } + + public int getCapacity() { + return capacity; + } + + public void setCapacity(int newCapacity) { + int oldCapacity = capacity; + capacity = newCapacity; + + clampContentsToCapacity(); + } + + protected void merge(FluidHelper other) { + if (other.capacity > capacity) { + capacity = other.capacity; + fluids = other.fluids; + } + } + + /** + * @return Total amount of stuff contained, across all fluid tanks + */ + public int getTotalAmount() { + int amt = 0; + for (int i = 0; i < fluids.length; i++) { + amt += getFluidAmount(i); + } + return amt; + } + + protected NBTTagCompound writeToNBT(NBTTagCompound destination) { + String[] tankNames = getNBTTankNames(); + + if (tankNames.length != fluids.length) { + throw new IllegalArgumentException( + "getNBTTankNames must return the same number of strings as there are fluid stacks"); + } + + FluidStack stack; + for (int i = 0; i < tankNames.length; i++) { + stack = fluids[i]; + if (stack != null) { + destination.setTag(tankNames[i], stack.writeToNBT(new NBTTagCompound())); + } + } + + return destination; + } + + protected void readFromNBT(NBTTagCompound data) { + String[] tankNames = getNBTTankNames(); + + if (tankNames.length != fluids.length) { + throw new IllegalArgumentException( + "getNBTTankNames must return the same number of strings as there are fluid stacks"); + } + + for (int i = 0; i < tankNames.length; i++) { + if (data.hasKey(tankNames[i])) { + fluids[i] = FluidStack.loadFluidStackFromNBT(data.getCompoundTag(tankNames[i])); + fluidLevelAtLastUpdate[i] = fluids[i].amount; + } else { + fluids[i] = null; + fluidLevelAtLastUpdate[i] = 0; + } + } + } + + ////// FLUID HELPERS ////// + protected void setFluid(int idx, FluidStack newFluid) { + fluids[idx] = newFluid; + } + + protected int getFluidAmount(int idx) { + if (fluids[idx] == null) { + return 0; + } else { + return fluids[idx].amount; + } + + } + + protected Fluid getFluidType(int idx) { + if (fluids[idx] == null) { + return null; + } else { + return fluids[idx].getFluid(); + } + } + + protected abstract boolean isFluidValidForStack(int stackIdx, Fluid fluid); + + protected boolean canAddToStack(int idx, Fluid incoming) { + if (idx < 0 || idx >= fluids.length || incoming == null) { + return false; + } else if (fluids[idx] == null) { + return isFluidValidForStack(idx, incoming); + } + return fluids[idx].getFluid() + .getID() == incoming.getID(); + } + + protected boolean canAddToStack(int idx, FluidStack incoming) { + if (idx < 0 || idx >= fluids.length || incoming == null) { + return false; + } else if (fluids[idx] == null) { + return isFluidValidForStack(idx, incoming.getFluid()); + } + return fluids[idx].isFluidEqual(incoming); + } + + protected int addFluidToStack(int idx, int fluidAmount) { + if (fluids[idx] == null || fluids[idx].getFluid() == null) { + throw new IllegalArgumentException("Cannot add fluid with only an integer when tank is empty!"); + } + + int amtToAdd = Math.min(fluidAmount, getRemainingSpaceForFluid(idx)); + + fluids[idx].amount += amtToAdd; + return amtToAdd; + } + + /** + * Drain some fluid from a given stack + * + * @param idx Index of the stack (FUEL or WASTE) + * @param amount Nominal amount to drain + * @return Amount actually drained + */ + protected int drainFluidFromStack(int idx, Fluid fluid, int amount) { + if (fluids[idx] == null) { + return 0; + } + + if (fluids[idx].getFluid() + .getID() != fluid.getID()) { + return 0; + } + + return drainFluidFromStack(idx, amount); + } + + /** + * Drain fluid from a given stack, without caring what type it is. + * + * @param idx Index of the stack + * @param amount Amount to drain + * @return + */ + protected int drainFluidFromStack(int idx, int amount) { + if (fluids[idx] == null) { + return 0; + } + + if (fluids[idx].amount <= amount) { + amount = fluids[idx].amount; + fluids[idx] = null; + } else { + fluids[idx].amount -= amount; + } + return amount; + } + + protected void clampContentsToCapacity() { + if (separateChambers) { + // Clamp each tank to capacity + for (int i = 0; i < fluids.length; i++) { + if (fluids[i] != null) { + fluids[i].amount = Math.min(getCapacity(), fluids[i].amount); + } + } + } else { + if (getTotalAmount() > capacity) { + int diff = getTotalAmount() - capacity; + + // Reduce stuff in the tanks. Start with waste, to be nice to players. + for (int i = fluids.length - 1; i >= 0 && diff > 0; i--) { + if (fluids[i] != null) { + if (diff > fluids[i].amount) { + diff -= fluids[i].amount; + fluids[i] = null; + } else { + fluids[i].amount -= diff; + diff = 0; + } + } + } + } + // Else: nothing to do, no need to clamp + } + } + + protected void resetLastSeenFluidLevels() { + for (int i = 0; i < numberOfFluids; i++) { + if (fluids[i] == null) { + fluidLevelAtLastUpdate[i] = 0; + } else { + fluidLevelAtLastUpdate[i] = fluids[i].amount; + } + } + } + + protected int getRemainingSpaceForFluid(int idx) { + int containedFluidAmt; + if (separateChambers) { + containedFluidAmt = getFluidAmount(idx); + } else { + containedFluidAmt = getTotalAmount(); + } + + return getCapacity() - containedFluidAmt; + } + + // IFluidHandler analogue + public int fill(int idx, FluidStack incoming, boolean doFill) { + if (incoming == null || idx < 0 || idx >= fluids.length) { + return 0; + } + + if (!canAddToStack(idx, incoming)) { + return 0; + } + + int amtToAdd = Math.min(incoming.amount, getRemainingSpaceForFluid(idx)); + + if (amtToAdd <= 0) { + return 0; + } + + if (!doFill) { + return amtToAdd; + } + + if (fluids[idx] == null) { + fluids[idx] = incoming.copy(); + fluids[idx].amount = amtToAdd; + } else { + fluids[idx].amount += amtToAdd; + } + + return amtToAdd; + } + + public FluidStack drain(int idx, FluidStack resource, boolean doDrain) { + if (resource == null || resource.amount <= 0 || idx < 0 || idx >= fluids.length) { + return null; + } + + Fluid existingFluid = getFluidType(idx); + if (existingFluid == null || existingFluid.getID() != resource.getFluid() + .getID()) { + return null; + } + + FluidStack drained = resource.copy(); + if (!doDrain) { + drained.amount = Math.min(resource.amount, getFluidAmount(idx)); + } else { + drained.amount = drainFluidFromStack(idx, resource.amount); + } + + return drained; + } + + public FluidStack drain(int idx, int maxDrain, boolean doDrain) { + if (maxDrain <= 0 || idx < 0 || idx >= fluids.length) { + return null; + } + + if (getFluidType(idx) == null) { + return null; + } + + FluidStack drained = new FluidStack(getFluidType(idx), 0); + + if (!doDrain) { + drained.amount = Math.min(getFluidAmount(idx), maxDrain); + } else { + drained.amount = drainFluidFromStack(idx, maxDrain); + } + + return drained; + } + + public boolean canFill(int idx, Fluid fluid) { + return canAddToStack(idx, fluid); + } + + public boolean canDrain(int idx, Fluid fluid) { + if (fluid == null || idx < 0 || idx >= fluids.length) { + return false; + } + + if (fluids[idx] == null) { + return false; + } + + return fluids[idx].getFluid() + .getID() == fluid.getID(); + } + + private static FluidTankInfo[] emptyTankArray = new FluidTankInfo[0]; + + public FluidTankInfo[] getTankInfo(int idx) { + if (idx >= fluids.length) { + return emptyTankArray; + } + + FluidTankInfo[] info; + + if (idx < 0) { + // All tanks + info = new FluidTankInfo[fluids.length]; + for (int i = 0; i < fluids.length; i++) { + info[i] = new FluidTankInfo(fluids[i] == null ? null : fluids[i].copy(), getCapacity()); + } + + return info; + } else { + info = new FluidTankInfo[1]; + info[0] = new FluidTankInfo(fluids[idx] == null ? null : fluids[idx].copy(), getCapacity()); + } + + return info; + } + + public String getDebugInfo() { + StringBuilder sb = new StringBuilder(); + sb.append("Capacity (per): ") + .append(Integer.toString(getCapacity())); + String[] tankNames = getNBTTankNames(); + for (int i = 0; i < fluids.length; i++) { + sb.append("[") + .append(Integer.toString(i)) + .append("] ") + .append(tankNames[i]) + .append(": "); + if (fluids[i] == null) { + sb.append("NULL"); + } else { + FluidStack stack = fluids[i]; + sb.append( + stack.getFluid() + .getName()) + .append(", ") + .append(Integer.toString(stack.amount)) + .append(" mB"); + } + sb.append("\n"); + } + return sb.toString(); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/FuelContainer.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/FuelContainer.java index b6d00958..842c85ab 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/FuelContainer.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/FuelContainer.java @@ -1,6 +1,7 @@ package erogenousbeef.bigreactors.common.multiblock.helpers; import net.minecraft.nbt.NBTTagCompound; + import erogenousbeef.bigreactors.api.data.ReactorReaction; import erogenousbeef.bigreactors.api.registry.Reactants; import erogenousbeef.bigreactors.api.registry.ReactorConversions; @@ -10,188 +11,195 @@ /** * Class to help with fuel/waste tracking in reactors. - * For now, + * For now, + * * @author ErogenousBeef * */ public class FuelContainer extends ReactantContainer { - private static final String[] tankNames = { "fuel", "waste" }; - private static final int FUEL = 0; - private static final int WASTE = 1; - - private float radiationFuelUsage; - - public FuelContainer() { - super(tankNames, 0); - radiationFuelUsage = 0f; - } - - public int getFuelAmount() { - return getReactantAmount(FUEL); - } - - public int getWasteAmount() { - return getReactantAmount(WASTE); - } - - @Override - public boolean isReactantValidForStack(int idx, String name) { - switch(idx) { - case FUEL: - return Reactants.isFuel(name); - case WASTE: - // Allow anything into our output slot, in case someone wants to do breeders or something - return true; - default: - return false; - } - } - - /** - * Add some fuel to the current pile, if possible. - * @param name The name of the reactant to add. - * @param amount The quantity of reactant to add. - * @param doAdd If true, this will only simulate a fill and will not alter the fuel amount. - * @return The amount of reactant actually added - */ - public int addFuel(String name, int amount, boolean doAdd) { - if(name == null || amount <= 0) { return 0; } - else { - return fill(FUEL, name, amount, doAdd); - } - } - - /** - * Add some waste to the current pile, if possible. - * @param incoming A FluidStack representing the fluid to fill, and the maximum amount to add to the tank. - * @return The amount of waste actually added - */ - public int addWaste(String name, int amount) { - int wasteAdded = fill(WASTE, name, amount, true); - return wasteAdded; - } - - private int addWaste(int wasteAmt) { - if(this.getWasteType() == null) { - BRLog.warning("System is using addWaste(int) when there's no waste present, defaulting to cyanite"); - return fill(WASTE, StandardReactants.cyanite, wasteAmt, true); - } - else { - return addToStack(WASTE, wasteAmt); - } - } - - public int dumpFuel() { - return dump(FUEL); - } - - public int dumpFuel(int amount) { - return dump(FUEL, amount); - } - - public int dumpWaste() { - return dump(WASTE); - } - - public int dumpWaste(int amount) { - return dump(WASTE, amount); - } - - public String getFuelType() { - return getReactantType(FUEL); - } - - public String getWasteType() { - return getReactantType(WASTE); - } - - public NBTTagCompound writeToNBT(NBTTagCompound destination) { - super.writeToNBT(destination); - - destination.setFloat("fuelUsage", radiationFuelUsage); - return destination; - } - - public void readFromNBT(NBTTagCompound data) { - super.readFromNBT(data); - - if(data.hasKey("fuelUsage")) { - radiationFuelUsage = data.getFloat("fuelUsage"); - } - } - - public void emptyFuel() { - setReactant(FUEL, null); - } - - public void emptyWaste() { - setReactant(WASTE, null); - } - - public void setFuel(ReactantStack newFuel) { - setReactant(FUEL, newFuel); - } - - public void setWaste(ReactantStack newWaste) { - setReactant(WASTE, newWaste); - } - - public void merge(FuelContainer other) { - radiationFuelUsage = Math.max(radiationFuelUsage, other.radiationFuelUsage); - - super.merge(other); - } - - public void onRadiationUsesFuel(float fuelUsed) { - if(Float.isInfinite(fuelUsed) || Float.isNaN(fuelUsed)) { return; } - - radiationFuelUsage += fuelUsed; - - if(radiationFuelUsage < 1f) { - return; - } - - int fuelToConvert = Math.min(getFuelAmount(), (int)radiationFuelUsage); - - if(fuelToConvert <= 0) { return; } - - radiationFuelUsage = Math.max(0f, radiationFuelUsage - fuelToConvert); - - String fuelType = getFuelType(); - if(fuelType != null) { - this.dumpFuel(fuelToConvert); - - if(getWasteType() != null) { - // If there's already waste, just keep on producing the same type. - this.addWaste(fuelToConvert); - } - else { - // Create waste type from registry - ReactorReaction reaction = ReactorConversions.get(fuelType); - String wasteType = reaction == null ? null : reaction.getProduct(); - - if(wasteType == null) { - BRLog.warning("Could not locate waste for reaction of fuel type " + fuelType + "; using cyanite"); - wasteType = StandardReactants.cyanite; - } - - this.addWaste(wasteType, fuelToConvert); - } - } - else { - BRLog.warning("Attempting to use %d fuel and there's no fuel in the tank", fuelToConvert); - } - } - - public float getFuelReactivity() { - String reactant = getFuelType(); - ReactorReaction reaction = ReactorConversions.get(reactant); - if(reaction == null) { - BRLog.warning("Could not locate reaction data for reactant type " + reactant + "; using default value for reactivity"); - return ReactorReaction.standardReactivity; - } - else { - return reaction.getReactivity(); - } - } + + private static final String[] tankNames = { "fuel", "waste" }; + private static final int FUEL = 0; + private static final int WASTE = 1; + + private float radiationFuelUsage; + + public FuelContainer() { + super(tankNames, 0); + radiationFuelUsage = 0f; + } + + public int getFuelAmount() { + return getReactantAmount(FUEL); + } + + public int getWasteAmount() { + return getReactantAmount(WASTE); + } + + @Override + public boolean isReactantValidForStack(int idx, String name) { + switch (idx) { + case FUEL: + return Reactants.isFuel(name); + case WASTE: + // Allow anything into our output slot, in case someone wants to do breeders or something + return true; + default: + return false; + } + } + + /** + * Add some fuel to the current pile, if possible. + * + * @param name The name of the reactant to add. + * @param amount The quantity of reactant to add. + * @param doAdd If true, this will only simulate a fill and will not alter the fuel amount. + * @return The amount of reactant actually added + */ + public int addFuel(String name, int amount, boolean doAdd) { + if (name == null || amount <= 0) { + return 0; + } else { + return fill(FUEL, name, amount, doAdd); + } + } + + /** + * Add some waste to the current pile, if possible. + * + * @param incoming A FluidStack representing the fluid to fill, and the maximum amount to add to the tank. + * @return The amount of waste actually added + */ + public int addWaste(String name, int amount) { + int wasteAdded = fill(WASTE, name, amount, true); + return wasteAdded; + } + + private int addWaste(int wasteAmt) { + if (this.getWasteType() == null) { + BRLog.warning("System is using addWaste(int) when there's no waste present, defaulting to cyanite"); + return fill(WASTE, StandardReactants.cyanite, wasteAmt, true); + } else { + return addToStack(WASTE, wasteAmt); + } + } + + public int dumpFuel() { + return dump(FUEL); + } + + public int dumpFuel(int amount) { + return dump(FUEL, amount); + } + + public int dumpWaste() { + return dump(WASTE); + } + + public int dumpWaste(int amount) { + return dump(WASTE, amount); + } + + public String getFuelType() { + return getReactantType(FUEL); + } + + public String getWasteType() { + return getReactantType(WASTE); + } + + public NBTTagCompound writeToNBT(NBTTagCompound destination) { + super.writeToNBT(destination); + + destination.setFloat("fuelUsage", radiationFuelUsage); + return destination; + } + + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + + if (data.hasKey("fuelUsage")) { + radiationFuelUsage = data.getFloat("fuelUsage"); + } + } + + public void emptyFuel() { + setReactant(FUEL, null); + } + + public void emptyWaste() { + setReactant(WASTE, null); + } + + public void setFuel(ReactantStack newFuel) { + setReactant(FUEL, newFuel); + } + + public void setWaste(ReactantStack newWaste) { + setReactant(WASTE, newWaste); + } + + public void merge(FuelContainer other) { + radiationFuelUsage = Math.max(radiationFuelUsage, other.radiationFuelUsage); + + super.merge(other); + } + + public void onRadiationUsesFuel(float fuelUsed) { + if (Float.isInfinite(fuelUsed) || Float.isNaN(fuelUsed)) { + return; + } + + radiationFuelUsage += fuelUsed; + + if (radiationFuelUsage < 1f) { + return; + } + + int fuelToConvert = Math.min(getFuelAmount(), (int) radiationFuelUsage); + + if (fuelToConvert <= 0) { + return; + } + + radiationFuelUsage = Math.max(0f, radiationFuelUsage - fuelToConvert); + + String fuelType = getFuelType(); + if (fuelType != null) { + this.dumpFuel(fuelToConvert); + + if (getWasteType() != null) { + // If there's already waste, just keep on producing the same type. + this.addWaste(fuelToConvert); + } else { + // Create waste type from registry + ReactorReaction reaction = ReactorConversions.get(fuelType); + String wasteType = reaction == null ? null : reaction.getProduct(); + + if (wasteType == null) { + BRLog.warning("Could not locate waste for reaction of fuel type " + fuelType + "; using cyanite"); + wasteType = StandardReactants.cyanite; + } + + this.addWaste(wasteType, fuelToConvert); + } + } else { + BRLog.warning("Attempting to use %d fuel and there's no fuel in the tank", fuelToConvert); + } + } + + public float getFuelReactivity() { + String reactant = getFuelType(); + ReactorReaction reaction = ReactorConversions.get(reactant); + if (reaction == null) { + BRLog.warning( + "Could not locate reaction data for reactant type " + reactant + + "; using default value for reactivity"); + return ReactorReaction.standardReactivity; + } else { + return reaction.getReactivity(); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/RadiationHelper.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/RadiationHelper.java index 2f5504ea..d8b3147c 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/RadiationHelper.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/RadiationHelper.java @@ -9,6 +9,7 @@ import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.IFluidBlock; + import cofh.lib.util.helpers.ItemHelper; import erogenousbeef.bigreactors.api.IHeatEntity; import erogenousbeef.bigreactors.api.IRadiationModerator; @@ -24,220 +25,233 @@ /** * Helper for reactor radiation game logic + * * @author Erogenous Beef */ public class RadiationHelper { - // Game Balance Values - public static final float fuelPerRadiationUnit = 0.0007f; // fuel units used per fission event - public static final float rfPerRadiationUnit = 10f; // RF generated per fission event - public static final float fissionEventsPerFuelUnit = 0.01f; // 1 fission event per 100 mB - - public static final ReactorInteriorData airData = new ReactorInteriorData(0.1f, 0.25f, 1.1f, IHeatEntity.conductivityAir); - public static final ReactorInteriorData waterData = new ReactorInteriorData(0.33f, 0.5f, 1.33f, IHeatEntity.conductivityWater); - - private float fertility; - - public RadiationHelper() { - fertility = 1f; - } - - public RadiationData radiate(World world, FuelContainer fuelContainer, TileEntityReactorFuelRod source, TileEntityReactorControlRod controlRod, float fuelHeat, float environmentHeat, int numControlRods) { - // No fuel? No radiation! - if(fuelContainer.getFuelAmount() <= 0) { return null; } - - // Determine radiation amount & intensity, heat amount, determine fuel usage - RadiationData data = new RadiationData(); - data.fuelAbsorbedRadiation = 0f; - - // Base value for radiation production penalties. 0-1, caps at about 3000C; - double radiationPenaltyBase = Math.exp(-15*Math.exp(-0.0025*fuelHeat)); - - // Raw amount - what's actually in the tanks - // Effective amount - how - int baseFuelAmount = fuelContainer.getFuelAmount() + (fuelContainer.getWasteAmount() / 100); - float fuelReactivity = fuelContainer.getFuelReactivity(); - - // Intensity = how strong the radiation is, hardness = how energetic the radiation is (penetration) - float rawRadIntensity = (float)baseFuelAmount * fissionEventsPerFuelUnit; - - // Scale up the "effective" intensity of radiation, to provide an incentive for bigger reactors in general. - float scaledRadIntensity = (float) Math.pow((rawRadIntensity), fuelReactivity); - - // Scale up a second time based on scaled amount in each fuel rod. Provides an incentive for making reactors that aren't just pancakes. - scaledRadIntensity = (float) Math.pow((scaledRadIntensity/numControlRods), fuelReactivity) * numControlRods; - - // Apply control rod moderation of radiation to the quantity of produced radiation. 100% insertion = 100% reduction. - float controlRodModifier = (float)(100-controlRod.getControlRodInsertion()) / 100f; - scaledRadIntensity = scaledRadIntensity * controlRodModifier; - rawRadIntensity = rawRadIntensity * controlRodModifier; - - // Now nerf actual radiation production based on heat. - float effectiveRadIntensity = scaledRadIntensity * (1f + (float)(-0.95f*Math.exp(-10f*Math.exp(-0.0012f*fuelHeat)))); - - // Radiation hardness starts at 20% and asymptotically approaches 100% as heat rises. - // This will make radiation harder and harder to capture. - float radHardness = 0.2f + (float)(0.8 * radiationPenaltyBase); - - // Calculate based on propagation-to-self - float rawFuelUsage = (fuelPerRadiationUnit * rawRadIntensity / getFertilityModifier()) * BigReactors.fuelUsageMultiplier; // Not a typo. Fuel usage is thus penalized at high heats. - data.fuelRfChange = rfPerRadiationUnit * effectiveRadIntensity; - data.environmentRfChange = 0f; - - // Propagate radiation to others - CoordTriplet originCoord = source.getWorldLocation(); - CoordTriplet currentCoord = new CoordTriplet(0, 0, 0); - - effectiveRadIntensity *= 0.25f; // We're going to do this four times, no need to repeat - RadiationPacket radPacket = new RadiationPacket(); - - for(ForgeDirection dir : StaticUtils.CardinalDirections) { - radPacket.hardness = radHardness; - radPacket.intensity = effectiveRadIntensity; - int ttl = 4; - currentCoord.copy(originCoord); - - while(ttl > 0 && radPacket.intensity > 0.0001f) { - ttl--; - currentCoord.translate(dir); - performIrradiation(world, data, radPacket, currentCoord.x, currentCoord.y, currentCoord.z); - } - } - - // Apply changes - fertility += data.fuelAbsorbedRadiation; - data.fuelAbsorbedRadiation = 0f; - - // Inform fuelContainer - fuelContainer.onRadiationUsesFuel(rawFuelUsage); - data.fuelUsage = rawFuelUsage; - - return data; - } - - public void tick(boolean active) { - float denominator = 20f; - if(!active) { denominator *= 200f; } // Much slower decay when off - - // Fertility decay, at least 0.1 rad/t, otherwise halve it every 10 ticks - fertility = Math.max(0f, fertility - Math.max(0.1f, fertility/denominator)); - } - - private void performIrradiation(World world, RadiationData data, RadiationPacket radiation, int x, int y, int z) { - TileEntity te = world.getTileEntity(x, y, z); - if(te instanceof IRadiationModerator) { - ((IRadiationModerator)te).moderateRadiation(data, radiation); - } - else if (world.isAirBlock(x, y, z)) { - moderateByAir(data, radiation); - } - else { - Block block = world.getBlock(x, y, z); - if(block != null) { - - if(block instanceof IFluidBlock) { - moderateByFluid(data, radiation, ((IFluidBlock)block).getFluid()); - } - else { - // Go by block - moderateByBlock(data, radiation, block, world.getBlockMetadata(x, y, z)); - } - } - else { - // Weird-ass problem. Assume it's air. - moderateByAir(data, radiation); - } - // Do it based on fluid? - } - } - - private void moderateByAir(RadiationData data, RadiationPacket radiation) { - applyModerationFactors(data, radiation, airData); - } - - private void moderateByBlock(RadiationData data, RadiationPacket radiation, Block block, int metadata) { - ReactorInteriorData moderatorData = null; - - if(block == Blocks.iron_block) { - moderatorData = ReactorInterior.getBlockData("blockIron"); - } - else if(block == Blocks.gold_block) { - moderatorData = ReactorInterior.getBlockData("blockGold"); - } - else if(block == Blocks.diamond_block) { - moderatorData = ReactorInterior.getBlockData("blockDiamond"); - } - else if(block == Blocks.emerald_block) { - moderatorData = ReactorInterior.getBlockData("blockEmerald"); - } - else { - // Check the ore dictionary. - moderatorData = ReactorInterior.getBlockData(ItemHelper.oreProxy.getOreName(new ItemStack(block, 1, metadata))); - } - - if(moderatorData == null) { - moderatorData = airData; - } - - applyModerationFactors(data, radiation, moderatorData); - } - - private void moderateByFluid(RadiationData data, RadiationPacket radiation, Fluid fluid) { - - float absorption, heatEfficiency, moderation; - - ReactorInteriorData moderatorData = ReactorInterior.getFluidData(fluid.getName()); - - if(moderatorData == null) { - moderatorData = waterData; - } - - applyModerationFactors(data, radiation, moderatorData); - } - - private static void applyModerationFactors(RadiationData data, RadiationPacket radiation, ReactorInteriorData moderatorData) { - float radiationAbsorbed = radiation.intensity * moderatorData.absorption * (1f - radiation.hardness); - radiation.intensity = Math.max(0f, radiation.intensity - radiationAbsorbed); - radiation.hardness /= moderatorData.moderation; - data.environmentRfChange += moderatorData.heatEfficiency * radiationAbsorbed * rfPerRadiationUnit; - } - - // Data Access - public float getFertility() { return fertility; } - - public float getFertilityModifier() { - if(fertility <= 1f) { return 1f; } - else { - return (float)(Math.log10(fertility) + 1); - } - } - - public void setFertility(float newFertility) { - if(Float.isNaN(newFertility) || Float.isInfinite(newFertility)) { - fertility = 1f; - } - else if(newFertility < 0f) { - fertility = 0f; - } - else { - fertility = newFertility; - } - } - - // Save/Load - public void readFromNBT(NBTTagCompound data) { - if(data.hasKey("fertility")) { - setFertility(data.getFloat("fertility")); - } - } - - public NBTTagCompound writeToNBT(NBTTagCompound data) { - data.setFloat("fertility", fertility); - return data; - } - - public void merge(RadiationHelper other) { - fertility = Math.max(fertility, other.fertility); - } + // Game Balance Values + public static final float fuelPerRadiationUnit = 0.0007f; // fuel units used per fission event + public static final float rfPerRadiationUnit = 10f; // RF generated per fission event + public static final float fissionEventsPerFuelUnit = 0.01f; // 1 fission event per 100 mB + + public static final ReactorInteriorData airData = new ReactorInteriorData( + 0.1f, + 0.25f, + 1.1f, + IHeatEntity.conductivityAir); + public static final ReactorInteriorData waterData = new ReactorInteriorData( + 0.33f, + 0.5f, + 1.33f, + IHeatEntity.conductivityWater); + + private float fertility; + + public RadiationHelper() { + fertility = 1f; + } + + public RadiationData radiate(World world, FuelContainer fuelContainer, TileEntityReactorFuelRod source, + TileEntityReactorControlRod controlRod, float fuelHeat, float environmentHeat, int numControlRods) { + // No fuel? No radiation! + if (fuelContainer.getFuelAmount() <= 0) { + return null; + } + + // Determine radiation amount & intensity, heat amount, determine fuel usage + RadiationData data = new RadiationData(); + data.fuelAbsorbedRadiation = 0f; + + // Base value for radiation production penalties. 0-1, caps at about 3000C; + double radiationPenaltyBase = Math.exp(-15 * Math.exp(-0.0025 * fuelHeat)); + + // Raw amount - what's actually in the tanks + // Effective amount - how + int baseFuelAmount = fuelContainer.getFuelAmount() + (fuelContainer.getWasteAmount() / 100); + float fuelReactivity = fuelContainer.getFuelReactivity(); + + // Intensity = how strong the radiation is, hardness = how energetic the radiation is (penetration) + float rawRadIntensity = (float) baseFuelAmount * fissionEventsPerFuelUnit; + + // Scale up the "effective" intensity of radiation, to provide an incentive for bigger reactors in general. + float scaledRadIntensity = (float) Math.pow((rawRadIntensity), fuelReactivity); + + // Scale up a second time based on scaled amount in each fuel rod. Provides an incentive for making reactors + // that aren't just pancakes. + scaledRadIntensity = (float) Math.pow((scaledRadIntensity / numControlRods), fuelReactivity) * numControlRods; + + // Apply control rod moderation of radiation to the quantity of produced radiation. 100% insertion = 100% + // reduction. + float controlRodModifier = (float) (100 - controlRod.getControlRodInsertion()) / 100f; + scaledRadIntensity = scaledRadIntensity * controlRodModifier; + rawRadIntensity = rawRadIntensity * controlRodModifier; + + // Now nerf actual radiation production based on heat. + float effectiveRadIntensity = scaledRadIntensity + * (1f + (float) (-0.95f * Math.exp(-10f * Math.exp(-0.0012f * fuelHeat)))); + + // Radiation hardness starts at 20% and asymptotically approaches 100% as heat rises. + // This will make radiation harder and harder to capture. + float radHardness = 0.2f + (float) (0.8 * radiationPenaltyBase); + + // Calculate based on propagation-to-self + float rawFuelUsage = (fuelPerRadiationUnit * rawRadIntensity / getFertilityModifier()) + * BigReactors.fuelUsageMultiplier; // Not a typo. Fuel usage is thus penalized at high heats. + data.fuelRfChange = rfPerRadiationUnit * effectiveRadIntensity; + data.environmentRfChange = 0f; + + // Propagate radiation to others + CoordTriplet originCoord = source.getWorldLocation(); + CoordTriplet currentCoord = new CoordTriplet(0, 0, 0); + + effectiveRadIntensity *= 0.25f; // We're going to do this four times, no need to repeat + RadiationPacket radPacket = new RadiationPacket(); + + for (ForgeDirection dir : StaticUtils.CardinalDirections) { + radPacket.hardness = radHardness; + radPacket.intensity = effectiveRadIntensity; + int ttl = 4; + currentCoord.copy(originCoord); + + while (ttl > 0 && radPacket.intensity > 0.0001f) { + ttl--; + currentCoord.translate(dir); + performIrradiation(world, data, radPacket, currentCoord.x, currentCoord.y, currentCoord.z); + } + } + + // Apply changes + fertility += data.fuelAbsorbedRadiation; + data.fuelAbsorbedRadiation = 0f; + + // Inform fuelContainer + fuelContainer.onRadiationUsesFuel(rawFuelUsage); + data.fuelUsage = rawFuelUsage; + + return data; + } + + public void tick(boolean active) { + float denominator = 20f; + if (!active) { + denominator *= 200f; + } // Much slower decay when off + + // Fertility decay, at least 0.1 rad/t, otherwise halve it every 10 ticks + fertility = Math.max(0f, fertility - Math.max(0.1f, fertility / denominator)); + } + + private void performIrradiation(World world, RadiationData data, RadiationPacket radiation, int x, int y, int z) { + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof IRadiationModerator) { + ((IRadiationModerator) te).moderateRadiation(data, radiation); + } else if (world.isAirBlock(x, y, z)) { + moderateByAir(data, radiation); + } else { + Block block = world.getBlock(x, y, z); + if (block != null) { + + if (block instanceof IFluidBlock) { + moderateByFluid(data, radiation, ((IFluidBlock) block).getFluid()); + } else { + // Go by block + moderateByBlock(data, radiation, block, world.getBlockMetadata(x, y, z)); + } + } else { + // Weird-ass problem. Assume it's air. + moderateByAir(data, radiation); + } + // Do it based on fluid? + } + } + + private void moderateByAir(RadiationData data, RadiationPacket radiation) { + applyModerationFactors(data, radiation, airData); + } + + private void moderateByBlock(RadiationData data, RadiationPacket radiation, Block block, int metadata) { + ReactorInteriorData moderatorData = null; + + if (block == Blocks.iron_block) { + moderatorData = ReactorInterior.getBlockData("blockIron"); + } else if (block == Blocks.gold_block) { + moderatorData = ReactorInterior.getBlockData("blockGold"); + } else if (block == Blocks.diamond_block) { + moderatorData = ReactorInterior.getBlockData("blockDiamond"); + } else if (block == Blocks.emerald_block) { + moderatorData = ReactorInterior.getBlockData("blockEmerald"); + } else { + // Check the ore dictionary. + moderatorData = ReactorInterior + .getBlockData(ItemHelper.oreProxy.getOreName(new ItemStack(block, 1, metadata))); + } + + if (moderatorData == null) { + moderatorData = airData; + } + + applyModerationFactors(data, radiation, moderatorData); + } + + private void moderateByFluid(RadiationData data, RadiationPacket radiation, Fluid fluid) { + + float absorption, heatEfficiency, moderation; + + ReactorInteriorData moderatorData = ReactorInterior.getFluidData(fluid.getName()); + + if (moderatorData == null) { + moderatorData = waterData; + } + + applyModerationFactors(data, radiation, moderatorData); + } + + private static void applyModerationFactors(RadiationData data, RadiationPacket radiation, + ReactorInteriorData moderatorData) { + float radiationAbsorbed = radiation.intensity * moderatorData.absorption * (1f - radiation.hardness); + radiation.intensity = Math.max(0f, radiation.intensity - radiationAbsorbed); + radiation.hardness /= moderatorData.moderation; + data.environmentRfChange += moderatorData.heatEfficiency * radiationAbsorbed * rfPerRadiationUnit; + } + + // Data Access + public float getFertility() { + return fertility; + } + + public float getFertilityModifier() { + if (fertility <= 1f) { + return 1f; + } else { + return (float) (Math.log10(fertility) + 1); + } + } + + public void setFertility(float newFertility) { + if (Float.isNaN(newFertility) || Float.isInfinite(newFertility)) { + fertility = 1f; + } else if (newFertility < 0f) { + fertility = 0f; + } else { + fertility = newFertility; + } + } + + // Save/Load + public void readFromNBT(NBTTagCompound data) { + if (data.hasKey("fertility")) { + setFertility(data.getFloat("fertility")); + } + } + + public NBTTagCompound writeToNBT(NBTTagCompound data) { + data.setFloat("fertility", fertility); + return data; + } + + public void merge(RadiationHelper other) { + fertility = Math.max(fertility, other.fertility); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/ReactantContainer.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/ReactantContainer.java index 0378c667..acd9e5dc 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/ReactantContainer.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/ReactantContainer.java @@ -1,12 +1,13 @@ package erogenousbeef.bigreactors.common.multiblock.helpers; -import io.netty.buffer.ByteBuf; import net.minecraft.nbt.NBTTagCompound; + import cpw.mods.fml.common.network.ByteBufUtils; import erogenousbeef.bigreactors.api.registry.Reactants; import erogenousbeef.bigreactors.common.BRLog; import erogenousbeef.bigreactors.common.data.ReactantStack; import erogenousbeef.bigreactors.common.multiblock.interfaces.IConditionalUpdater; +import io.netty.buffer.ByteBuf; /** * A helper class which allows multiple reactants to sit in one logical @@ -18,332 +19,342 @@ */ public abstract class ReactantContainer implements IConditionalUpdater { - private ReactantStack[] tanks; - private int capacity; - private String[] tankNames; - - private int ticksSinceLastUpdate; - private static final int minimumTicksBetweenUpdates = 60; - private static final float minimumDevianceForUpdate = 0.05f; // at least 5% difference before we send a fueling update to the client - - int[] levelAtLastUpdate; - - private static final int FORCE_UPDATE = -1000; - - public ReactantContainer(String[] tankNames, int capacity) { - assert(tankNames != null); - assert(tankNames.length > 0); - - this.tankNames = tankNames; - tanks = new ReactantStack[tankNames.length]; - levelAtLastUpdate = new int[tankNames.length]; - - for(int i = 0; i < tanks.length; i++) { - tanks[i] = null; - levelAtLastUpdate[i] = FORCE_UPDATE; - } - - this.capacity = capacity; - } - - public int getCapacity() { return capacity; } - - public void setCapacity(int newCapacity) { - int oldCapacity = capacity; - capacity = newCapacity; - - clampContentsToCapacity(); - } - - /// GETTERS - public String getReactantType(int reactantIdx) { - assert(reactantIdx >= 0 && reactantIdx < tanks.length); - return tanks[reactantIdx] == null ? null : tanks[reactantIdx].getName(); - } - - public int getReactantAmount(int reactantIdx) { - assert(reactantIdx >= 0 && reactantIdx < tanks.length); - return tanks[reactantIdx] == null ? 0 : tanks[reactantIdx].amount; - } - - /** - * @return Total amount of stuff contained, across all fluid tanks - */ - public int getTotalAmount() { - int amt = 0; - for(int i = 0; i < tanks.length; i++) { - amt += getReactantAmount(i); - } - return amt; - } - - /// SETTERS - public void setReactant(int reactantIdx, ReactantStack newStack ) { - assert(reactantIdx >= 0 && reactantIdx < tanks.length); - tanks[reactantIdx] = newStack; - } - - /// ADD/REMOVE HELPERS - protected int addToStack(int idx, int fluidAmount) { - if(tanks[idx] == null) { - throw new IllegalArgumentException("Cannot add reactant with only an integer when tank is empty!"); - } - - int amtToAdd = Math.min(fluidAmount, getRemainingSpace()); - - tanks[idx].amount += amtToAdd; - return amtToAdd; - } - - public int fill(int idx, String reactantName, int amount, boolean doFill) { - assert(idx >= 0 && idx < tanks.length); - if(reactantName == null || amount <= 0) { - return 0; - } - - if(!canAddToStack(idx, reactantName)) { - return 0; - } - - int amtToAdd = Math.min(amount, getRemainingSpace()); - if(amtToAdd <= 0) { - return 0; - } - if(!doFill) { - return amtToAdd; - } - - if(tanks[idx] == null) { - tanks[idx] = new ReactantStack(reactantName, amtToAdd); - } - else { - tanks[idx].amount += amtToAdd; - } - - return amtToAdd; - } - - /** - * Dump everything in a given reactant tank. - * @param idx Index of the tank to dump - */ - public int dump(int idx) { - assert(idx >= 0 && idx < tanks.length); - - int amt = tanks[idx] != null ? tanks[idx].amount : 0; - setReactant(idx, null); - - return amt; - } - - /** - * Remove some amount of reactant, but don't bother returning it. - * We're just dumping it into the ether. - * @param idx Index of the tank to dump from - * @param amount Maximum amount to dump - */ - public int dump(int idx, int amount) { - assert(idx >= 0 && idx < tanks.length); - if(tanks[idx] != null) { - if(tanks[idx].amount <= amount) { - amount = tanks[idx].amount; - setReactant(idx, null); - } - else { - tanks[idx].amount -= amount; - } - return amount; - } - else { - return 0; - } - } - - /// VALIDATION HELPERS - protected abstract boolean isReactantValidForStack(int stackIdx, String reactant); - - protected boolean canAddToStack(int idx, String incoming) { - if(idx < 0 || idx >= tanks.length || incoming == null) { return false; } - else if(tanks[idx] == null) { - return isReactantValidForStack(idx, incoming); - } - return tanks[idx].isReactantEqual(incoming); - } - - public boolean canDrain(int idx, ReactantStack reactant) { - if(reactant == null || idx < 0 || idx >= tanks.length) { return false; } - - if(tanks[idx] == null) { return false; } - - return tanks[idx].isReactantEqual(reactant) && tanks[idx].amount > 0; - } - - /// SAVE/LOAD - - protected NBTTagCompound writeToNBT(NBTTagCompound destination) { - ReactantStack stack; - for(int i = 0; i < tankNames.length; i++) { - stack = tanks[i]; - if(stack != null) { - destination.setTag(tankNames[i], stack.writeToNBT(new NBTTagCompound())); - } - } - - return destination; - } - - protected void readFromNBT(NBTTagCompound data) { - for(int i = 0; i < tankNames.length; i++) { - if(data.hasKey(tankNames[i])) { - tanks[i] = ReactantStack.createFromNBT(data.getCompoundTag(tankNames[i])); - levelAtLastUpdate[i] = tanks[i] != null ? tanks[i].amount : FORCE_UPDATE; - } - else { - tanks[i] = null; - levelAtLastUpdate[i] = FORCE_UPDATE; - } - } - } - - public void serialize(ByteBuf buffer) { - buffer.writeInt(capacity); - for(int i = 0; i < tankNames.length; i++) { - boolean hasReactant = getReactantAmount(i) > 0; - buffer.writeBoolean(hasReactant); - if(hasReactant) { - ByteBufUtils.writeUTF8String(buffer, tanks[i].getName()); - buffer.writeInt(tanks[i].amount); - } - } - } - - public void deserialize(ByteBuf buffer) { - capacity = buffer.readInt(); - for(int i = 0; i < tankNames.length; i++) { - tanks[i] = null; - - boolean hasReactant = buffer.readBoolean(); - if(hasReactant) { - String reactantName = ByteBufUtils.readUTF8String(buffer); - int amount = buffer.readInt(); - - if(!Reactants.isKnown(reactantName)) { - BRLog.warning("Read an unknown reactant <%s> from a network message; tank %s will remain empty", reactantName, tankNames[i]); - } - else { - tanks[i] = new ReactantStack(reactantName, amount); - levelAtLastUpdate[i] = amount; - } - } - } - } - - /// MULTIBLOCK HELPERS - protected void merge(ReactantContainer other) { - if(other.capacity > capacity) { - capacity = other.capacity; - tanks = other.tanks; - } - } - - /// Implementation: IConditionalUpdater - public boolean shouldUpdate() { - ticksSinceLastUpdate++; - - if(minimumTicksBetweenUpdates < ticksSinceLastUpdate) { - int dev = 0; - boolean shouldUpdate = false; - for(int i = 0; i < tanks.length && !shouldUpdate; i++) { - - if(tanks[i] == null && levelAtLastUpdate[i] > 0) { - shouldUpdate = true; - } - else if(tanks[i] != null) { - if(levelAtLastUpdate[i] == FORCE_UPDATE) { - shouldUpdate = true; - } - else { - dev += Math.abs(tanks[i].amount - levelAtLastUpdate[i]); - } - } - // else, both levels are zero, no-op - - float divisor = capacity; - if(divisor == 0) { divisor = 4000; } // totally arbitrary 4kmb - if(((float)dev/divisor) >= minimumDevianceForUpdate) { - // Only update if we're more than 5% off our current amount - shouldUpdate = true; - } - } - - if(shouldUpdate) { - resetLastSeenLevels(); - } - - ticksSinceLastUpdate = 0; - return shouldUpdate; - } - - return false; - } - - /// DATA HELPERS - protected void resetLastSeenLevels() { - for(int i = 0; i < tanks.length; i++) { - if(tanks[i] == null) { - levelAtLastUpdate[i] = 0; - } - else { - levelAtLastUpdate[i] = tanks[i].amount; - } - } - } - - /** - * @return The amount of space remaining in the container. - */ - public int getRemainingSpace() { - return getCapacity() - getTotalAmount(); - } - - /** - * When a container is overfilled, forcibly "spill" some reactants - * to return to a non-overfull state. - * This is most often useful when dealing with machine merges. - */ - protected void clampContentsToCapacity() { - if(getTotalAmount() > capacity) { - int diff = getTotalAmount() - capacity; - - // Reduce stuff in the tanks. Start with waste, to be nice to players. - for(int i = tanks.length - 1; i >= 0 && diff > 0; i--) { - if(tanks[i] != null) { - if(diff > tanks[i].amount) { - diff -= tanks[i].amount; - tanks[i] = null; - } - else { - tanks[i].amount -= diff; - diff = 0; - } - } - } - } - } - - public String getDebugInfo() { - StringBuilder sb = new StringBuilder(); - sb.append("Capacity: ").append(Integer.toString(getCapacity())); - for(int i = 0; i < tanks.length; i++) { - sb.append("[").append(Integer.toString(i)).append("] ").append(tankNames[i]).append(": "); - if(tanks[i] == null) { - sb.append("NULL"); - } - else { - sb.append(tanks[i].toString()); - } - sb.append("\n"); - } - return sb.toString(); - } + private ReactantStack[] tanks; + private int capacity; + private String[] tankNames; + + private int ticksSinceLastUpdate; + private static final int minimumTicksBetweenUpdates = 60; + private static final float minimumDevianceForUpdate = 0.05f; // at least 5% difference before we send a fueling + // update to the client + + int[] levelAtLastUpdate; + + private static final int FORCE_UPDATE = -1000; + + public ReactantContainer(String[] tankNames, int capacity) { + assert (tankNames != null); + assert (tankNames.length > 0); + + this.tankNames = tankNames; + tanks = new ReactantStack[tankNames.length]; + levelAtLastUpdate = new int[tankNames.length]; + + for (int i = 0; i < tanks.length; i++) { + tanks[i] = null; + levelAtLastUpdate[i] = FORCE_UPDATE; + } + + this.capacity = capacity; + } + + public int getCapacity() { + return capacity; + } + + public void setCapacity(int newCapacity) { + int oldCapacity = capacity; + capacity = newCapacity; + + clampContentsToCapacity(); + } + + /// GETTERS + public String getReactantType(int reactantIdx) { + assert (reactantIdx >= 0 && reactantIdx < tanks.length); + return tanks[reactantIdx] == null ? null : tanks[reactantIdx].getName(); + } + + public int getReactantAmount(int reactantIdx) { + assert (reactantIdx >= 0 && reactantIdx < tanks.length); + return tanks[reactantIdx] == null ? 0 : tanks[reactantIdx].amount; + } + + /** + * @return Total amount of stuff contained, across all fluid tanks + */ + public int getTotalAmount() { + int amt = 0; + for (int i = 0; i < tanks.length; i++) { + amt += getReactantAmount(i); + } + return amt; + } + + /// SETTERS + public void setReactant(int reactantIdx, ReactantStack newStack) { + assert (reactantIdx >= 0 && reactantIdx < tanks.length); + tanks[reactantIdx] = newStack; + } + + /// ADD/REMOVE HELPERS + protected int addToStack(int idx, int fluidAmount) { + if (tanks[idx] == null) { + throw new IllegalArgumentException("Cannot add reactant with only an integer when tank is empty!"); + } + + int amtToAdd = Math.min(fluidAmount, getRemainingSpace()); + + tanks[idx].amount += amtToAdd; + return amtToAdd; + } + + public int fill(int idx, String reactantName, int amount, boolean doFill) { + assert (idx >= 0 && idx < tanks.length); + if (reactantName == null || amount <= 0) { + return 0; + } + + if (!canAddToStack(idx, reactantName)) { + return 0; + } + + int amtToAdd = Math.min(amount, getRemainingSpace()); + if (amtToAdd <= 0) { + return 0; + } + if (!doFill) { + return amtToAdd; + } + + if (tanks[idx] == null) { + tanks[idx] = new ReactantStack(reactantName, amtToAdd); + } else { + tanks[idx].amount += amtToAdd; + } + + return amtToAdd; + } + + /** + * Dump everything in a given reactant tank. + * + * @param idx Index of the tank to dump + */ + public int dump(int idx) { + assert (idx >= 0 && idx < tanks.length); + + int amt = tanks[idx] != null ? tanks[idx].amount : 0; + setReactant(idx, null); + + return amt; + } + + /** + * Remove some amount of reactant, but don't bother returning it. + * We're just dumping it into the ether. + * + * @param idx Index of the tank to dump from + * @param amount Maximum amount to dump + */ + public int dump(int idx, int amount) { + assert (idx >= 0 && idx < tanks.length); + if (tanks[idx] != null) { + if (tanks[idx].amount <= amount) { + amount = tanks[idx].amount; + setReactant(idx, null); + } else { + tanks[idx].amount -= amount; + } + return amount; + } else { + return 0; + } + } + + /// VALIDATION HELPERS + protected abstract boolean isReactantValidForStack(int stackIdx, String reactant); + + protected boolean canAddToStack(int idx, String incoming) { + if (idx < 0 || idx >= tanks.length || incoming == null) { + return false; + } else if (tanks[idx] == null) { + return isReactantValidForStack(idx, incoming); + } + return tanks[idx].isReactantEqual(incoming); + } + + public boolean canDrain(int idx, ReactantStack reactant) { + if (reactant == null || idx < 0 || idx >= tanks.length) { + return false; + } + + if (tanks[idx] == null) { + return false; + } + + return tanks[idx].isReactantEqual(reactant) && tanks[idx].amount > 0; + } + + /// SAVE/LOAD + + protected NBTTagCompound writeToNBT(NBTTagCompound destination) { + ReactantStack stack; + for (int i = 0; i < tankNames.length; i++) { + stack = tanks[i]; + if (stack != null) { + destination.setTag(tankNames[i], stack.writeToNBT(new NBTTagCompound())); + } + } + + return destination; + } + + protected void readFromNBT(NBTTagCompound data) { + for (int i = 0; i < tankNames.length; i++) { + if (data.hasKey(tankNames[i])) { + tanks[i] = ReactantStack.createFromNBT(data.getCompoundTag(tankNames[i])); + levelAtLastUpdate[i] = tanks[i] != null ? tanks[i].amount : FORCE_UPDATE; + } else { + tanks[i] = null; + levelAtLastUpdate[i] = FORCE_UPDATE; + } + } + } + + public void serialize(ByteBuf buffer) { + buffer.writeInt(capacity); + for (int i = 0; i < tankNames.length; i++) { + boolean hasReactant = getReactantAmount(i) > 0; + buffer.writeBoolean(hasReactant); + if (hasReactant) { + ByteBufUtils.writeUTF8String(buffer, tanks[i].getName()); + buffer.writeInt(tanks[i].amount); + } + } + } + + public void deserialize(ByteBuf buffer) { + capacity = buffer.readInt(); + for (int i = 0; i < tankNames.length; i++) { + tanks[i] = null; + + boolean hasReactant = buffer.readBoolean(); + if (hasReactant) { + String reactantName = ByteBufUtils.readUTF8String(buffer); + int amount = buffer.readInt(); + + if (!Reactants.isKnown(reactantName)) { + BRLog.warning( + "Read an unknown reactant <%s> from a network message; tank %s will remain empty", + reactantName, + tankNames[i]); + } else { + tanks[i] = new ReactantStack(reactantName, amount); + levelAtLastUpdate[i] = amount; + } + } + } + } + + /// MULTIBLOCK HELPERS + protected void merge(ReactantContainer other) { + if (other.capacity > capacity) { + capacity = other.capacity; + tanks = other.tanks; + } + } + + /// Implementation: IConditionalUpdater + public boolean shouldUpdate() { + ticksSinceLastUpdate++; + + if (minimumTicksBetweenUpdates < ticksSinceLastUpdate) { + int dev = 0; + boolean shouldUpdate = false; + for (int i = 0; i < tanks.length && !shouldUpdate; i++) { + + if (tanks[i] == null && levelAtLastUpdate[i] > 0) { + shouldUpdate = true; + } else if (tanks[i] != null) { + if (levelAtLastUpdate[i] == FORCE_UPDATE) { + shouldUpdate = true; + } else { + dev += Math.abs(tanks[i].amount - levelAtLastUpdate[i]); + } + } + // else, both levels are zero, no-op + + float divisor = capacity; + if (divisor == 0) { + divisor = 4000; + } // totally arbitrary 4kmb + if (((float) dev / divisor) >= minimumDevianceForUpdate) { + // Only update if we're more than 5% off our current amount + shouldUpdate = true; + } + } + + if (shouldUpdate) { + resetLastSeenLevels(); + } + + ticksSinceLastUpdate = 0; + return shouldUpdate; + } + + return false; + } + + /// DATA HELPERS + protected void resetLastSeenLevels() { + for (int i = 0; i < tanks.length; i++) { + if (tanks[i] == null) { + levelAtLastUpdate[i] = 0; + } else { + levelAtLastUpdate[i] = tanks[i].amount; + } + } + } + + /** + * @return The amount of space remaining in the container. + */ + public int getRemainingSpace() { + return getCapacity() - getTotalAmount(); + } + + /** + * When a container is overfilled, forcibly "spill" some reactants + * to return to a non-overfull state. + * This is most often useful when dealing with machine merges. + */ + protected void clampContentsToCapacity() { + if (getTotalAmount() > capacity) { + int diff = getTotalAmount() - capacity; + + // Reduce stuff in the tanks. Start with waste, to be nice to players. + for (int i = tanks.length - 1; i >= 0 && diff > 0; i--) { + if (tanks[i] != null) { + if (diff > tanks[i].amount) { + diff -= tanks[i].amount; + tanks[i] = null; + } else { + tanks[i].amount -= diff; + diff = 0; + } + } + } + } + } + + public String getDebugInfo() { + StringBuilder sb = new StringBuilder(); + sb.append("Capacity: ") + .append(Integer.toString(getCapacity())); + for (int i = 0; i < tanks.length; i++) { + sb.append("[") + .append(Integer.toString(i)) + .append("] ") + .append(tankNames[i]) + .append(": "); + if (tanks[i] == null) { + sb.append("NULL"); + } else { + sb.append(tanks[i].toString()); + } + sb.append("\n"); + } + return sb.toString(); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/RotorInfo.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/RotorInfo.java index 935cdd9a..8f3f63c8 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/RotorInfo.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/helpers/RotorInfo.java @@ -3,15 +3,16 @@ import net.minecraftforge.common.util.ForgeDirection; public class RotorInfo { - // Location of bearing - public int x, y, z; - - // Rotor direction - public ForgeDirection rotorDirection = ForgeDirection.UNKNOWN; - - // Rotor length - public int rotorLength = 0; - - // Array of arrays, containing rotor lengths - public int[][] bladeLengths = null; + + // Location of bearing + public int x, y, z; + + // Rotor direction + public ForgeDirection rotorDirection = ForgeDirection.UNKNOWN; + + // Rotor length + public int rotorLength = 0; + + // Array of arrays, containing rotor lengths + public int[][] bladeLengths = null; } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/IActivateable.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/IActivateable.java index 55dee446..8763aa5b 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/IActivateable.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/IActivateable.java @@ -4,24 +4,25 @@ /** * Implement this on tile entities which can be activated + * * @author Erogenous Beef */ public interface IActivateable { - /** - * @return The coordinate at which your entities resides, - * or the reference coordinate of your multiblock. - */ - public CoordTriplet getReferenceCoord(); - - /** - * @return True if your entity is active - */ - public boolean getActive(); - - /** - * @param active Whether the user wishes this entity to be active - */ - public void setActive(boolean active); - + /** + * @return The coordinate at which your entities resides, + * or the reference coordinate of your multiblock. + */ + public CoordTriplet getReferenceCoord(); + + /** + * @return True if your entity is active + */ + public boolean getActive(); + + /** + * @param active Whether the user wishes this entity to be active + */ + public void setActive(boolean active); + } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/IConditionalUpdater.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/IConditionalUpdater.java index c92c1fe3..29e2bd07 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/IConditionalUpdater.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/IConditionalUpdater.java @@ -2,10 +2,11 @@ public interface IConditionalUpdater { - /** - * Call this once per active tick. - * @return True if this data helper needs to send data to nearby players. - */ - public boolean shouldUpdate(); - + /** + * Call this once per active tick. + * + * @return True if this data helper needs to send data to nearby players. + */ + public boolean shouldUpdate(); + } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/IMultiblockGuiHandler.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/IMultiblockGuiHandler.java index a309163b..a60720ac 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/IMultiblockGuiHandler.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/IMultiblockGuiHandler.java @@ -1,23 +1,24 @@ package erogenousbeef.bigreactors.common.multiblock.interfaces; import net.minecraft.entity.player.InventoryPlayer; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; public interface IMultiblockGuiHandler { - /** - * @param inventoryPlayer The inventory of the player opening the GUI. - * @return The Container object for use by the GUI. Null if there isn't any. - */ - public Object getContainer(InventoryPlayer inventoryPlayer); - - - /** - * Return the BeefGuiBase which will display this block's GUI. - * @param inventoryPlayer The inventory of the player opening the GUI - * @return The BeefGuiBase object which will display this block's GUI, or null if none. - */ - @SideOnly(Side.CLIENT) - public Object getGuiElement(InventoryPlayer inventoryPlayer); + /** + * @param inventoryPlayer The inventory of the player opening the GUI. + * @return The Container object for use by the GUI. Null if there isn't any. + */ + public Object getContainer(InventoryPlayer inventoryPlayer); + + /** + * Return the BeefGuiBase which will display this block's GUI. + * + * @param inventoryPlayer The inventory of the player opening the GUI + * @return The BeefGuiBase object which will display this block's GUI, or null if none. + */ + @SideOnly(Side.CLIENT) + public Object getGuiElement(InventoryPlayer inventoryPlayer); } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/INeighborUpdatableEntity.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/INeighborUpdatableEntity.java index 0bccf062..37a95f18 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/INeighborUpdatableEntity.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/INeighborUpdatableEntity.java @@ -5,27 +5,30 @@ import net.minecraft.world.World; public interface INeighborUpdatableEntity { - - /** - * Called from a Block class's onNeighborBlockChange - * @param world The world containing the tileentity - * @param x Tile Entity's xcoord - * @param y Tile Entity's ycoord - * @param z Tile Entity's zcoord - * @param neighborBlock Block that changed - */ - public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock); - - /** - * Called from a Block class's onNeighborTileChange - * @param world The world containing the TileEntity - * @param x Tile entity's Xcoord - * @param y Tile entity's Ycoord - * @param z Tile entity's Zcoord - * @param neighborX Changed neighbor's Xcoord - * @param neighborY Changed neighbor's Ycoord - * @param neighborZ Changed neighbor's Zcoord - */ - public void onNeighborTileChange(IBlockAccess world, int x, int y, int z, int neighborX, int neighborY, int neighborZ); + + /** + * Called from a Block class's onNeighborBlockChange + * + * @param world The world containing the tileentity + * @param x Tile Entity's xcoord + * @param y Tile Entity's ycoord + * @param z Tile Entity's zcoord + * @param neighborBlock Block that changed + */ + public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock); + + /** + * Called from a Block class's onNeighborTileChange + * + * @param world The world containing the TileEntity + * @param x Tile entity's Xcoord + * @param y Tile entity's Ycoord + * @param z Tile entity's Zcoord + * @param neighborX Changed neighbor's Xcoord + * @param neighborY Changed neighbor's Ycoord + * @param neighborZ Changed neighbor's Zcoord + */ + public void onNeighborTileChange(IBlockAccess world, int x, int y, int z, int neighborX, int neighborY, + int neighborZ); } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/ITickableMultiblockPart.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/ITickableMultiblockPart.java index b9662872..0056e7a7 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/ITickableMultiblockPart.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/interfaces/ITickableMultiblockPart.java @@ -2,13 +2,14 @@ /** * Implement this to receive once-per-tick updates from the multiblock. + * * @author Erogenous Beef * */ public interface ITickableMultiblockPart { - /** - * Called once every tick from the reactor's main server tick loop. - */ - public void onMultiblockServerTick(); + /** + * Called once every tick from the reactor's main server tick loop. + */ + public void onMultiblockServerTick(); } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorAccessPort.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorAccessPort.java index 1ef8d9d7..b5e16ec0 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorAccessPort.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorAccessPort.java @@ -14,6 +14,7 @@ import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; + import cofh.lib.util.helpers.BlockHelper; import cofh.lib.util.helpers.ItemHelper; import cpw.mods.fml.relauncher.Side; @@ -29,438 +30,457 @@ import erogenousbeef.bigreactors.utils.AdjacentInventoryHelper; import erogenousbeef.core.multiblock.MultiblockControllerBase; -public class TileEntityReactorAccessPort extends TileEntityReactorPart implements IInventory, ISidedInventory, INeighborUpdatableEntity { - - protected ItemStack[] _inventories; - protected boolean isInlet; - protected AdjacentInventoryHelper adjacencyHelper; - - public static final int SLOT_INLET = 0; - public static final int SLOT_OUTLET = 1; - public static final int NUM_SLOTS = 2; - - private static final int[] kInletExposed = {SLOT_INLET}; - private static final int[] kOutletExposed = {SLOT_OUTLET}; - - public TileEntityReactorAccessPort() { - super(); - - _inventories = new ItemStack[getSizeInventory()]; - isInlet = true; - } - - // Return the name of the reactant to which the item in the input slot - public String getInputReactantType() { - ItemStack inputItem = getStackInSlot(SLOT_INLET); - if(inputItem == null) { return null; } - SourceProductMapping mapping = Reactants.getSolidToReactant(inputItem); - return mapping != null ? mapping.getProduct() : null; - } - - // Returns the potential amount of reactant which can be produced from this port. - public int getInputReactantAmount() { - ItemStack inputItem = getStackInSlot(SLOT_INLET); - if(inputItem == null) { return 0; } - - SourceProductMapping mapping = Reactants.getSolidToReactant(inputItem); - return mapping != null ? mapping.getProductAmount(inputItem.stackSize) : 0; - } - - /** - * Consume items from the input slot. - * Returns the amount of reactant produced. - * @param reactantDesired The amount of reactant desired, in reactant units (mB) - * @return The amount of reactant actually produced, in reactant units (mB) - */ - public int consumeReactantItem(int reactantDesired) { - ItemStack inputItem = getStackInSlot(SLOT_INLET); - if(inputItem == null) { return 0; } - - SourceProductMapping mapping = Reactants.getSolidToReactant(inputItem); - if(mapping == null) { return 0; } - - int sourceItemsToConsume = Math.min(inputItem.stackSize, mapping.getSourceAmount(reactantDesired)); - - if(sourceItemsToConsume <= 0) { return 0; } - - decrStackSize(SLOT_INLET, sourceItemsToConsume); - return mapping.getProductAmount(sourceItemsToConsume); - } - - /** - * Try to emit a given amount of reactant as a solid item. - * Will either match the item type already present, or will select - * whatever type allows the most reactant to be ejected right now. - * @param reactantType Type of reactant to emit. - * @param amount - * @return - */ - public int emitReactant(String reactantType, int amount) { - if(reactantType == null || amount <= 0) { return 0; } - - ItemStack outputItem = getStackInSlot(SLOT_OUTLET); - if(outputItem != null && outputItem.stackSize >= getInventoryStackLimit()) { - // Already full? - return 0; - } - - // If we have an output item, try to produce more of it, given its mapping - if(outputItem != null) { - // Find matching mapping - SourceProductMapping mapping = Reactants.getSolidToReactant(outputItem); - if(mapping == null || !reactantType.equals(mapping.getProduct())) { - // Items are incompatible! - return 0; - } - - // We're using the original source item >> reactant mapping here - // This means that source == item, and product == reactant - int amtToProduce = mapping.getSourceAmount(amount); - amtToProduce = Math.min(amtToProduce, getInventoryStackLimit() - outputItem.stackSize); - if(amtToProduce <= 0) { return 0; } - - // Do we actually produce any reactant at this reduced amount? - int reactantToConsume = mapping.getProductAmount(amtToProduce); - if(reactantToConsume <= 0) { return 0; } - - outputItem.stackSize += amtToProduce; - onItemsReceived(); - - return reactantToConsume; - } - - // Ok, we have no items. We need to figure out candidate mappings. - // Below here, we're using the reactant >> source mappings. - // This means that source == reactant, and product == item. - SourceProductMapping bestMapping = null; - - List mappings = Reactants.getReactantToSolids(reactantType); - if(mappings != null) { - int bestReactantAmount = 0; - for(SourceProductMapping mapping: mappings) { - // How much product can we produce? - int potentialProducts = mapping.getProductAmount(amount); - - // And how much reactant will that consume? - int potentialReactant = mapping.getSourceAmount(potentialProducts); - - if(bestMapping == null || bestReactantAmount < potentialReactant) { - bestMapping = mapping; - bestReactantAmount = potentialReactant; - } - } - } - - if(bestMapping == null) { - BRLog.warning("There are no mapped item types for reactant %s. Using cyanite instead.", reactantType); - bestMapping = StandardReactants.cyaniteMapping; - } - - int itemsToProduce = Math.min(bestMapping.getProductAmount(amount), getInventoryStackLimit()); - if(itemsToProduce <= 0) { - // Can't produce even one ingot? Ok then. - return 0; - } - - // And clamp again in case we could produce more than 64 items - int reactantConsumed = bestMapping.getSourceAmount(itemsToProduce); - itemsToProduce = bestMapping.getProductAmount(reactantConsumed); - - ItemStack newItem = ItemHelper.getOre(bestMapping.getProduct()); - if(newItem == null) { - BRLog.warning("Could not find item for oredict entry %s, using cyanite instead.", bestMapping.getSource()); - newItem = BigReactors.ingotGeneric.getItemStackForType("ingotCyanite"); - } - else { - newItem = newItem.copy(); // Don't stomp the oredict - } - - newItem.stackSize = itemsToProduce; - setInventorySlotContents(SLOT_OUTLET, newItem); - onItemsReceived(); - - return reactantConsumed; - } - - // Multiblock overrides - @Override - public void onMachineAssembled(MultiblockControllerBase controller) { - super.onMachineAssembled(controller); - - adjacencyHelper = new AdjacentInventoryHelper(this.getOutwardsDir()); - checkForAdjacentInventories(); - } - - @Override - public void onMachineBroken() { - super.onMachineBroken(); - adjacencyHelper = null; - } - - // TileEntity overrides - - @Override - public void readFromNBT(NBTTagCompound tag) { - super.readFromNBT(tag); - _inventories = new ItemStack[getSizeInventory()]; - if(tag.hasKey("Items")) { - NBTTagList tagList = tag.getTagList("Items", 10); - for(int i = 0; i < tagList.tagCount(); i++) { - NBTTagCompound itemTag = (NBTTagCompound)tagList.getCompoundTagAt(i); - int slot = itemTag.getByte("Slot") & 0xff; - if(slot >= 0 && slot <= _inventories.length) { - ItemStack itemStack = new ItemStack((Block)null,0,0); - itemStack.readFromNBT(itemTag); - _inventories[slot] = itemStack; - } - } - } - - if(tag.hasKey("isInlet")) { - this.isInlet = tag.getBoolean("isInlet"); - } - } - - @Override - public void writeToNBT(NBTTagCompound tag) { - super.writeToNBT(tag); - NBTTagList tagList = new NBTTagList(); - - for(int i = 0; i < _inventories.length; i++) { - if((_inventories[i]) != null) { - NBTTagCompound itemTag = new NBTTagCompound(); - itemTag.setByte("Slot", (byte)i); - _inventories[i].writeToNBT(itemTag); - tagList.appendTag(itemTag); - } - } - - if(tagList.tagCount() > 0) { - tag.setTag("Items", tagList); - } - - tag.setBoolean("isInlet", isInlet); - } - - // MultiblockTileEntityBase - @Override - protected void encodeDescriptionPacket(NBTTagCompound packetData) { - super.encodeDescriptionPacket(packetData); - - packetData.setBoolean("inlet", isInlet); - } - - @Override - protected void decodeDescriptionPacket(NBTTagCompound packetData) { - super.decodeDescriptionPacket(packetData); - - if(packetData.hasKey("inlet")) { - setInlet(packetData.getBoolean("inlet")); - } - } - - // IInventory - - @Override - public int getSizeInventory() { - return NUM_SLOTS; - } - - @Override - public ItemStack getStackInSlot(int slot) { - return _inventories[slot]; - } - - @Override - public ItemStack decrStackSize(int slot, int amount) { - if(_inventories[slot] != null) - { - if(_inventories[slot].stackSize <= amount) - { - ItemStack itemstack = _inventories[slot]; - _inventories[slot] = null; - markDirty(); - return itemstack; - } - ItemStack newStack = _inventories[slot].splitStack(amount); - if(_inventories[slot].stackSize == 0) - { - _inventories[slot] = null; - } +public class TileEntityReactorAccessPort extends TileEntityReactorPart + implements IInventory, ISidedInventory, INeighborUpdatableEntity { + + protected ItemStack[] _inventories; + protected boolean isInlet; + protected AdjacentInventoryHelper adjacencyHelper; + + public static final int SLOT_INLET = 0; + public static final int SLOT_OUTLET = 1; + public static final int NUM_SLOTS = 2; + + private static final int[] kInletExposed = { SLOT_INLET }; + private static final int[] kOutletExposed = { SLOT_OUTLET }; + + public TileEntityReactorAccessPort() { + super(); + + _inventories = new ItemStack[getSizeInventory()]; + isInlet = true; + } + + // Return the name of the reactant to which the item in the input slot + public String getInputReactantType() { + ItemStack inputItem = getStackInSlot(SLOT_INLET); + if (inputItem == null) { + return null; + } + SourceProductMapping mapping = Reactants.getSolidToReactant(inputItem); + return mapping != null ? mapping.getProduct() : null; + } + + // Returns the potential amount of reactant which can be produced from this port. + public int getInputReactantAmount() { + ItemStack inputItem = getStackInSlot(SLOT_INLET); + if (inputItem == null) { + return 0; + } + + SourceProductMapping mapping = Reactants.getSolidToReactant(inputItem); + return mapping != null ? mapping.getProductAmount(inputItem.stackSize) : 0; + } + + /** + * Consume items from the input slot. + * Returns the amount of reactant produced. + * + * @param reactantDesired The amount of reactant desired, in reactant units (mB) + * @return The amount of reactant actually produced, in reactant units (mB) + */ + public int consumeReactantItem(int reactantDesired) { + ItemStack inputItem = getStackInSlot(SLOT_INLET); + if (inputItem == null) { + return 0; + } + + SourceProductMapping mapping = Reactants.getSolidToReactant(inputItem); + if (mapping == null) { + return 0; + } + + int sourceItemsToConsume = Math.min(inputItem.stackSize, mapping.getSourceAmount(reactantDesired)); + + if (sourceItemsToConsume <= 0) { + return 0; + } + + decrStackSize(SLOT_INLET, sourceItemsToConsume); + return mapping.getProductAmount(sourceItemsToConsume); + } + + /** + * Try to emit a given amount of reactant as a solid item. + * Will either match the item type already present, or will select + * whatever type allows the most reactant to be ejected right now. + * + * @param reactantType Type of reactant to emit. + * @param amount + * @return + */ + public int emitReactant(String reactantType, int amount) { + if (reactantType == null || amount <= 0) { + return 0; + } + + ItemStack outputItem = getStackInSlot(SLOT_OUTLET); + if (outputItem != null && outputItem.stackSize >= getInventoryStackLimit()) { + // Already full? + return 0; + } + + // If we have an output item, try to produce more of it, given its mapping + if (outputItem != null) { + // Find matching mapping + SourceProductMapping mapping = Reactants.getSolidToReactant(outputItem); + if (mapping == null || !reactantType.equals(mapping.getProduct())) { + // Items are incompatible! + return 0; + } + + // We're using the original source item >> reactant mapping here + // This means that source == item, and product == reactant + int amtToProduce = mapping.getSourceAmount(amount); + amtToProduce = Math.min(amtToProduce, getInventoryStackLimit() - outputItem.stackSize); + if (amtToProduce <= 0) { + return 0; + } + + // Do we actually produce any reactant at this reduced amount? + int reactantToConsume = mapping.getProductAmount(amtToProduce); + if (reactantToConsume <= 0) { + return 0; + } + + outputItem.stackSize += amtToProduce; + onItemsReceived(); + + return reactantToConsume; + } + + // Ok, we have no items. We need to figure out candidate mappings. + // Below here, we're using the reactant >> source mappings. + // This means that source == reactant, and product == item. + SourceProductMapping bestMapping = null; + + List mappings = Reactants.getReactantToSolids(reactantType); + if (mappings != null) { + int bestReactantAmount = 0; + for (SourceProductMapping mapping : mappings) { + // How much product can we produce? + int potentialProducts = mapping.getProductAmount(amount); + + // And how much reactant will that consume? + int potentialReactant = mapping.getSourceAmount(potentialProducts); + + if (bestMapping == null || bestReactantAmount < potentialReactant) { + bestMapping = mapping; + bestReactantAmount = potentialReactant; + } + } + } + + if (bestMapping == null) { + BRLog.warning("There are no mapped item types for reactant %s. Using cyanite instead.", reactantType); + bestMapping = StandardReactants.cyaniteMapping; + } + + int itemsToProduce = Math.min(bestMapping.getProductAmount(amount), getInventoryStackLimit()); + if (itemsToProduce <= 0) { + // Can't produce even one ingot? Ok then. + return 0; + } + + // And clamp again in case we could produce more than 64 items + int reactantConsumed = bestMapping.getSourceAmount(itemsToProduce); + itemsToProduce = bestMapping.getProductAmount(reactantConsumed); + + ItemStack newItem = ItemHelper.getOre(bestMapping.getProduct()); + if (newItem == null) { + BRLog.warning("Could not find item for oredict entry %s, using cyanite instead.", bestMapping.getSource()); + newItem = BigReactors.ingotGeneric.getItemStackForType("ingotCyanite"); + } else { + newItem = newItem.copy(); // Don't stomp the oredict + } + + newItem.stackSize = itemsToProduce; + setInventorySlotContents(SLOT_OUTLET, newItem); + onItemsReceived(); + + return reactantConsumed; + } + + // Multiblock overrides + @Override + public void onMachineAssembled(MultiblockControllerBase controller) { + super.onMachineAssembled(controller); + + adjacencyHelper = new AdjacentInventoryHelper(this.getOutwardsDir()); + checkForAdjacentInventories(); + } + + @Override + public void onMachineBroken() { + super.onMachineBroken(); + adjacencyHelper = null; + } + + // TileEntity overrides + + @Override + public void readFromNBT(NBTTagCompound tag) { + super.readFromNBT(tag); + _inventories = new ItemStack[getSizeInventory()]; + if (tag.hasKey("Items")) { + NBTTagList tagList = tag.getTagList("Items", 10); + for (int i = 0; i < tagList.tagCount(); i++) { + NBTTagCompound itemTag = (NBTTagCompound) tagList.getCompoundTagAt(i); + int slot = itemTag.getByte("Slot") & 0xff; + if (slot >= 0 && slot <= _inventories.length) { + ItemStack itemStack = new ItemStack((Block) null, 0, 0); + itemStack.readFromNBT(itemTag); + _inventories[slot] = itemStack; + } + } + } + + if (tag.hasKey("isInlet")) { + this.isInlet = tag.getBoolean("isInlet"); + } + } + + @Override + public void writeToNBT(NBTTagCompound tag) { + super.writeToNBT(tag); + NBTTagList tagList = new NBTTagList(); + + for (int i = 0; i < _inventories.length; i++) { + if ((_inventories[i]) != null) { + NBTTagCompound itemTag = new NBTTagCompound(); + itemTag.setByte("Slot", (byte) i); + _inventories[i].writeToNBT(itemTag); + tagList.appendTag(itemTag); + } + } + + if (tagList.tagCount() > 0) { + tag.setTag("Items", tagList); + } + + tag.setBoolean("isInlet", isInlet); + } + + // MultiblockTileEntityBase + @Override + protected void encodeDescriptionPacket(NBTTagCompound packetData) { + super.encodeDescriptionPacket(packetData); + + packetData.setBoolean("inlet", isInlet); + } + + @Override + protected void decodeDescriptionPacket(NBTTagCompound packetData) { + super.decodeDescriptionPacket(packetData); + + if (packetData.hasKey("inlet")) { + setInlet(packetData.getBoolean("inlet")); + } + } + + // IInventory + + @Override + public int getSizeInventory() { + return NUM_SLOTS; + } + + @Override + public ItemStack getStackInSlot(int slot) { + return _inventories[slot]; + } + + @Override + public ItemStack decrStackSize(int slot, int amount) { + if (_inventories[slot] != null) { + if (_inventories[slot].stackSize <= amount) { + ItemStack itemstack = _inventories[slot]; + _inventories[slot] = null; + markDirty(); + return itemstack; + } + ItemStack newStack = _inventories[slot].splitStack(amount); + if (_inventories[slot].stackSize == 0) { + _inventories[slot] = null; + } markDirty(); - return newStack; - } - else - { - return null; - } - } - - @Override - public ItemStack getStackInSlotOnClosing(int slot) { - return null; - } - - @Override - public void setInventorySlotContents(int slot, ItemStack itemstack) { - _inventories[slot] = itemstack; - if(itemstack != null && itemstack.stackSize > getInventoryStackLimit()) - { - itemstack.stackSize = getInventoryStackLimit(); - } + return newStack; + } else { + return null; + } + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return null; + } + + @Override + public void setInventorySlotContents(int slot, ItemStack itemstack) { + _inventories[slot] = itemstack; + if (itemstack != null && itemstack.stackSize > getInventoryStackLimit()) { + itemstack.stackSize = getInventoryStackLimit(); + } markDirty(); - } - - @Override - public String getInventoryName() { - return "Access Port"; - } - - @Override - public boolean hasCustomInventoryName() { - return false; - } - - @Override - public int getInventoryStackLimit() { - return 64; - } - - @Override - public boolean isUseableByPlayer(EntityPlayer entityplayer) { - if(worldObj.getTileEntity(xCoord, yCoord, zCoord) != this) - { - return false; - } - return entityplayer.getDistanceSq((double)xCoord + 0.5D, (double)yCoord + 0.5D, (double)zCoord + 0.5D) <= 64D; - } - - @Override - public void openInventory() { - } - - @Override - public void closeInventory() { - } - - @Override - public boolean isItemValidForSlot(int slot, ItemStack itemstack) { - if(itemstack == null) { return true; } - - if(slot == SLOT_INLET) { - return Reactants.isFuel(itemstack); - } - else if(slot == SLOT_OUTLET) { - return Reactants.isWaste(itemstack); - } - else { - return false; - } - } - - // ISidedInventory - - @Override - public int[] getAccessibleSlotsFromSide(int side) { - if(isInlet()) { - return kInletExposed; - } - else { - return kOutletExposed; - } - } - - @Override - public boolean canInsertItem(int slot, ItemStack itemstack, int side) { - return isItemValidForSlot(slot, itemstack); - } - - @Override - public boolean canExtractItem(int slot, ItemStack itemstack, int side) { - return isItemValidForSlot(slot, itemstack); - } - - // IMultiblockGuiHandler - @Override - public Object getContainer(InventoryPlayer inventoryPlayer) { - return new ContainerReactorAccessPort(this, inventoryPlayer); - } - - @SideOnly(Side.CLIENT) - @Override - public Object getGuiElement(InventoryPlayer inventoryPlayer) { - return new GuiReactorAccessPort(new ContainerReactorAccessPort(this, inventoryPlayer), this); - } - - /** - * Called when stuff has been placed in the access port - */ - public void onItemsReceived() { - distributeItems(); - markChunkDirty(); - } - - public boolean isInlet() { return this.isInlet; } - - public void setInlet(boolean shouldBeInlet) { - if(isInlet == shouldBeInlet) { return; } - - isInlet = shouldBeInlet; - - worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - - if(!worldObj.isRemote) { - distributeItems(); - markChunkDirty(); - } - - notifyNeighborsOfTileChange(); - } - - protected void distributeItems() { - if(worldObj.isRemote) { return; } - if(adjacencyHelper == null) { return; } - - if(this.isInlet()) { return; } - - _inventories[SLOT_OUTLET] = adjacencyHelper.distribute(_inventories[SLOT_OUTLET]); - markChunkDirty(); - } - - protected void checkForAdjacentInventories() { - ForgeDirection outDir = getOutwardsDir(); - - if(adjacencyHelper == null && outDir != ForgeDirection.UNKNOWN) { - adjacencyHelper = new AdjacentInventoryHelper(outDir); - } - - if(adjacencyHelper != null && outDir != ForgeDirection.UNKNOWN) { - TileEntity te = worldObj.getTileEntity(xCoord + outDir.offsetX, yCoord + outDir.offsetY, zCoord + outDir.offsetZ); - if(adjacencyHelper.set(te)) { - distributeItems(); - } - } - } - - protected void markChunkDirty() { - worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this); - } - - // INeighborUpdateableEntity - @Override - public void onNeighborBlockChange(World world, int x, int y, int z, - Block neighborBlock) { - checkForAdjacentInventories(); - } - - @Override - public void onNeighborTileChange(IBlockAccess world, int x, int y, int z, - int neighborX, int neighborY, int neighborZ) { - int side = BlockHelper.determineAdjacentSide(this, neighborX, neighborY, neighborZ); - if(side == getOutwardsDir().ordinal()) { - checkForAdjacentInventories(); - } - } + } + + @Override + public String getInventoryName() { + return "Access Port"; + } + + @Override + public boolean hasCustomInventoryName() { + return false; + } + + @Override + public int getInventoryStackLimit() { + return 64; + } + + @Override + public boolean isUseableByPlayer(EntityPlayer entityplayer) { + if (worldObj.getTileEntity(xCoord, yCoord, zCoord) != this) { + return false; + } + return entityplayer.getDistanceSq((double) xCoord + 0.5D, (double) yCoord + 0.5D, (double) zCoord + 0.5D) + <= 64D; + } + + @Override + public void openInventory() {} + + @Override + public void closeInventory() {} + + @Override + public boolean isItemValidForSlot(int slot, ItemStack itemstack) { + if (itemstack == null) { + return true; + } + + if (slot == SLOT_INLET) { + return Reactants.isFuel(itemstack); + } else if (slot == SLOT_OUTLET) { + return Reactants.isWaste(itemstack); + } else { + return false; + } + } + + // ISidedInventory + + @Override + public int[] getAccessibleSlotsFromSide(int side) { + if (isInlet()) { + return kInletExposed; + } else { + return kOutletExposed; + } + } + + @Override + public boolean canInsertItem(int slot, ItemStack itemstack, int side) { + return isItemValidForSlot(slot, itemstack); + } + + @Override + public boolean canExtractItem(int slot, ItemStack itemstack, int side) { + return isItemValidForSlot(slot, itemstack); + } + + // IMultiblockGuiHandler + @Override + public Object getContainer(InventoryPlayer inventoryPlayer) { + return new ContainerReactorAccessPort(this, inventoryPlayer); + } + + @SideOnly(Side.CLIENT) + @Override + public Object getGuiElement(InventoryPlayer inventoryPlayer) { + return new GuiReactorAccessPort(new ContainerReactorAccessPort(this, inventoryPlayer), this); + } + + /** + * Called when stuff has been placed in the access port + */ + public void onItemsReceived() { + distributeItems(); + markChunkDirty(); + } + + public boolean isInlet() { + return this.isInlet; + } + + public void setInlet(boolean shouldBeInlet) { + if (isInlet == shouldBeInlet) { + return; + } + + isInlet = shouldBeInlet; + + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + + if (!worldObj.isRemote) { + distributeItems(); + markChunkDirty(); + } + + notifyNeighborsOfTileChange(); + } + + protected void distributeItems() { + if (worldObj.isRemote) { + return; + } + if (adjacencyHelper == null) { + return; + } + + if (this.isInlet()) { + return; + } + + _inventories[SLOT_OUTLET] = adjacencyHelper.distribute(_inventories[SLOT_OUTLET]); + markChunkDirty(); + } + + protected void checkForAdjacentInventories() { + ForgeDirection outDir = getOutwardsDir(); + + if (adjacencyHelper == null && outDir != ForgeDirection.UNKNOWN) { + adjacencyHelper = new AdjacentInventoryHelper(outDir); + } + + if (adjacencyHelper != null && outDir != ForgeDirection.UNKNOWN) { + TileEntity te = worldObj + .getTileEntity(xCoord + outDir.offsetX, yCoord + outDir.offsetY, zCoord + outDir.offsetZ); + if (adjacencyHelper.set(te)) { + distributeItems(); + } + } + } + + protected void markChunkDirty() { + worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this); + } + + // INeighborUpdateableEntity + @Override + public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock) { + checkForAdjacentInventories(); + } + + @Override + public void onNeighborTileChange(IBlockAccess world, int x, int y, int z, int neighborX, int neighborY, + int neighborZ) { + int side = BlockHelper.determineAdjacentSide(this, neighborX, neighborY, neighborZ); + if (side == getOutwardsDir().ordinal()) { + checkForAdjacentInventories(); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorComputerPort.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorComputerPort.java index 1382b2f8..1a3a5e41 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorComputerPort.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorComputerPort.java @@ -3,372 +3,373 @@ import java.util.HashMap; import java.util.Map; -import li.cil.oc.api.machine.Arguments; -import li.cil.oc.api.machine.Context; -import li.cil.oc.api.network.ManagedPeripheral; -import li.cil.oc.api.network.SimpleComponent; import net.minecraft.tileentity.TileEntity; import net.minecraftforge.fluids.Fluid; + import cpw.mods.fml.common.Optional; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; -import erogenousbeef.bigreactors.common.BRLog; import erogenousbeef.bigreactors.common.multiblock.MultiblockReactor; import erogenousbeef.core.common.CoordTriplet; +import li.cil.oc.api.machine.Arguments; +import li.cil.oc.api.machine.Context; +import li.cil.oc.api.network.ManagedPeripheral; +import li.cil.oc.api.network.SimpleComponent; + +@Optional.InterfaceList({ @Optional.Interface(iface = "li.cil.oc.api.network.SimpleComponent", modid = "OpenComputers"), + @Optional.Interface(iface = "li.cil.oc.api.network.ManagedPeripheral", modid = "OpenComputers"), + @Optional.Interface(iface = "dan200.computercraft.api.peripheral.IPeripheral", modid = "ComputerCraft") }) +public class TileEntityReactorComputerPort extends TileEntityReactorPart + implements IPeripheral, SimpleComponent, ManagedPeripheral { + + public enum ComputerMethod { + getConnected, // No arguments + getActive, // No arguments + getFuelTemperature, // No arguments + getCasingTemperature, // No arguments + getEnergyStored, // No arguments + getFuelAmount, // No arguments + getWasteAmount, // No arguments + getFuelAmountMax, // No arguments + getControlRodName, // Required Arg: fuel rod index + getNumberOfControlRods, // No arguments + getControlRodLevel, // Required Arg: control rod index + getEnergyProducedLastTick, // No arguments + getHotFluidProducedLastTick, // No arguments + getCoolantAmount, // No arguments + getCoolantAmountMax, // No arguments + getCoolantType, // No arguments + getHotFluidAmount, // No arguments + getHotFluidAmountMax, // No arguments + getHotFluidType, // No arguments + getFuelReactivity, // No arguments + getFuelConsumedLastTick, // No arguments + getMinimumCoordinate, // No arguments + getMaximumCoordinate, // No arguments + getControlRodLocation, // Required Arg: integer (index) + isActivelyCooled, // No arguments + setActive, // Required Arg: integer (active) + setControlRodLevel, // Required Args: fuel rod index, integer (insertion) + setAllControlRodLevels, // Required Arg: integer (insertion) + setControlRodName, // Required Args: fuel rod index, string (name) + doEjectWaste, // No arguments + doEjectFuel // No arguments + } + + public static final int numMethods = ComputerMethod.values().length; + + public static final String[] methodNames = new String[numMethods]; + static { + ComputerMethod[] methods = ComputerMethod.values(); + for (ComputerMethod method : methods) { + methodNames[method.ordinal()] = method.toString(); + } + } + + public static final Map methodIds = new HashMap(); + static { + for (int i = 0; i < numMethods; ++i) { + methodIds.put(methodNames[i], i); + } + } + + public Object[] callMethod(int method, Object[] arguments) throws Exception { + if (method < 0 || method >= numMethods) { + throw new IllegalArgumentException("Invalid method number"); + } + + // Special case: getConnected can always be called. + if (method == 0) { + return new Object[] { this.isConnected() }; + } + + if (!this.isConnected()) { + throw new Exception("Unable to access reactor - port is not connected"); + } + MultiblockReactor reactor = this.getReactorController(); + + ComputerMethod computerMethod = ComputerMethod.values()[method]; + int index, newLevel; + boolean newState; + TileEntityReactorControlRod controlRod; + + switch (computerMethod) { + case getEnergyStored: + return new Object[] { (int) reactor.getEnergyStored() }; + case getNumberOfControlRods: + return new Object[] { (int) reactor.getFuelRodCount() }; + case getActive: + return new Object[] { reactor.getActive() }; + case getFuelTemperature: + return new Object[] { reactor.getFuelHeat() }; + case getCasingTemperature: + return new Object[] { reactor.getReactorHeat() }; + case getFuelAmount: + return new Object[] { (int) reactor.getFuelAmount() }; + case getWasteAmount: + return new Object[] { (int) reactor.getWasteAmount() }; + case getFuelAmountMax: + return new Object[] { reactor.getCapacity() }; + case getControlRodName: + if (arguments.length < 1) { + throw new IllegalArgumentException("Insufficient number of arguments, expected 1"); + } + + controlRod = getControlRodFromArguments(reactor, arguments, 0); + return new Object[] { controlRod.getName() }; + + case getControlRodLevel: + if (arguments.length < 1) { + throw new IllegalArgumentException("Insufficient number of arguments, expected 1"); + } + + controlRod = getControlRodFromArguments(reactor, arguments, 0); + return new Object[] { (int) controlRod.getControlRodInsertion() }; + + case getEnergyProducedLastTick: + return new Object[] { reactor.getEnergyGeneratedLastTick() }; + + case getHotFluidProducedLastTick: + if (reactor.isPassivelyCooled()) return new Object[] { 0f }; + else return new Object[] { reactor.getEnergyGeneratedLastTick() }; + + case isActivelyCooled: + return new Object[] { !reactor.isPassivelyCooled() }; + + case getCoolantAmount: + return new Object[] { reactor.getCoolantContainer() + .getCoolantAmount() }; + + case getCoolantAmountMax: + return new Object[] { reactor.getCoolantContainer() + .getCapacity() }; + + case getCoolantType: { + Fluid fluidType = reactor.getCoolantContainer() + .getCoolantType(); + if (fluidType == null) { + return null; + } else { + return new Object[] { fluidType.getName() }; + } + } + + case getHotFluidAmount: + return new Object[] { reactor.getCoolantContainer() + .getVaporAmount() }; + + case getHotFluidAmountMax: + return new Object[] { reactor.getCoolantContainer() + .getCapacity() }; + + case getHotFluidType: { + Fluid fluidType = reactor.getCoolantContainer() + .getVaporType(); + if (fluidType == null) { + return null; + } else { + return new Object[] { fluidType.getName() }; + } + } + + case getFuelReactivity: + return new Object[] { reactor.getFuelFertility() * 100f }; + + case getFuelConsumedLastTick: + return new Object[] { reactor.getFuelConsumedLastTick() }; + + case getMinimumCoordinate: { + CoordTriplet coord = reactor.getMinimumCoord(); + return new Object[] { coord.x, coord.y, coord.z }; + } + + case getMaximumCoordinate: { + CoordTriplet coord = reactor.getMaximumCoord(); + return new Object[] { coord.x, coord.y, coord.z }; + } + + case getControlRodLocation: { + if (arguments.length < 1) { + throw new IllegalArgumentException("Insufficient number of arguments, expected 1"); + } + + if (!(arguments[0] instanceof Double)) { + throw new IllegalArgumentException("Invalid argument 0, expected Number"); + } + + CoordTriplet rodCoord = getControlRodCoordFromArguments(reactor, arguments, 0); + CoordTriplet reactorMinCoord = reactor.getMinimumCoord(); + return new Object[] { rodCoord.x - reactorMinCoord.x, rodCoord.y - reactorMinCoord.y, + rodCoord.z - reactorMinCoord.z }; + } -@Optional.InterfaceList({ - @Optional.Interface(iface = "li.cil.oc.api.network.SimpleComponent", modid = "OpenComputers"), - @Optional.Interface(iface = "li.cil.oc.api.network.ManagedPeripheral", modid = "OpenComputers"), - @Optional.Interface(iface = "dan200.computercraft.api.peripheral.IPeripheral", modid = "ComputerCraft") -}) -public class TileEntityReactorComputerPort extends TileEntityReactorPart implements IPeripheral, SimpleComponent, ManagedPeripheral { - - public enum ComputerMethod { - getConnected, // No arguments - getActive, // No arguments - getFuelTemperature, // No arguments - getCasingTemperature, // No arguments - getEnergyStored, // No arguments - getFuelAmount, // No arguments - getWasteAmount, // No arguments - getFuelAmountMax, // No arguments - getControlRodName, // Required Arg: fuel rod index - getNumberOfControlRods, // No arguments - getControlRodLevel, // Required Arg: control rod index - getEnergyProducedLastTick, // No arguments - getHotFluidProducedLastTick, // No arguments - getCoolantAmount, // No arguments - getCoolantAmountMax, // No arguments - getCoolantType, // No arguments - getHotFluidAmount, // No arguments - getHotFluidAmountMax, // No arguments - getHotFluidType, // No arguments - getFuelReactivity, // No arguments - getFuelConsumedLastTick,// No arguments - getMinimumCoordinate, // No arguments - getMaximumCoordinate, // No arguments - getControlRodLocation, // Required Arg: integer (index) - isActivelyCooled, // No arguments - setActive, // Required Arg: integer (active) - setControlRodLevel, // Required Args: fuel rod index, integer (insertion) - setAllControlRodLevels, // Required Arg: integer (insertion) - setControlRodName, // Required Args: fuel rod index, string (name) - doEjectWaste, // No arguments - doEjectFuel // No arguments - } - - public static final int numMethods = ComputerMethod.values().length; - - public static final String[] methodNames = new String[numMethods]; - static { - ComputerMethod[] methods = ComputerMethod.values(); - for(ComputerMethod method : methods) { - methodNames[method.ordinal()] = method.toString(); - } - } - - public static final Map methodIds = new HashMap(); - static { - for (int i = 0; i < numMethods; ++i) { - methodIds.put(methodNames[i], i); - } - } - - public Object[] callMethod(int method, Object[] arguments) throws Exception { - if(method < 0 || method >= numMethods) { - throw new IllegalArgumentException("Invalid method number"); - } - - // Special case: getConnected can always be called. - if(method == 0) { - return new Object[] { this.isConnected() }; - } - - if(!this.isConnected()) { - throw new Exception("Unable to access reactor - port is not connected"); - } - MultiblockReactor reactor = this.getReactorController(); - - ComputerMethod computerMethod = ComputerMethod.values()[method]; - int index, newLevel; - boolean newState; - TileEntityReactorControlRod controlRod; - - switch(computerMethod) { - case getEnergyStored: - return new Object[] { (int)reactor.getEnergyStored() }; - case getNumberOfControlRods: - return new Object[] { (int)reactor.getFuelRodCount() }; - case getActive: - return new Object[] { reactor.getActive() }; - case getFuelTemperature: - return new Object[] { reactor.getFuelHeat() }; - case getCasingTemperature: - return new Object[] { reactor.getReactorHeat() }; - case getFuelAmount: - return new Object[] { (int)reactor.getFuelAmount() }; - case getWasteAmount: - return new Object[] { (int)reactor.getWasteAmount() }; - case getFuelAmountMax: - return new Object[] { reactor.getCapacity() }; - case getControlRodName: - if(arguments.length < 1) { - throw new IllegalArgumentException("Insufficient number of arguments, expected 1"); - } - - controlRod = getControlRodFromArguments(reactor, arguments, 0); - return new Object[] { controlRod.getName() }; - - case getControlRodLevel: - if(arguments.length < 1) { - throw new IllegalArgumentException("Insufficient number of arguments, expected 1"); - } - - controlRod = getControlRodFromArguments(reactor, arguments, 0); - return new Object[] { (int)controlRod.getControlRodInsertion() }; - - case getEnergyProducedLastTick: - return new Object[] { reactor.getEnergyGeneratedLastTick() }; - - case getHotFluidProducedLastTick: - if(reactor.isPassivelyCooled()) - return new Object[] { 0f }; - else - return new Object[] { reactor.getEnergyGeneratedLastTick() }; - - case isActivelyCooled: - return new Object[] { !reactor.isPassivelyCooled() }; - - case getCoolantAmount: - return new Object[] { reactor.getCoolantContainer().getCoolantAmount() }; - - case getCoolantAmountMax: - return new Object[] { reactor.getCoolantContainer().getCapacity() }; - - case getCoolantType: { - Fluid fluidType = reactor.getCoolantContainer().getCoolantType(); - if(fluidType == null) { - return null; - } - else { - return new Object[] { fluidType.getName() }; - } - } - - case getHotFluidAmount: - return new Object[] { reactor.getCoolantContainer().getVaporAmount() }; - - case getHotFluidAmountMax: - return new Object[] { reactor.getCoolantContainer().getCapacity() }; - - case getHotFluidType: { - Fluid fluidType = reactor.getCoolantContainer().getVaporType(); - if(fluidType == null) { - return null; - } - else { - return new Object[] { fluidType.getName() }; - } - } - - case getFuelReactivity: - return new Object[] { reactor.getFuelFertility() * 100f }; - - case getFuelConsumedLastTick: - return new Object[] { reactor.getFuelConsumedLastTick() }; - - case getMinimumCoordinate: - { - CoordTriplet coord = reactor.getMinimumCoord(); - return new Object[] { coord.x, coord.y, coord.z }; - } - - case getMaximumCoordinate: - { - CoordTriplet coord = reactor.getMaximumCoord(); - return new Object[] { coord.x, coord.y, coord.z }; - } - - case getControlRodLocation: - { - if(arguments.length < 1) { - throw new IllegalArgumentException("Insufficient number of arguments, expected 1"); - } - - if(!(arguments[0] instanceof Double)) { - throw new IllegalArgumentException("Invalid argument 0, expected Number"); - } - - CoordTriplet rodCoord = getControlRodCoordFromArguments(reactor, arguments, 0); - CoordTriplet reactorMinCoord = reactor.getMinimumCoord(); - return new Object[] { rodCoord.x - reactorMinCoord.x, - rodCoord.y - reactorMinCoord.y, - rodCoord.z - reactorMinCoord.z }; - } - - case setActive: - if(arguments.length < 1) { - throw new IllegalArgumentException("Insufficient number of arguments, expected 1"); - } - if(!(arguments[0] instanceof Boolean)) { - throw new IllegalArgumentException("Invalid argument 0, expected Boolean"); - } - newState = (Boolean)arguments[0]; - reactor.setActive(newState); - return null; - - case setAllControlRodLevels: - if(arguments.length < 1) { - throw new IllegalArgumentException("Insufficient number of arguments, expected 1"); - } - if(!(arguments[0] instanceof Double)) { - throw new IllegalArgumentException("Invalid argument 0, expected Number"); - } - newLevel = (int)Math.round((Double)arguments[0]); - reactor.setAllControlRodInsertionValues(newLevel); - return null; - - case setControlRodLevel: - if(arguments.length < 2) { - throw new IllegalArgumentException("Insufficient number of arguments, expected 2 (control rod index, level)"); - } - - if(!(arguments[1] instanceof Double)) { - throw new IllegalArgumentException("Invalid argument 0, expected Number"); - } - - newLevel = (int)Math.round((Double)arguments[1]); - if(newLevel < 0 || newLevel > 100) { - throw new IllegalArgumentException("Invalid argument 1, valid range is 0-100"); - } - - controlRod = getControlRodFromArguments(reactor, arguments, 0); - controlRod.setControlRodInsertion((short) newLevel); - - return null; - - case setControlRodName: - if(arguments.length < 2) { - throw new IllegalArgumentException("Insufficient number of arguments, expected 2 (control rod index, name)"); - } - - if(arguments[1] == null || !(arguments[1] instanceof String)) { - throw new IllegalArgumentException("Invalid argument 1, must be a non-null String"); - } - - controlRod = getControlRodFromArguments(reactor, arguments, 0); - controlRod.setName((String)arguments[1]);; - - return null; - - // "do" methods - void return, no inputs - case doEjectWaste: - reactor.ejectWaste(false, null); - return null; - case doEjectFuel: - reactor.ejectFuel(false, null); - return null; - - default: throw new Exception("Method unimplemented - yell at Beef"); - } - } - - private CoordTriplet getControlRodCoordFromArguments(MultiblockReactor reactor, Object[] arguments, int index) throws Exception { - if(!(arguments[index] instanceof Double)) { - throw new IllegalArgumentException(String.format("Invalid argument %d, expected Number", index)); - } - - int rodIndex = (int)Math.round((Double)arguments[index]); - - if(index < 0 || index >= reactor.getFuelRodCount()) { - throw new IndexOutOfBoundsException(String.format("Invalid argument %d, control rod index is out of bounds", index)); - } - - return reactor.getControlRodLocations()[rodIndex]; - } - - private TileEntityReactorControlRod getControlRodFromArguments(MultiblockReactor reactor, Object[] arguments, int index) throws Exception { - CoordTriplet coord = getControlRodCoordFromArguments(reactor, arguments, index); - - TileEntity te = worldObj.getTileEntity(coord.x, coord.y, coord.z); - if(!(te instanceof TileEntityReactorControlRod)) { - throw new Exception("Encountered an invalid tile entity when seeking a control rod. That's weird."); - } - - return (TileEntityReactorControlRod)te; - } - - // ComputerCraft - - @Override - @Optional.Method(modid = "ComputerCraft") - public String getType() { - return "BigReactors-Reactor"; - } - - @Override - @Optional.Method(modid = "ComputerCraft") - public String[] getMethodNames() { - return methodNames; - } - - @Override - @Optional.Method(modid = "ComputerCraft") - public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) throws LuaException { + case setActive: + if (arguments.length < 1) { + throw new IllegalArgumentException("Insufficient number of arguments, expected 1"); + } + if (!(arguments[0] instanceof Boolean)) { + throw new IllegalArgumentException("Invalid argument 0, expected Boolean"); + } + newState = (Boolean) arguments[0]; + reactor.setActive(newState); + return null; + + case setAllControlRodLevels: + if (arguments.length < 1) { + throw new IllegalArgumentException("Insufficient number of arguments, expected 1"); + } + if (!(arguments[0] instanceof Double)) { + throw new IllegalArgumentException("Invalid argument 0, expected Number"); + } + newLevel = (int) Math.round((Double) arguments[0]); + reactor.setAllControlRodInsertionValues(newLevel); + return null; + + case setControlRodLevel: + if (arguments.length < 2) { + throw new IllegalArgumentException( + "Insufficient number of arguments, expected 2 (control rod index, level)"); + } + + if (!(arguments[1] instanceof Double)) { + throw new IllegalArgumentException("Invalid argument 0, expected Number"); + } + + newLevel = (int) Math.round((Double) arguments[1]); + if (newLevel < 0 || newLevel > 100) { + throw new IllegalArgumentException("Invalid argument 1, valid range is 0-100"); + } + + controlRod = getControlRodFromArguments(reactor, arguments, 0); + controlRod.setControlRodInsertion((short) newLevel); + + return null; + + case setControlRodName: + if (arguments.length < 2) { + throw new IllegalArgumentException( + "Insufficient number of arguments, expected 2 (control rod index, name)"); + } + + if (arguments[1] == null || !(arguments[1] instanceof String)) { + throw new IllegalArgumentException("Invalid argument 1, must be a non-null String"); + } + + controlRod = getControlRodFromArguments(reactor, arguments, 0); + controlRod.setName((String) arguments[1]);; + + return null; + + // "do" methods - void return, no inputs + case doEjectWaste: + reactor.ejectWaste(false, null); + return null; + case doEjectFuel: + reactor.ejectFuel(false, null); + return null; + + default: + throw new Exception("Method unimplemented - yell at Beef"); + } + } + + private CoordTriplet getControlRodCoordFromArguments(MultiblockReactor reactor, Object[] arguments, int index) + throws Exception { + if (!(arguments[index] instanceof Double)) { + throw new IllegalArgumentException(String.format("Invalid argument %d, expected Number", index)); + } + + int rodIndex = (int) Math.round((Double) arguments[index]); + + if (index < 0 || index >= reactor.getFuelRodCount()) { + throw new IndexOutOfBoundsException( + String.format("Invalid argument %d, control rod index is out of bounds", index)); + } + + return reactor.getControlRodLocations()[rodIndex]; + } + + private TileEntityReactorControlRod getControlRodFromArguments(MultiblockReactor reactor, Object[] arguments, + int index) throws Exception { + CoordTriplet coord = getControlRodCoordFromArguments(reactor, arguments, index); + + TileEntity te = worldObj.getTileEntity(coord.x, coord.y, coord.z); + if (!(te instanceof TileEntityReactorControlRod)) { + throw new Exception("Encountered an invalid tile entity when seeking a control rod. That's weird."); + } + + return (TileEntityReactorControlRod) te; + } + + // ComputerCraft + + @Override + @Optional.Method(modid = "ComputerCraft") + public String getType() { + return "BigReactors-Reactor"; + } + + @Override + @Optional.Method(modid = "ComputerCraft") + public String[] getMethodNames() { + return methodNames; + } + + @Override + @Optional.Method(modid = "ComputerCraft") + public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) + throws LuaException { try { return callMethod(method, arguments); - } catch(Exception e) { - // Rethrow errors as LuaExceptions for CC - throw new LuaException(e.getMessage()); + } catch (Exception e) { + // Rethrow errors as LuaExceptions for CC + throw new LuaException(e.getMessage()); + } + } + + @Override + @Optional.Method(modid = "ComputerCraft") + public void attach(IComputerAccess computer) {} + + @Override + @Optional.Method(modid = "ComputerCraft") + public void detach(IComputerAccess computer) {} + + // OpenComputers + + @Override + @Optional.Method(modid = "OpenComputers") + public String getComponentName() { + // Convention for OC names is a) lower case, b) valid variable names, + // so this can be used as `component.br_reactor.setActive(true)` e.g. + return "br_reactor"; + } + + @Override + @Optional.Method(modid = "OpenComputers") + public String[] methods() { + return methodNames; + } + + @Override + @Optional.Method(modid = "OpenComputers") + public Object[] invoke(final String method, final Context context, final Arguments args) throws Exception { + final Object[] arguments = new Object[args.count()]; + for (int i = 0; i < args.count(); ++i) { + arguments[i] = args.checkAny(i); + } + final Integer methodId = methodIds.get(method); + if (methodId == null) { + throw new NoSuchMethodError(); } + return callMethod(methodId, arguments); + } + + @Override + @Optional.Method(modid = "ComputerCraft") + public boolean equals(IPeripheral other) { + return hashCode() == other.hashCode(); } - - @Override - @Optional.Method(modid = "ComputerCraft") - public void attach(IComputerAccess computer) { - } - - @Override - @Optional.Method(modid = "ComputerCraft") - public void detach(IComputerAccess computer) { - } - - // OpenComputers - - @Override - @Optional.Method(modid = "OpenComputers") - public String getComponentName() { - // Convention for OC names is a) lower case, b) valid variable names, - // so this can be used as `component.br_reactor.setActive(true)` e.g. - return "br_reactor"; - } - - @Override - @Optional.Method(modid = "OpenComputers") - public String[] methods() { - return methodNames; - } - - @Override - @Optional.Method(modid = "OpenComputers") - public Object[] invoke(final String method, final Context context, - final Arguments args) throws Exception { - final Object[] arguments = new Object[args.count()]; - for (int i = 0; i < args.count(); ++i) { - arguments[i] = args.checkAny(i); - } - final Integer methodId = methodIds.get(method); - if (methodId == null) { - throw new NoSuchMethodError(); - } - return callMethod(methodId, arguments); - } - - @Override - @Optional.Method(modid = "ComputerCraft") - public boolean equals(IPeripheral other) { - return hashCode() == other.hashCode(); - } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorControlRod.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorControlRod.java index 9776cf86..eeff36fb 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorControlRod.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorControlRod.java @@ -3,6 +3,7 @@ import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; + import cpw.mods.fml.common.network.NetworkRegistry; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -13,163 +14,182 @@ import erogenousbeef.core.multiblock.MultiblockValidationException; public class TileEntityReactorControlRod extends TileEntityReactorPart { - public final static short maxInsertion = 100; - public final static short minInsertion = 0; - - // Radiation - protected short controlRodInsertion; // 0 = retracted fully, 100 = inserted fully - - // User settings - protected String name; - - public TileEntityReactorControlRod() { - super(); - - controlRodInsertion = minInsertion; - name = ""; - } - - // Data accessors - public short getControlRodInsertion() { - return this.controlRodInsertion; - } - - public void setControlRodInsertion(short newInsertion) { - if(newInsertion > maxInsertion || newInsertion < minInsertion || newInsertion == controlRodInsertion) { return; } - if(!isConnected()) { return; } - - this.controlRodInsertion = (short)Math.max(Math.min(newInsertion, maxInsertion), minInsertion); - this.sendControlRodUpdate(); - } - - public void setName(String newName) { - if(this.name.equals(newName)) { return; } - - this.name = newName; - if(!this.worldObj.isRemote) { - this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - } - - public String getName() { - return this.name; - } - - // Network Messages - public void onClientControlRodChange(int amount) { - setControlRodInsertion((short)(this.controlRodInsertion + amount)); - } - - protected void sendControlRodUpdate() { - if(this.worldObj == null || this.worldObj.isRemote) { return; } - - CommonPacketHandler.INSTANCE.sendToAllAround(new ControlRodUpdateMessage(xCoord, yCoord, zCoord, controlRodInsertion), new NetworkRegistry.TargetPoint(worldObj.provider.dimensionId, xCoord, yCoord, zCoord, 50)); - } - - @SideOnly(Side.CLIENT) - public void onControlRodUpdate(short controlRodInsertion) { - this.controlRodInsertion = controlRodInsertion; - } - - // TileEntity overrides - @Override - public void readFromNBT(NBTTagCompound data) { - super.readFromNBT(data); - this.readLocalDataFromNBT(data); - } - - @Override - public void writeToNBT(NBTTagCompound data) { - super.writeToNBT(data); - this.writeLocalDataToNBT(data); - } - - // IMultiblockGuiHandler - /** - * @return The Container object for use by the GUI. Null if there isn't any. - */ - @Override - public Object getContainer(InventoryPlayer inventoryPlayer) { - return new ContainerBasic(); - } - - @SideOnly(Side.CLIENT) - @Override - public Object getGuiElement(InventoryPlayer inventoryPlayer) { - return new GuiReactorControlRod(new ContainerBasic(), this); - } - - // TileEntityReactorPart - @Override - public void isGoodForFrame() throws MultiblockValidationException { - throw new MultiblockValidationException(String.format("%d, %d, %d - Control rods may only be placed on the top face", xCoord, yCoord, zCoord)); - } - - @Override - public void isGoodForSides() throws MultiblockValidationException { - throw new MultiblockValidationException(String.format("%d, %d, %d - Control rods may only be placed on the top face", xCoord, yCoord, zCoord)); - } - - @Override - public void isGoodForTop() throws MultiblockValidationException { - // Check that the space below us is a fuel rod - TileEntity teBelow = this.worldObj.getTileEntity(xCoord, yCoord - 1, zCoord); - if(!(teBelow instanceof TileEntityReactorFuelRod)) { - throw new MultiblockValidationException(String.format("%d, %d, %d - Control rods may only be placed on the top face, atop a column of fuel rods", xCoord, yCoord, zCoord)); - } - } - - @Override - public void isGoodForBottom() throws MultiblockValidationException { - throw new MultiblockValidationException(String.format("%d, %d, %d - Control rods may only be placed on the top face", xCoord, yCoord, zCoord)); - } - - @Override - public void isGoodForInterior() throws MultiblockValidationException { - throw new MultiblockValidationException(String.format("%d, %d, %d - Control rods may only be placed on the top face", xCoord, yCoord, zCoord)); - } - - @Override - protected void encodeDescriptionPacket(NBTTagCompound packet) { - super.encodeDescriptionPacket(packet); - NBTTagCompound localData = new NBTTagCompound(); - this.writeLocalDataToNBT(localData); - packet.setTag("reactorControlRod", localData); - } - - @Override - protected void decodeDescriptionPacket(NBTTagCompound packet) { - super.decodeDescriptionPacket(packet); - - if(packet.hasKey("reactorControlRod")) { - NBTTagCompound localData = packet.getCompoundTag("reactorControlRod"); - this.readLocalDataFromNBT(localData); - - if(worldObj != null && worldObj.isRemote) { - this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - } - } - - // Save/Load Helpers - private void readLocalDataFromNBT(NBTTagCompound data) { - if(data.hasKey("controlRodInsertion")) { - this.controlRodInsertion = data.getShort("controlRodInsertion"); - } - - if(data.hasKey("name")) { - this.name = data.getString("name"); - } - else { - this.name = ""; - } - } - - private void writeLocalDataToNBT(NBTTagCompound data) { - data.setShort("controlRodInsertion", controlRodInsertion); - - if(!this.name.isEmpty()) { - data.setString("name", this.name); - } - } + + public final static short maxInsertion = 100; + public final static short minInsertion = 0; + + // Radiation + protected short controlRodInsertion; // 0 = retracted fully, 100 = inserted fully + + // User settings + protected String name; + + public TileEntityReactorControlRod() { + super(); + + controlRodInsertion = minInsertion; + name = ""; + } + + // Data accessors + public short getControlRodInsertion() { + return this.controlRodInsertion; + } + + public void setControlRodInsertion(short newInsertion) { + if (newInsertion > maxInsertion || newInsertion < minInsertion || newInsertion == controlRodInsertion) { + return; + } + if (!isConnected()) { + return; + } + + this.controlRodInsertion = (short) Math.max(Math.min(newInsertion, maxInsertion), minInsertion); + this.sendControlRodUpdate(); + } + + public void setName(String newName) { + if (this.name.equals(newName)) { + return; + } + + this.name = newName; + if (!this.worldObj.isRemote) { + this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + } + + public String getName() { + return this.name; + } + + // Network Messages + public void onClientControlRodChange(int amount) { + setControlRodInsertion((short) (this.controlRodInsertion + amount)); + } + + protected void sendControlRodUpdate() { + if (this.worldObj == null || this.worldObj.isRemote) { + return; + } + + CommonPacketHandler.INSTANCE.sendToAllAround( + new ControlRodUpdateMessage(xCoord, yCoord, zCoord, controlRodInsertion), + new NetworkRegistry.TargetPoint(worldObj.provider.dimensionId, xCoord, yCoord, zCoord, 50)); + } + + @SideOnly(Side.CLIENT) + public void onControlRodUpdate(short controlRodInsertion) { + this.controlRodInsertion = controlRodInsertion; + } + + // TileEntity overrides + @Override + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + this.readLocalDataFromNBT(data); + } + + @Override + public void writeToNBT(NBTTagCompound data) { + super.writeToNBT(data); + this.writeLocalDataToNBT(data); + } + + // IMultiblockGuiHandler + /** + * @return The Container object for use by the GUI. Null if there isn't any. + */ + @Override + public Object getContainer(InventoryPlayer inventoryPlayer) { + return new ContainerBasic(); + } + + @SideOnly(Side.CLIENT) + @Override + public Object getGuiElement(InventoryPlayer inventoryPlayer) { + return new GuiReactorControlRod(new ContainerBasic(), this); + } + + // TileEntityReactorPart + @Override + public void isGoodForFrame() throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%d, %d, %d - Control rods may only be placed on the top face", xCoord, yCoord, zCoord)); + } + + @Override + public void isGoodForSides() throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%d, %d, %d - Control rods may only be placed on the top face", xCoord, yCoord, zCoord)); + } + + @Override + public void isGoodForTop() throws MultiblockValidationException { + // Check that the space below us is a fuel rod + TileEntity teBelow = this.worldObj.getTileEntity(xCoord, yCoord - 1, zCoord); + if (!(teBelow instanceof TileEntityReactorFuelRod)) { + throw new MultiblockValidationException( + String.format( + "%d, %d, %d - Control rods may only be placed on the top face, atop a column of fuel rods", + xCoord, + yCoord, + zCoord)); + } + } + + @Override + public void isGoodForBottom() throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%d, %d, %d - Control rods may only be placed on the top face", xCoord, yCoord, zCoord)); + } + + @Override + public void isGoodForInterior() throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%d, %d, %d - Control rods may only be placed on the top face", xCoord, yCoord, zCoord)); + } + + @Override + protected void encodeDescriptionPacket(NBTTagCompound packet) { + super.encodeDescriptionPacket(packet); + NBTTagCompound localData = new NBTTagCompound(); + this.writeLocalDataToNBT(localData); + packet.setTag("reactorControlRod", localData); + } + + @Override + protected void decodeDescriptionPacket(NBTTagCompound packet) { + super.decodeDescriptionPacket(packet); + + if (packet.hasKey("reactorControlRod")) { + NBTTagCompound localData = packet.getCompoundTag("reactorControlRod"); + this.readLocalDataFromNBT(localData); + + if (worldObj != null && worldObj.isRemote) { + this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + } + } + + // Save/Load Helpers + private void readLocalDataFromNBT(NBTTagCompound data) { + if (data.hasKey("controlRodInsertion")) { + this.controlRodInsertion = data.getShort("controlRodInsertion"); + } + + if (data.hasKey("name")) { + this.name = data.getString("name"); + } else { + this.name = ""; + } + } + + private void writeLocalDataToNBT(NBTTagCompound data) { + data.setShort("controlRodInsertion", controlRodInsertion); + + if (!this.name.isEmpty()) { + data.setString("name", this.name); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorCoolantPort.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorCoolantPort.java index f2429abc..64b0a025 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorCoolantPort.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorCoolantPort.java @@ -10,213 +10,226 @@ import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTankInfo; import net.minecraftforge.fluids.IFluidHandler; + import erogenousbeef.bigreactors.common.multiblock.helpers.CoolantContainer; import erogenousbeef.bigreactors.common.multiblock.interfaces.INeighborUpdatableEntity; import erogenousbeef.bigreactors.common.multiblock.interfaces.ITickableMultiblockPart; import erogenousbeef.core.multiblock.MultiblockControllerBase; -public class TileEntityReactorCoolantPort extends TileEntityReactorPart implements IFluidHandler, INeighborUpdatableEntity, ITickableMultiblockPart { - - boolean inlet; - IFluidHandler pumpDestination; - - public TileEntityReactorCoolantPort() { - super(); - - inlet = true; - pumpDestination = null; - } - - public boolean isInlet() { return inlet; } - - public void setInlet(boolean shouldBeInlet, boolean markDirty) { - if(inlet == shouldBeInlet) { return; } - - inlet = shouldBeInlet; - worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - - if(!worldObj.isRemote) { - if(!inlet) { - checkForAdjacentTank(); - } - - if(markDirty) { - markDirty(); - } - else { - notifyNeighborsOfTileChange(); - } - } - else { - notifyNeighborsOfTileChange(); - } - } - - // MultiblockTileEntityBase - @Override - protected void encodeDescriptionPacket(NBTTagCompound packetData) { - super.encodeDescriptionPacket(packetData); - - packetData.setBoolean("inlet", inlet); - } - - @Override - protected void decodeDescriptionPacket(NBTTagCompound packetData) { - super.decodeDescriptionPacket(packetData); - - if(packetData.hasKey("inlet")) { - setInlet(packetData.getBoolean("inlet"), false); - } - } - - @Override - public void onMachineAssembled(MultiblockControllerBase multiblockControllerBase) - { - super.onMachineAssembled(multiblockControllerBase); - checkForAdjacentTank(); - - this.notifyNeighborsOfTileChange(); - - // Re-render on the client - if(worldObj.isRemote) { - worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - } - - @Override - public void onMachineBroken() - { - super.onMachineBroken(); - pumpDestination = null; - - if(worldObj.isRemote) { - worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - } - - // TileEntity - @Override - public void readFromNBT(NBTTagCompound tag) { - super.readFromNBT(tag); - - if(tag.hasKey("inlet")) { - inlet = tag.getBoolean("inlet"); - } - } - - @Override - public void writeToNBT(NBTTagCompound tag) { - super.writeToNBT(tag); - tag.setBoolean("inlet", inlet); - } - - // IFluidHandler - @Override - public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { - if(!isConnected() || !inlet || from != getOutwardsDir()) { return 0; } - - CoolantContainer cc = getReactorController().getCoolantContainer(); - return cc.fill(getConnectedTank(), resource, doFill); - } - - @Override - public FluidStack drain(ForgeDirection from, FluidStack resource, - boolean doDrain) { - if(!isConnected() || from != getOutwardsDir()) { return null; } - - CoolantContainer cc = getReactorController().getCoolantContainer(); - return cc.drain(getConnectedTank(), resource, doDrain); - } - - @Override - public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) { - if(!isConnected() || from != getOutwardsDir()) { return null; } - CoolantContainer cc = getReactorController().getCoolantContainer(); - return cc.drain(getConnectedTank(), maxDrain, doDrain); - } - - @Override - public boolean canFill(ForgeDirection from, Fluid fluid) { - if(!isConnected() || from != getOutwardsDir()) { return false; } - - if(!inlet) { return false; } // Prevent pipes from filling up the output tank inadvertently - - CoolantContainer cc = getReactorController().getCoolantContainer(); - return cc.canFill(getConnectedTank(), fluid); - } - - @Override - public boolean canDrain(ForgeDirection from, Fluid fluid) { - if(!isConnected() || from != getOutwardsDir()) { return false; } - CoolantContainer cc = getReactorController().getCoolantContainer(); - return cc.canDrain(getConnectedTank(), fluid); - } - - private static FluidTankInfo[] emptyTankArray = new FluidTankInfo[0]; - - @Override - public FluidTankInfo[] getTankInfo(ForgeDirection from) { - if(!isConnected() || from != getOutwardsDir()) { return emptyTankArray; } - - CoolantContainer cc = getReactorController().getCoolantContainer(); - return cc.getTankInfo(getConnectedTank()); - } - - // ITickableMultiblockPart - - @Override - public void onMultiblockServerTick() { - // Try to pump steam out, if an outlet - if(pumpDestination == null || isInlet()) - return; - - CoolantContainer cc = getReactorController().getCoolantContainer(); - FluidStack fluidToDrain = cc.drain(CoolantContainer.HOT, cc.getCapacity(), false); - - if(fluidToDrain != null && fluidToDrain.amount > 0) - { - fluidToDrain.amount = pumpDestination.fill(getOutwardsDir().getOpposite(), fluidToDrain, true); - cc.drain(CoolantContainer.HOT, fluidToDrain, true); - } - } - - // INeighborUpdatableEntity - @Override - public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock) { - checkForAdjacentTank(); - } - - @Override - public void onNeighborTileChange(IBlockAccess world, int x, int y, int z, int neighborX, int neighborY, int neighborZ) { - checkForAdjacentTank(); - } - - // Private Helpers - private int getConnectedTank() { - if(inlet) { - return CoolantContainer.COLD; - } - else { - return CoolantContainer.HOT; - } - } - - protected void checkForAdjacentTank() - { - pumpDestination = null; - if(worldObj.isRemote || isInlet()) { - return; - } - - ForgeDirection outDir = getOutwardsDir(); - if(outDir == ForgeDirection.UNKNOWN) { - return; - } - - TileEntity neighbor = worldObj.getTileEntity(xCoord + outDir.offsetX, yCoord + outDir.offsetY, zCoord + outDir.offsetZ); - if(neighbor instanceof IFluidHandler) { - pumpDestination = (IFluidHandler)neighbor; - } - } +public class TileEntityReactorCoolantPort extends TileEntityReactorPart + implements IFluidHandler, INeighborUpdatableEntity, ITickableMultiblockPart { + + boolean inlet; + IFluidHandler pumpDestination; + + public TileEntityReactorCoolantPort() { + super(); + + inlet = true; + pumpDestination = null; + } + + public boolean isInlet() { + return inlet; + } + + public void setInlet(boolean shouldBeInlet, boolean markDirty) { + if (inlet == shouldBeInlet) { + return; + } + + inlet = shouldBeInlet; + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + + if (!worldObj.isRemote) { + if (!inlet) { + checkForAdjacentTank(); + } + + if (markDirty) { + markDirty(); + } else { + notifyNeighborsOfTileChange(); + } + } else { + notifyNeighborsOfTileChange(); + } + } + + // MultiblockTileEntityBase + @Override + protected void encodeDescriptionPacket(NBTTagCompound packetData) { + super.encodeDescriptionPacket(packetData); + + packetData.setBoolean("inlet", inlet); + } + + @Override + protected void decodeDescriptionPacket(NBTTagCompound packetData) { + super.decodeDescriptionPacket(packetData); + + if (packetData.hasKey("inlet")) { + setInlet(packetData.getBoolean("inlet"), false); + } + } + + @Override + public void onMachineAssembled(MultiblockControllerBase multiblockControllerBase) { + super.onMachineAssembled(multiblockControllerBase); + checkForAdjacentTank(); + + this.notifyNeighborsOfTileChange(); + + // Re-render on the client + if (worldObj.isRemote) { + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + } + + @Override + public void onMachineBroken() { + super.onMachineBroken(); + pumpDestination = null; + + if (worldObj.isRemote) { + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + } + + // TileEntity + @Override + public void readFromNBT(NBTTagCompound tag) { + super.readFromNBT(tag); + + if (tag.hasKey("inlet")) { + inlet = tag.getBoolean("inlet"); + } + } + + @Override + public void writeToNBT(NBTTagCompound tag) { + super.writeToNBT(tag); + tag.setBoolean("inlet", inlet); + } + + // IFluidHandler + @Override + public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { + if (!isConnected() || !inlet || from != getOutwardsDir()) { + return 0; + } + + CoolantContainer cc = getReactorController().getCoolantContainer(); + return cc.fill(getConnectedTank(), resource, doFill); + } + + @Override + public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain) { + if (!isConnected() || from != getOutwardsDir()) { + return null; + } + + CoolantContainer cc = getReactorController().getCoolantContainer(); + return cc.drain(getConnectedTank(), resource, doDrain); + } + + @Override + public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) { + if (!isConnected() || from != getOutwardsDir()) { + return null; + } + CoolantContainer cc = getReactorController().getCoolantContainer(); + return cc.drain(getConnectedTank(), maxDrain, doDrain); + } + + @Override + public boolean canFill(ForgeDirection from, Fluid fluid) { + if (!isConnected() || from != getOutwardsDir()) { + return false; + } + + if (!inlet) { + return false; + } // Prevent pipes from filling up the output tank inadvertently + + CoolantContainer cc = getReactorController().getCoolantContainer(); + return cc.canFill(getConnectedTank(), fluid); + } + + @Override + public boolean canDrain(ForgeDirection from, Fluid fluid) { + if (!isConnected() || from != getOutwardsDir()) { + return false; + } + CoolantContainer cc = getReactorController().getCoolantContainer(); + return cc.canDrain(getConnectedTank(), fluid); + } + + private static FluidTankInfo[] emptyTankArray = new FluidTankInfo[0]; + + @Override + public FluidTankInfo[] getTankInfo(ForgeDirection from) { + if (!isConnected() || from != getOutwardsDir()) { + return emptyTankArray; + } + + CoolantContainer cc = getReactorController().getCoolantContainer(); + return cc.getTankInfo(getConnectedTank()); + } + + // ITickableMultiblockPart + + @Override + public void onMultiblockServerTick() { + // Try to pump steam out, if an outlet + if (pumpDestination == null || isInlet()) return; + + CoolantContainer cc = getReactorController().getCoolantContainer(); + FluidStack fluidToDrain = cc.drain(CoolantContainer.HOT, cc.getCapacity(), false); + + if (fluidToDrain != null && fluidToDrain.amount > 0) { + fluidToDrain.amount = pumpDestination.fill(getOutwardsDir().getOpposite(), fluidToDrain, true); + cc.drain(CoolantContainer.HOT, fluidToDrain, true); + } + } + + // INeighborUpdatableEntity + @Override + public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock) { + checkForAdjacentTank(); + } + + @Override + public void onNeighborTileChange(IBlockAccess world, int x, int y, int z, int neighborX, int neighborY, + int neighborZ) { + checkForAdjacentTank(); + } + + // Private Helpers + private int getConnectedTank() { + if (inlet) { + return CoolantContainer.COLD; + } else { + return CoolantContainer.HOT; + } + } + + protected void checkForAdjacentTank() { + pumpDestination = null; + if (worldObj.isRemote || isInlet()) { + return; + } + + ForgeDirection outDir = getOutwardsDir(); + if (outDir == ForgeDirection.UNKNOWN) { + return; + } + + TileEntity neighbor = worldObj + .getTileEntity(xCoord + outDir.offsetX, yCoord + outDir.offsetY, zCoord + outDir.offsetZ); + if (neighbor instanceof IFluidHandler) { + pumpDestination = (IFluidHandler) neighbor; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorFuelRod.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorFuelRod.java index 39ddb439..8366ee61 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorFuelRod.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorFuelRod.java @@ -7,6 +7,7 @@ import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.IFluidBlock; + import cofh.lib.util.helpers.ItemHelper; import erogenousbeef.bigreactors.api.IHeatEntity; import erogenousbeef.bigreactors.api.IRadiationModerator; @@ -22,192 +23,210 @@ public class TileEntityReactorFuelRod extends TileEntityReactorPartBase implements IRadiationModerator, IHeatEntity { - public TileEntityReactorFuelRod() { - super(); - } - - // IRadiationModerator - @Override - public void moderateRadiation(RadiationData data, RadiationPacket radiation) { - if(!isConnected()) { return; } - - // Grab control rod insertion and reactor heat - MultiblockReactor reactor = getReactorController(); - float heat = reactor.getFuelHeat(); - - int maxY = reactor.getMaximumCoord().y; - TileEntity te = worldObj.getTileEntity(xCoord, maxY, zCoord); - if(!(te instanceof TileEntityReactorControlRod)) { - return; - } - - // Scale control rod insertion 0..1 - float controlRodInsertion = Math.min(1f, Math.max(0f, ((float)((TileEntityReactorControlRod)te).getControlRodInsertion())/100f)); - - // Fuel absorptiveness is determined by control rod + a heat modifier. - // Starts at 1 and decays towards 0.05, reaching 0.6 at 1000 and just under 0.2 at 2000. Inflection point at about 500-600. - // Harder radiation makes absorption more difficult. - float baseAbsorption = (float)(1.0 - (0.95 * Math.exp(-10 * Math.exp(-0.0022 * heat)))) * (1f - (radiation.hardness / getFuelHardnessDivisor())); - - // Some fuels are better at absorbing radiation than others - float scaledAbsorption = Math.min(1f, baseAbsorption * getFuelAbsorptionCoefficient()); - - // Control rods increase total neutron absorption, but decrease the total neutrons which fertilize the fuel - // Absorb up to 50% better with control rods inserted. - float controlRodBonus = (1f - scaledAbsorption) * controlRodInsertion * 0.5f; - float controlRodPenalty = scaledAbsorption * controlRodInsertion * 0.5f; - - float radiationAbsorbed = (scaledAbsorption + controlRodBonus) * radiation.intensity; - float fertilityAbsorbed = (scaledAbsorption - controlRodPenalty) * radiation.intensity; - - float fuelModerationFactor = getFuelModerationFactor(); - fuelModerationFactor += fuelModerationFactor * controlRodInsertion + controlRodInsertion; // Full insertion doubles the moderation factor of the fuel as well as adding its own level - - radiation.intensity = Math.max(0f, radiation.intensity - radiationAbsorbed); - radiation.hardness /= fuelModerationFactor; - - // Being irradiated both heats up the fuel and also enhances its fertility - data.fuelRfChange += radiationAbsorbed * RadiationHelper.rfPerRadiationUnit; - data.fuelAbsorbedRadiation += fertilityAbsorbed; - } - - // 1, upwards. How well does this fuel moderate, but not stop, radiation? Anything under 1.5 is "poor", 2-2.5 is "good", above 4 is "excellent". - private float getFuelModerationFactor() { - return 1.5f; - } - - // 0..1. How well does this fuel absorb radiation? - private float getFuelAbsorptionCoefficient() { - // TODO: Lookup type of fuel and get data from there - return 0.5f; - } - - // Goes up from 1. How tolerant is this fuel of hard radiation? - private float getFuelHardnessDivisor() { - return 1.0f; - } - - // IHeatEntity - @Override - public float getThermalConductivity() { - return IHeatEntity.conductivityCopper; - } - - // RectangularMultiblockTileEntityBase - @Override - public void isGoodForFrame() throws MultiblockValidationException { - throw new MultiblockValidationException(String.format("%d, %d, %d - fuel rods may only be placed in the reactor interior", xCoord, yCoord, zCoord)); - } - - @Override - public void isGoodForSides() throws MultiblockValidationException { - throw new MultiblockValidationException(String.format("%d, %d, %d - fuel rods may only be placed in the reactor interior", xCoord, yCoord, zCoord)); - } - - @Override - public void isGoodForTop() throws MultiblockValidationException { - throw new MultiblockValidationException(String.format("%d, %d, %d - fuel rods may only be placed in the reactor interior", xCoord, yCoord, zCoord)); - } - - @Override - public void isGoodForBottom() throws MultiblockValidationException { - throw new MultiblockValidationException(String.format("%d, %d, %d - fuel rods may only be placed in the reactor interior", xCoord, yCoord, zCoord)); - } - - @Override - public void isGoodForInterior() throws MultiblockValidationException { - // Check above and below. Above must be fuel rod or control rod. - TileEntity entityAbove = this.worldObj.getTileEntity(xCoord, yCoord + 1, zCoord); - if(!(entityAbove instanceof TileEntityReactorFuelRod || entityAbove instanceof TileEntityReactorControlRod)) { - throw new MultiblockValidationException(String.format("Fuel rod at %d, %d, %d must be part of a vertical column that reaches the entire height of the reactor, with a control rod on top.", xCoord, yCoord, zCoord)); - } - - // Below must be fuel rod or the base of the reactor. - TileEntity entityBelow = this.worldObj.getTileEntity(xCoord, yCoord - 1, zCoord); - if(entityBelow instanceof TileEntityReactorFuelRod) { - return; - } - else if(entityBelow instanceof RectangularMultiblockTileEntityBase) { - ((RectangularMultiblockTileEntityBase)entityBelow).isGoodForBottom(); - return; - } - - throw new MultiblockValidationException(String.format("Fuel rod at %d, %d, %d must be part of a vertical column that reaches the entire height of the reactor, with a control rod on top.", xCoord, yCoord, zCoord)); - } - - @Override - public void onMachineActivated() { - } - - @Override - public void onMachineDeactivated() { - } - - // Reactor information retrieval methods - - /** - * Returns the rate of heat transfer from this block to the reactor environment, based on this block's surrounding blocks. - * Note that this method queries the world, so use it sparingly. - * - * @return Heat transfer rate from fuel rod to reactor environment, in Centigrade per tick. - */ - public float getHeatTransferRate() { - float heatTransferRate = 0f; - - TileEntity te; - for(ForgeDirection dir: StaticUtils.CardinalDirections) { - te = worldObj.getTileEntity(xCoord + dir.offsetX, yCoord + dir.offsetY, zCoord + dir.offsetZ); - if(te instanceof TileEntityReactorFuelRod) { - // We don't transfer to other fuel rods, due to heat pooling. - continue; - } - else if(te instanceof IHeatEntity) { - heatTransferRate += ((IHeatEntity)te).getThermalConductivity(); - } - else if(worldObj.isAirBlock(xCoord + dir.offsetX, yCoord + dir.offsetY, zCoord + dir.offsetZ)) { - heatTransferRate += IHeatEntity.conductivityAir; - } - else { - - Block block = worldObj.getBlock(xCoord + dir.offsetX, yCoord + dir.offsetY, zCoord + dir.offsetZ); - int metadata = worldObj.getBlockMetadata(xCoord + dir.offsetX, yCoord + dir.offsetY, zCoord + dir.offsetZ); - heatTransferRate += getConductivityFromBlock(block, metadata); - } - } - - return heatTransferRate; - } - - private float getConductivityFromBlock(Block block, int metadata) { - ReactorInteriorData interiorData = null; - - if(block == Blocks.iron_block) { - interiorData = ReactorInterior.getBlockData("blockIron"); - } - else if(block == Blocks.gold_block) { - interiorData = ReactorInterior.getBlockData("blockGold"); - } - else if(block == Blocks.diamond_block) { - interiorData = ReactorInterior.getBlockData("blockDiamond"); - } - else if(block == Blocks.emerald_block) { - interiorData = ReactorInterior.getBlockData("blockEmerald"); - } - else { - interiorData = ReactorInterior.getBlockData(ItemHelper.oreProxy.getOreName(new ItemStack(block, 1, metadata))); - - if(interiorData == null && block instanceof IFluidBlock) { - Fluid fluid = ((IFluidBlock)block).getFluid(); - if(fluid != null) { - interiorData = ReactorInterior.getFluidData(fluid.getName()); - } - } - } - - if(interiorData == null) { - interiorData = RadiationHelper.airData; - } - - return interiorData.heatConductivity; - } + public TileEntityReactorFuelRod() { + super(); + } + + // IRadiationModerator + @Override + public void moderateRadiation(RadiationData data, RadiationPacket radiation) { + if (!isConnected()) { + return; + } + + // Grab control rod insertion and reactor heat + MultiblockReactor reactor = getReactorController(); + float heat = reactor.getFuelHeat(); + + int maxY = reactor.getMaximumCoord().y; + TileEntity te = worldObj.getTileEntity(xCoord, maxY, zCoord); + if (!(te instanceof TileEntityReactorControlRod)) { + return; + } + + // Scale control rod insertion 0..1 + float controlRodInsertion = Math + .min(1f, Math.max(0f, ((float) ((TileEntityReactorControlRod) te).getControlRodInsertion()) / 100f)); + + // Fuel absorptiveness is determined by control rod + a heat modifier. + // Starts at 1 and decays towards 0.05, reaching 0.6 at 1000 and just under 0.2 at 2000. Inflection point at + // about 500-600. + // Harder radiation makes absorption more difficult. + float baseAbsorption = (float) (1.0 - (0.95 * Math.exp(-10 * Math.exp(-0.0022 * heat)))) + * (1f - (radiation.hardness / getFuelHardnessDivisor())); + + // Some fuels are better at absorbing radiation than others + float scaledAbsorption = Math.min(1f, baseAbsorption * getFuelAbsorptionCoefficient()); + + // Control rods increase total neutron absorption, but decrease the total neutrons which fertilize the fuel + // Absorb up to 50% better with control rods inserted. + float controlRodBonus = (1f - scaledAbsorption) * controlRodInsertion * 0.5f; + float controlRodPenalty = scaledAbsorption * controlRodInsertion * 0.5f; + + float radiationAbsorbed = (scaledAbsorption + controlRodBonus) * radiation.intensity; + float fertilityAbsorbed = (scaledAbsorption - controlRodPenalty) * radiation.intensity; + + float fuelModerationFactor = getFuelModerationFactor(); + fuelModerationFactor += fuelModerationFactor * controlRodInsertion + controlRodInsertion; // Full insertion + // doubles the + // moderation factor + // of the fuel as well + // as adding its own + // level + + radiation.intensity = Math.max(0f, radiation.intensity - radiationAbsorbed); + radiation.hardness /= fuelModerationFactor; + + // Being irradiated both heats up the fuel and also enhances its fertility + data.fuelRfChange += radiationAbsorbed * RadiationHelper.rfPerRadiationUnit; + data.fuelAbsorbedRadiation += fertilityAbsorbed; + } + + // 1, upwards. How well does this fuel moderate, but not stop, radiation? Anything under 1.5 is "poor", 2-2.5 is + // "good", above 4 is "excellent". + private float getFuelModerationFactor() { + return 1.5f; + } + + // 0..1. How well does this fuel absorb radiation? + private float getFuelAbsorptionCoefficient() { + // TODO: Lookup type of fuel and get data from there + return 0.5f; + } + + // Goes up from 1. How tolerant is this fuel of hard radiation? + private float getFuelHardnessDivisor() { + return 1.0f; + } + + // IHeatEntity + @Override + public float getThermalConductivity() { + return IHeatEntity.conductivityCopper; + } + + // RectangularMultiblockTileEntityBase + @Override + public void isGoodForFrame() throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%d, %d, %d - fuel rods may only be placed in the reactor interior", xCoord, yCoord, zCoord)); + } + + @Override + public void isGoodForSides() throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%d, %d, %d - fuel rods may only be placed in the reactor interior", xCoord, yCoord, zCoord)); + } + + @Override + public void isGoodForTop() throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%d, %d, %d - fuel rods may only be placed in the reactor interior", xCoord, yCoord, zCoord)); + } + + @Override + public void isGoodForBottom() throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%d, %d, %d - fuel rods may only be placed in the reactor interior", xCoord, yCoord, zCoord)); + } + + @Override + public void isGoodForInterior() throws MultiblockValidationException { + // Check above and below. Above must be fuel rod or control rod. + TileEntity entityAbove = this.worldObj.getTileEntity(xCoord, yCoord + 1, zCoord); + if (!(entityAbove instanceof TileEntityReactorFuelRod || entityAbove instanceof TileEntityReactorControlRod)) { + throw new MultiblockValidationException( + String.format( + "Fuel rod at %d, %d, %d must be part of a vertical column that reaches the entire height of the reactor, with a control rod on top.", + xCoord, + yCoord, + zCoord)); + } + + // Below must be fuel rod or the base of the reactor. + TileEntity entityBelow = this.worldObj.getTileEntity(xCoord, yCoord - 1, zCoord); + if (entityBelow instanceof TileEntityReactorFuelRod) { + return; + } else if (entityBelow instanceof RectangularMultiblockTileEntityBase) { + ((RectangularMultiblockTileEntityBase) entityBelow).isGoodForBottom(); + return; + } + + throw new MultiblockValidationException( + String.format( + "Fuel rod at %d, %d, %d must be part of a vertical column that reaches the entire height of the reactor, with a control rod on top.", + xCoord, + yCoord, + zCoord)); + } + + @Override + public void onMachineActivated() {} + + @Override + public void onMachineDeactivated() {} + + // Reactor information retrieval methods + + /** + * Returns the rate of heat transfer from this block to the reactor environment, based on this block's surrounding + * blocks. + * Note that this method queries the world, so use it sparingly. + * + * @return Heat transfer rate from fuel rod to reactor environment, in Centigrade per tick. + */ + public float getHeatTransferRate() { + float heatTransferRate = 0f; + + TileEntity te; + for (ForgeDirection dir : StaticUtils.CardinalDirections) { + te = worldObj.getTileEntity(xCoord + dir.offsetX, yCoord + dir.offsetY, zCoord + dir.offsetZ); + if (te instanceof TileEntityReactorFuelRod) { + // We don't transfer to other fuel rods, due to heat pooling. + continue; + } else if (te instanceof IHeatEntity) { + heatTransferRate += ((IHeatEntity) te).getThermalConductivity(); + } else if (worldObj.isAirBlock(xCoord + dir.offsetX, yCoord + dir.offsetY, zCoord + dir.offsetZ)) { + heatTransferRate += IHeatEntity.conductivityAir; + } else { + + Block block = worldObj.getBlock(xCoord + dir.offsetX, yCoord + dir.offsetY, zCoord + dir.offsetZ); + int metadata = worldObj + .getBlockMetadata(xCoord + dir.offsetX, yCoord + dir.offsetY, zCoord + dir.offsetZ); + heatTransferRate += getConductivityFromBlock(block, metadata); + } + } + + return heatTransferRate; + } + + private float getConductivityFromBlock(Block block, int metadata) { + ReactorInteriorData interiorData = null; + + if (block == Blocks.iron_block) { + interiorData = ReactorInterior.getBlockData("blockIron"); + } else if (block == Blocks.gold_block) { + interiorData = ReactorInterior.getBlockData("blockGold"); + } else if (block == Blocks.diamond_block) { + interiorData = ReactorInterior.getBlockData("blockDiamond"); + } else if (block == Blocks.emerald_block) { + interiorData = ReactorInterior.getBlockData("blockEmerald"); + } else { + interiorData = ReactorInterior + .getBlockData(ItemHelper.oreProxy.getOreName(new ItemStack(block, 1, metadata))); + + if (interiorData == null && block instanceof IFluidBlock) { + Fluid fluid = ((IFluidBlock) block).getFluid(); + if (fluid != null) { + interiorData = ReactorInterior.getFluidData(fluid.getName()); + } + } + } + + if (interiorData == null) { + interiorData = RadiationHelper.airData; + } + + return interiorData.heatConductivity; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorGlass.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorGlass.java index 5ec7b656..9b776935 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorGlass.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorGlass.java @@ -4,33 +4,38 @@ public class TileEntityReactorGlass extends TileEntityReactorPartBase { - @Override - public void isGoodForFrame() throws MultiblockValidationException { - throw new MultiblockValidationException(String.format("%d, %d, %d - Reactor glass may only be used on the exterior faces, not as part of a reactor's frame or interior", xCoord, yCoord, zCoord)); - } - - @Override - public void isGoodForSides() throws MultiblockValidationException { - } - - @Override - public void isGoodForTop() throws MultiblockValidationException { - } - - @Override - public void isGoodForBottom() throws MultiblockValidationException { - } - - @Override - public void isGoodForInterior() throws MultiblockValidationException { - throw new MultiblockValidationException(String.format("%d, %d, %d - Reactor glass may only be used on the exterior faces, not as part of a reactor's frame or interior", xCoord, yCoord, zCoord)); - } - - @Override - public void onMachineActivated() { - } - - @Override - public void onMachineDeactivated() { - } + @Override + public void isGoodForFrame() throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format( + "%d, %d, %d - Reactor glass may only be used on the exterior faces, not as part of a reactor's frame or interior", + xCoord, + yCoord, + zCoord)); + } + + @Override + public void isGoodForSides() throws MultiblockValidationException {} + + @Override + public void isGoodForTop() throws MultiblockValidationException {} + + @Override + public void isGoodForBottom() throws MultiblockValidationException {} + + @Override + public void isGoodForInterior() throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format( + "%d, %d, %d - Reactor glass may only be used on the exterior faces, not as part of a reactor's frame or interior", + xCoord, + yCoord, + zCoord)); + } + + @Override + public void onMachineActivated() {} + + @Override + public void onMachineDeactivated() {} } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorPart.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorPart.java index a7435799..514aeaa2 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorPart.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorPart.java @@ -1,6 +1,7 @@ package erogenousbeef.bigreactors.common.multiblock.tileentity; import net.minecraft.entity.player.InventoryPlayer; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import erogenousbeef.bigreactors.client.gui.GuiReactorStatus; @@ -12,102 +13,110 @@ public class TileEntityReactorPart extends TileEntityReactorPartBase { - public TileEntityReactorPart() { - super(); - } - - @Override - public void isGoodForFrame() throws MultiblockValidationException { - int metadata = this.worldObj.getBlockMetadata(this.xCoord, this.yCoord, this.zCoord); - if(BlockReactorPart.isCasing(metadata)) { return; } - - throw new MultiblockValidationException(String.format("%d, %d, %d - Only casing may be used as part of a reactor's frame", xCoord, yCoord, zCoord)); - } - - @Override - public void isGoodForSides() throws MultiblockValidationException { - // All parts are valid for sides, by default - } - - @Override - public void isGoodForTop() throws MultiblockValidationException { - // All parts are valid for the top, by default - } - - @Override - public void isGoodForBottom() throws MultiblockValidationException { - // All parts are valid for the bottom, by default - } - - @Override - public void isGoodForInterior() throws MultiblockValidationException { - throw new MultiblockValidationException(String.format("%d, %d, %d - This reactor part may not be placed in the reactor's interior", xCoord, yCoord, zCoord)); - } - - @Override - public void onMachineAssembled(MultiblockControllerBase multiblockController) { - super.onMachineAssembled(multiblockController); - } - - @Override - public void onMachineBroken() { - super.onMachineBroken(); - } - - @Override - public void onMachineActivated() { - // Re-render controllers on client - if(this.worldObj.isRemote) { - if(getBlockType() == BigReactors.blockReactorPart) { - int metadata = this.getBlockMetadata(); - if(BlockReactorPart.isController(metadata)) { - worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - } - } - } - - @Override - public void onMachineDeactivated() { - // Re-render controllers on client - if(this.worldObj.isRemote) { - if(getBlockType() == BigReactors.blockReactorPart) { - int metadata = this.getBlockMetadata(); - if(BlockReactorPart.isController(metadata)) { - worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - } - } - } - - // IMultiblockGuiHandler - /** - * @return The Container object for use by the GUI. Null if there isn't any. - */ - @Override - public Object getContainer(InventoryPlayer inventoryPlayer) { - if(!this.isConnected()) { - return null; - } - - int metadata = this.worldObj.getBlockMetadata(this.xCoord, this.yCoord, this.zCoord); - if(BlockReactorPart.isController(metadata)) { - return new ContainerReactorController(this, inventoryPlayer.player); - } - return null; - } - - @SideOnly(Side.CLIENT) - @Override - public Object getGuiElement(InventoryPlayer inventoryPlayer) { - if(!this.isConnected()) { - return null; - } - - int metadata = this.worldObj.getBlockMetadata(this.xCoord, this.yCoord, this.zCoord); - if(BlockReactorPart.isController(metadata)) { - return new GuiReactorStatus(new ContainerReactorController(this, inventoryPlayer.player), this); - } - return null; - } + public TileEntityReactorPart() { + super(); + } + + @Override + public void isGoodForFrame() throws MultiblockValidationException { + int metadata = this.worldObj.getBlockMetadata(this.xCoord, this.yCoord, this.zCoord); + if (BlockReactorPart.isCasing(metadata)) { + return; + } + + throw new MultiblockValidationException( + String.format("%d, %d, %d - Only casing may be used as part of a reactor's frame", xCoord, yCoord, zCoord)); + } + + @Override + public void isGoodForSides() throws MultiblockValidationException { + // All parts are valid for sides, by default + } + + @Override + public void isGoodForTop() throws MultiblockValidationException { + // All parts are valid for the top, by default + } + + @Override + public void isGoodForBottom() throws MultiblockValidationException { + // All parts are valid for the bottom, by default + } + + @Override + public void isGoodForInterior() throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format( + "%d, %d, %d - This reactor part may not be placed in the reactor's interior", + xCoord, + yCoord, + zCoord)); + } + + @Override + public void onMachineAssembled(MultiblockControllerBase multiblockController) { + super.onMachineAssembled(multiblockController); + } + + @Override + public void onMachineBroken() { + super.onMachineBroken(); + } + + @Override + public void onMachineActivated() { + // Re-render controllers on client + if (this.worldObj.isRemote) { + if (getBlockType() == BigReactors.blockReactorPart) { + int metadata = this.getBlockMetadata(); + if (BlockReactorPart.isController(metadata)) { + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + } + } + } + + @Override + public void onMachineDeactivated() { + // Re-render controllers on client + if (this.worldObj.isRemote) { + if (getBlockType() == BigReactors.blockReactorPart) { + int metadata = this.getBlockMetadata(); + if (BlockReactorPart.isController(metadata)) { + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + } + } + } + + // IMultiblockGuiHandler + /** + * @return The Container object for use by the GUI. Null if there isn't any. + */ + @Override + public Object getContainer(InventoryPlayer inventoryPlayer) { + if (!this.isConnected()) { + return null; + } + + int metadata = this.worldObj.getBlockMetadata(this.xCoord, this.yCoord, this.zCoord); + if (BlockReactorPart.isController(metadata)) { + return new ContainerReactorController(this, inventoryPlayer.player); + } + return null; + } + + @SideOnly(Side.CLIENT) + @Override + public Object getGuiElement(InventoryPlayer inventoryPlayer) { + if (!this.isConnected()) { + return null; + } + + int metadata = this.worldObj.getBlockMetadata(this.xCoord, this.yCoord, this.zCoord); + if (BlockReactorPart.isController(metadata)) { + return new GuiReactorStatus(new ContainerReactorController(this, inventoryPlayer.player), this); + } + return null; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorPartBase.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorPartBase.java index 91c5c883..4d463db2 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorPartBase.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorPartBase.java @@ -1,7 +1,7 @@ package erogenousbeef.bigreactors.common.multiblock.tileentity; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import erogenousbeef.bigreactors.api.IHeatEntity; @@ -17,122 +17,129 @@ import erogenousbeef.core.multiblock.MultiblockControllerBase; import erogenousbeef.core.multiblock.rectangular.RectangularMultiblockTileEntityBase; -public abstract class TileEntityReactorPartBase extends - RectangularMultiblockTileEntityBase implements IMultiblockGuiHandler, IHeatEntity, - IRadiationModerator, IActivateable, - IBeefDebuggableTile { - - public TileEntityReactorPartBase() { - } - - public MultiblockReactor getReactorController() { return (MultiblockReactor)this.getMultiblockController(); } - - @Override - public boolean canUpdate() { return false; } - - @Override - public MultiblockControllerBase createNewMultiblock() { - return new MultiblockReactor(this.worldObj); - } - - @Override - public Class getMultiblockControllerType() { return MultiblockReactor.class; } - - @Override - public void onMachineAssembled(MultiblockControllerBase controller) { - super.onMachineAssembled(controller); - - // Re-render this block on the client - if(worldObj.isRemote) { - this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - } - - @Override - public void onMachineBroken() { - super.onMachineBroken(); - - // Re-render this block on the client - if(worldObj.isRemote) { - this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - } - - // IMultiblockGuiHandler - /** - * @return The Container object for use by the GUI. Null if there isn't any. - */ - @Override - public Object getContainer(InventoryPlayer inventoryPlayer) { - return null; - } - - @SideOnly(Side.CLIENT) - @Override - public Object getGuiElement(InventoryPlayer inventoryPlayer) { - return null; - } - - // IHeatEntity - @Override - public float getHeat() { - if(!this.isConnected()) { return 0f; } - return getReactorController().getFuelHeat(); - } - - @Override - public float getThermalConductivity() { - return IHeatEntity.conductivityIron; - } - - // IRadiationModerator - @Override - public void moderateRadiation(RadiationData data, RadiationPacket radiation) { - // Discard all remaining radiation, sorry bucko - radiation.intensity = 0f; - } - - // IActivateable - @Override - public CoordTriplet getReferenceCoord() { - if(isConnected()) { - return getMultiblockController().getReferenceCoord(); - } - else { - return new CoordTriplet(xCoord, yCoord, zCoord); - } - } - - @Override - public boolean getActive() { - if(isConnected()) { - return getReactorController().getActive(); - } - else { - return false; - } - } - - @Override - public void setActive(boolean active) { - if(isConnected()) { - getReactorController().setActive(active); - } - else { - BRLog.error("Received a setActive command at %d, %d, %d, but not connected to a multiblock controller!", xCoord, yCoord, zCoord); - } - } - - @Override - public String getDebugInfo() { - MultiblockReactor r = getReactorController(); - StringBuilder sb = new StringBuilder(); - sb.append(getClass().toString()).append("\n"); - if(r == null) { - sb.append("Not attached to controller!"); - return sb.toString(); - } - sb.append(r.getDebugInfo()); - return sb.toString(); - } +public abstract class TileEntityReactorPartBase extends RectangularMultiblockTileEntityBase + implements IMultiblockGuiHandler, IHeatEntity, IRadiationModerator, IActivateable, IBeefDebuggableTile { + + public TileEntityReactorPartBase() {} + + public MultiblockReactor getReactorController() { + return (MultiblockReactor) this.getMultiblockController(); + } + + @Override + public boolean canUpdate() { + return false; + } + + @Override + public MultiblockControllerBase createNewMultiblock() { + return new MultiblockReactor(this.worldObj); + } + + @Override + public Class getMultiblockControllerType() { + return MultiblockReactor.class; + } + + @Override + public void onMachineAssembled(MultiblockControllerBase controller) { + super.onMachineAssembled(controller); + + // Re-render this block on the client + if (worldObj.isRemote) { + this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + } + + @Override + public void onMachineBroken() { + super.onMachineBroken(); + + // Re-render this block on the client + if (worldObj.isRemote) { + this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + } + + // IMultiblockGuiHandler + /** + * @return The Container object for use by the GUI. Null if there isn't any. + */ + @Override + public Object getContainer(InventoryPlayer inventoryPlayer) { + return null; + } + + @SideOnly(Side.CLIENT) + @Override + public Object getGuiElement(InventoryPlayer inventoryPlayer) { + return null; + } + + // IHeatEntity + @Override + public float getHeat() { + if (!this.isConnected()) { + return 0f; + } + return getReactorController().getFuelHeat(); + } + + @Override + public float getThermalConductivity() { + return IHeatEntity.conductivityIron; + } + + // IRadiationModerator + @Override + public void moderateRadiation(RadiationData data, RadiationPacket radiation) { + // Discard all remaining radiation, sorry bucko + radiation.intensity = 0f; + } + + // IActivateable + @Override + public CoordTriplet getReferenceCoord() { + if (isConnected()) { + return getMultiblockController().getReferenceCoord(); + } else { + return new CoordTriplet(xCoord, yCoord, zCoord); + } + } + + @Override + public boolean getActive() { + if (isConnected()) { + return getReactorController().getActive(); + } else { + return false; + } + } + + @Override + public void setActive(boolean active) { + if (isConnected()) { + getReactorController().setActive(active); + } else { + BRLog.error( + "Received a setActive command at %d, %d, %d, but not connected to a multiblock controller!", + xCoord, + yCoord, + zCoord); + } + } + + @Override + public String getDebugInfo() { + MultiblockReactor r = getReactorController(); + StringBuilder sb = new StringBuilder(); + sb.append(getClass().toString()) + .append("\n"); + if (r == null) { + sb.append("Not attached to controller!"); + return sb.toString(); + } + sb.append(r.getDebugInfo()); + return sb.toString(); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorPowerTap.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorPowerTap.java index 11083452..5afdf60d 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorPowerTap.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorPowerTap.java @@ -5,140 +5,147 @@ import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; + import cofh.api.energy.IEnergyProvider; import cofh.api.energy.IEnergyReceiver; import erogenousbeef.bigreactors.common.multiblock.interfaces.INeighborUpdatableEntity; import erogenousbeef.core.multiblock.MultiblockControllerBase; -public class TileEntityReactorPowerTap extends TileEntityReactorPart implements IEnergyProvider, INeighborUpdatableEntity { - IEnergyReceiver rfNetwork; - - public TileEntityReactorPowerTap() { - super(); - - rfNetwork = null; - } - - @Override - public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock) { - if(isConnected()) { - checkForConnections(world, x, y, z); - } - } - - @Override - public void onNeighborTileChange(IBlockAccess world, int x, int y, int z, int neighborX, int neighborY, int neighborZ) { - if(isConnected()) { - checkForConnections(world, x, y, z); - } - } - - // IMultiblockPart - @Override - public void onAttached(MultiblockControllerBase newController) { - super.onAttached(newController); - - checkForConnections(this.worldObj, xCoord, yCoord, zCoord); - } - - @Override - public void onMachineAssembled(MultiblockControllerBase multiblockControllerBase) { - super.onMachineAssembled(multiblockControllerBase); - - checkForConnections(this.worldObj, xCoord, yCoord, zCoord); - - // Force a connection to the power taps - this.notifyNeighborsOfTileChange(); - } - - // Custom PowerTap methods - /** - * Check for a world connection, if we're assembled. - * @param world - * @param x - * @param y - * @param z - */ - protected void checkForConnections(IBlockAccess world, int x, int y, int z) { - boolean wasConnected = (rfNetwork != null); - ForgeDirection out = getOutwardsDir(); - if(out == ForgeDirection.UNKNOWN) { - wasConnected = false; - rfNetwork = null; - } - else { - // See if our adjacent non-reactor coordinate has a TE - rfNetwork = null; - - TileEntity te = world.getTileEntity(x + out.offsetX, y + out.offsetY, z + out.offsetZ); - if(!(te instanceof TileEntityReactorPowerTap)) { - // Skip power taps, as they implement these APIs and we don't want to shit energy back and forth - if(te instanceof IEnergyReceiver) { - IEnergyReceiver handler = (IEnergyReceiver)te; - if(handler.canConnectEnergy(out.getOpposite())) { - rfNetwork = handler; - } - } - } - - } - - boolean isConnected = (rfNetwork != null); - if(wasConnected != isConnected) { - worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - } - - /** This will be called by the Reactor Controller when this tap should be providing power. - * @return Power units remaining after consumption. - */ - public int onProvidePower(int units) { - if(rfNetwork == null) { - return units; - } - - ForgeDirection approachDirection = getOutwardsDir().getOpposite(); - int energyConsumed = rfNetwork.receiveEnergy(approachDirection, (int)units, false); - units -= energyConsumed; - - return units; - } - - // IEnergyConnection - @Override - public boolean canConnectEnergy(ForgeDirection from) { - return from == getOutwardsDir(); - } - - // IEnergyProvider - @Override - public int extractEnergy(ForgeDirection from, int maxExtract, - boolean simulate) { - if(!this.isConnected()) - return 0; - - if(from == getOutwardsDir()) { - return this.getReactorController().extractEnergy(from, maxExtract, simulate); - } - - return 0; - } - - @Override - public int getEnergyStored(ForgeDirection from) { - if(!this.isConnected()) - return 0; - - return this.getReactorController().getEnergyStored(from); - } - - @Override - public int getMaxEnergyStored(ForgeDirection from) { - if(!this.isConnected()) - return 0; - - return this.getReactorController().getMaxEnergyStored(from); - } - - public boolean hasEnergyConnection() { return rfNetwork != null; } +public class TileEntityReactorPowerTap extends TileEntityReactorPart + implements IEnergyProvider, INeighborUpdatableEntity { + + IEnergyReceiver rfNetwork; + + public TileEntityReactorPowerTap() { + super(); + + rfNetwork = null; + } + + @Override + public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock) { + if (isConnected()) { + checkForConnections(world, x, y, z); + } + } + + @Override + public void onNeighborTileChange(IBlockAccess world, int x, int y, int z, int neighborX, int neighborY, + int neighborZ) { + if (isConnected()) { + checkForConnections(world, x, y, z); + } + } + + // IMultiblockPart + @Override + public void onAttached(MultiblockControllerBase newController) { + super.onAttached(newController); + + checkForConnections(this.worldObj, xCoord, yCoord, zCoord); + } + + @Override + public void onMachineAssembled(MultiblockControllerBase multiblockControllerBase) { + super.onMachineAssembled(multiblockControllerBase); + + checkForConnections(this.worldObj, xCoord, yCoord, zCoord); + + // Force a connection to the power taps + this.notifyNeighborsOfTileChange(); + } + + // Custom PowerTap methods + /** + * Check for a world connection, if we're assembled. + * + * @param world + * @param x + * @param y + * @param z + */ + protected void checkForConnections(IBlockAccess world, int x, int y, int z) { + boolean wasConnected = (rfNetwork != null); + ForgeDirection out = getOutwardsDir(); + if (out == ForgeDirection.UNKNOWN) { + wasConnected = false; + rfNetwork = null; + } else { + // See if our adjacent non-reactor coordinate has a TE + rfNetwork = null; + + TileEntity te = world.getTileEntity(x + out.offsetX, y + out.offsetY, z + out.offsetZ); + if (!(te instanceof TileEntityReactorPowerTap)) { + // Skip power taps, as they implement these APIs and we don't want to shit energy back and forth + if (te instanceof IEnergyReceiver) { + IEnergyReceiver handler = (IEnergyReceiver) te; + if (handler.canConnectEnergy(out.getOpposite())) { + rfNetwork = handler; + } + } + } + + } + + boolean isConnected = (rfNetwork != null); + if (wasConnected != isConnected) { + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + } + + /** + * This will be called by the Reactor Controller when this tap should be providing power. + * + * @return Power units remaining after consumption. + */ + public int onProvidePower(int units) { + if (rfNetwork == null) { + return units; + } + + ForgeDirection approachDirection = getOutwardsDir().getOpposite(); + int energyConsumed = rfNetwork.receiveEnergy(approachDirection, (int) units, false); + units -= energyConsumed; + + return units; + } + + // IEnergyConnection + @Override + public boolean canConnectEnergy(ForgeDirection from) { + return from == getOutwardsDir(); + } + + // IEnergyProvider + @Override + public int extractEnergy(ForgeDirection from, int maxExtract, boolean simulate) { + if (!this.isConnected()) return 0; + + if (from == getOutwardsDir()) { + return this.getReactorController() + .extractEnergy(from, maxExtract, simulate); + } + + return 0; + } + + @Override + public int getEnergyStored(ForgeDirection from) { + if (!this.isConnected()) return 0; + + return this.getReactorController() + .getEnergyStored(from); + } + + @Override + public int getMaxEnergyStored(ForgeDirection from) { + if (!this.isConnected()) return 0; + + return this.getReactorController() + .getMaxEnergyStored(from); + } + + public boolean hasEnergyConnection() { + return rfNetwork != null; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorRedNetPort.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorRedNetPort.java index ddbec75a..d4dafa7b 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorRedNetPort.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorRedNetPort.java @@ -8,8 +8,7 @@ import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; -import powercrystals.minefactoryreloaded.api.rednet.IRedNetInputNode; -import powercrystals.minefactoryreloaded.api.rednet.IRedNetNetworkContainer; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import erogenousbeef.bigreactors.client.gui.GuiReactorRedNetPort; @@ -23,440 +22,498 @@ import erogenousbeef.bigreactors.net.helpers.RedNetChange; import erogenousbeef.core.common.CoordTriplet; import erogenousbeef.core.multiblock.MultiblockControllerBase; +import powercrystals.minefactoryreloaded.api.rednet.IRedNetInputNode; +import powercrystals.minefactoryreloaded.api.rednet.IRedNetNetworkContainer; + +public class TileEntityReactorRedNetPort extends TileEntityReactorPart + implements ITickableMultiblockPart, INeighborUpdatableEntity { + + public enum CircuitType { + + DISABLED, + inputActive, // Input: reactor on/off + inputSetControlRod, // Input: control rod insertion (0-100) + inputEjectWaste, // Input: eject waste from the reactor + + outputFuelTemperature, // Output: Temperature of the reactor fuel + outputCasingTemperature, // Output: Temperature of the reactor casing + outputFuelMix, // Output: Fuel mix, % of contents that is fuel (0-100, 100 = 100% fuel) + outputFuelAmount, // Output: Fuel amount in a control rod, raw value, (0-4*height) + outputWasteAmount, // Output: Waste amount in a control rod, raw value, (0-4*height) + outputEnergyAmount; // Output: Energy in the reactor's buffer, percentile (0-100, 100 = 100% full) + + public static final CircuitType[] s_Types = CircuitType.values(); + + public static boolean hasCoordinate(TileEntityReactorRedNetPort.CircuitType circuitType) { + return circuitType == CircuitType.inputSetControlRod; + } + + public static boolean canBeToggledBetweenPulseAndNormal(CircuitType circuitType) { + return circuitType == CircuitType.inputActive; + } + } + + protected final static int minInputEnumValue = CircuitType.inputActive.ordinal(); + protected final static int maxInputEnumValue = CircuitType.inputEjectWaste.ordinal(); + protected final static int minOutputEnumValue = CircuitType.outputFuelTemperature.ordinal(); + protected final static int maxOutputEnumValue = CircuitType.outputEnergyAmount.ordinal(); + + protected CircuitType[] channelCircuitTypes; + protected CoordTriplet[] coordMappings; + protected boolean[] inputActivatesOnPulse; + protected int[] oldValue; + + public final static int numChannels = 16; + + IRedNetNetworkContainer redNetwork; + IRedNetInputNode redNetInput; + + int ticksSinceLastUpdate; + + public TileEntityReactorRedNetPort() { + super(); + + channelCircuitTypes = new CircuitType[numChannels]; + coordMappings = new CoordTriplet[numChannels]; + inputActivatesOnPulse = new boolean[numChannels]; + oldValue = new int[numChannels]; + + for (int i = 0; i < numChannels; i++) { + channelCircuitTypes[i] = CircuitType.DISABLED; + coordMappings[i] = null; + inputActivatesOnPulse[i] = false; + oldValue[i] = 0; + } + + redNetwork = null; + redNetInput = null; + + ticksSinceLastUpdate = 0; + } + + // IMultiblockPart + @Override + public void onAttached(MultiblockControllerBase newController) { + super.onAttached(newController); + + if (this.worldObj.isRemote) { + return; + } + + checkForConnections(this.worldObj, xCoord, yCoord, zCoord); + } + + @Override + public void onMachineAssembled(MultiblockControllerBase multiblockController) { + super.onMachineAssembled(multiblockController); + + if (this.worldObj.isRemote) { + return; + } + + checkForConnections(this.worldObj, xCoord, yCoord, zCoord); + } + + @Override + @SideOnly(Side.CLIENT) + public Object getGuiElement(InventoryPlayer inventoryPlayer) { + return new GuiReactorRedNetPort(new ContainerBasic(), this); + } + + @Override + public Object getContainer(InventoryPlayer inventoryPlayer) { + return new ContainerBasic(); + } + + @Override + public void writeToNBT(NBTTagCompound par1NBTTagCompound) { + super.writeToNBT(par1NBTTagCompound); + encodeSettings(par1NBTTagCompound); + } + + @Override + protected void encodeDescriptionPacket(NBTTagCompound packetData) { + super.encodeDescriptionPacket(packetData); + encodeSettings(packetData); + } + + @Override + public void readFromNBT(NBTTagCompound par1NBTTagCompound) { + super.readFromNBT(par1NBTTagCompound); + decodeSettings(par1NBTTagCompound); + } + + @Override + protected void decodeDescriptionPacket(NBTTagCompound packetData) { + super.decodeDescriptionPacket(packetData); + decodeSettings(packetData); + } + + // RedNet API + public int[] getOutputValues() { + int[] outputs = new int[numChannels]; + for (int i = 0; i < numChannels; i++) { + outputs[i] = getValueForChannel(i); + } + + return outputs; + } + + public int getValueForChannel(int channel) { + if (channel < 0 || channel >= numChannels) { + return 0; + } + + if (!this.isConnected()) { + return 0; + } + + TileEntity te = null; + + switch (channelCircuitTypes[channel]) { + case outputFuelTemperature: + return (int) Math.floor(getReactorController().getFuelHeat()); + case outputCasingTemperature: + return (int) Math.floor(getReactorController().getReactorHeat()); + case outputFuelMix: + MultiblockReactor controller = getReactorController(); + return (int) Math + .floor(((float) controller.getFuelAmount() / (float) controller.getCapacity()) * 100.0f); + case outputFuelAmount: + return getReactorController().getFuelAmount(); + case outputWasteAmount: + return getReactorController().getWasteAmount(); + case outputEnergyAmount: + int energyStored, energyTotal; + MultiblockReactor reactor = this.getReactorController(); + if (reactor != null) { + return reactor.getEnergyStoredPercentage(); + } + return 0; + default: + return 0; + } + } + + public void onInputValuesChanged(int[] newValues) { + for (int i = 0; i < newValues.length; i++) { + onInputValueChanged(i, newValues[i]); + } + } + + public void onInputValueChanged(int channel, int newValue) { + if (channel < 0 || channel >= numChannels) { + return; + } + CircuitType type = channelCircuitTypes[channel]; + if (!isInput(type)) { + return; + } + if (!this.isConnected()) { + return; + } + + if (newValue == oldValue[channel]) { + return; + } + boolean isPulse = (oldValue[channel] == 0 && newValue != 0); + + MultiblockReactor reactor = null; + switch (type) { + case inputActive: + reactor = getReactorController(); + if (inputActivatesOnPulse[channel]) { + if (isPulse) { + reactor.setActive(!reactor.getActive()); + } + } else { + boolean newActive = newValue != 0; + if (newActive != reactor.getActive()) { + reactor.setActive(newActive); + } + } + break; + case inputSetControlRod: + // This doesn't make sense for pulsing + newValue = Math.min(100, Math.max(0, newValue)); // Clamp to 0..100 + if (newValue == oldValue[channel]) { + return; + } + + if (coordMappings[channel] != null) { + setControlRodInsertion(channel, coordMappings[channel], newValue); + } else { + reactor = getReactorController(); + reactor.setAllControlRodInsertionValues(newValue); + } + break; + case inputEjectWaste: + // This only makes sense for pulsing + if (isPulse) { + reactor = getReactorController(); + reactor.ejectWaste(false, null); + } + default: + break; + } + + oldValue[channel] = newValue; + } + + // Public RedNet helpers for GUI & updates + @Override + public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock) { + checkForConnections(world, x, y, z); + } + + @Override + public void onNeighborTileChange(IBlockAccess world, int x, int y, int z, int neighborX, int neighborY, + int neighborZ) { + checkForConnections(world, x, y, z); + } + + /** + * Updates the connected RedNet network, if there is one. + * Will only send one update per N ticks, where N is a configurable setting. + */ + public void onMultiblockServerTick() { + if (!this.isConnected()) { + return; + } + + ticksSinceLastUpdate++; + if (ticksSinceLastUpdate < BigReactors.ticksPerRedstoneUpdate) { + return; + } + + ForgeDirection out = getOutwardsDir(); + + if (redNetwork != null) { + redNetwork.updateNetwork( + worldObj, + xCoord + out.offsetX, + yCoord + out.offsetY, + zCoord + out.offsetZ, + out.getOpposite()); + } + + if (redNetInput != null) { + redNetInput.onInputsChanged( + worldObj, + xCoord + out.offsetX, + yCoord + out.offsetY, + zCoord + out.offsetZ, + out.getOpposite(), + getOutputValues()); + } + + ticksSinceLastUpdate = 0; + } + + public CircuitType getChannelCircuitType(int channel) { + if (channel < 0 || channel >= numChannels) { + return CircuitType.DISABLED; + } + return channelCircuitTypes[channel]; + } + + public CoordTriplet getMappedCoord(int channel) { + return this.coordMappings[channel]; + } + + public boolean isInputActivatedOnPulse(int channel) { + return this.inputActivatesOnPulse[channel]; + } + + // RedNet helper methods + protected void clearChannel(int channel) { + channelCircuitTypes[channel] = CircuitType.DISABLED; + coordMappings[channel] = null; + inputActivatesOnPulse[channel] = false; + oldValue[channel] = 0; + } + + protected TileEntity getMappedTileEntity(int channel) { + if (channel < 0 || channel >= numChannels) { + return null; + } + if (coordMappings[channel] == null) { + return null; + } + + CoordTriplet coord = coordMappings[channel]; + + if (coord == null) { + return null; + } + if (!this.worldObj.checkChunksExist(coord.x, coord.y, coord.z, coord.x, coord.y, coord.z)) { + return null; + } + + return this.worldObj.getTileEntity(coord.x, coord.y, coord.z); + } + + protected void setControlRodInsertion(int channel, CoordTriplet coordTriplet, int newValue) { + if (!this.isConnected()) { + return; + } + if (!this.worldObj.checkChunksExist( + coordTriplet.x, + coordTriplet.y, + coordTriplet.z, + coordTriplet.x, + coordTriplet.y, + coordTriplet.z)) { + return; + } + + TileEntity te = this.worldObj.getTileEntity(coordTriplet.x, coordTriplet.y, coordTriplet.z); + if (te instanceof TileEntityReactorControlRod) { + ((TileEntityReactorControlRod) te).setControlRodInsertion((short) newValue); + } else { + clearChannel(channel); + } + } + + protected NBTTagCompound encodeSetting(int channel) { + NBTTagCompound entry = new NBTTagCompound(); + + entry.setInteger("channel", channel); + entry.setInteger("setting", this.channelCircuitTypes[channel].ordinal()); + if (isInput(this.channelCircuitTypes[channel]) + && CircuitType.canBeToggledBetweenPulseAndNormal(this.channelCircuitTypes[channel])) { + entry.setBoolean("pulse", this.inputActivatesOnPulse[channel]); + } + if (CircuitType.hasCoordinate(this.channelCircuitTypes[channel])) { + CoordTriplet coord = this.coordMappings[channel]; + if (coord != null) { + entry.setInteger("x", coord.x); + entry.setInteger("y", coord.y); + entry.setInteger("z", coord.z); + } + } + + return entry; + } + + protected void decodeSetting(NBTTagCompound settingTag) { + int channel = settingTag.getInteger("channel"); + int settingIdx = settingTag.getInteger("setting"); + + clearChannel(channel); + + channelCircuitTypes[channel] = CircuitType.values()[settingIdx]; + + if (isInput(this.channelCircuitTypes[channel]) + && CircuitType.canBeToggledBetweenPulseAndNormal(this.channelCircuitTypes[channel])) { + inputActivatesOnPulse[channel] = settingTag.getBoolean("pulse"); + } + + if (CircuitType.hasCoordinate(channelCircuitTypes[channel])) { + if (settingTag.hasKey("x")) { + int x, y, z; + x = settingTag.getInteger("x"); + y = settingTag.getInteger("y"); + z = settingTag.getInteger("z"); + coordMappings[channel] = new CoordTriplet(x, y, z); + } + } + } + + // Receives settings from a client via an update packet + public void onCircuitUpdate(RedNetChange[] changes) { + if (changes == null || changes.length < 1) { + return; + } + + for (int i = 0; i < changes.length; i++) { + int channelID = changes[i].getChannel(); + CircuitType newType = changes[i].getType(); + + channelCircuitTypes[channelID] = newType; + + if (CircuitType.canBeToggledBetweenPulseAndNormal(newType)) { + inputActivatesOnPulse[channelID] = changes[i].getPulseOrToggle(); + } + + if (CircuitType.hasCoordinate(newType)) { + CoordTriplet coord = changes[i].getCoord(); + + // Validate that we're pointing at the right thing, just in case. + if (coord != null) { + TileEntity te = worldObj.getTileEntity(coord.x, coord.y, coord.z); + if (!(te instanceof TileEntityReactorControlRod)) { + BRLog.warning( + "Invalid tile entity reference at coordinate %s - rednet circuit expected a control rod", + coord); + coord = null; + } + } + + coordMappings[channelID] = coord; + } else { + coordMappings[channelID] = null; + } + } + + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + markDirty(); + } + + // Helpers + protected void encodeSettings(NBTTagCompound destination) { + NBTTagList tagArray = new NBTTagList(); + + for (int i = 0; i < numChannels; i++) { + tagArray.appendTag(encodeSetting(i)); + } + + destination.setTag("redNetConfig", tagArray); + } + + protected void decodeSettings(NBTTagCompound source) { + NBTTagList tagArray = source.getTagList("redNetConfig", 10); + for (int i = 0; i < tagArray.tagCount(); i++) { + decodeSetting((NBTTagCompound) tagArray.getCompoundTagAt(i)); + } + } + + /** + * Check for a world connection, if we're assembled. + * + * @param world + * @param x + * @param y + * @param z + */ + protected void checkForConnections(IBlockAccess world, int x, int y, int z) { + ForgeDirection out = getOutwardsDir(); + + if (out == ForgeDirection.UNKNOWN) { + redNetwork = null; + redNetInput = null; + } else { + // Check for rednet connections nearby + redNetwork = null; + redNetInput = null; + + Block b = worldObj.getBlock(x + out.offsetX, y + out.offsetY, z + out.offsetZ); + if (!(b instanceof BlockReactorPart)) { + if (b instanceof IRedNetNetworkContainer) { + redNetwork = (IRedNetNetworkContainer) b; + } else if (b instanceof IRedNetInputNode) { + redNetInput = (IRedNetInputNode) b; + } + } + } + } + + // Static Helpers + public static boolean isInput(CircuitType type) { + return type.ordinal() >= minInputEnumValue && type.ordinal() <= maxInputEnumValue; + } -public class TileEntityReactorRedNetPort extends TileEntityReactorPart implements ITickableMultiblockPart, INeighborUpdatableEntity { - - public enum CircuitType { - DISABLED, - inputActive, // Input: reactor on/off - inputSetControlRod, // Input: control rod insertion (0-100) - inputEjectWaste, // Input: eject waste from the reactor - - outputFuelTemperature, // Output: Temperature of the reactor fuel - outputCasingTemperature, // Output: Temperature of the reactor casing - outputFuelMix, // Output: Fuel mix, % of contents that is fuel (0-100, 100 = 100% fuel) - outputFuelAmount, // Output: Fuel amount in a control rod, raw value, (0-4*height) - outputWasteAmount, // Output: Waste amount in a control rod, raw value, (0-4*height) - outputEnergyAmount; // Output: Energy in the reactor's buffer, percentile (0-100, 100 = 100% full) - - public static final CircuitType[] s_Types = CircuitType.values(); - - public static boolean hasCoordinate(TileEntityReactorRedNetPort.CircuitType circuitType) { - return circuitType == CircuitType.inputSetControlRod; - } - - public static boolean canBeToggledBetweenPulseAndNormal(CircuitType circuitType) { - return circuitType == CircuitType.inputActive; - } - } - - protected final static int minInputEnumValue = CircuitType.inputActive.ordinal(); - protected final static int maxInputEnumValue = CircuitType.inputEjectWaste.ordinal(); - protected final static int minOutputEnumValue = CircuitType.outputFuelTemperature.ordinal(); - protected final static int maxOutputEnumValue = CircuitType.outputEnergyAmount.ordinal(); - - protected CircuitType[] channelCircuitTypes; - protected CoordTriplet[] coordMappings; - protected boolean[] inputActivatesOnPulse; - protected int[] oldValue; - - public final static int numChannels = 16; - - IRedNetNetworkContainer redNetwork; - IRedNetInputNode redNetInput; - - int ticksSinceLastUpdate; - - public TileEntityReactorRedNetPort() { - super(); - - channelCircuitTypes = new CircuitType[numChannels]; - coordMappings = new CoordTriplet[numChannels]; - inputActivatesOnPulse = new boolean[numChannels]; - oldValue = new int[numChannels]; - - for(int i = 0; i < numChannels; i++) { - channelCircuitTypes[i] = CircuitType.DISABLED; - coordMappings[i] = null; - inputActivatesOnPulse[i] = false; - oldValue[i] = 0; - } - - redNetwork = null; - redNetInput = null; - - ticksSinceLastUpdate = 0; - } - - // IMultiblockPart - @Override - public void onAttached(MultiblockControllerBase newController) { - super.onAttached(newController); - - if(this.worldObj.isRemote) { return; } - - checkForConnections(this.worldObj, xCoord, yCoord, zCoord); - } - - @Override - public void onMachineAssembled(MultiblockControllerBase multiblockController) { - super.onMachineAssembled(multiblockController); - - if(this.worldObj.isRemote) { return; } - - checkForConnections(this.worldObj, xCoord, yCoord, zCoord); - } - - @Override - @SideOnly(Side.CLIENT) - public Object getGuiElement(InventoryPlayer inventoryPlayer) { - return new GuiReactorRedNetPort(new ContainerBasic(), this); - } - - @Override - public Object getContainer(InventoryPlayer inventoryPlayer) { - return new ContainerBasic(); - } - - @Override - public void writeToNBT(NBTTagCompound par1NBTTagCompound) - { - super.writeToNBT(par1NBTTagCompound); - encodeSettings(par1NBTTagCompound); - } - - @Override - protected void encodeDescriptionPacket(NBTTagCompound packetData) { - super.encodeDescriptionPacket(packetData); - encodeSettings(packetData); - } - - @Override - public void readFromNBT(NBTTagCompound par1NBTTagCompound) - { - super.readFromNBT(par1NBTTagCompound); - decodeSettings(par1NBTTagCompound); - } - - @Override - protected void decodeDescriptionPacket(NBTTagCompound packetData) { - super.decodeDescriptionPacket(packetData); - decodeSettings(packetData); - } - - // RedNet API - public int[] getOutputValues() { - int[] outputs = new int[numChannels]; - for(int i = 0; i < numChannels; i++) { - outputs[i] = getValueForChannel(i); - } - - return outputs; - } - - public int getValueForChannel(int channel) { - if(channel < 0 || channel >= numChannels) { return 0; } - - if(!this.isConnected()) { return 0; } - - TileEntity te = null; - - switch(channelCircuitTypes[channel]) { - case outputFuelTemperature: - return (int)Math.floor(getReactorController().getFuelHeat()); - case outputCasingTemperature: - return (int)Math.floor(getReactorController().getReactorHeat()); - case outputFuelMix: - MultiblockReactor controller = getReactorController(); - return (int)Math.floor(((float)controller.getFuelAmount() / (float)controller.getCapacity())*100.0f); - case outputFuelAmount: - return getReactorController().getFuelAmount(); - case outputWasteAmount: - return getReactorController().getWasteAmount(); - case outputEnergyAmount: - int energyStored, energyTotal; - MultiblockReactor reactor = this.getReactorController(); - if(reactor != null) { - return reactor.getEnergyStoredPercentage(); - } - return 0; - default: - return 0; - } - } - - public void onInputValuesChanged(int[] newValues) { - for(int i = 0; i < newValues.length; i++) { - onInputValueChanged(i, newValues[i]); - } - } - - public void onInputValueChanged(int channel, int newValue) { - if(channel < 0 || channel >= numChannels) { return; } - CircuitType type = channelCircuitTypes[channel]; - if(!isInput(type)) { return; } - if(!this.isConnected()) { return; } - - if(newValue == oldValue[channel]) { return; } - boolean isPulse = (oldValue[channel] == 0 && newValue != 0); - - MultiblockReactor reactor = null; - switch(type) { - case inputActive: - reactor = getReactorController(); - if(inputActivatesOnPulse[channel]) { - if(isPulse) { - reactor.setActive(!reactor.getActive()); - } - } - else { - boolean newActive = newValue != 0; - if(newActive != reactor.getActive()) { - reactor.setActive(newActive); - } - } - break; - case inputSetControlRod: - // This doesn't make sense for pulsing - newValue = Math.min(100, Math.max(0, newValue)); // Clamp to 0..100 - if(newValue == oldValue[channel]) { return; } - - if(coordMappings[channel] != null) { - setControlRodInsertion(channel, coordMappings[channel], newValue); - } - else { - reactor = getReactorController(); - reactor.setAllControlRodInsertionValues(newValue); - } - break; - case inputEjectWaste: - // This only makes sense for pulsing - if(isPulse) { - reactor = getReactorController(); - reactor.ejectWaste(false, null); - } - default: - break; - } - - oldValue[channel] = newValue; - } - - // Public RedNet helpers for GUI & updates - @Override - public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock) { - checkForConnections(world, x, y, z); - } - - @Override - public void onNeighborTileChange(IBlockAccess world, int x, int y, int z, int neighborX, int neighborY, int neighborZ) { - checkForConnections(world, x, y, z); - } - - /** - * Updates the connected RedNet network, if there is one. - * Will only send one update per N ticks, where N is a configurable setting. - */ - public void onMultiblockServerTick() { - if(!this.isConnected()) { return; } - - ticksSinceLastUpdate++; - if(ticksSinceLastUpdate < BigReactors.ticksPerRedstoneUpdate) { return; } - - ForgeDirection out = getOutwardsDir(); - - if(redNetwork != null) { - redNetwork.updateNetwork(worldObj, xCoord+out.offsetX, yCoord+out.offsetY, zCoord+out.offsetZ, out.getOpposite()); - } - - if(redNetInput != null) { - redNetInput.onInputsChanged(worldObj, xCoord+out.offsetX, yCoord+out.offsetY, zCoord+out.offsetZ, out.getOpposite(), getOutputValues()); - } - - ticksSinceLastUpdate = 0; - } - - public CircuitType getChannelCircuitType(int channel) { - if(channel < 0 || channel >= numChannels) { return CircuitType.DISABLED; } - return channelCircuitTypes[channel]; - } - - public CoordTriplet getMappedCoord(int channel) { - return this.coordMappings[channel]; - } - - public boolean isInputActivatedOnPulse(int channel) { - return this.inputActivatesOnPulse[channel]; - } - - // RedNet helper methods - protected void clearChannel(int channel) { - channelCircuitTypes[channel] = CircuitType.DISABLED; - coordMappings[channel] = null; - inputActivatesOnPulse[channel] = false; - oldValue[channel] = 0; - } - - protected TileEntity getMappedTileEntity(int channel) { - if(channel < 0 || channel >= numChannels) { return null; } - if(coordMappings[channel] == null) { return null; } - - CoordTriplet coord = coordMappings[channel]; - - if(coord == null) { return null; } - if(!this.worldObj.checkChunksExist(coord.x, coord.y, coord.z, coord.x, coord.y, coord.z)) { - return null; - } - - return this.worldObj.getTileEntity(coord.x, coord.y, coord.z); - } - - protected void setControlRodInsertion(int channel, CoordTriplet coordTriplet, int newValue) { - if(!this.isConnected()) { return; } - if(!this.worldObj.checkChunksExist(coordTriplet.x, coordTriplet.y, coordTriplet.z, - coordTriplet.x, coordTriplet.y, coordTriplet.z)) { - return; - } - - TileEntity te = this.worldObj.getTileEntity(coordTriplet.x, coordTriplet.y, coordTriplet.z); - if(te instanceof TileEntityReactorControlRod) { - ((TileEntityReactorControlRod)te).setControlRodInsertion((short)newValue); - } - else { - clearChannel(channel); - } - } - - protected NBTTagCompound encodeSetting(int channel) { - NBTTagCompound entry = new NBTTagCompound(); - - entry.setInteger("channel", channel); - entry.setInteger("setting", this.channelCircuitTypes[channel].ordinal()); - if(isInput(this.channelCircuitTypes[channel]) && CircuitType.canBeToggledBetweenPulseAndNormal(this.channelCircuitTypes[channel])) { - entry.setBoolean("pulse", this.inputActivatesOnPulse[channel]); - } - if( CircuitType.hasCoordinate(this.channelCircuitTypes[channel]) ) { - CoordTriplet coord = this.coordMappings[channel]; - if(coord != null) { - entry.setInteger("x", coord.x); - entry.setInteger("y", coord.y); - entry.setInteger("z", coord.z); - } - } - - return entry; - } - - protected void decodeSetting(NBTTagCompound settingTag) { - int channel = settingTag.getInteger("channel"); - int settingIdx = settingTag.getInteger("setting"); - - clearChannel(channel); - - channelCircuitTypes[channel] = CircuitType.values()[settingIdx]; - - if(isInput(this.channelCircuitTypes[channel]) && CircuitType.canBeToggledBetweenPulseAndNormal(this.channelCircuitTypes[channel])) { - inputActivatesOnPulse[channel] = settingTag.getBoolean("pulse"); - } - - if( CircuitType.hasCoordinate(channelCircuitTypes[channel]) ) { - if(settingTag.hasKey("x")) { - int x, y, z; - x = settingTag.getInteger("x"); - y = settingTag.getInteger("y"); - z = settingTag.getInteger("z"); - coordMappings[channel] = new CoordTriplet(x, y, z); - } - } - } - - // Receives settings from a client via an update packet - public void onCircuitUpdate(RedNetChange[] changes) { - if(changes == null || changes.length < 1) { return; } - - for(int i = 0; i < changes.length; i++) { - int channelID = changes[i].getChannel(); - CircuitType newType = changes[i].getType(); - - channelCircuitTypes[channelID] = newType; - - if(CircuitType.canBeToggledBetweenPulseAndNormal(newType)) { - inputActivatesOnPulse[channelID] = changes[i].getPulseOrToggle(); - } - - if(CircuitType.hasCoordinate(newType)) { - CoordTriplet coord = changes[i].getCoord(); - - // Validate that we're pointing at the right thing, just in case. - if(coord != null) { - TileEntity te = worldObj.getTileEntity(coord.x, coord.y, coord.z); - if(!(te instanceof TileEntityReactorControlRod)) { - BRLog.warning("Invalid tile entity reference at coordinate %s - rednet circuit expected a control rod", coord); - coord = null; - } - } - - coordMappings[channelID] = coord; - } - else { - coordMappings[channelID] = null; - } - } - - worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - markDirty(); - } - - // Helpers - protected void encodeSettings(NBTTagCompound destination) { - NBTTagList tagArray = new NBTTagList(); - - for(int i = 0; i < numChannels; i++) { - tagArray.appendTag(encodeSetting(i)); - } - - destination.setTag("redNetConfig", tagArray); - } - - protected void decodeSettings(NBTTagCompound source) { - NBTTagList tagArray = source.getTagList("redNetConfig", 10); - for(int i = 0; i < tagArray.tagCount(); i++) { - decodeSetting( (NBTTagCompound)tagArray.getCompoundTagAt(i) ); - } - } - - /** - * Check for a world connection, if we're assembled. - * @param world - * @param x - * @param y - * @param z - */ - protected void checkForConnections(IBlockAccess world, int x, int y, int z) { - ForgeDirection out = getOutwardsDir(); - - if(out == ForgeDirection.UNKNOWN) { - redNetwork = null; - redNetInput = null; - } - else { - // Check for rednet connections nearby - redNetwork = null; - redNetInput = null; - - Block b = worldObj.getBlock(x + out.offsetX, y + out.offsetY, z + out.offsetZ); - if(!(b instanceof BlockReactorPart)) { - if(b instanceof IRedNetNetworkContainer) { - redNetwork = (IRedNetNetworkContainer)b; - } - else if(b instanceof IRedNetInputNode) { - redNetInput = (IRedNetInputNode)b; - } - } - } - } - - // Static Helpers - public static boolean isInput(CircuitType type) { return type.ordinal() >= minInputEnumValue && type.ordinal() <= maxInputEnumValue; } - public static boolean isOutput(CircuitType type) { return type.ordinal() >= minOutputEnumValue && type.ordinal() <= maxOutputEnumValue; } + public static boolean isOutput(CircuitType type) { + return type.ordinal() >= minOutputEnumValue && type.ordinal() <= maxOutputEnumValue; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorRedstonePort.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorRedstonePort.java index 1d4de498..ef6d733d 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorRedstonePort.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorRedstonePort.java @@ -6,6 +6,7 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import erogenousbeef.bigreactors.client.gui.GuiReactorRedstonePort; @@ -18,398 +19,451 @@ import erogenousbeef.core.multiblock.MultiblockControllerBase; import erogenousbeef.core.multiblock.MultiblockValidationException; -public class TileEntityReactorRedstonePort extends TileEntityReactorPartBase - implements ITickableMultiblockPart { - - protected CircuitType circuitType; - protected int outputLevel; - protected boolean activeOnPulse; - protected boolean greaterThan; // if false, less than - - protected int ticksSinceLastUpdate; - - // These are local-only and used for handy state calculations - protected boolean isExternallyPowered; - - public TileEntityReactorRedstonePort() { - super(); - - circuitType = circuitType.DISABLED; - isExternallyPowered = false; - ticksSinceLastUpdate = 0; - } - - // Redstone methods - public boolean isRedstoneActive() { - if(!this.isConnected()) { return false; } - - MultiblockReactor reactor = (MultiblockReactor)getMultiblockController(); - - switch(circuitType) { - case outputFuelTemperature: - return checkVariable((int)reactor.getFuelHeat()); - case outputCasingTemperature: - return checkVariable((int)reactor.getReactorHeat()); - case outputFuelMix: - return checkVariable((int)(reactor.getFuelRichness()*100)); - case outputFuelAmount: - return checkVariable(reactor.getFuelAmount()); - case outputWasteAmount: - return checkVariable(reactor.getWasteAmount()); - case outputEnergyAmount: - return checkVariable(reactor.getEnergyStoredPercentage()); - case DISABLED: - return false; - default: - return this.isExternallyPowered; - } - } - - public boolean isInput() { - return TileEntityReactorRedNetPort.isInput(this.circuitType); - } - - public boolean isOutput() { - return TileEntityReactorRedNetPort.isOutput(this.circuitType); - } - - protected boolean checkVariable(int value) { - if(this.greaterThan) { - return value > getOutputLevel(); - } - else { - return value < getOutputLevel(); - } - } - - public void sendRedstoneUpdate() { - if(this.worldObj != null && !this.worldObj.isRemote) { - int md; - - if(this.isOutput()) { - md = isRedstoneActive() ? BlockReactorRedstonePort.META_REDSTONE_LIT : BlockReactorRedstonePort.META_REDSTONE_UNLIT; - } - else { - md = isExternallyPowered ? BlockReactorRedstonePort.META_REDSTONE_LIT : BlockReactorRedstonePort.META_REDSTONE_UNLIT; - } - - if(md != this.worldObj.getBlockMetadata(xCoord, yCoord, zCoord)) { - this.worldObj.setBlockMetadataWithNotify(xCoord, yCoord, zCoord, md, 3); - } - } - } - - public void onNeighborBlockChange(int x, int y, int z, Block neighborBlock) { - if(!this.isConnected()) { return; } - - if(this.isInput()) { - ForgeDirection out = getOutwardsDir(); - boolean nowPowered = isReceivingRedstonePowerFrom(worldObj, xCoord+out.offsetX, yCoord+out.offsetY, zCoord+out.offsetZ, out, neighborBlock); - - if(this.isExternallyPowered != nowPowered) { - this.isExternallyPowered = nowPowered; - this.onRedstoneInputUpdated(); - this.sendRedstoneUpdate(); - } - } - else { - this.isExternallyPowered = false; - } - } - - // Called to do business logic when the redstone value has changed - protected void onRedstoneInputUpdated() { - if(!this.isConnected()) { return; } - - MultiblockReactor reactor = (MultiblockReactor)getMultiblockController(); - switch(this.circuitType) { - case inputActive: - if(this.isInputActiveOnPulse()) { - if(this.isExternallyPowered) { - reactor.setActive(!reactor.getActive()); - } - } - else { - reactor.setActive(this.isExternallyPowered); - } - break; - case inputSetControlRod: - // On/off only - if(this.isInputActiveOnPulse()) { - if(this.isExternallyPowered) { - if(this.shouldSetControlRodsInsteadOfChange()) { - reactor.setAllControlRodInsertionValues(this.outputLevel); - } - else { - reactor.changeAllControlRodInsertionValues((short)this.outputLevel); // Can be negative, don't want to mask. - } - } - } - else { - if(this.isExternallyPowered) { - reactor.setAllControlRodInsertionValues(getControlRodLevelWhileOn()); - } - else { - reactor.setAllControlRodInsertionValues(getControlRodLevelWhileOff()); - } - } - break; - case inputEjectWaste: - // Pulse only - if(this.isExternallyPowered) { - reactor.ejectWaste(false, null); - } - break; - default: - break; - } - } - - public int getOutputLevel() { return outputLevel; } - public int getControlRodLevelWhileOff() { return ((outputLevel & 0xFF00) >> 8) & 0xFF; } - public int getControlRodLevelWhileOn () { return outputLevel & 0xFF; } - - public static int packControlRodLevels(byte off, byte on) { - return (((int)off << 8) & 0xFF00) | (on & 0xFF); - } - - public static int unpackControlRodLevelOn(int level) { - return level & 0xFF; - } - - public static int unpackControlRodLevelOff(int level) { - return ((level & 0xFF00) >> 8) & 0xFF; - } - - public boolean isInputActiveOnPulse() { - return this.activeOnPulse; - } - - /** - * @param newType The type of the new circuit. - * @param param1 For input/control rods, the level(s) to change or set. For outputs, the numerical value - * @param greaterThan For outputs, whether to activate when greater than or less than the outputLevel value. For input/control rods, whether to set (true) or change (false) the values. - */ - public void onReceiveUpdatePacket(int newType, int outputLevel, boolean greaterThan, boolean activeOnPulse) { - this.circuitType = CircuitType.values()[newType]; - this.outputLevel = outputLevel; - this.greaterThan = greaterThan; - this.activeOnPulse = activeOnPulse; - - if(isAlwaysActiveOnPulse(circuitType)) { this.activeOnPulse = true; } - else if(TileEntityReactorRedNetPort.isOutput(this.circuitType)) { this.activeOnPulse = false; } - - // Do updates - if(this.isInput()) { - // Update inputs so we don't pulse/change automatically - ForgeDirection out = getOutwardsDir(); - this.isExternallyPowered = isReceivingRedstonePowerFrom(worldObj, xCoord+out.offsetX, yCoord+out.offsetY, zCoord+out.offsetZ, out); - if(!this.isInputActiveOnPulse()) { - onRedstoneInputUpdated(); - } - } - else { - this.isExternallyPowered = false; - } - - // Ensure visuals and metadata reflect our new settings & state - this.sendRedstoneUpdate(); - - if(!this.worldObj.isRemote) { - // Propagate the new settings - this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - this.worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this); - } - } - - @SideOnly(Side.CLIENT) - public boolean getGreaterThan() { return this.greaterThan; } - - public CircuitType getCircuitType() { return this.circuitType; } - private boolean shouldSetControlRodsInsteadOfChange() { return !greaterThan; } - - public void onRedNetUpdate(int powerLevel) { - if(this.isInput()) { - boolean wasPowered = this.isExternallyPowered; - this.isExternallyPowered = powerLevel > 0; - if(wasPowered != this.isExternallyPowered) { - this.onRedstoneInputUpdated(); - this.sendRedstoneUpdate(); - } - } - } - - /** - * Call with the coordinates of the block to check and the direction - * towards that block from your block. - * If the block towards which this block is emitting power lies north, - * then pass in south. - */ - private boolean isReceivingRedstonePowerFrom(World world, int x, int y, int z, ForgeDirection dir) { - // This is because of bugs in vanilla redstone wires - Block block = world.getBlock(x, y, z); - return isReceivingRedstonePowerFrom(world, x, y, z, dir, block); - } - - /** - * Call with the coordinates of the block to check and the direction - * towards that block from your block. - * If the block towards which this block is emitting power lies north, - * then pass in south. - */ - private boolean isReceivingRedstonePowerFrom(World world, int x, int y, int z, ForgeDirection dir, Block neighborBlock) { - if(neighborBlock == Blocks.redstone_wire) { - // Use metadata because of vanilla redstone wire bugs - return world.getBlockMetadata(x, y, z) > 0; - } - else { - return world.getIndirectPowerOutput(x, y, z, dir.ordinal()) || world.isBlockProvidingPowerTo(x, y, z, dir.ordinal()) > 0; - } - } - - // TileEntity overrides - - // Only refresh if we're switching functionality - // Warning: dragonz! - @Override - public boolean shouldRefresh(Block oldID, Block newID, int oldMeta, int newMeta, World world, int x, int y, int z) - { - if(oldID != newID) { - return true; - } - - // All redstone ports are the same, we just use metadata to easily signal changes. - return false; - } - - // IReactorTickable - /** - * Updates the redstone block's status, if it's an output network, if there is one. - * Will only send one update per N ticks, where N is a configurable setting. - */ - public void onMultiblockServerTick() { - if(!this.isConnected()) { return; } - - ticksSinceLastUpdate++; - if(ticksSinceLastUpdate < BigReactors.ticksPerRedstoneUpdate) { return; } - - if(this.isOutput()) { - // Will no-op if there's no change. - this.sendRedstoneUpdate(); - } - ticksSinceLastUpdate = 0; - } - - // MultiblockTileEntityBase methods - private void readData(NBTTagCompound data) { - if(data.hasKey("circuitType")) { - this.circuitType = circuitType.values()[data.getInteger("circuitType")]; - } - - if(data.hasKey("outputLevel")) { - this.outputLevel = data.getInteger("outputLevel"); - } - - if(data.hasKey("greaterThan")) { - this.greaterThan = data.getBoolean("greaterThan"); - } - - if(data.hasKey("activeOnPulse")) { - this.activeOnPulse = data.getBoolean("activeOnPulse"); - } - } - - private void writeData(NBTTagCompound data) { - data.setInteger("circuitType", this.circuitType.ordinal()); - data.setInteger("outputLevel", this.outputLevel); - data.setBoolean("greaterThan", this.greaterThan); - data.setBoolean("activeOnPulse", this.activeOnPulse); - } - - @Override - public void readFromNBT(NBTTagCompound data) { - super.readFromNBT(data); - this.readData(data); - this.sendRedstoneUpdate(); - } - - @Override - public void writeToNBT(NBTTagCompound data) { - super.writeToNBT(data); - this.writeData(data); - } - - @Override - public void decodeDescriptionPacket(NBTTagCompound data) { - super.decodeDescriptionPacket(data); - this.readData(data); - } - - @Override - public void encodeDescriptionPacket(NBTTagCompound data) { - super.encodeDescriptionPacket(data); - this.writeData(data); - } - - @Override - public void isGoodForFrame() throws MultiblockValidationException { - throw new MultiblockValidationException(String.format("%d, %d, %d - Redstone ports may only be placed on a reactor's external side faces, not as part of the frame", xCoord, yCoord, zCoord)); - } - - @Override - public void isGoodForSides() throws MultiblockValidationException { - } - - @Override - public void isGoodForTop() throws MultiblockValidationException { - throw new MultiblockValidationException(String.format("%d, %d, %d - Redstone ports may only be placed on a reactor's external side faces, not the top", xCoord, yCoord, zCoord)); - } - - @Override - public void isGoodForBottom() throws MultiblockValidationException { - throw new MultiblockValidationException(String.format("%d, %d, %d - Redstone ports may only be placed on a reactor's external side faces, not the bottom", xCoord, yCoord, zCoord)); - } - - @Override - public void isGoodForInterior() throws MultiblockValidationException { - throw new MultiblockValidationException(String.format("%d, %d, %d - Redstone ports may not be placed in a reactor's interior", xCoord, yCoord, zCoord)); - } - - @Override - public void onMachineAssembled(MultiblockControllerBase controller) { - super.onMachineAssembled(controller); - this.sendRedstoneUpdate(); - } - - @Override - public void onMachineBroken() { - super.onMachineBroken(); - this.sendRedstoneUpdate(); - } - - @Override - public void onMachineActivated() { - this.sendRedstoneUpdate(); - } - - @Override - public void onMachineDeactivated() { - this.sendRedstoneUpdate(); - } - - // IBeefGuiEntity - @SideOnly(Side.CLIENT) - @Override - public Object getGuiElement(InventoryPlayer inventoryPlayer) { - return new GuiReactorRedstonePort(new ContainerBasic(), this); - } - - @Override - public Object getContainer(InventoryPlayer inventoryPlayer) { - return new ContainerBasic(); - } - - public static boolean isAlwaysActiveOnPulse(CircuitType circuitType) { - return circuitType == CircuitType.inputEjectWaste; - } +public class TileEntityReactorRedstonePort extends TileEntityReactorPartBase implements ITickableMultiblockPart { + + protected CircuitType circuitType; + protected int outputLevel; + protected boolean activeOnPulse; + protected boolean greaterThan; // if false, less than + + protected int ticksSinceLastUpdate; + + // These are local-only and used for handy state calculations + protected boolean isExternallyPowered; + + public TileEntityReactorRedstonePort() { + super(); + + circuitType = circuitType.DISABLED; + isExternallyPowered = false; + ticksSinceLastUpdate = 0; + } + + // Redstone methods + public boolean isRedstoneActive() { + if (!this.isConnected()) { + return false; + } + + MultiblockReactor reactor = (MultiblockReactor) getMultiblockController(); + + switch (circuitType) { + case outputFuelTemperature: + return checkVariable((int) reactor.getFuelHeat()); + case outputCasingTemperature: + return checkVariable((int) reactor.getReactorHeat()); + case outputFuelMix: + return checkVariable((int) (reactor.getFuelRichness() * 100)); + case outputFuelAmount: + return checkVariable(reactor.getFuelAmount()); + case outputWasteAmount: + return checkVariable(reactor.getWasteAmount()); + case outputEnergyAmount: + return checkVariable(reactor.getEnergyStoredPercentage()); + case DISABLED: + return false; + default: + return this.isExternallyPowered; + } + } + + public boolean isInput() { + return TileEntityReactorRedNetPort.isInput(this.circuitType); + } + + public boolean isOutput() { + return TileEntityReactorRedNetPort.isOutput(this.circuitType); + } + + protected boolean checkVariable(int value) { + if (this.greaterThan) { + return value > getOutputLevel(); + } else { + return value < getOutputLevel(); + } + } + + public void sendRedstoneUpdate() { + if (this.worldObj != null && !this.worldObj.isRemote) { + int md; + + if (this.isOutput()) { + md = isRedstoneActive() ? BlockReactorRedstonePort.META_REDSTONE_LIT + : BlockReactorRedstonePort.META_REDSTONE_UNLIT; + } else { + md = isExternallyPowered ? BlockReactorRedstonePort.META_REDSTONE_LIT + : BlockReactorRedstonePort.META_REDSTONE_UNLIT; + } + + if (md != this.worldObj.getBlockMetadata(xCoord, yCoord, zCoord)) { + this.worldObj.setBlockMetadataWithNotify(xCoord, yCoord, zCoord, md, 3); + } + } + } + + public void onNeighborBlockChange(int x, int y, int z, Block neighborBlock) { + if (!this.isConnected()) { + return; + } + + if (this.isInput()) { + ForgeDirection out = getOutwardsDir(); + boolean nowPowered = isReceivingRedstonePowerFrom( + worldObj, + xCoord + out.offsetX, + yCoord + out.offsetY, + zCoord + out.offsetZ, + out, + neighborBlock); + + if (this.isExternallyPowered != nowPowered) { + this.isExternallyPowered = nowPowered; + this.onRedstoneInputUpdated(); + this.sendRedstoneUpdate(); + } + } else { + this.isExternallyPowered = false; + } + } + + // Called to do business logic when the redstone value has changed + protected void onRedstoneInputUpdated() { + if (!this.isConnected()) { + return; + } + + MultiblockReactor reactor = (MultiblockReactor) getMultiblockController(); + switch (this.circuitType) { + case inputActive: + if (this.isInputActiveOnPulse()) { + if (this.isExternallyPowered) { + reactor.setActive(!reactor.getActive()); + } + } else { + reactor.setActive(this.isExternallyPowered); + } + break; + case inputSetControlRod: + // On/off only + if (this.isInputActiveOnPulse()) { + if (this.isExternallyPowered) { + if (this.shouldSetControlRodsInsteadOfChange()) { + reactor.setAllControlRodInsertionValues(this.outputLevel); + } else { + reactor.changeAllControlRodInsertionValues((short) this.outputLevel); // Can be negative, + // don't want to mask. + } + } + } else { + if (this.isExternallyPowered) { + reactor.setAllControlRodInsertionValues(getControlRodLevelWhileOn()); + } else { + reactor.setAllControlRodInsertionValues(getControlRodLevelWhileOff()); + } + } + break; + case inputEjectWaste: + // Pulse only + if (this.isExternallyPowered) { + reactor.ejectWaste(false, null); + } + break; + default: + break; + } + } + + public int getOutputLevel() { + return outputLevel; + } + + public int getControlRodLevelWhileOff() { + return ((outputLevel & 0xFF00) >> 8) & 0xFF; + } + + public int getControlRodLevelWhileOn() { + return outputLevel & 0xFF; + } + + public static int packControlRodLevels(byte off, byte on) { + return (((int) off << 8) & 0xFF00) | (on & 0xFF); + } + + public static int unpackControlRodLevelOn(int level) { + return level & 0xFF; + } + + public static int unpackControlRodLevelOff(int level) { + return ((level & 0xFF00) >> 8) & 0xFF; + } + + public boolean isInputActiveOnPulse() { + return this.activeOnPulse; + } + + /** + * @param newType The type of the new circuit. + * @param param1 For input/control rods, the level(s) to change or set. For outputs, the numerical value + * @param greaterThan For outputs, whether to activate when greater than or less than the outputLevel value. For + * input/control rods, whether to set (true) or change (false) the values. + */ + public void onReceiveUpdatePacket(int newType, int outputLevel, boolean greaterThan, boolean activeOnPulse) { + this.circuitType = CircuitType.values()[newType]; + this.outputLevel = outputLevel; + this.greaterThan = greaterThan; + this.activeOnPulse = activeOnPulse; + + if (isAlwaysActiveOnPulse(circuitType)) { + this.activeOnPulse = true; + } else if (TileEntityReactorRedNetPort.isOutput(this.circuitType)) { + this.activeOnPulse = false; + } + + // Do updates + if (this.isInput()) { + // Update inputs so we don't pulse/change automatically + ForgeDirection out = getOutwardsDir(); + this.isExternallyPowered = isReceivingRedstonePowerFrom( + worldObj, + xCoord + out.offsetX, + yCoord + out.offsetY, + zCoord + out.offsetZ, + out); + if (!this.isInputActiveOnPulse()) { + onRedstoneInputUpdated(); + } + } else { + this.isExternallyPowered = false; + } + + // Ensure visuals and metadata reflect our new settings & state + this.sendRedstoneUpdate(); + + if (!this.worldObj.isRemote) { + // Propagate the new settings + this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + this.worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this); + } + } + + @SideOnly(Side.CLIENT) + public boolean getGreaterThan() { + return this.greaterThan; + } + + public CircuitType getCircuitType() { + return this.circuitType; + } + + private boolean shouldSetControlRodsInsteadOfChange() { + return !greaterThan; + } + + public void onRedNetUpdate(int powerLevel) { + if (this.isInput()) { + boolean wasPowered = this.isExternallyPowered; + this.isExternallyPowered = powerLevel > 0; + if (wasPowered != this.isExternallyPowered) { + this.onRedstoneInputUpdated(); + this.sendRedstoneUpdate(); + } + } + } + + /** + * Call with the coordinates of the block to check and the direction + * towards that block from your block. + * If the block towards which this block is emitting power lies north, + * then pass in south. + */ + private boolean isReceivingRedstonePowerFrom(World world, int x, int y, int z, ForgeDirection dir) { + // This is because of bugs in vanilla redstone wires + Block block = world.getBlock(x, y, z); + return isReceivingRedstonePowerFrom(world, x, y, z, dir, block); + } + + /** + * Call with the coordinates of the block to check and the direction + * towards that block from your block. + * If the block towards which this block is emitting power lies north, + * then pass in south. + */ + private boolean isReceivingRedstonePowerFrom(World world, int x, int y, int z, ForgeDirection dir, + Block neighborBlock) { + if (neighborBlock == Blocks.redstone_wire) { + // Use metadata because of vanilla redstone wire bugs + return world.getBlockMetadata(x, y, z) > 0; + } else { + return world.getIndirectPowerOutput(x, y, z, dir.ordinal()) + || world.isBlockProvidingPowerTo(x, y, z, dir.ordinal()) > 0; + } + } + + // TileEntity overrides + + // Only refresh if we're switching functionality + // Warning: dragonz! + @Override + public boolean shouldRefresh(Block oldID, Block newID, int oldMeta, int newMeta, World world, int x, int y, int z) { + if (oldID != newID) { + return true; + } + + // All redstone ports are the same, we just use metadata to easily signal changes. + return false; + } + + // IReactorTickable + /** + * Updates the redstone block's status, if it's an output network, if there is one. + * Will only send one update per N ticks, where N is a configurable setting. + */ + public void onMultiblockServerTick() { + if (!this.isConnected()) { + return; + } + + ticksSinceLastUpdate++; + if (ticksSinceLastUpdate < BigReactors.ticksPerRedstoneUpdate) { + return; + } + + if (this.isOutput()) { + // Will no-op if there's no change. + this.sendRedstoneUpdate(); + } + ticksSinceLastUpdate = 0; + } + + // MultiblockTileEntityBase methods + private void readData(NBTTagCompound data) { + if (data.hasKey("circuitType")) { + this.circuitType = circuitType.values()[data.getInteger("circuitType")]; + } + + if (data.hasKey("outputLevel")) { + this.outputLevel = data.getInteger("outputLevel"); + } + + if (data.hasKey("greaterThan")) { + this.greaterThan = data.getBoolean("greaterThan"); + } + + if (data.hasKey("activeOnPulse")) { + this.activeOnPulse = data.getBoolean("activeOnPulse"); + } + } + + private void writeData(NBTTagCompound data) { + data.setInteger("circuitType", this.circuitType.ordinal()); + data.setInteger("outputLevel", this.outputLevel); + data.setBoolean("greaterThan", this.greaterThan); + data.setBoolean("activeOnPulse", this.activeOnPulse); + } + + @Override + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + this.readData(data); + this.sendRedstoneUpdate(); + } + + @Override + public void writeToNBT(NBTTagCompound data) { + super.writeToNBT(data); + this.writeData(data); + } + + @Override + public void decodeDescriptionPacket(NBTTagCompound data) { + super.decodeDescriptionPacket(data); + this.readData(data); + } + + @Override + public void encodeDescriptionPacket(NBTTagCompound data) { + super.encodeDescriptionPacket(data); + this.writeData(data); + } + + @Override + public void isGoodForFrame() throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format( + "%d, %d, %d - Redstone ports may only be placed on a reactor's external side faces, not as part of the frame", + xCoord, + yCoord, + zCoord)); + } + + @Override + public void isGoodForSides() throws MultiblockValidationException {} + + @Override + public void isGoodForTop() throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format( + "%d, %d, %d - Redstone ports may only be placed on a reactor's external side faces, not the top", + xCoord, + yCoord, + zCoord)); + } + + @Override + public void isGoodForBottom() throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format( + "%d, %d, %d - Redstone ports may only be placed on a reactor's external side faces, not the bottom", + xCoord, + yCoord, + zCoord)); + } + + @Override + public void isGoodForInterior() throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format( + "%d, %d, %d - Redstone ports may not be placed in a reactor's interior", + xCoord, + yCoord, + zCoord)); + } + + @Override + public void onMachineAssembled(MultiblockControllerBase controller) { + super.onMachineAssembled(controller); + this.sendRedstoneUpdate(); + } + + @Override + public void onMachineBroken() { + super.onMachineBroken(); + this.sendRedstoneUpdate(); + } + + @Override + public void onMachineActivated() { + this.sendRedstoneUpdate(); + } + + @Override + public void onMachineDeactivated() { + this.sendRedstoneUpdate(); + } + + // IBeefGuiEntity + @SideOnly(Side.CLIENT) + @Override + public Object getGuiElement(InventoryPlayer inventoryPlayer) { + return new GuiReactorRedstonePort(new ContainerBasic(), this); + } + + @Override + public Object getContainer(InventoryPlayer inventoryPlayer) { + return new ContainerBasic(); + } + + public static boolean isAlwaysActiveOnPulse(CircuitType circuitType) { + return circuitType == CircuitType.inputEjectWaste; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbineComputerPort.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbineComputerPort.java index 5e606307..e81b876d 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbineComputerPort.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbineComputerPort.java @@ -3,11 +3,8 @@ import java.util.HashMap; import java.util.Map; -import li.cil.oc.api.machine.Arguments; -import li.cil.oc.api.machine.Context; -import li.cil.oc.api.network.ManagedPeripheral; -import li.cil.oc.api.network.SimpleComponent; import net.minecraftforge.fluids.FluidTankInfo; + import cpw.mods.fml.common.Optional; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.peripheral.IComputerAccess; @@ -16,263 +13,258 @@ import erogenousbeef.bigreactors.common.multiblock.MultiblockTurbine; import erogenousbeef.bigreactors.common.multiblock.MultiblockTurbine.VentStatus; import erogenousbeef.core.common.CoordTriplet; +import li.cil.oc.api.machine.Arguments; +import li.cil.oc.api.machine.Context; +import li.cil.oc.api.network.ManagedPeripheral; +import li.cil.oc.api.network.SimpleComponent; -@Optional.InterfaceList({ - @Optional.Interface(iface = "li.cil.oc.api.network.SimpleComponent", modid = "OpenComputers"), - @Optional.Interface(iface = "li.cil.oc.api.network.ManagedPeripheral", modid = "OpenComputers"), - @Optional.Interface(iface = "dan200.computercraft.api.peripheral.IPeripheral", modid = "ComputerCraft") -}) -public class TileEntityTurbineComputerPort extends - TileEntityTurbinePartStandard implements IPeripheral, SimpleComponent, ManagedPeripheral { +@Optional.InterfaceList({ @Optional.Interface(iface = "li.cil.oc.api.network.SimpleComponent", modid = "OpenComputers"), + @Optional.Interface(iface = "li.cil.oc.api.network.ManagedPeripheral", modid = "OpenComputers"), + @Optional.Interface(iface = "dan200.computercraft.api.peripheral.IPeripheral", modid = "ComputerCraft") }) +public class TileEntityTurbineComputerPort extends TileEntityTurbinePartStandard + implements IPeripheral, SimpleComponent, ManagedPeripheral { - public enum ComputerMethod { - getConnected, // No arguments - getActive, // No arguments - getEnergyStored, // No arguments - getRotorSpeed, // No arguments - getInputAmount, // No arguments - getInputType, // No arguments - getOutputAmount, // No arguments - getOutputType, // No arguments - getFluidAmountMax, // No arguments - getFluidFlowRate, // No arguments - getFluidFlowRateMax, // No arguments - getFluidFlowRateMaxMax, // No arguments - getEnergyProducedLastTick, // No arguments - getNumberOfBlades, // No arguments - getBladeEfficiency, // No arguments - getRotorMass, // No arguments - getInductorEngaged, // No arguments - getMaximumCoordinate, // No arguments - getMinimumCoordinate, // No arguments - setActive, // Required Arg: integer (active) - setFluidFlowRateMax, // Required Arg: integer (active) - setVentNone, // No arguments - setVentOverflow, // No arguments - setVentAll, // No arguments - setInductorEngaged, // Required Arg: integer (active) - } + public enum ComputerMethod { + getConnected, // No arguments + getActive, // No arguments + getEnergyStored, // No arguments + getRotorSpeed, // No arguments + getInputAmount, // No arguments + getInputType, // No arguments + getOutputAmount, // No arguments + getOutputType, // No arguments + getFluidAmountMax, // No arguments + getFluidFlowRate, // No arguments + getFluidFlowRateMax, // No arguments + getFluidFlowRateMaxMax, // No arguments + getEnergyProducedLastTick, // No arguments + getNumberOfBlades, // No arguments + getBladeEfficiency, // No arguments + getRotorMass, // No arguments + getInductorEngaged, // No arguments + getMaximumCoordinate, // No arguments + getMinimumCoordinate, // No arguments + setActive, // Required Arg: integer (active) + setFluidFlowRateMax, // Required Arg: integer (active) + setVentNone, // No arguments + setVentOverflow, // No arguments + setVentAll, // No arguments + setInductorEngaged, // Required Arg: integer (active) + } - public static final int numMethods = ComputerMethod.values().length; + public static final int numMethods = ComputerMethod.values().length; - public static final String[] methodNames = new String[numMethods]; - static { - ComputerMethod[] methods = ComputerMethod.values(); - for(ComputerMethod method : methods) { - methodNames[method.ordinal()] = method.toString(); - } - } + public static final String[] methodNames = new String[numMethods]; + static { + ComputerMethod[] methods = ComputerMethod.values(); + for (ComputerMethod method : methods) { + methodNames[method.ordinal()] = method.toString(); + } + } + + public static final Map methodIds = new HashMap(); + static { + for (int i = 0; i < numMethods; ++i) { + methodIds.put(methodNames[i], i); + } + } + + public Object[] callMethod(int method, Object[] arguments) throws Exception { + if (method < 0 || method >= numMethods) { + throw new IllegalArgumentException("Invalid method number"); + } - public static final Map methodIds = new HashMap(); - static { - for (int i = 0; i < numMethods; ++i) { - methodIds.put(methodNames[i], i); - } - } + // Special case: getConnected can always be called. + if (method == 0) { + return new Object[] { this.isConnected() }; + } - public Object[] callMethod(int method, Object[] arguments) throws Exception { - if(method < 0 || method >= numMethods) { - throw new IllegalArgumentException("Invalid method number"); - } - - // Special case: getConnected can always be called. - if(method == 0) { - return new Object[] { this.isConnected() }; - } + if (!this.isConnected()) { + throw new Exception("Unable to access turbine - port is not connected"); + } - if(!this.isConnected()) { - throw new Exception("Unable to access turbine - port is not connected"); - } + ComputerMethod computerMethod = ComputerMethod.values()[method]; + MultiblockTurbine turbine = getTurbine(); + FluidTankInfo ti; - ComputerMethod computerMethod = ComputerMethod.values()[method]; - MultiblockTurbine turbine = getTurbine(); - FluidTankInfo ti; + switch (computerMethod) { + case getConnected: + return new Object[] { isConnected() }; + case getActive: + return new Object[] { turbine.getActive() }; + case getEnergyProducedLastTick: + return new Object[] { turbine.getEnergyGeneratedLastTick() }; + case getEnergyStored: + return new Object[] { turbine.getEnergyStored() }; + case getFluidAmountMax: + return new Object[] { MultiblockTurbine.TANK_SIZE }; + case getFluidFlowRate: + return new Object[] { turbine.getFluidConsumedLastTick() }; + case getFluidFlowRateMax: + return new Object[] { turbine.getMaxIntakeRate() }; + case getFluidFlowRateMaxMax: + return new Object[] { turbine.getMaxIntakeRateMax() }; + case getInputAmount: + ti = turbine.getTankInfo(MultiblockTurbine.TANK_INPUT); + if (ti != null && ti.fluid != null) { + return new Object[] { ti.fluid.amount }; + } else { + return new Object[] { 0f }; + } + case getInputType: + ti = turbine.getTankInfo(MultiblockTurbine.TANK_INPUT); + if (ti != null && ti.fluid != null) { + return new Object[] { ti.fluid.getFluid() + .getName() }; + } else { + return null; + } + case getOutputAmount: + ti = turbine.getTankInfo(MultiblockTurbine.TANK_OUTPUT); + if (ti != null && ti.fluid != null) { + return new Object[] { ti.fluid.amount }; + } else { + return new Object[] { 0f }; + } + case getOutputType: + ti = turbine.getTankInfo(MultiblockTurbine.TANK_OUTPUT); + if (ti != null && ti.fluid != null) { + return new Object[] { ti.fluid.getFluid() + .getName() }; + } else { + return null; + } + case getRotorSpeed: + return new Object[] { turbine.getRotorSpeed() }; + case getNumberOfBlades: + return new Object[] { turbine.getNumRotorBlades() }; + case getBladeEfficiency: + return new Object[] { turbine.getRotorEfficiencyLastTick() * 100f }; + case getRotorMass: + return new Object[] { turbine.getRotorMass() }; + case getInductorEngaged: + return new Object[] { turbine.getInductorEngaged() }; + case getMinimumCoordinate: { + CoordTriplet coord = turbine.getMinimumCoord(); + return new Object[] { coord.x, coord.y, coord.z }; + } - switch(computerMethod) { - case getConnected: - return new Object[] { isConnected() }; - case getActive: - return new Object[] { turbine.getActive() }; - case getEnergyProducedLastTick: - return new Object[] { turbine.getEnergyGeneratedLastTick() }; - case getEnergyStored: - return new Object[] { turbine.getEnergyStored() }; - case getFluidAmountMax: - return new Object[] { MultiblockTurbine.TANK_SIZE }; - case getFluidFlowRate: - return new Object[] { turbine.getFluidConsumedLastTick() }; - case getFluidFlowRateMax: - return new Object[] { turbine.getMaxIntakeRate() }; - case getFluidFlowRateMaxMax: - return new Object[] { turbine.getMaxIntakeRateMax() }; - case getInputAmount: - ti = turbine.getTankInfo(MultiblockTurbine.TANK_INPUT); - if(ti != null && ti.fluid != null) { - return new Object[] { ti.fluid.amount }; - } - else { - return new Object[] { 0f }; - } - case getInputType: - ti = turbine.getTankInfo(MultiblockTurbine.TANK_INPUT); - if(ti != null && ti.fluid != null) { - return new Object[] { ti.fluid.getFluid().getName() }; - } - else { - return null; - } - case getOutputAmount: - ti = turbine.getTankInfo(MultiblockTurbine.TANK_OUTPUT); - if(ti != null && ti.fluid != null) { - return new Object[] { ti.fluid.amount }; - } - else { - return new Object[] { 0f }; - } - case getOutputType: - ti = turbine.getTankInfo(MultiblockTurbine.TANK_OUTPUT); - if(ti != null && ti.fluid != null) { - return new Object[] { ti.fluid.getFluid().getName() }; - } - else { - return null; - } - case getRotorSpeed: - return new Object[] { turbine.getRotorSpeed() }; - case getNumberOfBlades: - return new Object[] { turbine.getNumRotorBlades() }; - case getBladeEfficiency: - return new Object[] { turbine.getRotorEfficiencyLastTick() * 100f }; - case getRotorMass: - return new Object[] { turbine.getRotorMass() }; - case getInductorEngaged: - return new Object[] { turbine.getInductorEngaged() }; - case getMinimumCoordinate: - { - CoordTriplet coord = turbine.getMinimumCoord(); - return new Object[] { coord.x, coord.y, coord.z }; - } - - case getMaximumCoordinate: - { - CoordTriplet coord = turbine.getMaximumCoord(); - return new Object[] { coord.x, coord.y, coord.z }; - } + case getMaximumCoordinate: { + CoordTriplet coord = turbine.getMaximumCoord(); + return new Object[] { coord.x, coord.y, coord.z }; + } + + case setActive: + if (arguments.length < 1) { + throw new IllegalArgumentException("Insufficient number of arguments, expected 1"); + } + if (!(arguments[0] instanceof Boolean)) { + throw new IllegalArgumentException("Invalid argument 0, expected Boolean"); + } + turbine.setActive((Boolean) arguments[0]); + break; + case setFluidFlowRateMax: + if (arguments.length < 1) { + throw new IllegalArgumentException("Insufficient number of arguments, expected 1"); + } + if (!(arguments[0] instanceof Double)) { + throw new IllegalArgumentException("Invalid argument 0, expected Number"); + } + int newRate = (int) Math.round((Double) arguments[0]); + turbine.setMaxIntakeRate(newRate); + break; + case setVentNone: + turbine.setVentStatus(VentStatus.DoNotVent, true); + break; + case setVentOverflow: + turbine.setVentStatus(VentStatus.VentOverflow, true); + break; + case setVentAll: + turbine.setVentStatus(VentStatus.VentAll, true); + break; + case setInductorEngaged: + if (arguments.length < 1) { + throw new IllegalArgumentException("Insufficient number of arguments, expected 1"); + } + if (!(arguments[0] instanceof Boolean)) { + throw new IllegalArgumentException("Invalid argument 0, expected Boolean"); + } + turbine.setInductorEngaged((Boolean) arguments[0], true); + break; + default: + throw new Exception("Method unimplemented - yell at Beef"); + } - case setActive: - if(arguments.length < 1) { - throw new IllegalArgumentException("Insufficient number of arguments, expected 1"); - } - if(!(arguments[0] instanceof Boolean)) { - throw new IllegalArgumentException("Invalid argument 0, expected Boolean"); - } - turbine.setActive((Boolean)arguments[0]); - break; - case setFluidFlowRateMax: - if(arguments.length < 1) { - throw new IllegalArgumentException("Insufficient number of arguments, expected 1"); - } - if(!(arguments[0] instanceof Double)) { - throw new IllegalArgumentException("Invalid argument 0, expected Number"); - } - int newRate = (int)Math.round((Double)arguments[0]); - turbine.setMaxIntakeRate(newRate); - break; - case setVentNone: - turbine.setVentStatus(VentStatus.DoNotVent, true); - break; - case setVentOverflow: - turbine.setVentStatus(VentStatus.VentOverflow, true); - break; - case setVentAll: - turbine.setVentStatus(VentStatus.VentAll, true); - break; - case setInductorEngaged: - if(arguments.length < 1) { - throw new IllegalArgumentException("Insufficient number of arguments, expected 1"); - } - if(!(arguments[0] instanceof Boolean)) { - throw new IllegalArgumentException("Invalid argument 0, expected Boolean"); - } - turbine.setInductorEngaged((Boolean)arguments[0], true); - break; - default: - throw new Exception("Method unimplemented - yell at Beef"); - } - - return null; - } - - // ComputerCraft - - @Override - @Optional.Method(modid = "ComputerCraft") - public String getType() { - return "BigReactors-Turbine"; - } - - @Override - @Optional.Method(modid = "ComputerCraft") - public String[] getMethodNames() { - return methodNames; - } - - @Override - @Optional.Method(modid = "ComputerCraft") - public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) { + return null; + } + + // ComputerCraft + + @Override + @Optional.Method(modid = "ComputerCraft") + public String getType() { + return "BigReactors-Turbine"; + } + + @Override + @Optional.Method(modid = "ComputerCraft") + public String[] getMethodNames() { + return methodNames; + } + + @Override + @Optional.Method(modid = "ComputerCraft") + public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) { try { return callMethod(method, arguments); - } catch(Exception e) { - BRLog.info("Exception encountered when invoking computercraft method: %s", e.getMessage()); + } catch (Exception e) { + BRLog.info("Exception encountered when invoking computercraft method: %s", e.getMessage()); e.printStackTrace(); } return null; } - - @Override - @Optional.Method(modid = "ComputerCraft") - public void attach(IComputerAccess computer) { - } - - @Override - @Optional.Method(modid = "ComputerCraft") - public void detach(IComputerAccess computer) { - } - - // OpenComputers - - @Override - @Optional.Method(modid = "OpenComputers") - public String getComponentName() { - // Convention for OC names is a) lower case, b) valid variable names, - // so this can be used as `component.br_turbine.setActive(true)` e.g. - return "br_turbine"; - } - - @Override - @Optional.Method(modid = "OpenComputers") - public String[] methods() { - return methodNames; - } - - @Override - @Optional.Method(modid = "OpenComputers") - public Object[] invoke(final String method, final Context context, - final Arguments args) throws Exception { - final Object[] arguments = new Object[args.count()]; - for (int i = 0; i < args.count(); ++i) { - arguments[i] = args.checkAny(i); - } - final Integer methodId = methodIds.get(method); - if (methodId == null) { - throw new NoSuchMethodError(); - } - return callMethod(methodId, arguments); - } - @Override - @Optional.Method(modid = "ComputerCraft") - public boolean equals(IPeripheral other) { - return hashCode() == other.hashCode(); - } + @Override + @Optional.Method(modid = "ComputerCraft") + public void attach(IComputerAccess computer) {} + + @Override + @Optional.Method(modid = "ComputerCraft") + public void detach(IComputerAccess computer) {} + + // OpenComputers + + @Override + @Optional.Method(modid = "OpenComputers") + public String getComponentName() { + // Convention for OC names is a) lower case, b) valid variable names, + // so this can be used as `component.br_turbine.setActive(true)` e.g. + return "br_turbine"; + } + + @Override + @Optional.Method(modid = "OpenComputers") + public String[] methods() { + return methodNames; + } + + @Override + @Optional.Method(modid = "OpenComputers") + public Object[] invoke(final String method, final Context context, final Arguments args) throws Exception { + final Object[] arguments = new Object[args.count()]; + for (int i = 0; i < args.count(); ++i) { + arguments[i] = args.checkAny(i); + } + final Integer methodId = methodIds.get(method); + if (methodId == null) { + throw new NoSuchMethodError(); + } + return callMethod(methodId, arguments); + } + + @Override + @Optional.Method(modid = "ComputerCraft") + public boolean equals(IPeripheral other) { + return hashCode() == other.hashCode(); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbineFluidPort.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbineFluidPort.java index 1c66dae4..451c186b 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbineFluidPort.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbineFluidPort.java @@ -10,197 +10,210 @@ import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTankInfo; import net.minecraftforge.fluids.IFluidHandler; + import erogenousbeef.bigreactors.common.multiblock.MultiblockTurbine; import erogenousbeef.bigreactors.common.multiblock.interfaces.INeighborUpdatableEntity; import erogenousbeef.bigreactors.common.multiblock.interfaces.ITickableMultiblockPart; import erogenousbeef.core.multiblock.MultiblockControllerBase; -public class TileEntityTurbineFluidPort extends TileEntityTurbinePartStandard implements IFluidHandler, INeighborUpdatableEntity, ITickableMultiblockPart { - - public enum FluidFlow { - In, - Out - } - - FluidFlow flowSetting; - IFluidHandler pumpDestination; - - public TileEntityTurbineFluidPort() { - super(); - flowSetting = FluidFlow.In; - pumpDestination = null; - } - - public void setFluidFlowDirection(FluidFlow newDirection, boolean markDirty) { - flowSetting = newDirection; - - if(!worldObj.isRemote) { - if(markDirty) { - this.markDirty(); - } - else { - notifyNeighborsOfTileChange(); - } - } - else { - notifyNeighborsOfTileChange(); - } - - worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - - @Override - public void onMachineAssembled(MultiblockControllerBase multiblockControllerBase) - { - super.onMachineAssembled(multiblockControllerBase); - checkForAdjacentTank(); - - this.notifyNeighborsOfTileChange(); - } - - @Override - public void onMachineBroken() - { - super.onMachineBroken(); - pumpDestination = null; - } - - @Override - public void writeToNBT(NBTTagCompound data) { - super.writeToNBT(data); - data.setInteger("flowSetting", flowSetting.ordinal()); - } - - @Override - public void readFromNBT(NBTTagCompound data) { - super.readFromNBT(data); - if(data.hasKey("flowSetting")) { - flowSetting = FluidFlow.values()[data.getInteger("flowSetting")]; - } - } - - @Override - public void encodeDescriptionPacket(NBTTagCompound data) { - super.encodeDescriptionPacket(data); - data.setInteger("flowSetting", flowSetting.ordinal()); - } - - @Override - public void decodeDescriptionPacket(NBTTagCompound data) { - super.decodeDescriptionPacket(data); - if(data.hasKey("flowSetting")) { - flowSetting = FluidFlow.values()[data.getInteger("flowSetting")]; - } - } - - @Override - public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { - if(!isConnected() || from != getOutwardsDir()) { return 0; } - - if(flowSetting != FluidFlow.In) { - return 0; - } - - return getTurbine().fill(getTankIndex(), resource, doFill); - } - - @Override - public FluidStack drain(ForgeDirection from, FluidStack resource, - boolean doDrain) { - if(resource == null || !isConnected() || from != getOutwardsDir()) { return resource; } - - return getTurbine().drain(getTankIndex(), resource, doDrain); - } - - @Override - public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) { - if(!isConnected() || from != getOutwardsDir()) { return null; } - - return getTurbine().drain(getTankIndex(), maxDrain, doDrain); - } - - @Override - public boolean canFill(ForgeDirection from, Fluid fluid) { - if(!isConnected() || from != getOutwardsDir()) { return false; } - - if(flowSetting != FluidFlow.In) { - return false; - } - - return getTurbine().canFill(getTankIndex(), fluid); - } - - @Override - public boolean canDrain(ForgeDirection from, Fluid fluid) { - if(!isConnected() || from != getOutwardsDir()) { return false; } - - return getTurbine().canDrain(getTankIndex(), fluid); - } - - protected static final FluidTankInfo[] emptyTankInfoArray = new FluidTankInfo[0]; - - @Override - public FluidTankInfo[] getTankInfo(ForgeDirection from) { - if(!isConnected() || from != getOutwardsDir()) { return emptyTankInfoArray; } - return new FluidTankInfo[] { getTurbine().getTankInfo(getTankIndex()) }; - } - - private int getTankIndex() { - if(flowSetting == FluidFlow.In) { return MultiblockTurbine.TANK_INPUT; } - else { return MultiblockTurbine.TANK_OUTPUT; } - } - - public FluidFlow getFlowDirection() { return flowSetting; } - - // ITickableMultiblockPart - - @Override - public void onMultiblockServerTick() { - // Try to pump steam out, if an outlet - if(pumpDestination == null || flowSetting != FluidFlow.Out) - return; - - MultiblockTurbine turbine = getTurbine(); - FluidStack fluidToDrain = turbine.drain(MultiblockTurbine.TANK_OUTPUT, turbine.TANK_SIZE, false); - - if(fluidToDrain != null && fluidToDrain.amount > 0) - { - fluidToDrain.amount = pumpDestination.fill(getOutwardsDir().getOpposite(), fluidToDrain, true); - turbine.drain(MultiblockTurbine.TANK_OUTPUT, fluidToDrain, true); - } - } - - // INeighborUpdatableEntity - @Override - public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock) { - if(!world.isRemote) { - checkForAdjacentTank(); - } - } - - @Override - public void onNeighborTileChange(IBlockAccess world, int x, int y, int z, int neighborX, int neighborY, int neighborZ) { - if(!worldObj.isRemote) { - checkForAdjacentTank(); - } - } - - // Private Helpers - protected void checkForAdjacentTank() - { - pumpDestination = null; - if(worldObj.isRemote || flowSetting == FluidFlow.In) { - return; - } - - ForgeDirection outDir = getOutwardsDir(); - if(outDir == ForgeDirection.UNKNOWN) { - return; - } - - TileEntity neighbor = worldObj.getTileEntity(xCoord + outDir.offsetX, yCoord + outDir.offsetY, zCoord + outDir.offsetZ); - if(neighbor instanceof IFluidHandler) { - pumpDestination = (IFluidHandler)neighbor; - } - } +public class TileEntityTurbineFluidPort extends TileEntityTurbinePartStandard + implements IFluidHandler, INeighborUpdatableEntity, ITickableMultiblockPart { + + public enum FluidFlow { + In, + Out + } + + FluidFlow flowSetting; + IFluidHandler pumpDestination; + + public TileEntityTurbineFluidPort() { + super(); + flowSetting = FluidFlow.In; + pumpDestination = null; + } + + public void setFluidFlowDirection(FluidFlow newDirection, boolean markDirty) { + flowSetting = newDirection; + + if (!worldObj.isRemote) { + if (markDirty) { + this.markDirty(); + } else { + notifyNeighborsOfTileChange(); + } + } else { + notifyNeighborsOfTileChange(); + } + + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + + @Override + public void onMachineAssembled(MultiblockControllerBase multiblockControllerBase) { + super.onMachineAssembled(multiblockControllerBase); + checkForAdjacentTank(); + + this.notifyNeighborsOfTileChange(); + } + + @Override + public void onMachineBroken() { + super.onMachineBroken(); + pumpDestination = null; + } + + @Override + public void writeToNBT(NBTTagCompound data) { + super.writeToNBT(data); + data.setInteger("flowSetting", flowSetting.ordinal()); + } + + @Override + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + if (data.hasKey("flowSetting")) { + flowSetting = FluidFlow.values()[data.getInteger("flowSetting")]; + } + } + + @Override + public void encodeDescriptionPacket(NBTTagCompound data) { + super.encodeDescriptionPacket(data); + data.setInteger("flowSetting", flowSetting.ordinal()); + } + + @Override + public void decodeDescriptionPacket(NBTTagCompound data) { + super.decodeDescriptionPacket(data); + if (data.hasKey("flowSetting")) { + flowSetting = FluidFlow.values()[data.getInteger("flowSetting")]; + } + } + + @Override + public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { + if (!isConnected() || from != getOutwardsDir()) { + return 0; + } + + if (flowSetting != FluidFlow.In) { + return 0; + } + + return getTurbine().fill(getTankIndex(), resource, doFill); + } + + @Override + public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain) { + if (resource == null || !isConnected() || from != getOutwardsDir()) { + return resource; + } + + return getTurbine().drain(getTankIndex(), resource, doDrain); + } + + @Override + public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) { + if (!isConnected() || from != getOutwardsDir()) { + return null; + } + + return getTurbine().drain(getTankIndex(), maxDrain, doDrain); + } + + @Override + public boolean canFill(ForgeDirection from, Fluid fluid) { + if (!isConnected() || from != getOutwardsDir()) { + return false; + } + + if (flowSetting != FluidFlow.In) { + return false; + } + + return getTurbine().canFill(getTankIndex(), fluid); + } + + @Override + public boolean canDrain(ForgeDirection from, Fluid fluid) { + if (!isConnected() || from != getOutwardsDir()) { + return false; + } + + return getTurbine().canDrain(getTankIndex(), fluid); + } + + protected static final FluidTankInfo[] emptyTankInfoArray = new FluidTankInfo[0]; + + @Override + public FluidTankInfo[] getTankInfo(ForgeDirection from) { + if (!isConnected() || from != getOutwardsDir()) { + return emptyTankInfoArray; + } + return new FluidTankInfo[] { getTurbine().getTankInfo(getTankIndex()) }; + } + + private int getTankIndex() { + if (flowSetting == FluidFlow.In) { + return MultiblockTurbine.TANK_INPUT; + } else { + return MultiblockTurbine.TANK_OUTPUT; + } + } + + public FluidFlow getFlowDirection() { + return flowSetting; + } + + // ITickableMultiblockPart + + @Override + public void onMultiblockServerTick() { + // Try to pump steam out, if an outlet + if (pumpDestination == null || flowSetting != FluidFlow.Out) return; + + MultiblockTurbine turbine = getTurbine(); + FluidStack fluidToDrain = turbine.drain(MultiblockTurbine.TANK_OUTPUT, turbine.TANK_SIZE, false); + + if (fluidToDrain != null && fluidToDrain.amount > 0) { + fluidToDrain.amount = pumpDestination.fill(getOutwardsDir().getOpposite(), fluidToDrain, true); + turbine.drain(MultiblockTurbine.TANK_OUTPUT, fluidToDrain, true); + } + } + + // INeighborUpdatableEntity + @Override + public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock) { + if (!world.isRemote) { + checkForAdjacentTank(); + } + } + + @Override + public void onNeighborTileChange(IBlockAccess world, int x, int y, int z, int neighborX, int neighborY, + int neighborZ) { + if (!worldObj.isRemote) { + checkForAdjacentTank(); + } + } + + // Private Helpers + protected void checkForAdjacentTank() { + pumpDestination = null; + if (worldObj.isRemote || flowSetting == FluidFlow.In) { + return; + } + + ForgeDirection outDir = getOutwardsDir(); + if (outDir == ForgeDirection.UNKNOWN) { + return; + } + + TileEntity neighbor = worldObj + .getTileEntity(xCoord + outDir.offsetX, yCoord + outDir.offsetY, zCoord + outDir.offsetZ); + if (neighbor instanceof IFluidHandler) { + pumpDestination = (IFluidHandler) neighbor; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbinePartBase.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbinePartBase.java index ab4821f5..034a3b6b 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbinePartBase.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbinePartBase.java @@ -1,6 +1,7 @@ package erogenousbeef.bigreactors.common.multiblock.tileentity; import net.minecraft.entity.player.InventoryPlayer; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import erogenousbeef.bigreactors.common.BRLog; @@ -12,111 +13,110 @@ import erogenousbeef.core.multiblock.MultiblockControllerBase; import erogenousbeef.core.multiblock.rectangular.RectangularMultiblockTileEntityBase; -public abstract class TileEntityTurbinePartBase extends RectangularMultiblockTileEntityBase implements IMultiblockGuiHandler, - IActivateable, IBeefDebuggableTile { - - public TileEntityTurbinePartBase() { - } - - @Override - public MultiblockControllerBase createNewMultiblock() { - return new MultiblockTurbine(worldObj); - } - - @Override - public Class getMultiblockControllerType() { - return MultiblockTurbine.class; - } - - @Override - public void onMachineAssembled(MultiblockControllerBase controller) { - super.onMachineAssembled(controller); - - // Re-render this block on the client - if(worldObj.isRemote) { - this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - } - - @Override - public void onMachineBroken() { - super.onMachineBroken(); - - // Re-render this block on the client - if(worldObj.isRemote) { - this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - } - - @Override - public void onMachineActivated() { - } - - @Override - public void onMachineDeactivated() { - } - - /// GUI Support - IMultiblockGuiHandler - /** - * @return The Container object for use by the GUI. Null if there isn't any. - */ - @Override - public Object getContainer(InventoryPlayer inventoryPlayer) { - return null; - } - - @SideOnly(Side.CLIENT) - @Override - public Object getGuiElement(InventoryPlayer inventoryPlayer) { - return null; - } - - public MultiblockTurbine getTurbine() { - return (MultiblockTurbine)getMultiblockController(); - } - - // IActivateable - // IActivateable - @Override - public CoordTriplet getReferenceCoord() { - if(isConnected()) { - return getMultiblockController().getReferenceCoord(); - } - else { - return new CoordTriplet(xCoord, yCoord, zCoord); - } - } - - @Override - public boolean getActive() { - if(isConnected()) { - return getTurbine().getActive(); - } - else { - return false; - } - } - - @Override - public void setActive(boolean active) { - if(isConnected()) { - getTurbine().setActive(active); - } - else { - BRLog.error("Received a setActive command at %d, %d, %d, but not connected to a multiblock controller!", xCoord, yCoord, zCoord); - } - } - - @Override - public String getDebugInfo() { - MultiblockTurbine t = getTurbine(); - StringBuilder sb = new StringBuilder(); - sb.append(getClass().toString()).append("\n"); - if(t == null) { - sb.append("Not attached to controller!"); - return sb.toString(); - } - sb.append(t.getDebugInfo()); - return sb.toString(); - } +public abstract class TileEntityTurbinePartBase extends RectangularMultiblockTileEntityBase + implements IMultiblockGuiHandler, IActivateable, IBeefDebuggableTile { + + public TileEntityTurbinePartBase() {} + + @Override + public MultiblockControllerBase createNewMultiblock() { + return new MultiblockTurbine(worldObj); + } + + @Override + public Class getMultiblockControllerType() { + return MultiblockTurbine.class; + } + + @Override + public void onMachineAssembled(MultiblockControllerBase controller) { + super.onMachineAssembled(controller); + + // Re-render this block on the client + if (worldObj.isRemote) { + this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + } + + @Override + public void onMachineBroken() { + super.onMachineBroken(); + + // Re-render this block on the client + if (worldObj.isRemote) { + this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + } + + @Override + public void onMachineActivated() {} + + @Override + public void onMachineDeactivated() {} + + /// GUI Support - IMultiblockGuiHandler + /** + * @return The Container object for use by the GUI. Null if there isn't any. + */ + @Override + public Object getContainer(InventoryPlayer inventoryPlayer) { + return null; + } + + @SideOnly(Side.CLIENT) + @Override + public Object getGuiElement(InventoryPlayer inventoryPlayer) { + return null; + } + + public MultiblockTurbine getTurbine() { + return (MultiblockTurbine) getMultiblockController(); + } + + // IActivateable + // IActivateable + @Override + public CoordTriplet getReferenceCoord() { + if (isConnected()) { + return getMultiblockController().getReferenceCoord(); + } else { + return new CoordTriplet(xCoord, yCoord, zCoord); + } + } + + @Override + public boolean getActive() { + if (isConnected()) { + return getTurbine().getActive(); + } else { + return false; + } + } + + @Override + public void setActive(boolean active) { + if (isConnected()) { + getTurbine().setActive(active); + } else { + BRLog.error( + "Received a setActive command at %d, %d, %d, but not connected to a multiblock controller!", + xCoord, + yCoord, + zCoord); + } + } + + @Override + public String getDebugInfo() { + MultiblockTurbine t = getTurbine(); + StringBuilder sb = new StringBuilder(); + sb.append(getClass().toString()) + .append("\n"); + if (t == null) { + sb.append("Not attached to controller!"); + return sb.toString(); + } + sb.append(t.getDebugInfo()); + return sb.toString(); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbinePartGlass.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbinePartGlass.java index f079f42f..94abfb35 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbinePartGlass.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbinePartGlass.java @@ -4,28 +4,27 @@ public class TileEntityTurbinePartGlass extends TileEntityTurbinePartBase { - public TileEntityTurbinePartGlass() { - } - - @Override - public void isGoodForFrame() throws MultiblockValidationException { - throw new MultiblockValidationException(String.format("%s, %s, %s - Glass cannot be used as part of a turbine's frame", xCoord, yCoord, zCoord)); - } - - @Override - public void isGoodForSides() throws MultiblockValidationException { - } - - @Override - public void isGoodForTop() throws MultiblockValidationException { - } - - @Override - public void isGoodForBottom() throws MultiblockValidationException { - } - - @Override - public void isGoodForInterior() throws MultiblockValidationException { - throw new MultiblockValidationException(String.format("%s, %s, %s - Glass can only be used as part of a turbine's exterior", xCoord, yCoord, zCoord)); - } + public TileEntityTurbinePartGlass() {} + + @Override + public void isGoodForFrame() throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%s, %s, %s - Glass cannot be used as part of a turbine's frame", xCoord, yCoord, zCoord)); + } + + @Override + public void isGoodForSides() throws MultiblockValidationException {} + + @Override + public void isGoodForTop() throws MultiblockValidationException {} + + @Override + public void isGoodForBottom() throws MultiblockValidationException {} + + @Override + public void isGoodForInterior() throws MultiblockValidationException { + throw new MultiblockValidationException( + String + .format("%s, %s, %s - Glass can only be used as part of a turbine's exterior", xCoord, yCoord, zCoord)); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbinePartStandard.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbinePartStandard.java index f1dc2cca..e4fe784a 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbinePartStandard.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbinePartStandard.java @@ -2,6 +2,7 @@ import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.inventory.Container; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import erogenousbeef.bigreactors.client.gui.GuiTurbineController; @@ -11,75 +12,82 @@ public class TileEntityTurbinePartStandard extends TileEntityTurbinePartBase { - public TileEntityTurbinePartStandard() { - super(); - } - - @Override - public void isGoodForFrame() throws MultiblockValidationException { - if(getBlockMetadata() != BlockTurbinePart.METADATA_HOUSING) { - throw new MultiblockValidationException(String.format("%d, %d, %d - only turbine housing may be used as part of the turbine's frame", xCoord, yCoord, zCoord)); - } - } - - @Override - public void isGoodForSides() { - } - - @Override - public void isGoodForTop() { - } - - @Override - public void isGoodForBottom() { - } - - @Override - public void isGoodForInterior() throws MultiblockValidationException { - if(getBlockMetadata() != BlockTurbinePart.METADATA_HOUSING) { - throw new MultiblockValidationException(String.format("%d, %d, %d - this part is not valid for the interior of a turbine", xCoord, yCoord, zCoord)); - } - } - - @Override - public Object getContainer(InventoryPlayer inventoryPlayer) { - if(!this.isConnected()) { - return null; - } - - if(getBlockMetadata() == BlockTurbinePart.METADATA_CONTROLLER) { - return (Object)(new ContainerSlotless(getTurbine(), inventoryPlayer.player)); - } - - return null; - } - - @SideOnly(Side.CLIENT) - @Override - public Object getGuiElement(InventoryPlayer inventoryPlayer) { - if(!this.isConnected()) { - return null; - } - - if(getBlockMetadata() == BlockTurbinePart.METADATA_CONTROLLER) { - return new GuiTurbineController((Container)getContainer(inventoryPlayer), this); - } - return null; - } - - @Override - public void onMachineActivated() { - // Re-render controller as active state has changed - if(worldObj.isRemote && getBlockMetadata() == BlockTurbinePart.METADATA_CONTROLLER) { - worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - } - - @Override - public void onMachineDeactivated() { - // Re-render controller as active state has changed - if(worldObj.isRemote && getBlockMetadata() == BlockTurbinePart.METADATA_CONTROLLER) { - worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - } + public TileEntityTurbinePartStandard() { + super(); + } + + @Override + public void isGoodForFrame() throws MultiblockValidationException { + if (getBlockMetadata() != BlockTurbinePart.METADATA_HOUSING) { + throw new MultiblockValidationException( + String.format( + "%d, %d, %d - only turbine housing may be used as part of the turbine's frame", + xCoord, + yCoord, + zCoord)); + } + } + + @Override + public void isGoodForSides() {} + + @Override + public void isGoodForTop() {} + + @Override + public void isGoodForBottom() {} + + @Override + public void isGoodForInterior() throws MultiblockValidationException { + if (getBlockMetadata() != BlockTurbinePart.METADATA_HOUSING) { + throw new MultiblockValidationException( + String.format( + "%d, %d, %d - this part is not valid for the interior of a turbine", + xCoord, + yCoord, + zCoord)); + } + } + + @Override + public Object getContainer(InventoryPlayer inventoryPlayer) { + if (!this.isConnected()) { + return null; + } + + if (getBlockMetadata() == BlockTurbinePart.METADATA_CONTROLLER) { + return (Object) (new ContainerSlotless(getTurbine(), inventoryPlayer.player)); + } + + return null; + } + + @SideOnly(Side.CLIENT) + @Override + public Object getGuiElement(InventoryPlayer inventoryPlayer) { + if (!this.isConnected()) { + return null; + } + + if (getBlockMetadata() == BlockTurbinePart.METADATA_CONTROLLER) { + return new GuiTurbineController((Container) getContainer(inventoryPlayer), this); + } + return null; + } + + @Override + public void onMachineActivated() { + // Re-render controller as active state has changed + if (worldObj.isRemote && getBlockMetadata() == BlockTurbinePart.METADATA_CONTROLLER) { + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + } + + @Override + public void onMachineDeactivated() { + // Re-render controller as active state has changed + if (worldObj.isRemote && getBlockMetadata() == BlockTurbinePart.METADATA_CONTROLLER) { + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbinePowerTap.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbinePowerTap.java index b2b690d4..ad10a57d 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbinePowerTap.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbinePowerTap.java @@ -5,140 +5,151 @@ import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; + import cofh.api.energy.IEnergyProvider; import cofh.api.energy.IEnergyReceiver; import erogenousbeef.bigreactors.common.multiblock.interfaces.INeighborUpdatableEntity; import erogenousbeef.core.multiblock.MultiblockControllerBase; -public class TileEntityTurbinePowerTap extends TileEntityTurbinePartStandard implements IEnergyProvider, INeighborUpdatableEntity { - - IEnergyReceiver rfNetwork; - - public TileEntityTurbinePowerTap() { - super(); - rfNetwork = null; - } - - // INeighborUpdatableEntity - @Override - public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock) { - if(isConnected()) { - checkForConnections(world, x, y, z); - } - } - - @Override - public void onNeighborTileChange(IBlockAccess world, int x, int y, int z, int neighborX, int neighborY, int neighborZ) { - if(isConnected()) { - checkForConnections(world, x, y, z); - } - } - - public boolean isAttachedToPowerNetwork() { - return rfNetwork != null; - } - - // IMultiblockPart - @Override - public void onAttached(MultiblockControllerBase newController) { - super.onAttached(newController); - - checkForConnections(this.worldObj, xCoord, yCoord, zCoord); - - this.notifyNeighborsOfTileChange(); - } - - @Override - public void onMachineAssembled(MultiblockControllerBase multiblockControllerBase) { - super.onMachineAssembled(multiblockControllerBase); - - - checkForConnections(this.worldObj, xCoord, yCoord, zCoord); - - this.notifyNeighborsOfTileChange(); - } - - /** - * Check for a world connection, if we're assembled. - * @param world - * @param x - * @param y - * @param z - */ - protected void checkForConnections(IBlockAccess world, int x, int y, int z) { - boolean wasConnected = (rfNetwork != null); - ForgeDirection out = getOutwardsDir(); - if(out == ForgeDirection.UNKNOWN) { - wasConnected = false; - rfNetwork = null; - } - else { - // See if our adjacent non-reactor coordinate has a TE - rfNetwork = null; - - TileEntity te = world.getTileEntity(x + out.offsetX, y + out.offsetY, z + out.offsetZ); - if(!(te instanceof TileEntityReactorPowerTap)) { - // Skip power taps, as they implement these APIs and we don't want to shit energy back and forth - if(te instanceof IEnergyReceiver) { - IEnergyReceiver handler = (IEnergyReceiver)te; - if(handler.canConnectEnergy(out.getOpposite())) { - rfNetwork = handler; - } - } - } - } - - boolean isConnected = (rfNetwork != null); - if(wasConnected != isConnected && worldObj.isRemote) { - // Re-render on clients +public class TileEntityTurbinePowerTap extends TileEntityTurbinePartStandard + implements IEnergyProvider, INeighborUpdatableEntity { + + IEnergyReceiver rfNetwork; + + public TileEntityTurbinePowerTap() { + super(); + rfNetwork = null; + } + + // INeighborUpdatableEntity + @Override + public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock) { + if (isConnected()) { + checkForConnections(world, x, y, z); + } + } + + @Override + public void onNeighborTileChange(IBlockAccess world, int x, int y, int z, int neighborX, int neighborY, + int neighborZ) { + if (isConnected()) { + checkForConnections(world, x, y, z); + } + } + + public boolean isAttachedToPowerNetwork() { + return rfNetwork != null; + } + + // IMultiblockPart + @Override + public void onAttached(MultiblockControllerBase newController) { + super.onAttached(newController); + + checkForConnections(this.worldObj, xCoord, yCoord, zCoord); + + this.notifyNeighborsOfTileChange(); + } + + @Override + public void onMachineAssembled(MultiblockControllerBase multiblockControllerBase) { + super.onMachineAssembled(multiblockControllerBase); + + checkForConnections(this.worldObj, xCoord, yCoord, zCoord); + + this.notifyNeighborsOfTileChange(); + } + + /** + * Check for a world connection, if we're assembled. + * + * @param world + * @param x + * @param y + * @param z + */ + protected void checkForConnections(IBlockAccess world, int x, int y, int z) { + boolean wasConnected = (rfNetwork != null); + ForgeDirection out = getOutwardsDir(); + if (out == ForgeDirection.UNKNOWN) { + wasConnected = false; + rfNetwork = null; + } else { + // See if our adjacent non-reactor coordinate has a TE + rfNetwork = null; + + TileEntity te = world.getTileEntity(x + out.offsetX, y + out.offsetY, z + out.offsetZ); + if (!(te instanceof TileEntityReactorPowerTap)) { + // Skip power taps, as they implement these APIs and we don't want to shit energy back and forth + if (te instanceof IEnergyReceiver) { + IEnergyReceiver handler = (IEnergyReceiver) te; + if (handler.canConnectEnergy(out.getOpposite())) { + rfNetwork = handler; + } + } + } + } + + boolean isConnected = (rfNetwork != null); + if (wasConnected != isConnected && worldObj.isRemote) { + // Re-render on clients worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - } - - /** This will be called by the Reactor Controller when this tap should be providing power. - * @return Power units remaining after consumption. - */ - public int onProvidePower(int units) { - if(rfNetwork == null) { - return units; - } - - ForgeDirection approachDirection = getOutwardsDir().getOpposite(); - int energyConsumed = rfNetwork.receiveEnergy(approachDirection, (int)units, false); - units -= energyConsumed; - - return units; - } - - // IEnergyConnection - @Override - public boolean canConnectEnergy(ForgeDirection from) { - if(!this.isConnected()) { return false; } - - return from == getOutwardsDir(); - } - - // IEnergyProvider - @Override - public int extractEnergy(ForgeDirection from, int maxExtract, - boolean simulate) { - if(!this.isConnected()) { return 0; } - - return getTurbine().extractEnergy(from, maxExtract, simulate); - } - - @Override - public int getEnergyStored(ForgeDirection from) { - if(!this.isConnected()) { return 0; } - - return getTurbine().getEnergyStored(from); - } - - @Override - public int getMaxEnergyStored(ForgeDirection from) { - if(!this.isConnected()) { return 0; } - - return getTurbine().getMaxEnergyStored(from); - } + } + } + + /** + * This will be called by the Reactor Controller when this tap should be providing power. + * + * @return Power units remaining after consumption. + */ + public int onProvidePower(int units) { + if (rfNetwork == null) { + return units; + } + + ForgeDirection approachDirection = getOutwardsDir().getOpposite(); + int energyConsumed = rfNetwork.receiveEnergy(approachDirection, (int) units, false); + units -= energyConsumed; + + return units; + } + + // IEnergyConnection + @Override + public boolean canConnectEnergy(ForgeDirection from) { + if (!this.isConnected()) { + return false; + } + + return from == getOutwardsDir(); + } + + // IEnergyProvider + @Override + public int extractEnergy(ForgeDirection from, int maxExtract, boolean simulate) { + if (!this.isConnected()) { + return 0; + } + + return getTurbine().extractEnergy(from, maxExtract, simulate); + } + + @Override + public int getEnergyStored(ForgeDirection from) { + if (!this.isConnected()) { + return 0; + } + + return getTurbine().getEnergyStored(from); + } + + @Override + public int getMaxEnergyStored(ForgeDirection from) { + if (!this.isConnected()) { + return 0; + } + + return getTurbine().getMaxEnergyStored(from); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbineRotorBearing.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbineRotorBearing.java index a7ba2fb4..e846dc99 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbineRotorBearing.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbineRotorBearing.java @@ -2,6 +2,7 @@ import net.minecraft.util.AxisAlignedBB; import net.minecraftforge.common.util.ForgeDirection; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import erogenousbeef.bigreactors.common.BigReactors; @@ -11,102 +12,115 @@ import erogenousbeef.core.common.CoordTriplet; import erogenousbeef.core.multiblock.MultiblockControllerBase; -public class TileEntityTurbineRotorBearing extends - TileEntityTurbinePartStandard { - - RotorInfo rotorInfo = null; - Integer displayList = null; - float angle = 0f; - - @SideOnly(Side.CLIENT) - public Integer getDisplayList() { return displayList; } - - @SideOnly(Side.CLIENT) - public void setDisplayList(int newList) { displayList = newList; } - - @SideOnly(Side.CLIENT) - public void clearDisplayList() { displayList = null; } - - @SideOnly(Side.CLIENT) - public float getAngle() { return angle; } - - @SideOnly(Side.CLIENT) - public void setAngle(float newAngle) { angle = newAngle; } - - protected AxisAlignedBB boundingBox; - - @Override - public void onMachineAssembled(MultiblockControllerBase controller) { - super.onMachineAssembled(controller); - displayList = null; - calculateRotorInfo(); - } - - @SideOnly(Side.CLIENT) - public RotorInfo getRotorInfo() { - return rotorInfo; - } - - public AxisAlignedBB getAABB() { return boundingBox; } - - private void calculateRotorInfo() { - // Calculate bounding box - MultiblockTurbine turbine = getTurbine(); - CoordTriplet minCoord = turbine.getMinimumCoord(); - CoordTriplet maxCoord = turbine.getMaximumCoord(); - - boundingBox = AxisAlignedBB.getBoundingBox(minCoord.x, minCoord.y, minCoord.z, maxCoord.x + 1, maxCoord.y + 1, maxCoord.z + 1); - - if(worldObj.isRemote) { - // Calculate rotor info - rotorInfo = new RotorInfo(); - rotorInfo.rotorDirection = getOutwardsDir().getOpposite(); - switch(rotorInfo.rotorDirection) { - case DOWN: - case UP: - case UNKNOWN: - rotorInfo.rotorLength = maxCoord.y - minCoord.y - 1; - break; - case EAST: - case WEST: - rotorInfo.rotorLength = maxCoord.x - minCoord.x - 1; - break; - case NORTH: - case SOUTH: - rotorInfo.rotorLength = maxCoord.z - minCoord.z - 1; - break; - } - - CoordTriplet currentCoord = getWorldLocation(); - CoordTriplet bladeCoord = new CoordTriplet(0,0,0); - - ForgeDirection[] dirsToCheck = StaticUtils.neighborsBySide[rotorInfo.rotorDirection.ordinal()]; - rotorInfo.bladeLengths = new int[rotorInfo.rotorLength][4]; - - int rotorPosition = 0; - currentCoord.translate(rotorInfo.rotorDirection); - - while(rotorPosition < rotorInfo.rotorLength) { - // Current block is a rotor - // Get list of normals - int bladeLength; - ForgeDirection bladeDir; - for(int bladeIdx = 0; bladeIdx < dirsToCheck.length; bladeIdx++) { - bladeDir = dirsToCheck[bladeIdx]; - bladeCoord.copy(currentCoord); - bladeCoord.translate(bladeDir); - bladeLength = 0; - while(worldObj.getBlock(bladeCoord.x, bladeCoord.y, bladeCoord.z) == BigReactors.blockTurbineRotorPart && bladeLength < 32) { - bladeLength++; - bladeCoord.translate(bladeDir); - } - - rotorInfo.bladeLengths[rotorPosition][bladeIdx] = bladeLength; - } - - rotorPosition++; - currentCoord.translate(rotorInfo.rotorDirection); - } - } - } +public class TileEntityTurbineRotorBearing extends TileEntityTurbinePartStandard { + + RotorInfo rotorInfo = null; + Integer displayList = null; + float angle = 0f; + + @SideOnly(Side.CLIENT) + public Integer getDisplayList() { + return displayList; + } + + @SideOnly(Side.CLIENT) + public void setDisplayList(int newList) { + displayList = newList; + } + + @SideOnly(Side.CLIENT) + public void clearDisplayList() { + displayList = null; + } + + @SideOnly(Side.CLIENT) + public float getAngle() { + return angle; + } + + @SideOnly(Side.CLIENT) + public void setAngle(float newAngle) { + angle = newAngle; + } + + protected AxisAlignedBB boundingBox; + + @Override + public void onMachineAssembled(MultiblockControllerBase controller) { + super.onMachineAssembled(controller); + displayList = null; + calculateRotorInfo(); + } + + @SideOnly(Side.CLIENT) + public RotorInfo getRotorInfo() { + return rotorInfo; + } + + public AxisAlignedBB getAABB() { + return boundingBox; + } + + private void calculateRotorInfo() { + // Calculate bounding box + MultiblockTurbine turbine = getTurbine(); + CoordTriplet minCoord = turbine.getMinimumCoord(); + CoordTriplet maxCoord = turbine.getMaximumCoord(); + + boundingBox = AxisAlignedBB + .getBoundingBox(minCoord.x, minCoord.y, minCoord.z, maxCoord.x + 1, maxCoord.y + 1, maxCoord.z + 1); + + if (worldObj.isRemote) { + // Calculate rotor info + rotorInfo = new RotorInfo(); + rotorInfo.rotorDirection = getOutwardsDir().getOpposite(); + switch (rotorInfo.rotorDirection) { + case DOWN: + case UP: + case UNKNOWN: + rotorInfo.rotorLength = maxCoord.y - minCoord.y - 1; + break; + case EAST: + case WEST: + rotorInfo.rotorLength = maxCoord.x - minCoord.x - 1; + break; + case NORTH: + case SOUTH: + rotorInfo.rotorLength = maxCoord.z - minCoord.z - 1; + break; + } + + CoordTriplet currentCoord = getWorldLocation(); + CoordTriplet bladeCoord = new CoordTriplet(0, 0, 0); + + ForgeDirection[] dirsToCheck = StaticUtils.neighborsBySide[rotorInfo.rotorDirection.ordinal()]; + rotorInfo.bladeLengths = new int[rotorInfo.rotorLength][4]; + + int rotorPosition = 0; + currentCoord.translate(rotorInfo.rotorDirection); + + while (rotorPosition < rotorInfo.rotorLength) { + // Current block is a rotor + // Get list of normals + int bladeLength; + ForgeDirection bladeDir; + for (int bladeIdx = 0; bladeIdx < dirsToCheck.length; bladeIdx++) { + bladeDir = dirsToCheck[bladeIdx]; + bladeCoord.copy(currentCoord); + bladeCoord.translate(bladeDir); + bladeLength = 0; + while (worldObj.getBlock(bladeCoord.x, bladeCoord.y, bladeCoord.z) + == BigReactors.blockTurbineRotorPart && bladeLength < 32) { + bladeLength++; + bladeCoord.translate(bladeDir); + } + + rotorInfo.bladeLengths[rotorPosition][bladeIdx] = bladeLength; + } + + rotorPosition++; + currentCoord.translate(rotorInfo.rotorDirection); + } + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbineRotorPart.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbineRotorPart.java index 1d868a1c..54261b54 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbineRotorPart.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityTurbineRotorPart.java @@ -5,38 +5,36 @@ public class TileEntityTurbineRotorPart extends TileEntityTurbinePartBase { - public TileEntityTurbineRotorPart() { - } - - @Override - public void isGoodForFrame() throws MultiblockValidationException { - throw new MultiblockValidationException("Rotor parts may only be placed in the turbine interior"); - } - - @Override - public void isGoodForSides() throws MultiblockValidationException { - throw new MultiblockValidationException("Rotor parts may only be placed in the turbine interior"); - } - - @Override - public void isGoodForTop() throws MultiblockValidationException { - throw new MultiblockValidationException("Rotor parts may only be placed in the turbine interior"); - } - - @Override - public void isGoodForBottom() throws MultiblockValidationException { - throw new MultiblockValidationException("Rotor parts may only be placed in the turbine interior"); - } - - @Override - public void isGoodForInterior() throws MultiblockValidationException { - } - - public boolean isRotorShaft() { - return BlockTurbineRotorPart.isRotorShaft(getBlockMetadata()); - } - - public boolean isRotorBlade() { - return BlockTurbineRotorPart.isRotorBlade(getBlockMetadata()); - } + public TileEntityTurbineRotorPart() {} + + @Override + public void isGoodForFrame() throws MultiblockValidationException { + throw new MultiblockValidationException("Rotor parts may only be placed in the turbine interior"); + } + + @Override + public void isGoodForSides() throws MultiblockValidationException { + throw new MultiblockValidationException("Rotor parts may only be placed in the turbine interior"); + } + + @Override + public void isGoodForTop() throws MultiblockValidationException { + throw new MultiblockValidationException("Rotor parts may only be placed in the turbine interior"); + } + + @Override + public void isGoodForBottom() throws MultiblockValidationException { + throw new MultiblockValidationException("Rotor parts may only be placed in the turbine interior"); + } + + @Override + public void isGoodForInterior() throws MultiblockValidationException {} + + public boolean isRotorShaft() { + return BlockTurbineRotorPart.isRotorShaft(getBlockMetadata()); + } + + public boolean isRotorBlade() { + return BlockTurbineRotorPart.isRotorBlade(getBlockMetadata()); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/creative/TileEntityReactorCreativeCoolantPort.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/creative/TileEntityReactorCreativeCoolantPort.java index c504f78a..1a95e9a1 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/creative/TileEntityReactorCreativeCoolantPort.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/creative/TileEntityReactorCreativeCoolantPort.java @@ -2,39 +2,46 @@ import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; + import erogenousbeef.bigreactors.common.multiblock.MultiblockReactor; import erogenousbeef.bigreactors.common.multiblock.helpers.CoolantContainer; import erogenousbeef.bigreactors.common.multiblock.interfaces.ITickableMultiblockPart; import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorCoolantPort; -public class TileEntityReactorCreativeCoolantPort extends TileEntityReactorCoolantPort implements ITickableMultiblockPart { - - public TileEntityReactorCreativeCoolantPort() { - super(); - } - - @Override - public void onMultiblockServerTick() { - if(!isConnected()) { return; } - - MultiblockReactor reactor = getReactorController(); - - if(isInlet()) { - CoolantContainer cc = reactor.getCoolantContainer(); - if(cc.getCoolantAmount() < cc.getCapacity()) - { - reactor.getCoolantContainer().addCoolant(new FluidStack(FluidRegistry.WATER, cc.getCapacity())); - } - } - else { - reactor.getCoolantContainer().emptyVapor(); - } - } - - public void forceAddWater() { - if(!isConnected()) { return; } - - MultiblockReactor reactor = getReactorController(); - reactor.getCoolantContainer().addCoolant(new FluidStack(FluidRegistry.WATER, 1000)); - } +public class TileEntityReactorCreativeCoolantPort extends TileEntityReactorCoolantPort + implements ITickableMultiblockPart { + + public TileEntityReactorCreativeCoolantPort() { + super(); + } + + @Override + public void onMultiblockServerTick() { + if (!isConnected()) { + return; + } + + MultiblockReactor reactor = getReactorController(); + + if (isInlet()) { + CoolantContainer cc = reactor.getCoolantContainer(); + if (cc.getCoolantAmount() < cc.getCapacity()) { + reactor.getCoolantContainer() + .addCoolant(new FluidStack(FluidRegistry.WATER, cc.getCapacity())); + } + } else { + reactor.getCoolantContainer() + .emptyVapor(); + } + } + + public void forceAddWater() { + if (!isConnected()) { + return; + } + + MultiblockReactor reactor = getReactorController(); + reactor.getCoolantContainer() + .addCoolant(new FluidStack(FluidRegistry.WATER, 1000)); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/creative/TileEntityTurbineCreativeSteamGenerator.java b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/creative/TileEntityTurbineCreativeSteamGenerator.java index 5088bf27..943ff1db 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/creative/TileEntityTurbineCreativeSteamGenerator.java +++ b/src/main/java/erogenousbeef/bigreactors/common/multiblock/tileentity/creative/TileEntityTurbineCreativeSteamGenerator.java @@ -3,22 +3,25 @@ import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; + import erogenousbeef.bigreactors.common.multiblock.MultiblockTurbine; import erogenousbeef.bigreactors.common.multiblock.interfaces.ITickableMultiblockPart; import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityTurbinePartStandard; -public class TileEntityTurbineCreativeSteamGenerator extends TileEntityTurbinePartStandard implements ITickableMultiblockPart { +public class TileEntityTurbineCreativeSteamGenerator extends TileEntityTurbinePartStandard + implements ITickableMultiblockPart { + + public TileEntityTurbineCreativeSteamGenerator() { + super(); + } - public TileEntityTurbineCreativeSteamGenerator() { - super(); - } + @Override + public void onMultiblockServerTick() { + if (isConnected() && getTurbine().getActive()) { + Fluid steam = FluidRegistry.getFluid("steam"); - @Override - public void onMultiblockServerTick() { - if(isConnected() && getTurbine().getActive()) { - Fluid steam = FluidRegistry.getFluid("steam"); - - getTurbine().fill(MultiblockTurbine.TANK_INPUT, new FluidStack(steam, getTurbine().getMaxIntakeRate()), true); - } - } + getTurbine() + .fill(MultiblockTurbine.TANK_INPUT, new FluidStack(steam, getTurbine().getMaxIntakeRate()), true); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/tileentity/TileEntityCyaniteReprocessor.java b/src/main/java/erogenousbeef/bigreactors/common/tileentity/TileEntityCyaniteReprocessor.java index 2b106d11..e299b2a4 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/tileentity/TileEntityCyaniteReprocessor.java +++ b/src/main/java/erogenousbeef/bigreactors/common/tileentity/TileEntityCyaniteReprocessor.java @@ -7,11 +7,11 @@ import net.minecraft.inventory.Container; import net.minecraft.item.ItemStack; import net.minecraft.util.IIcon; -import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidContainerRegistry; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; + import cofh.core.util.oredict.OreDictionaryArbiter; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -24,195 +24,203 @@ public class TileEntityCyaniteReprocessor extends TileEntityPoweredInventoryFluid { - public static final int SLOT_INLET = 0; - public static final int SLOT_OUTLET = 1; - public static final int NUM_SLOTS = 2; - - public static final int FLUIDTANK_WATER = 0; - public static final int NUM_TANKS = 1; - - protected static final int FLUID_CONSUMED = FluidContainerRegistry.BUCKET_VOLUME * 1; - protected static final int INGOTS_CONSUMED = 2; - - public TileEntityCyaniteReprocessor() { - super(); - - // Do not transmit energy from the internal buffer. - m_ProvidesEnergy = false; - } - - @Override - public int getSizeInventory() { - return NUM_SLOTS; - } - - @Override - public String getInventoryName() { - return "Cyanite Reprocessor"; - } - - @Override - public boolean isItemValidForSlot(int slot, ItemStack itemstack) { - if(itemstack == null) { return true; } - - if(slot == SLOT_OUTLET) { - return Reactants.isFuel(itemstack); - } - else if(slot == SLOT_INLET) { - return Reactants.isWaste(itemstack); - } - - return false; - } - - @Override - public int getMaxEnergyStored() { - return 10000; - } - - @Override - public int getCycleEnergyCost() { - return 2000; - } - - @Override - public int getCycleLength() { - return 200; // 10 seconds / 20tps - } - - @Override - public boolean canBeginCycle() { - FluidStack fluid = drain(0, FLUID_CONSUMED, false); - if(fluid == null || fluid.amount < FLUID_CONSUMED) { - return false; - } - - if(_inventories[SLOT_INLET] != null && _inventories[SLOT_INLET].stackSize >= INGOTS_CONSUMED) { - if(_inventories[SLOT_OUTLET] != null && _inventories[SLOT_OUTLET].stackSize >= getInventoryStackLimit()) { - return false; - } - return true; - } - - return false; - } - - @Override - public void onPoweredCycleBegin() { - } - - @Override - public void onPoweredCycleEnd() { - if(_inventories[SLOT_OUTLET] != null) { - if(consumeInputs()) { - _inventories[SLOT_OUTLET].stackSize += 1; - } - } - else { - // TODO: Make this query the input for the right type of output to create. - ArrayList candidates = OreDictionaryArbiter.getOres("ingotBlutonium"); - if(candidates == null || candidates.isEmpty()) { - // WTF? - return; - } - - if(consumeInputs()) { - _inventories[SLOT_OUTLET] = candidates.get(0).copy(); - _inventories[SLOT_OUTLET].stackSize = 1; - } - } - - distributeItemsFromSlot(SLOT_OUTLET); - markChunkDirty(); - } - - private boolean consumeInputs() { - _inventories[SLOT_INLET] = StaticUtils.Inventory.consumeItem(_inventories[SLOT_INLET], INGOTS_CONSUMED); - drain(0, FLUID_CONSUMED, true); - - return true; - } - - @Override - public int getNumTanks() { - return NUM_TANKS; - } - - @Override - public int getTankSize(int tankIndex) { - return FluidContainerRegistry.BUCKET_VOLUME * 5; - } - - @Override - protected boolean isFluidValidForTank(int tankIdx, FluidStack type) { - if(type == null) { return false; } - return type.getFluid().getID() == FluidRegistry.getFluid("water").getID(); - } - - /// BeefGUI - @SideOnly(Side.CLIENT) - @Override - public GuiScreen getGUI(EntityPlayer player) { - return new GuiCyaniteReprocessor(getContainer(player), this); - } - - @Override - public Container getContainer(EntityPlayer player) { - return new ContainerCyaniteReprocessor(this, player); - } - - @Override - protected int getDefaultTankForFluid(Fluid fluid) { - if(fluid.getName() == "water") - return 0; - else - return FLUIDTANK_NONE; - } - - // IReconfigurableSides & IBeefReconfigurableSides - @SideOnly(Side.CLIENT) - public IIcon getIconForSide(int side) { - if(side == facing) { - // This should never happen - return getBlockType().getIcon(side, getBlockMetadata()); - } - - int exposure = getExposure(side); - - switch(exposure) { - case 0: - return ClientProxy.CommonBlockIcons.getIcon(ClientProxy.CommonBlockIcons.ITEM_RED); - case 1: - return ClientProxy.CommonBlockIcons.getIcon(ClientProxy.CommonBlockIcons.ITEM_GREEN); - case 2: - return ClientProxy.CommonBlockIcons.getIcon(ClientProxy.CommonBlockIcons.FLUID_BLUE); - default: - return ClientProxy.CommonBlockIcons.getIcon(ClientProxy.CommonBlockIcons.DEFAULT); - } - } - - @Override - public int getNumConfig(int side) { - if(facing == side) { - return 0; - } - else { - return 3; - } - } - - @Override - public int getExposedTankFromSide(int side) { - int exposure = getExposure(side); - if(exposure == 2) { return FLUIDTANK_WATER; } - return FLUIDTANK_NONE; - } - - @Override - protected int getExposedInventorySlotFromSide(int side) { - int exposure = getExposure(side); - if(exposure == 0) { return SLOT_INLET; } - if(exposure == 1) { return SLOT_OUTLET; } - return SLOT_NONE; - } + public static final int SLOT_INLET = 0; + public static final int SLOT_OUTLET = 1; + public static final int NUM_SLOTS = 2; + + public static final int FLUIDTANK_WATER = 0; + public static final int NUM_TANKS = 1; + + protected static final int FLUID_CONSUMED = FluidContainerRegistry.BUCKET_VOLUME * 1; + protected static final int INGOTS_CONSUMED = 2; + + public TileEntityCyaniteReprocessor() { + super(); + + // Do not transmit energy from the internal buffer. + m_ProvidesEnergy = false; + } + + @Override + public int getSizeInventory() { + return NUM_SLOTS; + } + + @Override + public String getInventoryName() { + return "Cyanite Reprocessor"; + } + + @Override + public boolean isItemValidForSlot(int slot, ItemStack itemstack) { + if (itemstack == null) { + return true; + } + + if (slot == SLOT_OUTLET) { + return Reactants.isFuel(itemstack); + } else if (slot == SLOT_INLET) { + return Reactants.isWaste(itemstack); + } + + return false; + } + + @Override + public int getMaxEnergyStored() { + return 10000; + } + + @Override + public int getCycleEnergyCost() { + return 2000; + } + + @Override + public int getCycleLength() { + return 200; // 10 seconds / 20tps + } + + @Override + public boolean canBeginCycle() { + FluidStack fluid = drain(0, FLUID_CONSUMED, false); + if (fluid == null || fluid.amount < FLUID_CONSUMED) { + return false; + } + + if (_inventories[SLOT_INLET] != null && _inventories[SLOT_INLET].stackSize >= INGOTS_CONSUMED) { + if (_inventories[SLOT_OUTLET] != null && _inventories[SLOT_OUTLET].stackSize >= getInventoryStackLimit()) { + return false; + } + return true; + } + + return false; + } + + @Override + public void onPoweredCycleBegin() {} + + @Override + public void onPoweredCycleEnd() { + if (_inventories[SLOT_OUTLET] != null) { + if (consumeInputs()) { + _inventories[SLOT_OUTLET].stackSize += 1; + } + } else { + // TODO: Make this query the input for the right type of output to create. + ArrayList candidates = OreDictionaryArbiter.getOres("ingotBlutonium"); + if (candidates == null || candidates.isEmpty()) { + // WTF? + return; + } + + if (consumeInputs()) { + _inventories[SLOT_OUTLET] = candidates.get(0) + .copy(); + _inventories[SLOT_OUTLET].stackSize = 1; + } + } + + distributeItemsFromSlot(SLOT_OUTLET); + markChunkDirty(); + } + + private boolean consumeInputs() { + _inventories[SLOT_INLET] = StaticUtils.Inventory.consumeItem(_inventories[SLOT_INLET], INGOTS_CONSUMED); + drain(0, FLUID_CONSUMED, true); + + return true; + } + + @Override + public int getNumTanks() { + return NUM_TANKS; + } + + @Override + public int getTankSize(int tankIndex) { + return FluidContainerRegistry.BUCKET_VOLUME * 5; + } + + @Override + protected boolean isFluidValidForTank(int tankIdx, FluidStack type) { + if (type == null) { + return false; + } + return type.getFluid() + .getID() + == FluidRegistry.getFluid("water") + .getID(); + } + + /// BeefGUI + @SideOnly(Side.CLIENT) + @Override + public GuiScreen getGUI(EntityPlayer player) { + return new GuiCyaniteReprocessor(getContainer(player), this); + } + + @Override + public Container getContainer(EntityPlayer player) { + return new ContainerCyaniteReprocessor(this, player); + } + + @Override + protected int getDefaultTankForFluid(Fluid fluid) { + if (fluid.getName() == "water") return 0; + else return FLUIDTANK_NONE; + } + + // IReconfigurableSides & IBeefReconfigurableSides + @SideOnly(Side.CLIENT) + public IIcon getIconForSide(int side) { + if (side == facing) { + // This should never happen + return getBlockType().getIcon(side, getBlockMetadata()); + } + + int exposure = getExposure(side); + + switch (exposure) { + case 0: + return ClientProxy.CommonBlockIcons.getIcon(ClientProxy.CommonBlockIcons.ITEM_RED); + case 1: + return ClientProxy.CommonBlockIcons.getIcon(ClientProxy.CommonBlockIcons.ITEM_GREEN); + case 2: + return ClientProxy.CommonBlockIcons.getIcon(ClientProxy.CommonBlockIcons.FLUID_BLUE); + default: + return ClientProxy.CommonBlockIcons.getIcon(ClientProxy.CommonBlockIcons.DEFAULT); + } + } + + @Override + public int getNumConfig(int side) { + if (facing == side) { + return 0; + } else { + return 3; + } + } + + @Override + public int getExposedTankFromSide(int side) { + int exposure = getExposure(side); + if (exposure == 2) { + return FLUIDTANK_WATER; + } + return FLUIDTANK_NONE; + } + + @Override + protected int getExposedInventorySlotFromSide(int side) { + int exposure = getExposure(side); + if (exposure == 0) { + return SLOT_INLET; + } + if (exposure == 1) { + return SLOT_OUTLET; + } + return SLOT_NONE; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/tileentity/base/TileEntityBeefBase.java b/src/main/java/erogenousbeef/bigreactors/common/tileentity/base/TileEntityBeefBase.java index 67298440..7c98912a 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/tileentity/base/TileEntityBeefBase.java +++ b/src/main/java/erogenousbeef/bigreactors/common/tileentity/base/TileEntityBeefBase.java @@ -10,6 +10,7 @@ import net.minecraft.network.Packet; import net.minecraft.network.play.server.S35PacketUpdateTileEntity; import net.minecraftforge.common.util.ForgeDirection; + import cofh.api.tileentity.IReconfigurableFacing; import cofh.core.block.TileCoFHBase; import cofh.lib.util.helpers.BlockHelper; @@ -23,270 +24,297 @@ import erogenousbeef.bigreactors.net.message.DeviceUpdateMessage; import erogenousbeef.bigreactors.net.message.DeviceUpdateRotationMessage; -public abstract class TileEntityBeefBase extends TileCoFHBase implements IBeefGuiEntity, IBeefReconfigurableSides, IReconfigurableFacing, IWrenchable { - private Set updatePlayers; - private int ticksSinceLastUpdate; - private static final int ticksBetweenUpdates = 3; +public abstract class TileEntityBeefBase extends TileCoFHBase + implements IBeefGuiEntity, IBeefReconfigurableSides, IReconfigurableFacing, IWrenchable { + + private Set updatePlayers; + private int ticksSinceLastUpdate; + private static final int ticksBetweenUpdates = 3; - protected static final int SIDE_UNEXPOSED = -1; - protected static final int[] kEmptyIntArray = new int[0]; + protected static final int SIDE_UNEXPOSED = -1; + protected static final int[] kEmptyIntArray = new int[0]; - protected int facing; // Tile rotation - int[] exposures; // Inventory/Fluid tank exposure + protected int facing; // Tile rotation + int[] exposures; // Inventory/Fluid tank exposure - public TileEntityBeefBase() { - super(); + public TileEntityBeefBase() { + super(); - facing = ForgeDirection.NORTH.ordinal(); + facing = ForgeDirection.NORTH.ordinal(); - exposures = new int[6]; - for(int i = 0; i < exposures.length; i++) { - exposures[i] = SIDE_UNEXPOSED; - } + exposures = new int[6]; + for (int i = 0; i < exposures.length; i++) { + exposures[i] = SIDE_UNEXPOSED; + } - ticksSinceLastUpdate = 0; - updatePlayers = new HashSet(); - } + ticksSinceLastUpdate = 0; + updatePlayers = new HashSet(); + } - // IReconfigurableFacing - @Override - public int getFacing() { return facing; } + // IReconfigurableFacing + @Override + public int getFacing() { + return facing; + } - @Override - public boolean setFacing(int newFacing) { - if(facing == newFacing) { return false; } + @Override + public boolean setFacing(int newFacing) { + if (facing == newFacing) { + return false; + } - if(!allowYAxisFacing() && (newFacing == ForgeDirection.UP.ordinal() || newFacing == ForgeDirection.DOWN.ordinal())) { - return false; - } - - facing = newFacing; - if(!worldObj.isRemote) { - CommonPacketHandler.INSTANCE.sendToAllAround(new DeviceUpdateRotationMessage(xCoord, yCoord, zCoord, facing), new NetworkRegistry.TargetPoint(worldObj.provider.dimensionId, xCoord, yCoord, zCoord, 50)); + if (!allowYAxisFacing() + && (newFacing == ForgeDirection.UP.ordinal() || newFacing == ForgeDirection.DOWN.ordinal())) { + return false; + } + + facing = newFacing; + if (!worldObj.isRemote) { + CommonPacketHandler.INSTANCE.sendToAllAround( + new DeviceUpdateRotationMessage(xCoord, yCoord, zCoord, facing), + new NetworkRegistry.TargetPoint(worldObj.provider.dimensionId, xCoord, yCoord, zCoord, 50)); this.markChunkDirty(); - } - - this.callNeighborBlockChange(); - return true; - } - - public int getRotatedSide(int side) { - return BlockHelper.ICON_ROTATION_MAP[facing][side]; - } - - @Override - public boolean rotateBlock() { - return setFacing(BlockHelper.SIDE_LEFT[facing]); - } - - @Override - public boolean onWrench(EntityPlayer player, int hitSide) { - return rotateBlock(); - } - - @Override - public boolean allowYAxisFacing() { return false; } - - // Save/Load - @Override - public void readFromNBT(NBTTagCompound tag) { - super.readFromNBT(tag); - - // Rotation - if(tag.hasKey("facing")) { - facing = Math.max(0, Math.min(5, tag.getInteger("facing"))); - } - else { - facing = 2; - } - - // Exposure settings - if(tag.hasKey("exposures")) { - int[] tagExposures = tag.getIntArray("exposures"); - assert(tagExposures.length == exposures.length); - System.arraycopy(tagExposures, 0, exposures, 0, exposures.length); - } - } - - @Override - public void writeToNBT(NBTTagCompound tag) { - super.writeToNBT(tag); - - tag.setInteger("facing", facing); - tag.setIntArray("exposures", exposures); - } - - // Network Communication - @Override - public Packet getDescriptionPacket() - { - NBTTagCompound tagCompound = new NBTTagCompound(); - this.writeToNBT(tagCompound); - - return new S35PacketUpdateTileEntity(xCoord, yCoord, zCoord, 0, tagCompound); - } - - @Override - public void onDataPacket(NetworkManager network, S35PacketUpdateTileEntity packet) { - this.readFromNBT(packet.func_148857_g()); - } - - @Override - public void updateEntity() { - super.updateEntity(); - - if(!this.worldObj.isRemote && this.updatePlayers.size() > 0) { - ticksSinceLastUpdate++; - if(ticksSinceLastUpdate >= ticksBetweenUpdates) { - sendUpdatePacket(); - ticksSinceLastUpdate = 0; - } - } - } - - // Return true if this machine is active. - public abstract boolean isActive(); - - // Player updates via IBeefGuiEntity - @Override - public void beginUpdatingPlayer(EntityPlayer player) { - updatePlayers.add(player); - sendUpdatePacketToClient(player); - } - - @Override - public void stopUpdatingPlayer(EntityPlayer player) { - updatePlayers.remove(player); - } - - protected IMessage getUpdatePacket() { - NBTTagCompound childData = new NBTTagCompound(); - onSendUpdate(childData); - - return new DeviceUpdateMessage(xCoord, yCoord, zCoord, childData); - } - - private void sendUpdatePacketToClient(EntityPlayer recipient) { - if(this.worldObj.isRemote) { return; } - - CommonPacketHandler.INSTANCE.sendTo(getUpdatePacket(), (EntityPlayerMP)recipient); - - } - - private void sendUpdatePacket() { - if(this.worldObj.isRemote) { return; } - if(this.updatePlayers.size() <= 0) { return; } - - for(EntityPlayer player : updatePlayers) { - CommonPacketHandler.INSTANCE.sendTo(getUpdatePacket(), (EntityPlayerMP)player); - } - } - - // Side Exposure Helpers - @Override - public boolean setSide(int side, int config) { - int rotatedSide = this.getRotatedSide(side); - - int numConfig = getNumConfig(side); - if(config >= numConfig || config < -1) { config = SIDE_UNEXPOSED; } - - exposures[rotatedSide] = config; - sendExposureUpdate(); - return true; - } - - /** - * Autocorrecting getter for checking exposures without having to do the rotation yerself. - * @param worldSide The world side whose exposure you wish to get. - * @return The current exposure setting for the world side. - */ - protected int getExposure(int worldSide) { - return exposures[getRotatedSide(worldSide)]; - } - - /** - * Used when sending updates from server to client; batch-updates all exposures. - * @param newExposures The new set of inventory exposures. - */ - public void setSides(int[] newExposures) { - assert(newExposures.length == exposures.length); - System.arraycopy(newExposures, 0, exposures, 0, newExposures.length); - sendExposureUpdate(); // On client, should just notify neighbors - } - - @Override - public boolean incrSide(int side) { - return changeSide(side, 1); - } - - @Override - public boolean decrSide(int side) { - return changeSide(side, -1); - } - - private boolean changeSide(int side, int amount) { - int rotatedSide = this.getRotatedSide(side); - - int numConfig = getNumConfig(side); - if(numConfig <= 0) { return false; } - - int newConfig = exposures[rotatedSide] + amount; - if(newConfig >= numConfig) { newConfig = SIDE_UNEXPOSED; } - - return setSide(side, newConfig); - } - - @Override - public boolean resetSides() { - boolean changed = false; - - for(int i = 0; i < exposures.length; i++) { - if(exposures[i] != SIDE_UNEXPOSED) { - changed = true; - exposures[i] = SIDE_UNEXPOSED; - } - } - - if(changed) { - sendExposureUpdate(); - } - - return true; - } - - private void sendExposureUpdate() { - if(!this.worldObj.isRemote) { - // Send unrotated, as the rotation will be re-applied on the client - CommonPacketHandler.INSTANCE.sendToAllAround(new DeviceUpdateExposureMessage(xCoord, yCoord, zCoord, exposures), new NetworkRegistry.TargetPoint(worldObj.provider.dimensionId, xCoord, yCoord, zCoord, 50)); + } + + this.callNeighborBlockChange(); + return true; + } + + public int getRotatedSide(int side) { + return BlockHelper.ICON_ROTATION_MAP[facing][side]; + } + + @Override + public boolean rotateBlock() { + return setFacing(BlockHelper.SIDE_LEFT[facing]); + } + + @Override + public boolean onWrench(EntityPlayer player, int hitSide) { + return rotateBlock(); + } + + @Override + public boolean allowYAxisFacing() { + return false; + } + + // Save/Load + @Override + public void readFromNBT(NBTTagCompound tag) { + super.readFromNBT(tag); + + // Rotation + if (tag.hasKey("facing")) { + facing = Math.max(0, Math.min(5, tag.getInteger("facing"))); + } else { + facing = 2; + } + + // Exposure settings + if (tag.hasKey("exposures")) { + int[] tagExposures = tag.getIntArray("exposures"); + assert (tagExposures.length == exposures.length); + System.arraycopy(tagExposures, 0, exposures, 0, exposures.length); + } + } + + @Override + public void writeToNBT(NBTTagCompound tag) { + super.writeToNBT(tag); + + tag.setInteger("facing", facing); + tag.setIntArray("exposures", exposures); + } + + // Network Communication + @Override + public Packet getDescriptionPacket() { + NBTTagCompound tagCompound = new NBTTagCompound(); + this.writeToNBT(tagCompound); + + return new S35PacketUpdateTileEntity(xCoord, yCoord, zCoord, 0, tagCompound); + } + + @Override + public void onDataPacket(NetworkManager network, S35PacketUpdateTileEntity packet) { + this.readFromNBT(packet.func_148857_g()); + } + + @Override + public void updateEntity() { + super.updateEntity(); + + if (!this.worldObj.isRemote && this.updatePlayers.size() > 0) { + ticksSinceLastUpdate++; + if (ticksSinceLastUpdate >= ticksBetweenUpdates) { + sendUpdatePacket(); + ticksSinceLastUpdate = 0; + } + } + } + + // Return true if this machine is active. + public abstract boolean isActive(); + + // Player updates via IBeefGuiEntity + @Override + public void beginUpdatingPlayer(EntityPlayer player) { + updatePlayers.add(player); + sendUpdatePacketToClient(player); + } + + @Override + public void stopUpdatingPlayer(EntityPlayer player) { + updatePlayers.remove(player); + } + + protected IMessage getUpdatePacket() { + NBTTagCompound childData = new NBTTagCompound(); + onSendUpdate(childData); + + return new DeviceUpdateMessage(xCoord, yCoord, zCoord, childData); + } + + private void sendUpdatePacketToClient(EntityPlayer recipient) { + if (this.worldObj.isRemote) { + return; + } + + CommonPacketHandler.INSTANCE.sendTo(getUpdatePacket(), (EntityPlayerMP) recipient); + + } + + private void sendUpdatePacket() { + if (this.worldObj.isRemote) { + return; + } + if (this.updatePlayers.size() <= 0) { + return; + } + + for (EntityPlayer player : updatePlayers) { + CommonPacketHandler.INSTANCE.sendTo(getUpdatePacket(), (EntityPlayerMP) player); + } + } + + // Side Exposure Helpers + @Override + public boolean setSide(int side, int config) { + int rotatedSide = this.getRotatedSide(side); + + int numConfig = getNumConfig(side); + if (config >= numConfig || config < -1) { + config = SIDE_UNEXPOSED; + } + + exposures[rotatedSide] = config; + sendExposureUpdate(); + return true; + } + + /** + * Autocorrecting getter for checking exposures without having to do the rotation yerself. + * + * @param worldSide The world side whose exposure you wish to get. + * @return The current exposure setting for the world side. + */ + protected int getExposure(int worldSide) { + return exposures[getRotatedSide(worldSide)]; + } + + /** + * Used when sending updates from server to client; batch-updates all exposures. + * + * @param newExposures The new set of inventory exposures. + */ + public void setSides(int[] newExposures) { + assert (newExposures.length == exposures.length); + System.arraycopy(newExposures, 0, exposures, 0, newExposures.length); + sendExposureUpdate(); // On client, should just notify neighbors + } + + @Override + public boolean incrSide(int side) { + return changeSide(side, 1); + } + + @Override + public boolean decrSide(int side) { + return changeSide(side, -1); + } + + private boolean changeSide(int side, int amount) { + int rotatedSide = this.getRotatedSide(side); + + int numConfig = getNumConfig(side); + if (numConfig <= 0) { + return false; + } + + int newConfig = exposures[rotatedSide] + amount; + if (newConfig >= numConfig) { + newConfig = SIDE_UNEXPOSED; + } + + return setSide(side, newConfig); + } + + @Override + public boolean resetSides() { + boolean changed = false; + + for (int i = 0; i < exposures.length; i++) { + if (exposures[i] != SIDE_UNEXPOSED) { + changed = true; + exposures[i] = SIDE_UNEXPOSED; + } + } + + if (changed) { + sendExposureUpdate(); + } + + return true; + } + + private void sendExposureUpdate() { + if (!this.worldObj.isRemote) { + // Send unrotated, as the rotation will be re-applied on the client + CommonPacketHandler.INSTANCE.sendToAllAround( + new DeviceUpdateExposureMessage(xCoord, yCoord, zCoord, exposures), + new NetworkRegistry.TargetPoint(worldObj.provider.dimensionId, xCoord, yCoord, zCoord, 50)); this.markChunkDirty(); - } - else { - // Re-render block on client - worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - - this.callNeighborTileChange(); - this.callNeighborBlockChange(); - } - - /** - * Fill this NBT Tag Compound with your custom entity data. - * @param updateTag The tag to which your data should be written - */ - protected void onSendUpdate(NBTTagCompound updateTag) {} - - /** - * Read your custom update data from this NBT Tag Compound. - * @param updateTag The tag which should contain your data. - */ - public void onReceiveUpdate(NBTTagCompound updateTag) {} - - // Weird shit from TileCoFHBase - public String getName() { - return this.getBlockType().getUnlocalizedName(); - } - - public int getType() { - return getBlockMetadata(); - } + } else { + // Re-render block on client + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + + this.callNeighborTileChange(); + this.callNeighborBlockChange(); + } + + /** + * Fill this NBT Tag Compound with your custom entity data. + * + * @param updateTag The tag to which your data should be written + */ + protected void onSendUpdate(NBTTagCompound updateTag) {} + + /** + * Read your custom update data from this NBT Tag Compound. + * + * @param updateTag The tag which should contain your data. + */ + public void onReceiveUpdate(NBTTagCompound updateTag) {} + + // Weird shit from TileCoFHBase + public String getName() { + return this.getBlockType() + .getUnlocalizedName(); + } + + public int getType() { + return getBlockMetadata(); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/tileentity/base/TileEntityInventory.java b/src/main/java/erogenousbeef/bigreactors/common/tileentity/base/TileEntityInventory.java index f0afbd06..b23c5886 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/tileentity/base/TileEntityInventory.java +++ b/src/main/java/erogenousbeef/bigreactors/common/tileentity/base/TileEntityInventory.java @@ -9,270 +9,272 @@ import net.minecraft.nbt.NBTTagList; import net.minecraft.tileentity.TileEntity; import net.minecraftforge.common.util.ForgeDirection; + import cofh.lib.util.helpers.BlockHelper; import erogenousbeef.bigreactors.utils.AdjacentInventoryHelper; public abstract class TileEntityInventory extends TileEntityBeefBase implements IInventory, ISidedInventory { - - // Inventory - protected ItemStack[] _inventories; - protected int[][] invSlotExposures; - - private AdjacentInventoryHelper[] adjacentInvs; - - protected static final int SLOT_NONE = TileEntityBeefBase.SIDE_UNEXPOSED; - - public TileEntityInventory() { - super(); - _inventories = new ItemStack[getSizeInventory()]; - invSlotExposures = new int[getSizeInventory()][1]; - for(int i = 0; i < invSlotExposures.length; i++) { - // Set up a cached array with all possible exposed inventory slots, so we don't have to alloc at runtime - invSlotExposures[i][0] = i; - } - - adjacentInvs = new AdjacentInventoryHelper[ForgeDirection.VALID_DIRECTIONS.length]; - for(ForgeDirection dir: ForgeDirection.VALID_DIRECTIONS) { - adjacentInvs[dir.ordinal()] = new AdjacentInventoryHelper(dir); - } - - resetAdjacentInventories(); - } - - @Override - public void onNeighborBlockChange() { - super.onNeighborBlockChange(); - - checkAdjacentInventories(); - } - - @Override - public void onNeighborTileChange(int x, int y, int z) { - super.onNeighborTileChange(x, y, z); - int side = BlockHelper.determineAdjacentSide(this, x, y, z); - checkAdjacentInventory(ForgeDirection.getOrientation(side)); - } - - // TileEntity overrides - @Override - public void readFromNBT(NBTTagCompound tag) { - super.readFromNBT(tag); - - // Inventories - _inventories = new ItemStack[getSizeInventory()]; - if(tag.hasKey("Items")) { - NBTTagList tagList = tag.getTagList("Items", 10); - for(int i = 0; i < tagList.tagCount(); i++) { - NBTTagCompound itemTag = (NBTTagCompound)tagList.getCompoundTagAt(i); - int slot = itemTag.getByte("Slot") & 0xff; - if(slot >= 0 && slot <= _inventories.length) { - ItemStack itemStack = new ItemStack((Block)null,0,0); - itemStack.readFromNBT(itemTag); - _inventories[slot] = itemStack; - } - } - } - } - - @Override - public void writeToNBT(NBTTagCompound tag) { - super.writeToNBT(tag); - - // Inventories - NBTTagList tagList = new NBTTagList(); - for(int i = 0; i < _inventories.length; i++) { - if((_inventories[i]) != null) { - NBTTagCompound itemTag = new NBTTagCompound(); - itemTag.setByte("Slot", (byte)i); - _inventories[i].writeToNBT(itemTag); - tagList.appendTag(itemTag); - } - } - - if(tagList.tagCount() > 0) { - tag.setTag("Items", tagList); - } - } - - // IInventory - @Override - public abstract int getSizeInventory(); - - @Override - public ItemStack getStackInSlot(int slot) { - return _inventories[slot]; - } - - @Override - public ItemStack decrStackSize(int slot, int amount) { - if(_inventories[slot] != null) - { - if(_inventories[slot].stackSize <= amount) - { - ItemStack itemstack = _inventories[slot]; - _inventories[slot] = null; - return itemstack; - } - ItemStack newStack = _inventories[slot].splitStack(amount); - if(_inventories[slot].stackSize == 0) - { - _inventories[slot] = null; - } - return newStack; - } - else - { - return null; - } - } - - @Override - public ItemStack getStackInSlotOnClosing(int slot) { - return null; - } - - @Override - public void setInventorySlotContents(int slot, ItemStack itemstack) { - _inventories[slot] = itemstack; - if(itemstack != null && itemstack.stackSize > getInventoryStackLimit()) - { - itemstack.stackSize = getInventoryStackLimit(); - } - } - - @Override - public abstract String getInventoryName(); - - @Override - public boolean hasCustomInventoryName() { - return false; - } - - @Override - public int getInventoryStackLimit() { - return 64; - } - - @Override - public boolean isUseableByPlayer(EntityPlayer entityplayer) { - if(worldObj.getTileEntity(xCoord, yCoord, zCoord) != this) - { - return false; - } - return entityplayer.getDistanceSq((double)xCoord + 0.5D, (double)yCoord + 0.5D, (double)zCoord + 0.5D) <= 64D; - } - - @Override - public void openInventory() { - } - - @Override - public void closeInventory() { - } - - @Override - public abstract boolean isItemValidForSlot(int slot, ItemStack itemstack); - - // ISidedInventory - /** - * Get the exposed inventory slot from a given world side. - * Remember to translate this into a reference side! - * @param side The side being queried for exposure. - * @return The index of the exposed slot, -1 (SLOT_UNEXPOSED) if none. - */ - protected abstract int getExposedInventorySlotFromSide(int side); - - @Override - public int[] getAccessibleSlotsFromSide(int side) { - int exposedSlot = getExposedInventorySlotFromSide(side); - if(exposedSlot >= 0 && exposedSlot < invSlotExposures.length) { - return invSlotExposures[exposedSlot]; - } - else { - return kEmptyIntArray; - } - } - - @Override - public boolean canInsertItem(int slot, ItemStack itemstack, int side) { - return isItemValidForSlot(slot, itemstack); - } - - @Override - public boolean canExtractItem(int slot, ItemStack itemstack, int side) { - return isItemValidForSlot(slot, itemstack); - } - - // IItemDuctConnection - public boolean canConduitConnect(ForgeDirection from) { - return from != ForgeDirection.UNKNOWN; - } - - /** - * This method distributes items from all exposed slots to linked inventories - * on their respective sides. - */ - protected void distributeItems() - { - for(ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { - distributeSide(dir); - } - } - - protected void distributeItemsFromSlot(int slot) { - if(slot == SLOT_NONE) { return; } - for(ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { - int sideSlot = getExposedInventorySlotFromSide(dir.ordinal()); - if(slot == sideSlot) { - _inventories[slot] = distributeItemToSide(dir, _inventories[slot]); - } - - if(_inventories[slot] == null) { break; } - } - } - - /** - * Distributes items from whichever slot is currently exposed on a given - * side to any adjacent pipes/ducts/inventories. - * @param dir The side whose exposed items you wish to distribute. - */ - protected void distributeSide(ForgeDirection dir) { - int slot = getExposedInventorySlotFromSide(dir.ordinal()); - if(slot == SLOT_NONE) { return; } - if(_inventories[slot] == null) { return; } - - _inventories[slot] = distributeItemToSide(dir, _inventories[slot]); - } - - /** - * Distributes a given item stack to a given side. - * Note that this method does not check for exposures. - * @param dir Direction/side to which you wish to distribute items. - * @param itemstack An item stack to distribute. - * @return An itemstack containing the undistributed items, or null if all items were distributed. - */ - protected ItemStack distributeItemToSide(ForgeDirection dir, ItemStack itemstack) { - return adjacentInvs[dir.ordinal()].distribute(itemstack); - } - - // Adjacent Inventory Detection - private void checkAdjacentInventories() { - boolean changed = false; - for(ForgeDirection dir: ForgeDirection.VALID_DIRECTIONS) { - checkAdjacentInventory(dir); - } - } - - private void checkAdjacentInventory(ForgeDirection dir) { - TileEntity te = worldObj.getTileEntity(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ); - if(adjacentInvs[dir.ordinal()].set(te)) { - distributeSide(dir); - } - } - - private void resetAdjacentInventories() { - for(int i = 0; i < ForgeDirection.VALID_DIRECTIONS.length; i++) { - adjacentInvs[i].set(null); - } - } + + // Inventory + protected ItemStack[] _inventories; + protected int[][] invSlotExposures; + + private AdjacentInventoryHelper[] adjacentInvs; + + protected static final int SLOT_NONE = TileEntityBeefBase.SIDE_UNEXPOSED; + + public TileEntityInventory() { + super(); + _inventories = new ItemStack[getSizeInventory()]; + invSlotExposures = new int[getSizeInventory()][1]; + for (int i = 0; i < invSlotExposures.length; i++) { + // Set up a cached array with all possible exposed inventory slots, so we don't have to alloc at runtime + invSlotExposures[i][0] = i; + } + + adjacentInvs = new AdjacentInventoryHelper[ForgeDirection.VALID_DIRECTIONS.length]; + for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { + adjacentInvs[dir.ordinal()] = new AdjacentInventoryHelper(dir); + } + + resetAdjacentInventories(); + } + + @Override + public void onNeighborBlockChange() { + super.onNeighborBlockChange(); + + checkAdjacentInventories(); + } + + @Override + public void onNeighborTileChange(int x, int y, int z) { + super.onNeighborTileChange(x, y, z); + int side = BlockHelper.determineAdjacentSide(this, x, y, z); + checkAdjacentInventory(ForgeDirection.getOrientation(side)); + } + + // TileEntity overrides + @Override + public void readFromNBT(NBTTagCompound tag) { + super.readFromNBT(tag); + + // Inventories + _inventories = new ItemStack[getSizeInventory()]; + if (tag.hasKey("Items")) { + NBTTagList tagList = tag.getTagList("Items", 10); + for (int i = 0; i < tagList.tagCount(); i++) { + NBTTagCompound itemTag = (NBTTagCompound) tagList.getCompoundTagAt(i); + int slot = itemTag.getByte("Slot") & 0xff; + if (slot >= 0 && slot <= _inventories.length) { + ItemStack itemStack = new ItemStack((Block) null, 0, 0); + itemStack.readFromNBT(itemTag); + _inventories[slot] = itemStack; + } + } + } + } + + @Override + public void writeToNBT(NBTTagCompound tag) { + super.writeToNBT(tag); + + // Inventories + NBTTagList tagList = new NBTTagList(); + for (int i = 0; i < _inventories.length; i++) { + if ((_inventories[i]) != null) { + NBTTagCompound itemTag = new NBTTagCompound(); + itemTag.setByte("Slot", (byte) i); + _inventories[i].writeToNBT(itemTag); + tagList.appendTag(itemTag); + } + } + + if (tagList.tagCount() > 0) { + tag.setTag("Items", tagList); + } + } + + // IInventory + @Override + public abstract int getSizeInventory(); + + @Override + public ItemStack getStackInSlot(int slot) { + return _inventories[slot]; + } + + @Override + public ItemStack decrStackSize(int slot, int amount) { + if (_inventories[slot] != null) { + if (_inventories[slot].stackSize <= amount) { + ItemStack itemstack = _inventories[slot]; + _inventories[slot] = null; + return itemstack; + } + ItemStack newStack = _inventories[slot].splitStack(amount); + if (_inventories[slot].stackSize == 0) { + _inventories[slot] = null; + } + return newStack; + } else { + return null; + } + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return null; + } + + @Override + public void setInventorySlotContents(int slot, ItemStack itemstack) { + _inventories[slot] = itemstack; + if (itemstack != null && itemstack.stackSize > getInventoryStackLimit()) { + itemstack.stackSize = getInventoryStackLimit(); + } + } + + @Override + public abstract String getInventoryName(); + + @Override + public boolean hasCustomInventoryName() { + return false; + } + + @Override + public int getInventoryStackLimit() { + return 64; + } + + @Override + public boolean isUseableByPlayer(EntityPlayer entityplayer) { + if (worldObj.getTileEntity(xCoord, yCoord, zCoord) != this) { + return false; + } + return entityplayer.getDistanceSq((double) xCoord + 0.5D, (double) yCoord + 0.5D, (double) zCoord + 0.5D) + <= 64D; + } + + @Override + public void openInventory() {} + + @Override + public void closeInventory() {} + + @Override + public abstract boolean isItemValidForSlot(int slot, ItemStack itemstack); + + // ISidedInventory + /** + * Get the exposed inventory slot from a given world side. + * Remember to translate this into a reference side! + * + * @param side The side being queried for exposure. + * @return The index of the exposed slot, -1 (SLOT_UNEXPOSED) if none. + */ + protected abstract int getExposedInventorySlotFromSide(int side); + + @Override + public int[] getAccessibleSlotsFromSide(int side) { + int exposedSlot = getExposedInventorySlotFromSide(side); + if (exposedSlot >= 0 && exposedSlot < invSlotExposures.length) { + return invSlotExposures[exposedSlot]; + } else { + return kEmptyIntArray; + } + } + + @Override + public boolean canInsertItem(int slot, ItemStack itemstack, int side) { + return isItemValidForSlot(slot, itemstack); + } + + @Override + public boolean canExtractItem(int slot, ItemStack itemstack, int side) { + return isItemValidForSlot(slot, itemstack); + } + + // IItemDuctConnection + public boolean canConduitConnect(ForgeDirection from) { + return from != ForgeDirection.UNKNOWN; + } + + /** + * This method distributes items from all exposed slots to linked inventories + * on their respective sides. + */ + protected void distributeItems() { + for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { + distributeSide(dir); + } + } + + protected void distributeItemsFromSlot(int slot) { + if (slot == SLOT_NONE) { + return; + } + for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { + int sideSlot = getExposedInventorySlotFromSide(dir.ordinal()); + if (slot == sideSlot) { + _inventories[slot] = distributeItemToSide(dir, _inventories[slot]); + } + + if (_inventories[slot] == null) { + break; + } + } + } + + /** + * Distributes items from whichever slot is currently exposed on a given + * side to any adjacent pipes/ducts/inventories. + * + * @param dir The side whose exposed items you wish to distribute. + */ + protected void distributeSide(ForgeDirection dir) { + int slot = getExposedInventorySlotFromSide(dir.ordinal()); + if (slot == SLOT_NONE) { + return; + } + if (_inventories[slot] == null) { + return; + } + + _inventories[slot] = distributeItemToSide(dir, _inventories[slot]); + } + + /** + * Distributes a given item stack to a given side. + * Note that this method does not check for exposures. + * + * @param dir Direction/side to which you wish to distribute items. + * @param itemstack An item stack to distribute. + * @return An itemstack containing the undistributed items, or null if all items were distributed. + */ + protected ItemStack distributeItemToSide(ForgeDirection dir, ItemStack itemstack) { + return adjacentInvs[dir.ordinal()].distribute(itemstack); + } + + // Adjacent Inventory Detection + private void checkAdjacentInventories() { + boolean changed = false; + for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { + checkAdjacentInventory(dir); + } + } + + private void checkAdjacentInventory(ForgeDirection dir) { + TileEntity te = worldObj.getTileEntity(xCoord + dir.offsetX, yCoord + dir.offsetY, zCoord + dir.offsetZ); + if (adjacentInvs[dir.ordinal()].set(te)) { + distributeSide(dir); + } + } + + private void resetAdjacentInventories() { + for (int i = 0; i < ForgeDirection.VALID_DIRECTIONS.length; i++) { + adjacentInvs[i].set(null); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/tileentity/base/TileEntityPoweredInventory.java b/src/main/java/erogenousbeef/bigreactors/common/tileentity/base/TileEntityPoweredInventory.java index ca592504..e50c3844 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/tileentity/base/TileEntityPoweredInventory.java +++ b/src/main/java/erogenousbeef/bigreactors/common/tileentity/base/TileEntityPoweredInventory.java @@ -2,183 +2,194 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.common.util.ForgeDirection; + import cofh.api.energy.EnergyStorage; import cofh.api.energy.IEnergyHandler; public abstract class TileEntityPoweredInventory extends TileEntityInventory implements IEnergyHandler { - public static float energyPerRF = 1f; - - protected boolean m_ReceivesEnergy = true; - protected boolean m_ProvidesEnergy = true; - - // Internal power - private int cycledTicks; - private EnergyStorage energyStorage; - - public TileEntityPoweredInventory() { - super(); - - energyStorage = new EnergyStorage(getMaxEnergyStored()); - - cycledTicks = -1; - } - - // Internal energy methods - /** - * The amount of energy stored in this type of TileEntity - * @return The amount of energy stored. 0 or more. Only called at construction time. - */ - protected abstract int getMaxEnergyStored(); - - /** - * Returns the energy cost to run a cycle. Consumed instantly when a cycle begins. - * @return Amount of RF needed to start a cycle. - */ - public abstract int getCycleEnergyCost(); - - /** - * @return The length of a powered processing cycle, in ticks. - */ - public abstract int getCycleLength(); - - /** - * Check material/non-energy requirements for starting a cycle. - * These requirements should NOT be consumed at the start of a cycle. - * @return True if a cycle can start/continue, false otherwise. - */ - public abstract boolean canBeginCycle(); - - /** - * Perform any necessary operations at the start of a cycle. - * Do NOT consume resources here. Powered cycles should only consume - * resources at the end of a cycle. - * canBeginCycle() will be called each tick to ensure that the necessary - * conditions remain met throughout the cycle. - */ - public abstract void onPoweredCycleBegin(); - - /** - * Perform any necessary operations at the end of a cycle. - * Consume and produce resources here. - */ - public abstract void onPoweredCycleEnd(); - - public int getCurrentCycleTicks() { - return cycledTicks; - } - - @Override - public boolean isActive() { - return cycledTicks >= 0; - } - - public float getCycleCompletion() { - if(cycledTicks < 0) { return 0f; } - else { return (float)cycledTicks / (float)getCycleLength(); } - } - - // TileEntity overrides - @Override - public void readFromNBT(NBTTagCompound tag) { - super.readFromNBT(tag); - - if(tag.hasKey("energyStorage")) { - this.energyStorage.readFromNBT(tag.getCompoundTag("energyStorage")); - } - - if(tag.hasKey("cycledTicks")) { - cycledTicks = tag.getInteger("cycledTicks"); - } - } - - @Override - public void writeToNBT(NBTTagCompound tag) { - super.writeToNBT(tag); - NBTTagCompound energyTag = new NBTTagCompound(); - this.energyStorage.writeToNBT(energyTag); - tag.setTag("energyStorage", energyTag); - tag.setInteger("cycledTicks", cycledTicks); - } - - // TileEntity methods - @Override - public void updateEntity() { - super.updateEntity(); - - if(!worldObj.isRemote) { - // Energy consumption is all callback-based now. - - // If we're running, continue the cycle until we're done. - if(cycledTicks >= 0) { - cycledTicks++; - - // If we don't have the stuff to begin a cycle, stop now - if(!canBeginCycle()) { - cycledTicks = -1; - this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - else if(cycledTicks >= getCycleLength()) { - onPoweredCycleEnd(); - cycledTicks = -1; - this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - } - - // If we've stopped running, but we can start, then start running. - if(cycledTicks < 0 && getCycleEnergyCost() <= energyStorage.getEnergyStored() && canBeginCycle()) { - this.energyStorage.extractEnergy(getCycleEnergyCost(), false); - cycledTicks = 0; - onPoweredCycleBegin(); - this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - } - } - - // TileEntityBeefBase methods - @Override - protected void onSendUpdate(NBTTagCompound updateTag) { - super.onSendUpdate(updateTag); - NBTTagCompound energyTag = new NBTTagCompound(); - this.energyStorage.writeToNBT(energyTag); - updateTag.setTag("energyStorage", energyTag); - updateTag.setInteger("cycledTicks", this.cycledTicks); - } - - @Override - public void onReceiveUpdate(NBTTagCompound updateTag) { - super.onReceiveUpdate(updateTag); - this.energyStorage.readFromNBT(updateTag.getCompoundTag("energyStorage")); - this.cycledTicks = updateTag.getInteger("cycledTicks"); - } - - /* IEnergyHandler */ - @Override - public int receiveEnergy(ForgeDirection from, int maxReceive, boolean simulate) { - if(!m_ReceivesEnergy) { return 0; } - return energyStorage.receiveEnergy(maxReceive, simulate); - } - - @Override - public int extractEnergy(ForgeDirection from, int maxExtract, boolean simulate) { - if(!m_ProvidesEnergy) { return 0; } - return energyStorage.extractEnergy(maxExtract, simulate); - } - - @Override - public boolean canConnectEnergy(ForgeDirection from) { - - return true; - } - - @Override - public int getEnergyStored(ForgeDirection from) { - - return energyStorage.getEnergyStored(); - } - - @Override - public int getMaxEnergyStored(ForgeDirection from) { - - return energyStorage.getMaxEnergyStored(); - } + + public static float energyPerRF = 1f; + + protected boolean m_ReceivesEnergy = true; + protected boolean m_ProvidesEnergy = true; + + // Internal power + private int cycledTicks; + private EnergyStorage energyStorage; + + public TileEntityPoweredInventory() { + super(); + + energyStorage = new EnergyStorage(getMaxEnergyStored()); + + cycledTicks = -1; + } + + // Internal energy methods + /** + * The amount of energy stored in this type of TileEntity + * + * @return The amount of energy stored. 0 or more. Only called at construction time. + */ + protected abstract int getMaxEnergyStored(); + + /** + * Returns the energy cost to run a cycle. Consumed instantly when a cycle begins. + * + * @return Amount of RF needed to start a cycle. + */ + public abstract int getCycleEnergyCost(); + + /** + * @return The length of a powered processing cycle, in ticks. + */ + public abstract int getCycleLength(); + + /** + * Check material/non-energy requirements for starting a cycle. + * These requirements should NOT be consumed at the start of a cycle. + * + * @return True if a cycle can start/continue, false otherwise. + */ + public abstract boolean canBeginCycle(); + + /** + * Perform any necessary operations at the start of a cycle. + * Do NOT consume resources here. Powered cycles should only consume + * resources at the end of a cycle. + * canBeginCycle() will be called each tick to ensure that the necessary + * conditions remain met throughout the cycle. + */ + public abstract void onPoweredCycleBegin(); + + /** + * Perform any necessary operations at the end of a cycle. + * Consume and produce resources here. + */ + public abstract void onPoweredCycleEnd(); + + public int getCurrentCycleTicks() { + return cycledTicks; + } + + @Override + public boolean isActive() { + return cycledTicks >= 0; + } + + public float getCycleCompletion() { + if (cycledTicks < 0) { + return 0f; + } else { + return (float) cycledTicks / (float) getCycleLength(); + } + } + + // TileEntity overrides + @Override + public void readFromNBT(NBTTagCompound tag) { + super.readFromNBT(tag); + + if (tag.hasKey("energyStorage")) { + this.energyStorage.readFromNBT(tag.getCompoundTag("energyStorage")); + } + + if (tag.hasKey("cycledTicks")) { + cycledTicks = tag.getInteger("cycledTicks"); + } + } + + @Override + public void writeToNBT(NBTTagCompound tag) { + super.writeToNBT(tag); + NBTTagCompound energyTag = new NBTTagCompound(); + this.energyStorage.writeToNBT(energyTag); + tag.setTag("energyStorage", energyTag); + tag.setInteger("cycledTicks", cycledTicks); + } + + // TileEntity methods + @Override + public void updateEntity() { + super.updateEntity(); + + if (!worldObj.isRemote) { + // Energy consumption is all callback-based now. + + // If we're running, continue the cycle until we're done. + if (cycledTicks >= 0) { + cycledTicks++; + + // If we don't have the stuff to begin a cycle, stop now + if (!canBeginCycle()) { + cycledTicks = -1; + this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } else if (cycledTicks >= getCycleLength()) { + onPoweredCycleEnd(); + cycledTicks = -1; + this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + } + + // If we've stopped running, but we can start, then start running. + if (cycledTicks < 0 && getCycleEnergyCost() <= energyStorage.getEnergyStored() && canBeginCycle()) { + this.energyStorage.extractEnergy(getCycleEnergyCost(), false); + cycledTicks = 0; + onPoweredCycleBegin(); + this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + } + } + + // TileEntityBeefBase methods + @Override + protected void onSendUpdate(NBTTagCompound updateTag) { + super.onSendUpdate(updateTag); + NBTTagCompound energyTag = new NBTTagCompound(); + this.energyStorage.writeToNBT(energyTag); + updateTag.setTag("energyStorage", energyTag); + updateTag.setInteger("cycledTicks", this.cycledTicks); + } + + @Override + public void onReceiveUpdate(NBTTagCompound updateTag) { + super.onReceiveUpdate(updateTag); + this.energyStorage.readFromNBT(updateTag.getCompoundTag("energyStorage")); + this.cycledTicks = updateTag.getInteger("cycledTicks"); + } + + /* IEnergyHandler */ + @Override + public int receiveEnergy(ForgeDirection from, int maxReceive, boolean simulate) { + if (!m_ReceivesEnergy) { + return 0; + } + return energyStorage.receiveEnergy(maxReceive, simulate); + } + + @Override + public int extractEnergy(ForgeDirection from, int maxExtract, boolean simulate) { + if (!m_ProvidesEnergy) { + return 0; + } + return energyStorage.extractEnergy(maxExtract, simulate); + } + + @Override + public boolean canConnectEnergy(ForgeDirection from) { + + return true; + } + + @Override + public int getEnergyStored(ForgeDirection from) { + + return energyStorage.getEnergyStored(); + } + + @Override + public int getMaxEnergyStored(ForgeDirection from) { + + return energyStorage.getMaxEnergyStored(); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/common/tileentity/base/TileEntityPoweredInventoryFluid.java b/src/main/java/erogenousbeef/bigreactors/common/tileentity/base/TileEntityPoweredInventoryFluid.java index 026ea56d..0efb8798 100644 --- a/src/main/java/erogenousbeef/bigreactors/common/tileentity/base/TileEntityPoweredInventoryFluid.java +++ b/src/main/java/erogenousbeef/bigreactors/common/tileentity/base/TileEntityPoweredInventoryFluid.java @@ -9,257 +9,264 @@ import net.minecraftforge.fluids.FluidTankInfo; import net.minecraftforge.fluids.IFluidHandler; import net.minecraftforge.fluids.IFluidTank; + import erogenousbeef.bigreactors.common.interfaces.IMultipleFluidHandler; -public abstract class TileEntityPoweredInventoryFluid extends - TileEntityPoweredInventory implements IFluidHandler, IMultipleFluidHandler { - - private FluidTank[] tanks; - private FluidTank[][] tankExposureCache; - - protected static final FluidTank[] kEmptyFluidTankList = new FluidTank[0]; - protected static final int FLUIDTANK_NONE = -1; - - public TileEntityPoweredInventoryFluid() { - super(); - - tanks = new FluidTank[getNumTanks()]; - tankExposureCache = new FluidTank[getNumTanks()][1]; - - for(int i = 0; i < getNumTanks(); i++) { - tanks[i] = new FluidTank(getTankSize(i)); - tankExposureCache[i][0] = tanks[i]; - } - } - - // Internal Helpers - - private void readFluidsFromNBT(NBTTagCompound tag) { - // Initialize tanks to empty, as we send sparse updates. - for(int i = 0; i < tanks.length; i++) { - tanks[i].setFluid(null); - } - - if(tag.hasKey("fluids")) { - NBTTagList tagList = tag.getTagList("fluids", 10); - for(int i = 0; i < tagList.tagCount(); i++) { - NBTTagCompound fluidTag = tagList.getCompoundTagAt(i); - int fluidIdx = fluidTag.getInteger("tagIdx"); - FluidStack newFluid = FluidStack.loadFluidStackFromNBT(fluidTag); - tanks[fluidIdx].setFluid(newFluid); - } - } - } - - private void writeFluidsToNBT(NBTTagCompound tag) { - NBTTagList fluidTagList = new NBTTagList(); - for(int i = 0; i < getNumTanks(); i++) { - if(tanks[i] != null && tanks[i].getFluid() != null) { - NBTTagCompound fluidTag = new NBTTagCompound(); - fluidTag.setInteger("tagIdx", i); - tanks[i].getFluid().writeToNBT(fluidTag); - fluidTagList.appendTag(fluidTag); - } - } - - if(fluidTagList.tagCount() > 0) { - tag.setTag("fluids", fluidTagList); - } - } - - // TileEntity overrides - @Override - public void readFromNBT(NBTTagCompound tag) { - super.readFromNBT(tag); - readFluidsFromNBT(tag); - } - - @Override - public void writeToNBT(NBTTagCompound tag) { - super.writeToNBT(tag); - writeFluidsToNBT(tag); - } - - // TileEntityBeefBase - @Override - protected void onSendUpdate(NBTTagCompound updateTag) { - super.onSendUpdate(updateTag); - writeFluidsToNBT(updateTag); - } - - @Override - public void onReceiveUpdate(NBTTagCompound updateTag) { - super.onReceiveUpdate(updateTag); - readFluidsFromNBT(updateTag); - } - - // IFluidHandler - - /** - * The number of fluid tanks in this machine. - * @return The number of fluid tanks in this machine. - */ - public abstract int getNumTanks(); - - /** - * Returns the size of the tank at a given position - * @param tankIndex The index of the given tank in the tanks array. - * @return The volume of the tank, in fluid units. 1000 = 1 Bucket. - */ - public abstract int getTankSize(int tankIndex); - - /** - * Returns the index of the tank which is exposed on a given world side. - * Remember to translate this into a reference side! - * @param side The world side on which the device is being queried for fluid tank exposures. - * @return The index of the exposed tank, or -1 for none. - */ - public abstract int getExposedTankFromSide(int side); - - /** +public abstract class TileEntityPoweredInventoryFluid extends TileEntityPoweredInventory + implements IFluidHandler, IMultipleFluidHandler { + + private FluidTank[] tanks; + private FluidTank[][] tankExposureCache; + + protected static final FluidTank[] kEmptyFluidTankList = new FluidTank[0]; + protected static final int FLUIDTANK_NONE = -1; + + public TileEntityPoweredInventoryFluid() { + super(); + + tanks = new FluidTank[getNumTanks()]; + tankExposureCache = new FluidTank[getNumTanks()][1]; + + for (int i = 0; i < getNumTanks(); i++) { + tanks[i] = new FluidTank(getTankSize(i)); + tankExposureCache[i][0] = tanks[i]; + } + } + + // Internal Helpers + + private void readFluidsFromNBT(NBTTagCompound tag) { + // Initialize tanks to empty, as we send sparse updates. + for (int i = 0; i < tanks.length; i++) { + tanks[i].setFluid(null); + } + + if (tag.hasKey("fluids")) { + NBTTagList tagList = tag.getTagList("fluids", 10); + for (int i = 0; i < tagList.tagCount(); i++) { + NBTTagCompound fluidTag = tagList.getCompoundTagAt(i); + int fluidIdx = fluidTag.getInteger("tagIdx"); + FluidStack newFluid = FluidStack.loadFluidStackFromNBT(fluidTag); + tanks[fluidIdx].setFluid(newFluid); + } + } + } + + private void writeFluidsToNBT(NBTTagCompound tag) { + NBTTagList fluidTagList = new NBTTagList(); + for (int i = 0; i < getNumTanks(); i++) { + if (tanks[i] != null && tanks[i].getFluid() != null) { + NBTTagCompound fluidTag = new NBTTagCompound(); + fluidTag.setInteger("tagIdx", i); + tanks[i].getFluid() + .writeToNBT(fluidTag); + fluidTagList.appendTag(fluidTag); + } + } + + if (fluidTagList.tagCount() > 0) { + tag.setTag("fluids", fluidTagList); + } + } + + // TileEntity overrides + @Override + public void readFromNBT(NBTTagCompound tag) { + super.readFromNBT(tag); + readFluidsFromNBT(tag); + } + + @Override + public void writeToNBT(NBTTagCompound tag) { + super.writeToNBT(tag); + writeFluidsToNBT(tag); + } + + // TileEntityBeefBase + @Override + protected void onSendUpdate(NBTTagCompound updateTag) { + super.onSendUpdate(updateTag); + writeFluidsToNBT(updateTag); + } + + @Override + public void onReceiveUpdate(NBTTagCompound updateTag) { + super.onReceiveUpdate(updateTag); + readFluidsFromNBT(updateTag); + } + + // IFluidHandler + + /** + * The number of fluid tanks in this machine. + * + * @return The number of fluid tanks in this machine. + */ + public abstract int getNumTanks(); + + /** + * Returns the size of the tank at a given position + * + * @param tankIndex The index of the given tank in the tanks array. + * @return The volume of the tank, in fluid units. 1000 = 1 Bucket. + */ + public abstract int getTankSize(int tankIndex); + + /** + * Returns the index of the tank which is exposed on a given world side. + * Remember to translate this into a reference side! + * + * @param side The world side on which the device is being queried for fluid tank exposures. + * @return The index of the exposed tank, or -1 for none. + */ + public abstract int getExposedTankFromSide(int side); + + /** * Fills fluid into internal tanks, distribution is left to the ITankContainer. - * @param from Orientation the fluid is pumped in from. + * + * @param from Orientation the fluid is pumped in from. * @param resource FluidStack representing the maximum amount of fluid filled into the ITankContainer - * @param doFill If false filling will only be simulated. + * @param doFill If false filling will only be simulated. * @return Amount of resource that was filled into internal tanks. */ public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { - int tankToFill = FLUIDTANK_NONE; - if(from != ForgeDirection.UNKNOWN) { - tankToFill = getExposedTankFromSide(from.ordinal()); - } - else { - tankToFill = getDefaultTankForFluid(resource.getFluid()); - } - - if(tankToFill <= FLUIDTANK_NONE) { - return 0; - } else { - return fill(tankToFill, resource, doFill); - } + int tankToFill = FLUIDTANK_NONE; + if (from != ForgeDirection.UNKNOWN) { + tankToFill = getExposedTankFromSide(from.ordinal()); + } else { + tankToFill = getDefaultTankForFluid(resource.getFluid()); + } + + if (tankToFill <= FLUIDTANK_NONE) { + return 0; + } else { + return fill(tankToFill, resource, doFill); + } } - + /** * Fills fluid into the specified internal tank. + * * @param tankIndex the index of the tank to fill - * @param resource FluidStack representing the maximum amount of fluid filled into the ITankContainer - * @param doFill If false filling will only be simulated. + * @param resource FluidStack representing the maximum amount of fluid filled into the ITankContainer + * @param doFill If false filling will only be simulated. * @return Amount of resource that was filled into internal tanks. */ public int fill(int tankIndex, FluidStack resource, boolean doFill) { - if(!isFluidValidForTank(tankIndex, resource)) { - return 0; - } - - int res = tanks[tankIndex].fill(resource, doFill); - return res; + if (!isFluidValidForTank(tankIndex, resource)) { + return 0; + } + + int res = tanks[tankIndex].fill(resource, doFill); + return res; } - /** Drains fluid out of internal tanks, distribution is left entirely to the IFluidHandler. - * - * This method is not Fluid-sensitive. - * @param from Orientation the fluid is drained to. + /** + * Drains fluid out of internal tanks, distribution is left entirely to the IFluidHandler. + * + * This method is not Fluid-sensitive. + * + * @param from Orientation the fluid is drained to. * @param maxDrain Maximum amount of fluid to drain. - * @param doDrain If false draining will only be simulated. + * @param doDrain If false draining will only be simulated. * @return FluidStack representing the fluid and amount actually drained from the ITankContainer */ public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) { - int tankToDrain = 0; - if(from != ForgeDirection.UNKNOWN) { - tankToDrain = getExposedTankFromSide(from.ordinal()); - } - - if(tankToDrain <= FLUIDTANK_NONE) { - return null; - } else { - return drain(tankToDrain, maxDrain, doDrain); - } + int tankToDrain = 0; + if (from != ForgeDirection.UNKNOWN) { + tankToDrain = getExposedTankFromSide(from.ordinal()); + } + + if (tankToDrain <= FLUIDTANK_NONE) { + return null; + } else { + return drain(tankToDrain, maxDrain, doDrain); + } } - + /** * Drains fluid out of the specified internal tank. + * * @param tankIndex the index of the tank to drain - * @param maxDrain Maximum amount of fluid to drain. - * @param doDrain If false draining will only be simulated. + * @param maxDrain Maximum amount of fluid to drain. + * @param doDrain If false draining will only be simulated. * @return FluidStack representing the fluid and amount actually drained from the ITankContainer */ public FluidStack drain(int tankIndex, int maxDrain, boolean doDrain) { - return tanks[tankIndex].drain(maxDrain, doDrain); + return tanks[tankIndex].drain(maxDrain, doDrain); } /** * Drains fluid out of internal tanks, distribution is left entirely to the IFluidHandler. * * @param from - * Orientation the Fluid is drained to. + * Orientation the Fluid is drained to. * @param resource - * FluidStack representing the Fluid and maximum amount of fluid to be drained. + * FluidStack representing the Fluid and maximum amount of fluid to be drained. * @param doDrain - * If false, drain will only be simulated. + * If false, drain will only be simulated. * @return FluidStack representing the Fluid and amount that was (or would have been, if * simulated) drained. */ public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain) { - int tankToDrain = 0; - if(from != ForgeDirection.UNKNOWN) { - tankToDrain = getExposedTankFromSide(from.ordinal()); - } - - if(tankToDrain == FLUIDTANK_NONE) { - return null; - } - else { - // Can't drain that fluid from that side. - if(!resource.isFluidEqual( tanks[tankToDrain].getFluid() )) { - return null; - } - - return drain(tankToDrain, resource.amount, doDrain); - } + int tankToDrain = 0; + if (from != ForgeDirection.UNKNOWN) { + tankToDrain = getExposedTankFromSide(from.ordinal()); + } + + if (tankToDrain == FLUIDTANK_NONE) { + return null; + } else { + // Can't drain that fluid from that side. + if (!resource.isFluidEqual(tanks[tankToDrain].getFluid())) { + return null; + } + + return drain(tankToDrain, resource.amount, doDrain); + } } - + /** * @param direction tank side: UNKNOWN for default tank set * @return Array of {@link FluidTank}s contained in this ITankContainer for this direction */ public IFluidTank[] getTanks(ForgeDirection direction) { - if(direction == ForgeDirection.UNKNOWN) { - return tanks; - } - else { - int exposure = getExposedTankFromSide(direction.ordinal()); - if(exposure == FLUIDTANK_NONE) { - return kEmptyFluidTankList; - } - - return tankExposureCache[exposure]; - } + if (direction == ForgeDirection.UNKNOWN) { + return tanks; + } else { + int exposure = getExposedTankFromSide(direction.ordinal()); + if (exposure == FLUIDTANK_NONE) { + return kEmptyFluidTankList; + } + + return tankExposureCache[exposure]; + } } /** - * Return the tank that this tank container desired to be used for the specified fluid type from the specified direction + * Return the tank that this tank container desired to be used for the specified fluid type from the specified + * direction * * @param direction the direction - * @param type the fluid type, null is always an acceptable value + * @param type the fluid type, null is always an acceptable value * @return a tank or null for no such tank */ public IFluidTank getTank(ForgeDirection direction, FluidStack type) { - if(direction == ForgeDirection.UNKNOWN) { - return null; - } - else { - int tankIdx = getExposedTankFromSide(direction.ordinal()); - if(tankIdx == FLUIDTANK_NONE) { - return null; - } - - IFluidTank t = tanks[tankIdx]; - if(type == null || isFluidValidForTank(tankIdx, type)) { - return t; - } - - return null; - } + if (direction == ForgeDirection.UNKNOWN) { + return null; + } else { + int tankIdx = getExposedTankFromSide(direction.ordinal()); + if (tankIdx == FLUIDTANK_NONE) { + return null; + } + + IFluidTank t = tanks[tankIdx]; + if (type == null || isFluidValidForTank(tankIdx, type)) { + return t; + } + + return null; + } } /** @@ -268,20 +275,22 @@ public IFluidTank getTank(ForgeDirection direction, FluidStack type) { * More formally, this should return true if fluid is able to enter from the given direction. */ public boolean canFill(ForgeDirection from, Fluid fluid) { - int tankIdx = 0; - if(from != ForgeDirection.UNKNOWN) { - tankIdx = getExposedTankFromSide(from.ordinal()); - } - - if(tankIdx == FLUIDTANK_NONE) { return false; } - - IFluidTank tank = tanks[tankIdx]; - if(tank.getFluidAmount() <= 0) { - return true; - } - else { - return tank.getFluid().fluidID == fluid.getID(); - } + int tankIdx = 0; + if (from != ForgeDirection.UNKNOWN) { + tankIdx = getExposedTankFromSide(from.ordinal()); + } + + if (tankIdx == FLUIDTANK_NONE) { + return false; + } + + IFluidTank tank = tanks[tankIdx]; + if (tank.getFluidAmount() <= 0) { + return true; + } else { + return tank.getFluid() + .getFluidID() == fluid.getID(); + } } /** @@ -290,20 +299,22 @@ public boolean canFill(ForgeDirection from, Fluid fluid) { * More formally, this should return true if fluid is able to leave from the given direction. */ public boolean canDrain(ForgeDirection from, Fluid fluid) { - int tankIdx = 0; - if(from != ForgeDirection.UNKNOWN) { - tankIdx = getExposedTankFromSide(from.ordinal()); - } - - if(tankIdx == FLUIDTANK_NONE) { return false; } - - IFluidTank tank = tanks[tankIdx]; - if(tank.getFluidAmount() <= 0) { - return false; - } - else { - return tank.getFluid().fluidID == fluid.getID(); - } + int tankIdx = 0; + if (from != ForgeDirection.UNKNOWN) { + tankIdx = getExposedTankFromSide(from.ordinal()); + } + + if (tankIdx == FLUIDTANK_NONE) { + return false; + } + + IFluidTank tank = tanks[tankIdx]; + if (tank.getFluidAmount() <= 0) { + return false; + } else { + return tank.getFluid() + .getFluidID() == fluid.getID(); + } } /** @@ -311,11 +322,11 @@ public boolean canDrain(ForgeDirection from, Fluid fluid) { * to manipulate the internal tanks. See {@link FluidTankInfo}. * * @param from - * Orientation determining which tanks should be queried. + * Orientation determining which tanks should be queried. * @return Info for the relevant internal tanks. */ public FluidTankInfo[] getTankInfo(ForgeDirection from) { - return getTankInfo(); + return getTankInfo(); } /** @@ -325,28 +336,28 @@ public FluidTankInfo[] getTankInfo(ForgeDirection from) { * @return Info for the relevant internal tanks. */ public FluidTankInfo[] getTankInfo() { - FluidTankInfo[] infos = new FluidTankInfo[tanks.length]; - for(int i = 0; i < tanks.length; i++) { - infos[i] = tanks[i].getInfo(); - } - - return infos; + FluidTankInfo[] infos = new FluidTankInfo[tanks.length]; + for (int i = 0; i < tanks.length; i++) { + infos[i] = tanks[i].getInfo(); + } + + return infos; } - + /** * Check if the given fluid is valid for the given tank. * Note that the fluid may be null. * * @param tankIdx The index of the tank to check validity for. - * @param type The fluid to check validity for, or null. + * @param type The fluid to check validity for, or null. * @return True if the fluid can go in the identified tank, false otherwise. */ - protected abstract boolean isFluidValidForTank(int tankIdx, FluidStack type); - - // Helpers - /** - * @param fluid The fluid whose default tank is being queried. - * @return The index of the tank into which a given fluid should be deposited by default. - */ - protected abstract int getDefaultTankForFluid(Fluid fluid); + protected abstract boolean isFluidValidForTank(int tankIdx, FluidStack type); + + // Helpers + /** + * @param fluid The fluid whose default tank is being queried. + * @return The index of the tank into which a given fluid should be deposited by default. + */ + protected abstract int getDefaultTankForFluid(Fluid fluid); } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/BeefGuiControlBase.java b/src/main/java/erogenousbeef/bigreactors/gui/BeefGuiControlBase.java index 8d98ce3f..ed9b1512 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/BeefGuiControlBase.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/BeefGuiControlBase.java @@ -9,99 +9,126 @@ public abstract class BeefGuiControlBase implements IBeefGuiControl { - protected BeefGuiBase guiContainer; - protected int absoluteX, absoluteY; // Screen-relative X/Y (for backgrounds) - protected int relativeX, relativeY; // GUI-relative X/Y (for foregrounds) - protected int width, height; - - public boolean visible; - - // We use absolute coords to match other Minecraft controls. - protected BeefGuiControlBase(BeefGuiBase container, int absoluteX, int absoluteY, int width, int height) { - this.guiContainer = container; - this.absoluteX = absoluteX; - this.absoluteY = absoluteY; - this.relativeX = absoluteX - container.getGuiLeft(); - this.relativeY = absoluteY - container.getGuiTop(); - this.height = height; - this.width = width; - visible = true; - } - - /** - * Check if the mouse is over this control. - * @param mouseX Screen-relative mouse X coordinate. - * @param mouseY Screen-relative mouse Y coordinate. - * @return True if the mouse is over this control, false otherwise. - */ - public boolean isMouseOver(int mouseX, int mouseY) { - if(mouseX < absoluteX || mouseX > absoluteX+width || mouseY < absoluteY || mouseY > absoluteY+height) { return false; } - return true; - } - - public int getWidth() { return width; } - public int getHeight() { return height; } - - - /** - * Handle mouse clicks. Called for all clicks, not just ones inside the control. - * @param mouseX Screen-relative mouse X coordinate. - * @param mouseY Screen-relative mouse Y coordinate. - * @param mouseButton Button being pressed. 0 = left, 1 = right, 2 = middle. - */ - public void onMouseClicked(int mouseX, int mouseY, int mouseButton) {} - - // Static Helpers - protected static void drawRect(int xMin, int yMin, int xMax, int yMax, int color) - { - float a = (float)(color >> 24 & 255) / 255.0F; - float r = (float)(color >> 16 & 255) / 255.0F; - float g = (float)(color >> 8 & 255) / 255.0F; - float b = (float)(color & 255) / 255.0F; - drawRect(xMin, yMin, xMax, yMax, r, g, b, a); - } - - protected static void drawRect(int xMin, int yMin, int xMax, int yMax, float r, float g, float b, float a) - { - int temp; - - if (xMax < xMin) { - temp = xMin; - xMin = xMax; - xMax = temp; - } - - if (yMax < yMin) { - temp = yMin; - yMin = yMax; - yMax = temp; - } - - Tessellator tessellator = Tessellator.instance; - GL11.glEnable(GL11.GL_BLEND); - GL11.glDisable(GL11.GL_TEXTURE_2D); - GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - GL11.glColor4f(r, g, b, a); - tessellator.startDrawingQuads(); - tessellator.addVertex(xMin, yMax, 0.0D); - tessellator.addVertex(xMax, yMax, 0.0D); - tessellator.addVertex(xMax, yMin, 0.0D); - tessellator.addVertex(xMin, yMin, 0.0D); - tessellator.draw(); - GL11.glEnable(GL11.GL_TEXTURE_2D); - GL11.glDisable(GL11.GL_BLEND); - } - - protected static void drawTexturedModelRectFromIcon(int x, int y, IIcon icon, int width, int height) - { + protected BeefGuiBase guiContainer; + protected int absoluteX, absoluteY; // Screen-relative X/Y (for backgrounds) + protected int relativeX, relativeY; // GUI-relative X/Y (for foregrounds) + protected int width, height; + + public boolean visible; + + // We use absolute coords to match other Minecraft controls. + protected BeefGuiControlBase(BeefGuiBase container, int absoluteX, int absoluteY, int width, int height) { + this.guiContainer = container; + this.absoluteX = absoluteX; + this.absoluteY = absoluteY; + this.relativeX = absoluteX - container.getGuiLeft(); + this.relativeY = absoluteY - container.getGuiTop(); + this.height = height; + this.width = width; + visible = true; + } + + /** + * Check if the mouse is over this control. + * + * @param mouseX Screen-relative mouse X coordinate. + * @param mouseY Screen-relative mouse Y coordinate. + * @return True if the mouse is over this control, false otherwise. + */ + public boolean isMouseOver(int mouseX, int mouseY) { + if (mouseX < absoluteX || mouseX > absoluteX + width || mouseY < absoluteY || mouseY > absoluteY + height) { + return false; + } + return true; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + /** + * Handle mouse clicks. Called for all clicks, not just ones inside the control. + * + * @param mouseX Screen-relative mouse X coordinate. + * @param mouseY Screen-relative mouse Y coordinate. + * @param mouseButton Button being pressed. 0 = left, 1 = right, 2 = middle. + */ + public void onMouseClicked(int mouseX, int mouseY, int mouseButton) {} + + // Static Helpers + protected static void drawRect(int xMin, int yMin, int xMax, int yMax, int color) { + float a = (float) (color >> 24 & 255) / 255.0F; + float r = (float) (color >> 16 & 255) / 255.0F; + float g = (float) (color >> 8 & 255) / 255.0F; + float b = (float) (color & 255) / 255.0F; + drawRect(xMin, yMin, xMax, yMax, r, g, b, a); + } + + protected static void drawRect(int xMin, int yMin, int xMax, int yMax, float r, float g, float b, float a) { + int temp; + + if (xMax < xMin) { + temp = xMin; + xMin = xMax; + xMax = temp; + } + + if (yMax < yMin) { + temp = yMin; + yMin = yMax; + yMax = temp; + } + Tessellator tessellator = Tessellator.instance; + GL11.glEnable(GL11.GL_BLEND); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL11.glColor4f(r, g, b, a); tessellator.startDrawingQuads(); - tessellator.addVertexWithUV((double)(x + 0), (double)(y + height), 0.0D, (double)icon.getMinU(), (double)icon.getMaxV()); - tessellator.addVertexWithUV((double)(x + width), (double)(y + height), 0.0D, (double)icon.getMaxU(), (double)icon.getMaxV()); - tessellator.addVertexWithUV((double)(x + width), (double)(y + 0), 0.0D, (double)icon.getMaxU(), (double)icon.getMinV()); - tessellator.addVertexWithUV((double)(x + 0), (double)(y + 0), 0.0D, (double)icon.getMinU(), (double)icon.getMinV()); + tessellator.addVertex(xMin, yMax, 0.0D); + tessellator.addVertex(xMax, yMax, 0.0D); + tessellator.addVertex(xMax, yMin, 0.0D); + tessellator.addVertex(xMin, yMin, 0.0D); tessellator.draw(); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_BLEND); + } + + protected static void drawTexturedModelRectFromIcon(int x, int y, IIcon icon, int width, int height) { + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + tessellator.addVertexWithUV( + (double) (x + 0), + (double) (y + height), + 0.0D, + (double) icon.getMinU(), + (double) icon.getMaxV()); + tessellator.addVertexWithUV( + (double) (x + width), + (double) (y + height), + 0.0D, + (double) icon.getMaxU(), + (double) icon.getMaxV()); + tessellator.addVertexWithUV( + (double) (x + width), + (double) (y + 0), + 0.0D, + (double) icon.getMaxU(), + (double) icon.getMinV()); + tessellator.addVertexWithUV( + (double) (x + 0), + (double) (y + 0), + 0.0D, + (double) icon.getMinU(), + (double) icon.getMinV()); + tessellator.draw(); + } + + public boolean isVisible() { + return visible; } - - public boolean isVisible() { return visible; } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/BeefGuiIconManager.java b/src/main/java/erogenousbeef/bigreactors/gui/BeefGuiIconManager.java index 569a722f..be1faa88 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/BeefGuiIconManager.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/BeefGuiIconManager.java @@ -4,87 +4,56 @@ public class BeefGuiIconManager extends BeefIconManager { - public static final int COOLANT_IN = 0; - public static final int COOLANT_OUT = 1; - public static final int COOLANT_TEMPERATURE = 2; - public static final int ENERGY_OUTPUT = 3; - public static final int FUEL_USAGE_RATE = 4; - public static final int HOT_FLUID_IN = 5; - public static final int HOT_FLUID_OUT = 6; - public static final int OFF_OFF = 7; - public static final int OFF_ON = 8; - public static final int ON_OFF = 9; - public static final int ON_ON = 10; - public static final int TEMPERATURE = 11; - public static final int WASTE_EJECT_OFF = 12; - public static final int WASTE_EJECT_ON = 13; - public static final int WASTE_MANUAL_OFF = 14; - public static final int WASTE_MANUAL_ON = 15; - public static final int WASTE_EJECT = 16; - public static final int REACTIVITY = 17; - public static final int ENERGY_STORED = 18; - public static final int RPM = 19; - public static final int UP_ARROW = 20; - public static final int DOWN_ARROW = 21; - public static final int FUEL_EJECT = 22; - public static final int INLET_ON = 23; - public static final int INLET_OFF = 24; - public static final int OUTLET_ON = 25; - public static final int OUTLET_OFF = 26; - public static final int VENT_ALL_OFF = 27; - public static final int VENT_ALL_ON = 28; - public static final int VENT_OVERFLOW_OFF = 29; - public static final int VENT_OVERFLOW_ON = 30; - public static final int VENT_NONE_OFF = 31; - public static final int VENT_NONE_ON = 32; - public static final int ROTOR_EFFICIENCY = 33; - public static final int FLOW_RATE = 34; - public static final int COIL = 35; + public static final int COOLANT_IN = 0; + public static final int COOLANT_OUT = 1; + public static final int COOLANT_TEMPERATURE = 2; + public static final int ENERGY_OUTPUT = 3; + public static final int FUEL_USAGE_RATE = 4; + public static final int HOT_FLUID_IN = 5; + public static final int HOT_FLUID_OUT = 6; + public static final int OFF_OFF = 7; + public static final int OFF_ON = 8; + public static final int ON_OFF = 9; + public static final int ON_ON = 10; + public static final int TEMPERATURE = 11; + public static final int WASTE_EJECT_OFF = 12; + public static final int WASTE_EJECT_ON = 13; + public static final int WASTE_MANUAL_OFF = 14; + public static final int WASTE_MANUAL_ON = 15; + public static final int WASTE_EJECT = 16; + public static final int REACTIVITY = 17; + public static final int ENERGY_STORED = 18; + public static final int RPM = 19; + public static final int UP_ARROW = 20; + public static final int DOWN_ARROW = 21; + public static final int FUEL_EJECT = 22; + public static final int INLET_ON = 23; + public static final int INLET_OFF = 24; + public static final int OUTLET_ON = 25; + public static final int OUTLET_OFF = 26; + public static final int VENT_ALL_OFF = 27; + public static final int VENT_ALL_ON = 28; + public static final int VENT_OVERFLOW_OFF = 29; + public static final int VENT_OVERFLOW_ON = 30; + public static final int VENT_NONE_OFF = 31; + public static final int VENT_NONE_ON = 32; + public static final int ROTOR_EFFICIENCY = 33; + public static final int FLOW_RATE = 34; + public static final int COIL = 35; + + @Override + protected String[] getIconNames() { + return new String[] { "coolantIn", "coolantOut", "coolantTemperature", "energyOutput", "fuelUsageRate", + "hotFluidIn", "hotFluidOut", "Off_off", "Off_on", "On_off", "On_on", "temperature", "wasteEject_off", + "wasteEject_on", "wasteManual_off", "wasteManual_on", "wasteEject", "reactivity", "energyStored", "rpm", + "upArrow", "downArrow", "fuelEject", "inletOn", "inletOff", "outletOn", "outletOff", "ventAllOff", + "ventAllOn", "ventOverflowOff", "ventOverflowOn", "ventNoneOff", "ventNoneOn", "rotorEfficiency", + "flowRate", "coil", "controlRod" }; + } + + @Override + protected String getPath() { + return "guiIcons/"; + } - @Override - protected String[] getIconNames() { - return new String[] { - "coolantIn", - "coolantOut", - "coolantTemperature", - "energyOutput", - "fuelUsageRate", - "hotFluidIn", - "hotFluidOut", - "Off_off", - "Off_on", - "On_off", - "On_on", - "temperature", - "wasteEject_off", - "wasteEject_on", - "wasteManual_off", - "wasteManual_on", - "wasteEject", - "reactivity", - "energyStored", - "rpm", - "upArrow", - "downArrow", - "fuelEject", - "inletOn", - "inletOff", - "outletOn", - "outletOff", - "ventAllOff", - "ventAllOn", - "ventOverflowOff", - "ventOverflowOn", - "ventNoneOff", - "ventNoneOn", - "rotorEfficiency", - "flowRate", - "coil", - "controlRod" - }; - } - - @Override - protected String getPath() { return "guiIcons/"; } - } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/BigReactorsGUIHandler.java b/src/main/java/erogenousbeef/bigreactors/gui/BigReactorsGUIHandler.java index faec4c10..452b67e5 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/BigReactorsGUIHandler.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/BigReactorsGUIHandler.java @@ -3,46 +3,42 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; + import cpw.mods.fml.common.network.IGuiHandler; import erogenousbeef.bigreactors.common.multiblock.interfaces.IMultiblockGuiHandler; public class BigReactorsGUIHandler implements IGuiHandler { - @Override - public Object getServerGuiElement(int ID, EntityPlayer player, World world, - int x, int y, int z) { - - TileEntity te = world.getTileEntity(x, y, z); - if(te == null) { - return null; - } - else if(te instanceof IMultiblockGuiHandler) { - return ((IMultiblockGuiHandler)te).getContainer(player.inventory); - } - else if(te instanceof IBeefGuiEntity) { - return ((IBeefGuiEntity)te).getContainer(player); - } - - return null; - } - - @Override - public Object getClientGuiElement(int ID, EntityPlayer player, World world, - int x, int y, int z) { - TileEntity te = world.getTileEntity(x, y, z); - if(te == null) { - return null; - } - - if(te instanceof IMultiblockGuiHandler) { - IMultiblockGuiHandler part = (IMultiblockGuiHandler)te; - return part.getGuiElement(player.inventory); - } - else if(te instanceof IBeefGuiEntity) { - return ((IBeefGuiEntity)te).getGUI(player); - } - - return null; - } + @Override + public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { + + TileEntity te = world.getTileEntity(x, y, z); + if (te == null) { + return null; + } else if (te instanceof IMultiblockGuiHandler) { + return ((IMultiblockGuiHandler) te).getContainer(player.inventory); + } else if (te instanceof IBeefGuiEntity) { + return ((IBeefGuiEntity) te).getContainer(player); + } + + return null; + } + + @Override + public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { + TileEntity te = world.getTileEntity(x, y, z); + if (te == null) { + return null; + } + + if (te instanceof IMultiblockGuiHandler) { + IMultiblockGuiHandler part = (IMultiblockGuiHandler) te; + return part.getGuiElement(player.inventory); + } else if (te instanceof IBeefGuiEntity) { + return ((IBeefGuiEntity) te).getGUI(player); + } + + return null; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/IBeefGuiControl.java b/src/main/java/erogenousbeef/bigreactors/gui/IBeefGuiControl.java index 4b9fc827..30a914a9 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/IBeefGuiControl.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/IBeefGuiControl.java @@ -3,25 +3,29 @@ import net.minecraft.client.renderer.texture.TextureManager; public interface IBeefGuiControl { - /** - * Draw control background. Has window-relative coordinates. - * @param mouseX Window-relative X position of the mouse cursor. - * @param mouseY Window-relative Y position of the mouse cursor. - */ - public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY); - - /** - * Draw control foreground. Has window-relative coordinates. - * @param mouseX Window-relative X position of the mouse cursor. - * @param mouseY Window-relative Y position of the mouse cursor. - */ - public void drawForeground(TextureManager renderEngine, int mouseX, int mouseY); - /** - * Handle mouse clicks. Called for all clicks, not just ones inside the control. - * @param mouseX Screen-relative mouse X coordinate. - * @param mouseY Screen-relative mouse Y coordinate. - * @param mouseButton Button being pressed. 0 = left, 1 = right, 2 = middle. - */ - public void onMouseClicked(int mouseX, int mouseY, int mouseButton); + /** + * Draw control background. Has window-relative coordinates. + * + * @param mouseX Window-relative X position of the mouse cursor. + * @param mouseY Window-relative Y position of the mouse cursor. + */ + public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY); + + /** + * Draw control foreground. Has window-relative coordinates. + * + * @param mouseX Window-relative X position of the mouse cursor. + * @param mouseY Window-relative Y position of the mouse cursor. + */ + public void drawForeground(TextureManager renderEngine, int mouseX, int mouseY); + + /** + * Handle mouse clicks. Called for all clicks, not just ones inside the control. + * + * @param mouseX Screen-relative mouse X coordinate. + * @param mouseY Screen-relative mouse Y coordinate. + * @param mouseButton Button being pressed. 0 = left, 1 = right, 2 = middle. + */ + public void onMouseClicked(int mouseX, int mouseY, int mouseButton); } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/IBeefGuiEntity.java b/src/main/java/erogenousbeef/bigreactors/gui/IBeefGuiEntity.java index b85c3469..195f0ceb 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/IBeefGuiEntity.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/IBeefGuiEntity.java @@ -9,29 +9,34 @@ * Handles network UI updates and basic button presses. */ public interface IBeefGuiEntity { - /** - * Retrieve the GUIScreen for this block - * @param player The player opening the screen - * @return A GUIScreen to show - */ - public GuiScreen getGUI(EntityPlayer player); - - /** - * Retrieve the Container object for this block. - * @param player The player opening the GUI/container. - * @return A Container for use by the server/ - */ - public Container getContainer(EntityPlayer player); - - /** - * Call when a player should begin receiving UI updates - * @param player Player who should begin receiving UI updates - */ - public void beginUpdatingPlayer(EntityPlayer player); - - /** - * Call when a player should stop receiving UI updates - * @param player Player who should no longer receive UI updates - */ - public void stopUpdatingPlayer(EntityPlayer player); + + /** + * Retrieve the GUIScreen for this block + * + * @param player The player opening the screen + * @return A GUIScreen to show + */ + public GuiScreen getGUI(EntityPlayer player); + + /** + * Retrieve the Container object for this block. + * + * @param player The player opening the GUI/container. + * @return A Container for use by the server/ + */ + public Container getContainer(EntityPlayer player); + + /** + * Call when a player should begin receiving UI updates + * + * @param player Player who should begin receiving UI updates + */ + public void beginUpdatingPlayer(EntityPlayer player); + + /** + * Call when a player should stop receiving UI updates + * + * @param player Player who should no longer receive UI updates + */ + public void stopUpdatingPlayer(EntityPlayer player); } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/IBeefListBoxEntry.java b/src/main/java/erogenousbeef/bigreactors/gui/IBeefListBoxEntry.java index dcde209a..613f85ba 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/IBeefListBoxEntry.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/IBeefListBoxEntry.java @@ -4,8 +4,8 @@ public interface IBeefListBoxEntry { - public int getHeight(); - - public void draw(FontRenderer fontRenderer, int x, int y, int backgroundColor, int foregroundColor); - + public int getHeight(); + + public void draw(FontRenderer fontRenderer, int x, int y, int backgroundColor, int foregroundColor); + } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/IBeefTooltipControl.java b/src/main/java/erogenousbeef/bigreactors/gui/IBeefTooltipControl.java index 3bcd4b90..71ed8229 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/IBeefTooltipControl.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/IBeefTooltipControl.java @@ -1,9 +1,10 @@ package erogenousbeef.bigreactors.gui; - public interface IBeefTooltipControl { - boolean isMouseOver(int mouseX, int mouseY); - String[] getTooltip(); - - public boolean isVisible(); + + boolean isMouseOver(int mouseX, int mouseY); + + String[] getTooltip(); + + public boolean isVisible(); } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerBasic.java b/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerBasic.java index 789b6e75..69716c63 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerBasic.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerBasic.java @@ -5,13 +5,13 @@ public class ContainerBasic extends Container { - public ContainerBasic() { - super(); - } - - @Override - public boolean canInteractWith(EntityPlayer entityplayer) { - return true; - } + public ContainerBasic() { + super(); + } + + @Override + public boolean canInteractWith(EntityPlayer entityplayer) { + return true; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerCyaniteReprocessor.java b/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerCyaniteReprocessor.java index ef0a7fca..660630bd 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerCyaniteReprocessor.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerCyaniteReprocessor.java @@ -5,202 +5,171 @@ import net.minecraft.inventory.Container; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; + import erogenousbeef.bigreactors.common.tileentity.TileEntityCyaniteReprocessor; import erogenousbeef.bigreactors.gui.slot.SlotReactorInput; import erogenousbeef.bigreactors.gui.slot.SlotRemoveOnly; public class ContainerCyaniteReprocessor extends Container { - protected TileEntityCyaniteReprocessor _entity; - - public ContainerCyaniteReprocessor(TileEntityCyaniteReprocessor entity, EntityPlayer player) { - super(); - _entity = entity; - addSlots(); - addPlayerInventory(player.inventory); - _entity.beginUpdatingPlayer(player); - } - - protected void addSlots() { - // Input Slot - addSlotToContainer(new SlotReactorInput(_entity, 0, 44, 41, false)); - - // Output Slot - addSlotToContainer(new SlotRemoveOnly(_entity, 1, 116, 41)); - } - - protected int getPlayerInventoryVerticalOffset() - { - return 93; - } - - protected void addPlayerInventory(InventoryPlayer inventoryPlayer) - { - for (int i = 0; i < 3; i++) - { - for (int j = 0; j < 9; j++) - { - addSlotToContainer(new Slot(inventoryPlayer, j + i * 9 + 9, 8 + j * 18, getPlayerInventoryVerticalOffset() + i * 18)); - } - } - - for (int i = 0; i < 9; i++) - { - addSlotToContainer(new Slot(inventoryPlayer, i, 8 + i * 18, getPlayerInventoryVerticalOffset() + 58)); - } - } - - @Override - public boolean canInteractWith(EntityPlayer player) - { - return _entity.isUseableByPlayer(player); - } - - @Override - public ItemStack transferStackInSlot(EntityPlayer player, int slot) - { - ItemStack stack = null; - Slot slotObject = (Slot) inventorySlots.get(slot); - int numSlots = _entity.getSizeInventory(); - - if(slotObject != null && slotObject.getHasStack()) - { - ItemStack stackInSlot = slotObject.getStack(); - stack = stackInSlot.copy(); - - if(slot < numSlots) - { - if(!mergeItemStack(stackInSlot, numSlots, inventorySlots.size(), true)) - { - return null; - } - } - else if(!mergeItemStack(stackInSlot, 0, numSlots, false)) - { - return null; - } - - if(stackInSlot.stackSize == 0) - { - slotObject.putStack(null); - } - else - { - slotObject.onSlotChanged(); - } - - if(stackInSlot.stackSize == stack.stackSize) - { - return null; - } - - slotObject.onPickupFromSlot(player, stackInSlot); - } - - return stack; - } - - // Override this so we can check if stuff is valid for the slot - // Stolen directly from powercrystals - @Override - protected boolean mergeItemStack(ItemStack stack, int slotStart, int slotRange, boolean reverse) - { - boolean successful = false; - int slotIndex = slotStart; - int maxStack = Math.min(stack.getMaxStackSize(), _entity.getInventoryStackLimit()); - - if(reverse) - { - slotIndex = slotRange - 1; - } - - Slot slot; - ItemStack existingStack; - - if(stack.isStackable()) - { - while(stack.stackSize > 0 && (!reverse && slotIndex < slotRange || reverse && slotIndex >= slotStart)) - { - slot = (Slot)this.inventorySlots.get(slotIndex); - existingStack = slot.getStack(); - - if(slot.isItemValid(stack) && existingStack != null && existingStack.getItem() == stack.getItem() && (!stack.getHasSubtypes() || stack.getItemDamage() == existingStack.getItemDamage()) && ItemStack.areItemStackTagsEqual(stack, existingStack)) - { - int existingSize = existingStack.stackSize + stack.stackSize; - - if(existingSize <= maxStack) - { - stack.stackSize = 0; - existingStack.stackSize = existingSize; - slot.onSlotChanged(); - successful = true; - } - else if (existingStack.stackSize < maxStack) - { - stack.stackSize -= maxStack - existingStack.stackSize; - existingStack.stackSize = maxStack; - slot.onSlotChanged(); - successful = true; - } - } - - if(reverse) - { - --slotIndex; - } - else - { - ++slotIndex; - } - } - } - - if(stack.stackSize > 0) - { - if(reverse) - { - slotIndex = slotRange - 1; - } - else - { - slotIndex = slotStart; - } - - while(!reverse && slotIndex < slotRange || reverse && slotIndex >= slotStart) - { - slot = (Slot)this.inventorySlots.get(slotIndex); - existingStack = slot.getStack(); - - if(slot.isItemValid(stack) && existingStack == null) - { - slot.putStack(stack.copy()); - slot.onSlotChanged(); - stack.stackSize = 0; - successful = true; - break; - } - - if(reverse) - { - --slotIndex; - } - else - { - ++slotIndex; - } - } - } - - return successful; - } - - // Update subscription - - @Override + protected TileEntityCyaniteReprocessor _entity; + + public ContainerCyaniteReprocessor(TileEntityCyaniteReprocessor entity, EntityPlayer player) { + super(); + _entity = entity; + addSlots(); + addPlayerInventory(player.inventory); + _entity.beginUpdatingPlayer(player); + } + + protected void addSlots() { + // Input Slot + addSlotToContainer(new SlotReactorInput(_entity, 0, 44, 41, false)); + + // Output Slot + addSlotToContainer(new SlotRemoveOnly(_entity, 1, 116, 41)); + } + + protected int getPlayerInventoryVerticalOffset() { + return 93; + } + + protected void addPlayerInventory(InventoryPlayer inventoryPlayer) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 9; j++) { + addSlotToContainer( + new Slot(inventoryPlayer, j + i * 9 + 9, 8 + j * 18, getPlayerInventoryVerticalOffset() + i * 18)); + } + } + + for (int i = 0; i < 9; i++) { + addSlotToContainer(new Slot(inventoryPlayer, i, 8 + i * 18, getPlayerInventoryVerticalOffset() + 58)); + } + } + + @Override + public boolean canInteractWith(EntityPlayer player) { + return _entity.isUseableByPlayer(player); + } + + @Override + public ItemStack transferStackInSlot(EntityPlayer player, int slot) { + ItemStack stack = null; + Slot slotObject = (Slot) inventorySlots.get(slot); + int numSlots = _entity.getSizeInventory(); + + if (slotObject != null && slotObject.getHasStack()) { + ItemStack stackInSlot = slotObject.getStack(); + stack = stackInSlot.copy(); + + if (slot < numSlots) { + if (!mergeItemStack(stackInSlot, numSlots, inventorySlots.size(), true)) { + return null; + } + } else if (!mergeItemStack(stackInSlot, 0, numSlots, false)) { + return null; + } + + if (stackInSlot.stackSize == 0) { + slotObject.putStack(null); + } else { + slotObject.onSlotChanged(); + } + + if (stackInSlot.stackSize == stack.stackSize) { + return null; + } + + slotObject.onPickupFromSlot(player, stackInSlot); + } + + return stack; + } + + // Override this so we can check if stuff is valid for the slot + // Stolen directly from powercrystals + @Override + protected boolean mergeItemStack(ItemStack stack, int slotStart, int slotRange, boolean reverse) { + boolean successful = false; + int slotIndex = slotStart; + int maxStack = Math.min(stack.getMaxStackSize(), _entity.getInventoryStackLimit()); + + if (reverse) { + slotIndex = slotRange - 1; + } + + Slot slot; + ItemStack existingStack; + + if (stack.isStackable()) { + while (stack.stackSize > 0 && (!reverse && slotIndex < slotRange || reverse && slotIndex >= slotStart)) { + slot = (Slot) this.inventorySlots.get(slotIndex); + existingStack = slot.getStack(); + + if (slot.isItemValid(stack) && existingStack != null + && existingStack.getItem() == stack.getItem() + && (!stack.getHasSubtypes() || stack.getItemDamage() == existingStack.getItemDamage()) + && ItemStack.areItemStackTagsEqual(stack, existingStack)) { + int existingSize = existingStack.stackSize + stack.stackSize; + + if (existingSize <= maxStack) { + stack.stackSize = 0; + existingStack.stackSize = existingSize; + slot.onSlotChanged(); + successful = true; + } else if (existingStack.stackSize < maxStack) { + stack.stackSize -= maxStack - existingStack.stackSize; + existingStack.stackSize = maxStack; + slot.onSlotChanged(); + successful = true; + } + } + + if (reverse) { + --slotIndex; + } else { + ++slotIndex; + } + } + } + + if (stack.stackSize > 0) { + if (reverse) { + slotIndex = slotRange - 1; + } else { + slotIndex = slotStart; + } + + while (!reverse && slotIndex < slotRange || reverse && slotIndex >= slotStart) { + slot = (Slot) this.inventorySlots.get(slotIndex); + existingStack = slot.getStack(); + + if (slot.isItemValid(stack) && existingStack == null) { + slot.putStack(stack.copy()); + slot.onSlotChanged(); + stack.stackSize = 0; + successful = true; + break; + } + + if (reverse) { + --slotIndex; + } else { + ++slotIndex; + } + } + } + + return successful; + } + + // Update subscription + + @Override public void onContainerClosed(EntityPlayer player) { - super.onContainerClosed(player); - - _entity.stopUpdatingPlayer(player); - } - + super.onContainerClosed(player); + + _entity.stopUpdatingPlayer(player); + } + } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerReactorAccessPort.java b/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerReactorAccessPort.java index a53f2c23..8a427fdb 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerReactorAccessPort.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerReactorAccessPort.java @@ -5,191 +5,160 @@ import net.minecraft.inventory.Container; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; + import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorAccessPort; import erogenousbeef.bigreactors.gui.slot.SlotReactorInput; import erogenousbeef.bigreactors.gui.slot.SlotRemoveOnly; public class ContainerReactorAccessPort extends Container { - protected TileEntityReactorAccessPort _port; - - public ContainerReactorAccessPort(TileEntityReactorAccessPort port, InventoryPlayer inv) { - super(); - _port = port; - addSlots(); - addPlayerInventory(inv); - } - - protected void addSlots() { - // Input Slot - addSlotToContainer(new SlotReactorInput(_port, 0, 44, 18, true)); - - // Output Slot - addSlotToContainer(new SlotRemoveOnly(_port, 1, 116, 18)); - } - - protected int getPlayerInventoryVerticalOffset() - { - return 74; - } - - protected void addPlayerInventory(InventoryPlayer inventoryPlayer) - { - for (int i = 0; i < 3; i++) - { - for (int j = 0; j < 9; j++) - { - addSlotToContainer(new Slot(inventoryPlayer, j + i * 9 + 9, 8 + j * 18, getPlayerInventoryVerticalOffset() + i * 18)); - } - } - - for (int i = 0; i < 9; i++) - { - addSlotToContainer(new Slot(inventoryPlayer, i, 8 + i * 18, getPlayerInventoryVerticalOffset() + 58)); - } - } - - @Override - public boolean canInteractWith(EntityPlayer player) - { - return _port.isUseableByPlayer(player); - } - - @Override - public ItemStack transferStackInSlot(EntityPlayer player, int slot) - { - ItemStack stack = null; - Slot slotObject = (Slot) inventorySlots.get(slot); - int numSlots = _port.getSizeInventory(); - - if(slotObject != null && slotObject.getHasStack()) - { - ItemStack stackInSlot = slotObject.getStack(); - stack = stackInSlot.copy(); - - if(slot < numSlots) - { - if(!mergeItemStack(stackInSlot, numSlots, inventorySlots.size(), true)) - { - return null; - } - } - else if(!mergeItemStack(stackInSlot, 0, numSlots, false)) - { - return null; - } - - if(stackInSlot.stackSize == 0) - { - slotObject.putStack(null); - } - else - { - slotObject.onSlotChanged(); - } - - if(stackInSlot.stackSize == stack.stackSize) - { - return null; - } - - slotObject.onPickupFromSlot(player, stackInSlot); - } - - return stack; - } - - // Override this so we can check if stuff is valid for the slot - // Stolen directly from powercrystals - @Override - protected boolean mergeItemStack(ItemStack stack, int slotStart, int slotRange, boolean reverse) - { - boolean successful = false; - int slotIndex = slotStart; - int maxStack = Math.min(stack.getMaxStackSize(), _port.getInventoryStackLimit()); - - if(reverse) - { - slotIndex = slotRange - 1; - } - - Slot slot; - ItemStack existingStack; - - if(stack.isStackable()) - { - while(stack.stackSize > 0 && (!reverse && slotIndex < slotRange || reverse && slotIndex >= slotStart)) - { - slot = (Slot)this.inventorySlots.get(slotIndex); - existingStack = slot.getStack(); - - if(slot.isItemValid(stack) && existingStack != null && existingStack.getItem() == stack.getItem() && (!stack.getHasSubtypes() || stack.getItemDamage() == existingStack.getItemDamage()) && ItemStack.areItemStackTagsEqual(stack, existingStack)) - { - int existingSize = existingStack.stackSize + stack.stackSize; - - if(existingSize <= maxStack) - { - stack.stackSize = 0; - existingStack.stackSize = existingSize; - slot.onSlotChanged(); - successful = true; - } - else if (existingStack.stackSize < maxStack) - { - stack.stackSize -= maxStack - existingStack.stackSize; - existingStack.stackSize = maxStack; - slot.onSlotChanged(); - successful = true; - } - } - - if(reverse) - { - --slotIndex; - } - else - { - ++slotIndex; - } - } - } - - if(stack.stackSize > 0) - { - if(reverse) - { - slotIndex = slotRange - 1; - } - else - { - slotIndex = slotStart; - } - - while(!reverse && slotIndex < slotRange || reverse && slotIndex >= slotStart) - { - slot = (Slot)this.inventorySlots.get(slotIndex); - existingStack = slot.getStack(); - - if(slot.isItemValid(stack) && existingStack == null) - { - slot.putStack(stack.copy()); - slot.onSlotChanged(); - stack.stackSize = 0; - successful = true; - break; - } - - if(reverse) - { - --slotIndex; - } - else - { - ++slotIndex; - } - } - } - - return successful; - } + protected TileEntityReactorAccessPort _port; + + public ContainerReactorAccessPort(TileEntityReactorAccessPort port, InventoryPlayer inv) { + super(); + _port = port; + addSlots(); + addPlayerInventory(inv); + } + + protected void addSlots() { + // Input Slot + addSlotToContainer(new SlotReactorInput(_port, 0, 44, 18, true)); + + // Output Slot + addSlotToContainer(new SlotRemoveOnly(_port, 1, 116, 18)); + } + + protected int getPlayerInventoryVerticalOffset() { + return 74; + } + + protected void addPlayerInventory(InventoryPlayer inventoryPlayer) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 9; j++) { + addSlotToContainer( + new Slot(inventoryPlayer, j + i * 9 + 9, 8 + j * 18, getPlayerInventoryVerticalOffset() + i * 18)); + } + } + + for (int i = 0; i < 9; i++) { + addSlotToContainer(new Slot(inventoryPlayer, i, 8 + i * 18, getPlayerInventoryVerticalOffset() + 58)); + } + } + + @Override + public boolean canInteractWith(EntityPlayer player) { + return _port.isUseableByPlayer(player); + } + + @Override + public ItemStack transferStackInSlot(EntityPlayer player, int slot) { + ItemStack stack = null; + Slot slotObject = (Slot) inventorySlots.get(slot); + int numSlots = _port.getSizeInventory(); + + if (slotObject != null && slotObject.getHasStack()) { + ItemStack stackInSlot = slotObject.getStack(); + stack = stackInSlot.copy(); + + if (slot < numSlots) { + if (!mergeItemStack(stackInSlot, numSlots, inventorySlots.size(), true)) { + return null; + } + } else if (!mergeItemStack(stackInSlot, 0, numSlots, false)) { + return null; + } + + if (stackInSlot.stackSize == 0) { + slotObject.putStack(null); + } else { + slotObject.onSlotChanged(); + } + + if (stackInSlot.stackSize == stack.stackSize) { + return null; + } + + slotObject.onPickupFromSlot(player, stackInSlot); + } + + return stack; + } + + // Override this so we can check if stuff is valid for the slot + // Stolen directly from powercrystals + @Override + protected boolean mergeItemStack(ItemStack stack, int slotStart, int slotRange, boolean reverse) { + boolean successful = false; + int slotIndex = slotStart; + int maxStack = Math.min(stack.getMaxStackSize(), _port.getInventoryStackLimit()); + + if (reverse) { + slotIndex = slotRange - 1; + } + + Slot slot; + ItemStack existingStack; + + if (stack.isStackable()) { + while (stack.stackSize > 0 && (!reverse && slotIndex < slotRange || reverse && slotIndex >= slotStart)) { + slot = (Slot) this.inventorySlots.get(slotIndex); + existingStack = slot.getStack(); + + if (slot.isItemValid(stack) && existingStack != null + && existingStack.getItem() == stack.getItem() + && (!stack.getHasSubtypes() || stack.getItemDamage() == existingStack.getItemDamage()) + && ItemStack.areItemStackTagsEqual(stack, existingStack)) { + int existingSize = existingStack.stackSize + stack.stackSize; + + if (existingSize <= maxStack) { + stack.stackSize = 0; + existingStack.stackSize = existingSize; + slot.onSlotChanged(); + successful = true; + } else if (existingStack.stackSize < maxStack) { + stack.stackSize -= maxStack - existingStack.stackSize; + existingStack.stackSize = maxStack; + slot.onSlotChanged(); + successful = true; + } + } + + if (reverse) { + --slotIndex; + } else { + ++slotIndex; + } + } + } + + if (stack.stackSize > 0) { + if (reverse) { + slotIndex = slotRange - 1; + } else { + slotIndex = slotStart; + } + + while (!reverse && slotIndex < slotRange || reverse && slotIndex >= slotStart) { + slot = (Slot) this.inventorySlots.get(slotIndex); + existingStack = slot.getStack(); + + if (slot.isItemValid(stack) && existingStack == null) { + slot.putStack(stack.copy()); + slot.onSlotChanged(); + stack.stackSize = 0; + successful = true; + break; + } + + if (reverse) { + --slotIndex; + } else { + ++slotIndex; + } + } + } + + return successful; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerReactorController.java b/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerReactorController.java index f695d2b6..9b7647d4 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerReactorController.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerReactorController.java @@ -3,33 +3,35 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.Container; import net.minecraft.item.ItemStack; + import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorPart; public class ContainerReactorController extends Container { - TileEntityReactorPart part; - - public ContainerReactorController(TileEntityReactorPart reactorPart, EntityPlayer player) { - part = reactorPart; - - part.getReactorController().beginUpdatingPlayer(player); - } - - @Override - public boolean canInteractWith(EntityPlayer entityplayer) { - return true; - } - - @Override - public void putStackInSlot(int slot, ItemStack stack) { - return; - } - - @Override + TileEntityReactorPart part; + + public ContainerReactorController(TileEntityReactorPart reactorPart, EntityPlayer player) { + part = reactorPart; + + part.getReactorController() + .beginUpdatingPlayer(player); + } + + @Override + public boolean canInteractWith(EntityPlayer entityplayer) { + return true; + } + + @Override + public void putStackInSlot(int slot, ItemStack stack) { + return; + } + + @Override public void onContainerClosed(EntityPlayer player) { - super.onContainerClosed(player); - - if(part != null && part.getReactorController() != null) - part.getReactorController().stopUpdatingPlayer(player); - } + super.onContainerClosed(player); + + if (part != null && part.getReactorController() != null) part.getReactorController() + .stopUpdatingPlayer(player); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerSlotless.java b/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerSlotless.java index 94373c39..e5bcd8bd 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerSlotless.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/container/ContainerSlotless.java @@ -5,27 +5,29 @@ /** * Generic container for entities which need to know about players for updates, but do not bind slots. + * * @author Erogenous Beef */ public class ContainerSlotless extends Container { - protected ISlotlessUpdater entity; - - public ContainerSlotless(ISlotlessUpdater theEntity, EntityPlayer player) { - super(); - - entity = theEntity; - entity.beginUpdatingPlayer(player); - } - - @Override - public boolean canInteractWith(EntityPlayer entityplayer) { - return entity.isUseableByPlayer(entityplayer); - } - - @Override + + protected ISlotlessUpdater entity; + + public ContainerSlotless(ISlotlessUpdater theEntity, EntityPlayer player) { + super(); + + entity = theEntity; + entity.beginUpdatingPlayer(player); + } + + @Override + public boolean canInteractWith(EntityPlayer entityplayer) { + return entity.isUseableByPlayer(entityplayer); + } + + @Override public void onContainerClosed(EntityPlayer player) { - super.onContainerClosed(player); - - entity.stopUpdatingPlayer(player); - } + super.onContainerClosed(player); + + entity.stopUpdatingPlayer(player); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/container/ISlotlessUpdater.java b/src/main/java/erogenousbeef/bigreactors/gui/container/ISlotlessUpdater.java index 919161f1..1f7dc21e 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/container/ISlotlessUpdater.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/container/ISlotlessUpdater.java @@ -4,21 +4,23 @@ public interface ISlotlessUpdater { - /** - * Called when your updater should begin updating a player. - * @param player The player to begin updating. - */ - void beginUpdatingPlayer(EntityPlayer player); - - /** - * Called when your updater should cease updating a player. - * @param player The player to cease updating. - */ - void stopUpdatingPlayer(EntityPlayer player); - - /** - * @param player The player to check. - * @return True if the player is able to interact with this object, false otherwise. - */ - boolean isUseableByPlayer(EntityPlayer player); + /** + * Called when your updater should begin updating a player. + * + * @param player The player to begin updating. + */ + void beginUpdatingPlayer(EntityPlayer player); + + /** + * Called when your updater should cease updating a player. + * + * @param player The player to cease updating. + */ + void stopUpdatingPlayer(EntityPlayer player); + + /** + * @param player The player to check. + * @return True if the player is able to interact with this object, false otherwise. + */ + boolean isUseableByPlayer(EntityPlayer player); } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiFluidBar.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiFluidBar.java index 96e2dbdf..e9f398ab 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiFluidBar.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiFluidBar.java @@ -5,77 +5,83 @@ import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTankInfo; + import erogenousbeef.bigreactors.client.gui.BeefGuiBase; import erogenousbeef.bigreactors.common.interfaces.IMultipleFluidHandler; import erogenousbeef.bigreactors.gui.IBeefTooltipControl; -public class BeefGuiFluidBar extends BeefGuiIconProgressBar implements - IBeefTooltipControl { +public class BeefGuiFluidBar extends BeefGuiIconProgressBar implements IBeefTooltipControl { + + IMultipleFluidHandler _entity; + int tankIdx; + + public BeefGuiFluidBar(BeefGuiBase container, int x, int y, IMultipleFluidHandler entity, int tankIdx) { + super(container, x, y); + + this._entity = entity; + this.tankIdx = tankIdx; + } + + @Override + protected IIcon getProgressBarIcon() { + FluidTankInfo[] tanks = this._entity.getTankInfo(); + if (tanks != null && tankIdx < tanks.length) { + if (tanks[tankIdx].fluid != null) { + return tanks[tankIdx].fluid.getFluid() + .getIcon(); + } + } + return null; + } + + @Override + protected float getProgress() { + FluidTankInfo[] tanks = this._entity.getTankInfo(); + if (tanks != null && tankIdx < tanks.length) { + FluidStack tankFluid = tanks[tankIdx].fluid; + if (tankFluid != null) { + return (float) tankFluid.amount / (float) tanks[tankIdx].capacity; + } + } + return 0.0f; + } - IMultipleFluidHandler _entity; - int tankIdx; - - public BeefGuiFluidBar(BeefGuiBase container, int x, int y, - IMultipleFluidHandler entity, int tankIdx) { - super(container, x, y); - - this._entity = entity; - this.tankIdx = tankIdx; - } + @Override + public String[] getTooltip() { + if (!visible) { + return null; + } - @Override - protected IIcon getProgressBarIcon() { - FluidTankInfo[] tanks = this._entity.getTankInfo(); - if(tanks != null && tankIdx < tanks.length) { - if(tanks[tankIdx].fluid != null) { - return tanks[tankIdx].fluid.getFluid().getIcon(); - } - } - return null; - } - - @Override - protected float getProgress() { - FluidTankInfo[] tanks = this._entity.getTankInfo(); - if(tanks != null && tankIdx < tanks.length) { - FluidStack tankFluid = tanks[tankIdx].fluid; - if(tankFluid != null) { - return (float)tankFluid.amount / (float)tanks[tankIdx].capacity; - } - } - return 0.0f; - } - - @Override - public String[] getTooltip() { - if(!visible) { return null; } + FluidTankInfo[] tanks = this._entity.getTankInfo(); + if (tanks != null && tankIdx < tanks.length) { + FluidStack tankFluid = tanks[tankIdx].fluid; + if (tankFluid != null) { + String fluidName = tankFluid.getFluid() + .getLocalizedName(tankFluid); + if (tankFluid.getFluid() + .getID() == FluidRegistry.WATER.getID()) { + fluidName = "Water"; + } else if (tankFluid.getFluid() + .getID() == FluidRegistry.LAVA.getID()) { + fluidName = "Lava"; + } - FluidTankInfo[] tanks = this._entity.getTankInfo(); - if(tanks != null && tankIdx < tanks.length) { - FluidStack tankFluid = tanks[tankIdx].fluid; - if(tankFluid != null) { - String fluidName = tankFluid.getFluid().getLocalizedName(tankFluid); - if(tankFluid.getFluid().getID() == FluidRegistry.WATER.getID()) { - fluidName = "Water"; - } - else if(tankFluid.getFluid().getID() == FluidRegistry.LAVA.getID()) { - fluidName = "Lava"; - } + return new String[] { fluidName, + String.format("%d / %d mB", tankFluid.amount, tanks[tankIdx].capacity) }; + } else { + return new String[] { "Empty", String.format("0 / %d mB", tanks[tankIdx].capacity) }; + } + } + return null; + } - return new String[] { fluidName, String.format("%d / %d mB", tankFluid.amount, tanks[tankIdx].capacity) }; - } - else { - return new String[] { "Empty", String.format("0 / %d mB", tanks[tankIdx].capacity) }; - } - } - return null; - } + @Override + protected ResourceLocation getResourceLocation() { + return net.minecraft.client.renderer.texture.TextureMap.locationBlocksTexture; + } - @Override - protected ResourceLocation getResourceLocation() { - return net.minecraft.client.renderer.texture.TextureMap.locationBlocksTexture; - } - - @Override - protected boolean drawGradationMarks() { return true; } + @Override + protected boolean drawGradationMarks() { + return true; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiFuelMixBar.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiFuelMixBar.java index 2c1bc57d..30e4251c 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiFuelMixBar.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiFuelMixBar.java @@ -3,116 +3,138 @@ import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.util.EnumChatFormatting; + import erogenousbeef.bigreactors.client.gui.BeefGuiBase; import erogenousbeef.bigreactors.common.interfaces.IReactorFuelInfo; import erogenousbeef.bigreactors.gui.IBeefTooltipControl; -public class BeefGuiFuelMixBar extends BeefGuiVerticalProgressBar implements - IBeefTooltipControl { - - IReactorFuelInfo entity; - - protected double fuelLeftU = 0.25; - protected double fuelRightU = 0.4999; - protected double wasteLeftU = 0.5; - protected double wasteRightU = 0.7499; - - public BeefGuiFuelMixBar(BeefGuiBase container, int x, int y, IReactorFuelInfo entity) { - super(container, x, y); - this.entity = entity; - } - - @Override - protected double getBackgroundLeftU() { return 0; } - - @Override - protected double getBackgroundRightU() { return 0.2499; } - - @Override - protected String getBackgroundTexture() { return "controls/FuelMixBar.png"; } - - private final static double maxV = 63.0/64.0; - private final static double minV = 1.0/64.0; - - @Override - protected void drawProgressBar(Tessellator tessellator, - TextureManager renderEngine, int barMinX, int barMaxX, int barMinY, - int barMaxY, int zLevel) { - - int barMaxHeight = this.height - 1; - int barHeight = Math.max(1, Math.round(getProgress() * barMaxHeight)); - - double fullness = (double)(entity.getFuelAmount() + entity.getWasteAmount()) / (double)entity.getCapacity(); - double fuelProportion = (double)entity.getFuelAmount() / (double)(entity.getFuelAmount() + entity.getWasteAmount()); - double wasteProportion = (double)entity.getWasteAmount() / (double)(entity.getFuelAmount() + entity.getWasteAmount()); - - renderEngine.bindTexture(controlResource); - if(fuelProportion > 0) { - double fuelMinV = 1.0 - fullness*maxV; - double fuelMaxV = maxV; - tessellator.startDrawingQuads(); - tessellator.addVertexWithUV(this.absoluteX, this.absoluteY + this.height - 1, zLevel, fuelLeftU, fuelMaxV); - tessellator.addVertexWithUV(this.absoluteX + this.width, this.absoluteY + this.height - 1, zLevel, fuelRightU, fuelMaxV); - tessellator.addVertexWithUV(this.absoluteX + this.width, this.absoluteY + this.height - barHeight, zLevel, fuelRightU, fuelMinV); - tessellator.addVertexWithUV(this.absoluteX, this.absoluteY + this.height - barHeight, zLevel, fuelLeftU, fuelMinV); - tessellator.draw(); - } - - if(wasteProportion > 0) { - double wasteMinV = 1.0 - fullness * wasteProportion * maxV; - double wasteMaxV = maxV; - double wasteHeight = Math.round(barHeight * wasteProportion); - - if(wasteHeight > 0) { - double wasteTop = this.absoluteY + this.height - 1 - wasteHeight; - - tessellator.startDrawingQuads(); - tessellator.addVertexWithUV(this.absoluteX, this.absoluteY + this.height - 1, zLevel+1, wasteLeftU, wasteMaxV); - tessellator.addVertexWithUV(this.absoluteX + this.width, this.absoluteY + this.height - 1, zLevel+1, wasteRightU, wasteMaxV); - tessellator.addVertexWithUV(this.absoluteX + this.width, wasteTop, zLevel+1, wasteRightU, wasteMinV); - tessellator.addVertexWithUV(this.absoluteX, wasteTop, zLevel+1, wasteLeftU, wasteMinV); - tessellator.draw(); - } - } - } - - @Override - public String[] getTooltip() { - float fullness = getProgress() * 100f; - float depletion; - String fuelString, wasteString; - fuelString = wasteString = "Empty"; - - if(entity.getFuelAmount() + entity.getWasteAmount() == 0) { - depletion = 0f; - } - else { - depletion = ((float)entity.getWasteAmount() / (float)(entity.getFuelAmount() + entity.getWasteAmount())) * 100f; - - if(entity.getFuelAmount() > 0) { - fuelString = Integer.toString(entity.getFuelAmount()) + " mB"; - } - - if(entity.getWasteAmount() > 0) { - wasteString = Integer.toString(entity.getWasteAmount()) + " mB"; - - } - } - return new String[] { - EnumChatFormatting.AQUA + "Core Fuel Status", - String.format(" %2.1f%% full", fullness), - String.format(" %2.1f%% depleted", depletion), - "", - String.format("Fuel Rods: %d", entity.getFuelRodCount()), - String.format("Max Capacity: %d mB", entity.getCapacity()), - String.format("Fuel: %s", fuelString), - String.format("Waste: %s", wasteString), - String.format("Total: %d mB", entity.getFuelAmount() + entity.getWasteAmount()) - }; - } - - @Override - protected float getProgress() { - return (float)(entity.getFuelAmount() + entity.getWasteAmount()) / (float)entity.getCapacity(); - } +public class BeefGuiFuelMixBar extends BeefGuiVerticalProgressBar implements IBeefTooltipControl { + + IReactorFuelInfo entity; + + protected double fuelLeftU = 0.25; + protected double fuelRightU = 0.4999; + protected double wasteLeftU = 0.5; + protected double wasteRightU = 0.7499; + + public BeefGuiFuelMixBar(BeefGuiBase container, int x, int y, IReactorFuelInfo entity) { + super(container, x, y); + this.entity = entity; + } + + @Override + protected double getBackgroundLeftU() { + return 0; + } + + @Override + protected double getBackgroundRightU() { + return 0.2499; + } + + @Override + protected String getBackgroundTexture() { + return "controls/FuelMixBar.png"; + } + + private final static double maxV = 63.0 / 64.0; + private final static double minV = 1.0 / 64.0; + + @Override + protected void drawProgressBar(Tessellator tessellator, TextureManager renderEngine, int barMinX, int barMaxX, + int barMinY, int barMaxY, int zLevel) { + + int barMaxHeight = this.height - 1; + int barHeight = Math.max(1, Math.round(getProgress() * barMaxHeight)); + + double fullness = (double) (entity.getFuelAmount() + entity.getWasteAmount()) / (double) entity.getCapacity(); + double fuelProportion = (double) entity.getFuelAmount() + / (double) (entity.getFuelAmount() + entity.getWasteAmount()); + double wasteProportion = (double) entity.getWasteAmount() + / (double) (entity.getFuelAmount() + entity.getWasteAmount()); + + renderEngine.bindTexture(controlResource); + if (fuelProportion > 0) { + double fuelMinV = 1.0 - fullness * maxV; + double fuelMaxV = maxV; + tessellator.startDrawingQuads(); + tessellator.addVertexWithUV(this.absoluteX, this.absoluteY + this.height - 1, zLevel, fuelLeftU, fuelMaxV); + tessellator.addVertexWithUV( + this.absoluteX + this.width, + this.absoluteY + this.height - 1, + zLevel, + fuelRightU, + fuelMaxV); + tessellator.addVertexWithUV( + this.absoluteX + this.width, + this.absoluteY + this.height - barHeight, + zLevel, + fuelRightU, + fuelMinV); + tessellator + .addVertexWithUV(this.absoluteX, this.absoluteY + this.height - barHeight, zLevel, fuelLeftU, fuelMinV); + tessellator.draw(); + } + + if (wasteProportion > 0) { + double wasteMinV = 1.0 - fullness * wasteProportion * maxV; + double wasteMaxV = maxV; + double wasteHeight = Math.round(barHeight * wasteProportion); + + if (wasteHeight > 0) { + double wasteTop = this.absoluteY + this.height - 1 - wasteHeight; + + tessellator.startDrawingQuads(); + tessellator.addVertexWithUV( + this.absoluteX, + this.absoluteY + this.height - 1, + zLevel + 1, + wasteLeftU, + wasteMaxV); + tessellator.addVertexWithUV( + this.absoluteX + this.width, + this.absoluteY + this.height - 1, + zLevel + 1, + wasteRightU, + wasteMaxV); + tessellator.addVertexWithUV(this.absoluteX + this.width, wasteTop, zLevel + 1, wasteRightU, wasteMinV); + tessellator.addVertexWithUV(this.absoluteX, wasteTop, zLevel + 1, wasteLeftU, wasteMinV); + tessellator.draw(); + } + } + } + + @Override + public String[] getTooltip() { + float fullness = getProgress() * 100f; + float depletion; + String fuelString, wasteString; + fuelString = wasteString = "Empty"; + + if (entity.getFuelAmount() + entity.getWasteAmount() == 0) { + depletion = 0f; + } else { + depletion = ((float) entity.getWasteAmount() / (float) (entity.getFuelAmount() + entity.getWasteAmount())) + * 100f; + + if (entity.getFuelAmount() > 0) { + fuelString = Integer.toString(entity.getFuelAmount()) + " mB"; + } + + if (entity.getWasteAmount() > 0) { + wasteString = Integer.toString(entity.getWasteAmount()) + " mB"; + + } + } + return new String[] { EnumChatFormatting.AQUA + "Core Fuel Status", String.format(" %2.1f%% full", fullness), + String.format(" %2.1f%% depleted", depletion), "", String.format("Fuel Rods: %d", entity.getFuelRodCount()), + String.format("Max Capacity: %d mB", entity.getCapacity()), String.format("Fuel: %s", fuelString), + String.format("Waste: %s", wasteString), + String.format("Total: %d mB", entity.getFuelAmount() + entity.getWasteAmount()) }; + } + + @Override + protected float getProgress() { + return (float) (entity.getFuelAmount() + entity.getWasteAmount()) / (float) entity.getCapacity(); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiHeatBar.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiHeatBar.java index 81283910..7c92c03e 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiHeatBar.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiHeatBar.java @@ -3,48 +3,48 @@ import erogenousbeef.bigreactors.client.gui.BeefGuiBase; import erogenousbeef.bigreactors.gui.IBeefTooltipControl; -public class BeefGuiHeatBar extends BeefGuiTextureProgressBar implements - IBeefTooltipControl { - - private float heatMax = 2000f; - private float heat; - - private String[] tooltip; - - public BeefGuiHeatBar(BeefGuiBase container, int x, int y, String tooltipTitle, String[] tooltipExtra) { - super(container, x, y); - heat = 0f; - - if(tooltipExtra == null) { - tooltip = new String[3]; - } - else { - tooltip = new String[3 + tooltipExtra.length]; - for(int i = 0; i < tooltipExtra.length; i++) { - tooltip[i+3] = tooltipExtra[i]; - } - } - - tooltip[0] = tooltipTitle; - tooltip[1] = ""; - tooltip[2] = ""; - } - - public void setHeat(float newHeat) { - heat = newHeat; - tooltip[1] = String.format(" %.0f C", newHeat); - } - - @Override - protected String getBackgroundTexture() { return "controls/HeatBar.png"; } - - @Override - protected float getProgress() { - return Math.min(1, Math.max(0, heat / heatMax)); - } - - @Override - public String[] getTooltip() { - return tooltip; - } +public class BeefGuiHeatBar extends BeefGuiTextureProgressBar implements IBeefTooltipControl { + + private float heatMax = 2000f; + private float heat; + + private String[] tooltip; + + public BeefGuiHeatBar(BeefGuiBase container, int x, int y, String tooltipTitle, String[] tooltipExtra) { + super(container, x, y); + heat = 0f; + + if (tooltipExtra == null) { + tooltip = new String[3]; + } else { + tooltip = new String[3 + tooltipExtra.length]; + for (int i = 0; i < tooltipExtra.length; i++) { + tooltip[i + 3] = tooltipExtra[i]; + } + } + + tooltip[0] = tooltipTitle; + tooltip[1] = ""; + tooltip[2] = ""; + } + + public void setHeat(float newHeat) { + heat = newHeat; + tooltip[1] = String.format(" %.0f C", newHeat); + } + + @Override + protected String getBackgroundTexture() { + return "controls/HeatBar.png"; + } + + @Override + protected float getProgress() { + return Math.min(1, Math.max(0, heat / heatMax)); + } + + @Override + public String[] getTooltip() { + return tooltip; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiIcon.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiIcon.java index 4001c996..76015370 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiIcon.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiIcon.java @@ -12,54 +12,53 @@ public class BeefGuiIcon extends BeefGuiControlBase implements IBeefTooltipControl { - protected IIcon icon; - protected String[] tooltip; + protected IIcon icon; + protected String[] tooltip; - public BeefGuiIcon(BeefGuiBase container, int absoluteX, int absoluteY) { - this(container, absoluteX, absoluteY, 16, 16); - } - - public BeefGuiIcon(BeefGuiBase container, int absoluteX, int absoluteY, int sizeX, int sizeY, IIcon icon, String[] tooltip) { - this(container, absoluteX, absoluteY, sizeX, sizeY); - this.icon = icon; - this.tooltip = tooltip; - } + public BeefGuiIcon(BeefGuiBase container, int absoluteX, int absoluteY) { + this(container, absoluteX, absoluteY, 16, 16); + } - - public BeefGuiIcon(BeefGuiBase container, int absoluteX, int absoluteY, - int width, int height) { - super(container, absoluteX, absoluteY, width, height); - icon = null; - tooltip = null; - } + public BeefGuiIcon(BeefGuiBase container, int absoluteX, int absoluteY, int sizeX, int sizeY, IIcon icon, + String[] tooltip) { + this(container, absoluteX, absoluteY, sizeX, sizeY); + this.icon = icon; + this.tooltip = tooltip; + } - public void setIcon(IIcon icon) { - this.icon = icon; - } - - @Override - public void drawBackground(TextureManager renderEngine, int mouseX, - int mouseY) { - if(!visible) { return; } - if(icon == null) { return; } - + public BeefGuiIcon(BeefGuiBase container, int absoluteX, int absoluteY, int width, int height) { + super(container, absoluteX, absoluteY, width, height); + icon = null; + tooltip = null; + } + + public void setIcon(IIcon icon) { + this.icon = icon; + } + + @Override + public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY) { + if (!visible) { + return; + } + if (icon == null) { + return; + } GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); renderEngine.bindTexture(TextureMap.locationBlocksTexture); - drawTexturedModelRectFromIcon(this.absoluteX, this.absoluteY, this.icon, this.width, this.height); - } + drawTexturedModelRectFromIcon(this.absoluteX, this.absoluteY, this.icon, this.width, this.height); + } - @Override - public void drawForeground(TextureManager renderEngine, int mouseX, - int mouseY) { - } + @Override + public void drawForeground(TextureManager renderEngine, int mouseX, int mouseY) {} - @Override - public String[] getTooltip() { - return tooltip; - } + @Override + public String[] getTooltip() { + return tooltip; + } - public void setTooltip(String[] newTooltip) { - tooltip = newTooltip; - } + public void setTooltip(String[] newTooltip) { + tooltip = newTooltip; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiIconProgressBar.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiIconProgressBar.java index 4bf3f268..19af46b1 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiIconProgressBar.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiIconProgressBar.java @@ -4,41 +4,46 @@ import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.util.IIcon; import net.minecraft.util.ResourceLocation; + import erogenousbeef.bigreactors.client.gui.BeefGuiBase; public abstract class BeefGuiIconProgressBar extends BeefGuiVerticalProgressBar { - public BeefGuiIconProgressBar(BeefGuiBase container, int x, int y) { - super(container, x, y); - - } - - protected abstract IIcon getProgressBarIcon(); - protected abstract ResourceLocation getResourceLocation(); - - @Override - protected void drawProgressBar(Tessellator tessellator, TextureManager renderEngine, int barMinX, int barMaxX, int barMinY, int barMaxY, int zLevel) { - IIcon progressBarIcon = getProgressBarIcon(); - if(progressBarIcon == null) { - return; - } - - double minU = progressBarIcon.getMinU(); - double minV = progressBarIcon.getMinV(); - double maxU = progressBarIcon.getMaxU(); - double maxV = progressBarIcon.getMaxV(); - - renderEngine.bindTexture(getResourceLocation()); - - // Draw the bar in 16-pixel slices from the bottom up. - for(int slicedBarY = barMaxY; slicedBarY > 0; slicedBarY -= 16) { - int slicedBarHeight = (int)Math.min(slicedBarY - barMinY, 16.0f); - tessellator.startDrawingQuads(); - tessellator.addVertexWithUV(barMinX, slicedBarY, zLevel, minU, minV + (maxV - minV) * slicedBarHeight / 16.0f); - tessellator.addVertexWithUV(barMaxX, slicedBarY, zLevel, maxU, minV + (maxV - minV) * slicedBarHeight / 16.0f); - tessellator.addVertexWithUV(barMaxX, slicedBarY - slicedBarHeight, zLevel, maxU, minV); - tessellator.addVertexWithUV(barMinX, slicedBarY - slicedBarHeight, zLevel, minU, minV); - tessellator.draw(); - } - } + public BeefGuiIconProgressBar(BeefGuiBase container, int x, int y) { + super(container, x, y); + + } + + protected abstract IIcon getProgressBarIcon(); + + protected abstract ResourceLocation getResourceLocation(); + + @Override + protected void drawProgressBar(Tessellator tessellator, TextureManager renderEngine, int barMinX, int barMaxX, + int barMinY, int barMaxY, int zLevel) { + IIcon progressBarIcon = getProgressBarIcon(); + if (progressBarIcon == null) { + return; + } + + double minU = progressBarIcon.getMinU(); + double minV = progressBarIcon.getMinV(); + double maxU = progressBarIcon.getMaxU(); + double maxV = progressBarIcon.getMaxV(); + + renderEngine.bindTexture(getResourceLocation()); + + // Draw the bar in 16-pixel slices from the bottom up. + for (int slicedBarY = barMaxY; slicedBarY > 0; slicedBarY -= 16) { + int slicedBarHeight = (int) Math.min(slicedBarY - barMinY, 16.0f); + tessellator.startDrawingQuads(); + tessellator + .addVertexWithUV(barMinX, slicedBarY, zLevel, minU, minV + (maxV - minV) * slicedBarHeight / 16.0f); + tessellator + .addVertexWithUV(barMaxX, slicedBarY, zLevel, maxU, minV + (maxV - minV) * slicedBarHeight / 16.0f); + tessellator.addVertexWithUV(barMaxX, slicedBarY - slicedBarHeight, zLevel, maxU, minV); + tessellator.addVertexWithUV(barMinX, slicedBarY - slicedBarHeight, zLevel, minU, minV); + tessellator.draw(); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiInsertionProgressBar.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiInsertionProgressBar.java index 51e174fd..23e4cebd 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiInsertionProgressBar.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiInsertionProgressBar.java @@ -14,77 +14,78 @@ public class BeefGuiInsertionProgressBar extends BeefGuiControlBase implements IBeefTooltipControl { - public final static int controlWidth = 20; - public final static int controlHeight = 64; - - protected ResourceLocation controlResource; - - private double backgroundLeftU = 0; - private double backgroundRightU = 0.5; - - private double rodLeftU = 0.51; - private double rodRightU = 1; - - protected float barAbsoluteMaxHeight; - protected float insertion = 0f; - - protected String[] tooltip = { - EnumChatFormatting.AQUA + "Control Rod", - "", - "Insertion: XX%" - }; - - public BeefGuiInsertionProgressBar(BeefGuiBase container, int x, int y) { - super(container, x, y, controlWidth, controlHeight); - - controlResource = new ResourceLocation(BigReactors.GUI_DIRECTORY + getBackgroundTexture()); - barAbsoluteMaxHeight = this.height - 1; - } - - public void setInsertion(float insertion) { this.insertion = Math.min(1f, Math.max(0f, insertion)); } - - protected String getBackgroundTexture() { return "controls/ControlRod.png"; } - - @Override - public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY) { - if(!this.visible) { return; } - - // Draw the background - GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - renderEngine.bindTexture(controlResource); - Tessellator tessellator = Tessellator.instance; - tessellator.startDrawingQuads(); - tessellator.addVertexWithUV(this.absoluteX, this.absoluteY + this.height, 0, backgroundLeftU, 1.0); - tessellator.addVertexWithUV(this.absoluteX + this.width, this.absoluteY + this.height, 0, backgroundRightU, 1.0); - tessellator.addVertexWithUV(this.absoluteX + this.width, this.absoluteY, 0, backgroundRightU, 0); - tessellator.addVertexWithUV(this.absoluteX, this.absoluteY, 0, backgroundLeftU, 0); - tessellator.draw(); - - // Draw the rod itself, on top of the background - if(insertion > 0f) { - int barHeight = Math.max(1, (int)Math.floor(insertion * barAbsoluteMaxHeight)); - int rodMaxY = this.absoluteY + barHeight; - - float rodTopV = 1f - insertion; // TODO - - tessellator.startDrawingQuads(); - tessellator.addVertexWithUV(this.absoluteX, rodMaxY, 2, rodLeftU, 1f); - tessellator.addVertexWithUV(this.absoluteX + this.width, rodMaxY, 2, rodRightU, 1f); - tessellator.addVertexWithUV(this.absoluteX + this.width, this.absoluteY, 2, rodRightU, rodTopV); - tessellator.addVertexWithUV(this.absoluteX, this.absoluteY, 2, rodLeftU, rodTopV); - tessellator.draw(); - } - } - - @Override - public void drawForeground(TextureManager renderEngine, int mouseX, - int mouseY) { - } - - @Override - public String[] getTooltip() { - tooltip[2] = String.format("Insertion: %.0f%%", this.insertion*100f); - return tooltip; - } + public final static int controlWidth = 20; + public final static int controlHeight = 64; + + protected ResourceLocation controlResource; + + private double backgroundLeftU = 0; + private double backgroundRightU = 0.5; + + private double rodLeftU = 0.51; + private double rodRightU = 1; + + protected float barAbsoluteMaxHeight; + protected float insertion = 0f; + + protected String[] tooltip = { EnumChatFormatting.AQUA + "Control Rod", "", "Insertion: XX%" }; + + public BeefGuiInsertionProgressBar(BeefGuiBase container, int x, int y) { + super(container, x, y, controlWidth, controlHeight); + + controlResource = new ResourceLocation(BigReactors.GUI_DIRECTORY + getBackgroundTexture()); + barAbsoluteMaxHeight = this.height - 1; + } + + public void setInsertion(float insertion) { + this.insertion = Math.min(1f, Math.max(0f, insertion)); + } + + protected String getBackgroundTexture() { + return "controls/ControlRod.png"; + } + + @Override + public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY) { + if (!this.visible) { + return; + } + + // Draw the background + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + renderEngine.bindTexture(controlResource); + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + tessellator.addVertexWithUV(this.absoluteX, this.absoluteY + this.height, 0, backgroundLeftU, 1.0); + tessellator + .addVertexWithUV(this.absoluteX + this.width, this.absoluteY + this.height, 0, backgroundRightU, 1.0); + tessellator.addVertexWithUV(this.absoluteX + this.width, this.absoluteY, 0, backgroundRightU, 0); + tessellator.addVertexWithUV(this.absoluteX, this.absoluteY, 0, backgroundLeftU, 0); + tessellator.draw(); + + // Draw the rod itself, on top of the background + if (insertion > 0f) { + int barHeight = Math.max(1, (int) Math.floor(insertion * barAbsoluteMaxHeight)); + int rodMaxY = this.absoluteY + barHeight; + + float rodTopV = 1f - insertion; // TODO + + tessellator.startDrawingQuads(); + tessellator.addVertexWithUV(this.absoluteX, rodMaxY, 2, rodLeftU, 1f); + tessellator.addVertexWithUV(this.absoluteX + this.width, rodMaxY, 2, rodRightU, 1f); + tessellator.addVertexWithUV(this.absoluteX + this.width, this.absoluteY, 2, rodRightU, rodTopV); + tessellator.addVertexWithUV(this.absoluteX, this.absoluteY, 2, rodLeftU, rodTopV); + tessellator.draw(); + } + } + + @Override + public void drawForeground(TextureManager renderEngine, int mouseX, int mouseY) {} + + @Override + public String[] getTooltip() { + tooltip[2] = String.format("Insertion: %.0f%%", this.insertion * 100f); + return tooltip; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiLabel.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiLabel.java index 15d0c6a8..a8db6469 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiLabel.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiLabel.java @@ -2,6 +2,7 @@ import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.renderer.texture.TextureManager; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import erogenousbeef.bigreactors.client.gui.BeefGuiBase; @@ -11,77 +12,97 @@ @SideOnly(Side.CLIENT) public class BeefGuiLabel extends BeefGuiControlBase implements IBeefTooltipControl { - protected int xMax; // If >0, wrap text at this pixel level. Does not split words. - protected String labelText; - protected String labelTooltip; - protected boolean dropShadow; - protected int color; - - public String getLabelText() { return labelText; } - public String getLabelTooltip() { return labelTooltip; } - - public void setLabelText(String newText) { - if(newText.equals(labelText)) { return; } - labelText = newText; - recalculateSize(); - } - - public void setLabelTooltip(String newTooltip) { labelTooltip = newTooltip; } - public void setDropShadow(boolean shadow) { dropShadow = shadow; } - public void setColor(int color) { this.color = color; } - - // If set to 0 or less, disables wrapping. - public void setWordWrapLength(int pixels) { xMax = pixels; } - - public BeefGuiLabel(BeefGuiBase container, String text, int x, int y) { - super(container, x, y, 0, 0); - this.labelText = text; - recalculateSize(); - } - - private void recalculateSize() { - FontRenderer fontRenderer = guiContainer.getFontRenderer(); - if(xMax > 0) { - this.width = fontRenderer.splitStringWidth(labelText, xMax); - int totalWidth = fontRenderer.getStringWidth(labelText); - this.height = fontRenderer.FONT_HEIGHT * Math.max(1, (totalWidth / width)); - } - else { - this.width = fontRenderer.getStringWidth(labelText); - this.height = fontRenderer.FONT_HEIGHT; - } - } - - @Override - public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY) { - } - - @Override - public void drawForeground(TextureManager renderEngine, int mouseX, int mouseY) { - FontRenderer fontRenderer = guiContainer.getFontRenderer(); - if(xMax > 0) { - fontRenderer.drawSplitString(labelText, relativeX, relativeY, color, xMax); - } - else { - fontRenderer.drawString(labelText, relativeX, relativeY, color, dropShadow); - } - } - @Override - public String[] getTooltip() { - if(labelTooltip == null || labelTooltip.isEmpty()) { return null; } - return new String[] { labelTooltip }; - } - - @Override - /** - * Check if the mouse is over this control. - * @param mouseX Screen-relative mouse X coordinate. - * @param mouseY Screen-relative mouse Y coordinate. - * @return True if the mouse is over this control, false otherwise. - */ - public boolean isMouseOver(int mouseX, int mouseY) { - if(mouseX < absoluteX || mouseX > absoluteX+width || mouseY < absoluteY || mouseY > absoluteY+height) { return false; } - return true; - } - + protected int xMax; // If >0, wrap text at this pixel level. Does not split words. + protected String labelText; + protected String labelTooltip; + protected boolean dropShadow; + protected int color; + + public String getLabelText() { + return labelText; + } + + public String getLabelTooltip() { + return labelTooltip; + } + + public void setLabelText(String newText) { + if (newText.equals(labelText)) { + return; + } + labelText = newText; + recalculateSize(); + } + + public void setLabelTooltip(String newTooltip) { + labelTooltip = newTooltip; + } + + public void setDropShadow(boolean shadow) { + dropShadow = shadow; + } + + public void setColor(int color) { + this.color = color; + } + + // If set to 0 or less, disables wrapping. + public void setWordWrapLength(int pixels) { + xMax = pixels; + } + + public BeefGuiLabel(BeefGuiBase container, String text, int x, int y) { + super(container, x, y, 0, 0); + this.labelText = text; + recalculateSize(); + } + + private void recalculateSize() { + FontRenderer fontRenderer = guiContainer.getFontRenderer(); + if (xMax > 0) { + this.width = fontRenderer.splitStringWidth(labelText, xMax); + int totalWidth = fontRenderer.getStringWidth(labelText); + this.height = fontRenderer.FONT_HEIGHT * Math.max(1, (totalWidth / width)); + } else { + this.width = fontRenderer.getStringWidth(labelText); + this.height = fontRenderer.FONT_HEIGHT; + } + } + + @Override + public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY) {} + + @Override + public void drawForeground(TextureManager renderEngine, int mouseX, int mouseY) { + FontRenderer fontRenderer = guiContainer.getFontRenderer(); + if (xMax > 0) { + fontRenderer.drawSplitString(labelText, relativeX, relativeY, color, xMax); + } else { + fontRenderer.drawString(labelText, relativeX, relativeY, color, dropShadow); + } + } + + @Override + public String[] getTooltip() { + if (labelTooltip == null || labelTooltip.isEmpty()) { + return null; + } + return new String[] { labelTooltip }; + } + + @Override + /** + * Check if the mouse is over this control. + * + * @param mouseX Screen-relative mouse X coordinate. + * @param mouseY Screen-relative mouse Y coordinate. + * @return True if the mouse is over this control, false otherwise. + */ + public boolean isMouseOver(int mouseX, int mouseY) { + if (mouseX < absoluteX || mouseX > absoluteX + width || mouseY < absoluteY || mouseY > absoluteY + height) { + return false; + } + return true; + } + } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiListBox.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiListBox.java index 7b355b88..7ced1754 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiListBox.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiListBox.java @@ -4,98 +4,119 @@ import java.util.List; import net.minecraft.client.renderer.texture.TextureManager; + import erogenousbeef.bigreactors.client.gui.BeefGuiBase; import erogenousbeef.bigreactors.gui.BeefGuiControlBase; import erogenousbeef.bigreactors.gui.IBeefListBoxEntry; public class BeefGuiListBox extends BeefGuiControlBase { - protected int borderColor = 0xffaaaaaa; - protected int backgroundColor = 0xff000000; - protected int selectedLineColor = 0xff000000; - protected int textColor = 0xffcdcdcd; - protected int selectedTextColor = 0xffffffff; - - private List entries; - - private int displayTop; - private int selectedEntryIdx; - - private static final int NO_ENTRY = -1; - private static final int margin = 2; - - public BeefGuiListBox(BeefGuiBase container, int x, int y, int width, - int height) { - super(container, x, y, width, height); - - entries = new ArrayList(); - displayTop = 0; - selectedEntryIdx = NO_ENTRY; - } - - public void add(IBeefListBoxEntry entry) { - entries.add(entry); - } - - public void remove(IBeefListBoxEntry entry) { - entries.remove(entry); - } - - - - @Override - public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY) { - drawRect(absoluteX, absoluteY, absoluteX+width, absoluteY+height, borderColor); - drawRect(absoluteX+margin, absoluteY+margin, absoluteX+width-margin*2, absoluteY+height-margin*2, backgroundColor); - } - - @Override - public void drawForeground(TextureManager renderEngine, int mouseX, int mouseY) { - int drawnY = 0; - IBeefListBoxEntry entry; - for(int i = displayTop; i < entries.size(); i++) { - entry = entries.get(i); - if(entry.getHeight() + drawnY > this.height) { break; } - else { - if(this.selectedEntryIdx == i) { - entry.draw(this.guiContainer.getFontRenderer(), relativeX+margin, relativeY+margin+drawnY, selectedLineColor, selectedTextColor); - } - else { - entry.draw(this.guiContainer.getFontRenderer(), relativeX+margin, relativeY+margin+drawnY, backgroundColor, textColor); - } - } - if(drawnY >= this.height) { break; } - } - } - - @Override - public void onMouseClicked(int mouseX, int mouseY, int mouseButton) { - int checkedY = 0; - for(int i = displayTop; i < entries.size(); i++) { - int entryHeight = entries.get(i).getHeight(); - if(checkedY + entryHeight > (this.height-margin*2)) { - break; - } - - if(this.absoluteY + margin + checkedY <= mouseY && this.absoluteY + margin + entryHeight + checkedY >= mouseY) { - setSelectedIndex(i); - onEntryClicked(entries.get(i)); - break; - } - - checkedY += entryHeight; - } - } - - protected void setSelectedIndex(int newSelectedIdx) { - if(newSelectedIdx < 0 || newSelectedIdx >= this.entries.size()) { return; } - if(this.selectedEntryIdx == newSelectedIdx) { return; } - this.selectedEntryIdx = newSelectedIdx; - this.guiContainer.onListBoxSelectionChanged(this, entries.get(this.selectedEntryIdx)); - } - - public void onEntryClicked(IBeefListBoxEntry entry) { - this.guiContainer.onListBoxEntryClicked(this, entry); - } - + protected int borderColor = 0xffaaaaaa; + protected int backgroundColor = 0xff000000; + protected int selectedLineColor = 0xff000000; + protected int textColor = 0xffcdcdcd; + protected int selectedTextColor = 0xffffffff; + + private List entries; + + private int displayTop; + private int selectedEntryIdx; + + private static final int NO_ENTRY = -1; + private static final int margin = 2; + + public BeefGuiListBox(BeefGuiBase container, int x, int y, int width, int height) { + super(container, x, y, width, height); + + entries = new ArrayList(); + displayTop = 0; + selectedEntryIdx = NO_ENTRY; + } + + public void add(IBeefListBoxEntry entry) { + entries.add(entry); + } + + public void remove(IBeefListBoxEntry entry) { + entries.remove(entry); + } + + @Override + public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY) { + drawRect(absoluteX, absoluteY, absoluteX + width, absoluteY + height, borderColor); + drawRect( + absoluteX + margin, + absoluteY + margin, + absoluteX + width - margin * 2, + absoluteY + height - margin * 2, + backgroundColor); + } + + @Override + public void drawForeground(TextureManager renderEngine, int mouseX, int mouseY) { + int drawnY = 0; + IBeefListBoxEntry entry; + for (int i = displayTop; i < entries.size(); i++) { + entry = entries.get(i); + if (entry.getHeight() + drawnY > this.height) { + break; + } else { + if (this.selectedEntryIdx == i) { + entry.draw( + this.guiContainer.getFontRenderer(), + relativeX + margin, + relativeY + margin + drawnY, + selectedLineColor, + selectedTextColor); + } else { + entry.draw( + this.guiContainer.getFontRenderer(), + relativeX + margin, + relativeY + margin + drawnY, + backgroundColor, + textColor); + } + } + if (drawnY >= this.height) { + break; + } + } + } + + @Override + public void onMouseClicked(int mouseX, int mouseY, int mouseButton) { + int checkedY = 0; + for (int i = displayTop; i < entries.size(); i++) { + int entryHeight = entries.get(i) + .getHeight(); + if (checkedY + entryHeight > (this.height - margin * 2)) { + break; + } + + if (this.absoluteY + margin + checkedY <= mouseY + && this.absoluteY + margin + entryHeight + checkedY >= mouseY) { + setSelectedIndex(i); + onEntryClicked(entries.get(i)); + break; + } + + checkedY += entryHeight; + } + } + + protected void setSelectedIndex(int newSelectedIdx) { + if (newSelectedIdx < 0 || newSelectedIdx >= this.entries.size()) { + return; + } + if (this.selectedEntryIdx == newSelectedIdx) { + return; + } + this.selectedEntryIdx = newSelectedIdx; + this.guiContainer.onListBoxSelectionChanged(this, entries.get(this.selectedEntryIdx)); + } + + public void onEntryClicked(IBeefListBoxEntry entry) { + this.guiContainer.onListBoxEntryClicked(this, entry); + } + } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiPowerBar.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiPowerBar.java index f2ff850a..5ece94e8 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiPowerBar.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiPowerBar.java @@ -1,37 +1,42 @@ package erogenousbeef.bigreactors.gui.controls; import net.minecraftforge.common.util.ForgeDirection; + import cofh.api.energy.IEnergyProvider; import erogenousbeef.bigreactors.client.gui.BeefGuiBase; import erogenousbeef.bigreactors.gui.IBeefTooltipControl; -public class BeefGuiPowerBar extends BeefGuiTextureProgressBar implements - IBeefTooltipControl { - - IEnergyProvider _entity; - - public BeefGuiPowerBar(BeefGuiBase container, int x, int y, IEnergyProvider entity) { - super(container, x, y); - _entity = entity; - } - - @Override - protected String getBackgroundTexture() { return "controls/Energy.png"; } - - @Override - protected float getProgress() { - float val = Math.min(1f, Math.max(0f, (float)_entity.getEnergyStored(ForgeDirection.UNKNOWN) / (float)_entity.getMaxEnergyStored(ForgeDirection.UNKNOWN))); - return val; - } - - @Override - public String[] getTooltip() { - int energyStored = _entity.getEnergyStored(ForgeDirection.UNKNOWN); - int energyMax = _entity.getMaxEnergyStored(ForgeDirection.UNKNOWN); - float fullness = (float)energyStored / (float)energyMax * 100f; - return new String[] { "Energy Buffer", - String.format("%d / %d RF", energyStored, energyMax), - String.format("%2.1f%% full", fullness) - }; - } +public class BeefGuiPowerBar extends BeefGuiTextureProgressBar implements IBeefTooltipControl { + + IEnergyProvider _entity; + + public BeefGuiPowerBar(BeefGuiBase container, int x, int y, IEnergyProvider entity) { + super(container, x, y); + _entity = entity; + } + + @Override + protected String getBackgroundTexture() { + return "controls/Energy.png"; + } + + @Override + protected float getProgress() { + float val = Math.min( + 1f, + Math.max( + 0f, + (float) _entity.getEnergyStored(ForgeDirection.UNKNOWN) + / (float) _entity.getMaxEnergyStored(ForgeDirection.UNKNOWN))); + return val; + } + + @Override + public String[] getTooltip() { + int energyStored = _entity.getEnergyStored(ForgeDirection.UNKNOWN); + int energyMax = _entity.getMaxEnergyStored(ForgeDirection.UNKNOWN); + float fullness = (float) energyStored / (float) energyMax * 100f; + return new String[] { "Energy Buffer", String.format("%d / %d RF", energyStored, energyMax), + String.format("%2.1f%% full", fullness) }; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiProgressArrow.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiProgressArrow.java index 18d716af..af3871c3 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiProgressArrow.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiProgressArrow.java @@ -1,34 +1,36 @@ package erogenousbeef.bigreactors.gui.controls; import net.minecraft.client.renderer.texture.TextureManager; + import erogenousbeef.bigreactors.client.gui.BeefGuiBase; import erogenousbeef.bigreactors.common.tileentity.base.TileEntityPoweredInventory; import erogenousbeef.bigreactors.gui.BeefGuiControlBase; public class BeefGuiProgressArrow extends BeefGuiControlBase { - TileEntityPoweredInventory entity; - private int arrowU; - private int arrowV; - - public BeefGuiProgressArrow(BeefGuiBase container, int x, int y, int arrowU, int arrowV, TileEntityPoweredInventory entity) { - super(container, x, y, 25, 16); - this.arrowU = arrowU; - this.arrowV = arrowV; - this.entity = entity; - } - - @Override - public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY) { - if(entity.getCycleCompletion() > 0.0) { - int progressWidth = (int)(entity.getCycleCompletion() * (float)(this.width-1)); - renderEngine.bindTexture(this.guiContainer.getGuiBackground()); - guiContainer.drawTexturedModalRect(this.absoluteX, this.absoluteY, arrowU, arrowV, 1+progressWidth, this.height); - } - } - - @Override - public void drawForeground(TextureManager renderEngine, int mouseX, int mouseY) { - } + TileEntityPoweredInventory entity; + private int arrowU; + private int arrowV; + + public BeefGuiProgressArrow(BeefGuiBase container, int x, int y, int arrowU, int arrowV, + TileEntityPoweredInventory entity) { + super(container, x, y, 25, 16); + this.arrowU = arrowU; + this.arrowV = arrowV; + this.entity = entity; + } + + @Override + public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY) { + if (entity.getCycleCompletion() > 0.0) { + int progressWidth = (int) (entity.getCycleCompletion() * (float) (this.width - 1)); + renderEngine.bindTexture(this.guiContainer.getGuiBackground()); + guiContainer + .drawTexturedModalRect(this.absoluteX, this.absoluteY, arrowU, arrowV, 1 + progressWidth, this.height); + } + } + + @Override + public void drawForeground(TextureManager renderEngine, int mouseX, int mouseY) {} } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiRedNetChannelSelector.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiRedNetChannelSelector.java index 10f55097..03a84aad 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiRedNetChannelSelector.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiRedNetChannelSelector.java @@ -2,93 +2,106 @@ import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.entity.passive.EntitySheep; + import erogenousbeef.bigreactors.client.gui.BeefGuiBase; import erogenousbeef.bigreactors.gui.BeefGuiControlBase; import erogenousbeef.bigreactors.gui.IBeefGuiControl; import erogenousbeef.bigreactors.gui.IBeefTooltipControl; -public class BeefGuiRedNetChannelSelector extends BeefGuiControlBase implements IBeefGuiControl, - IBeefTooltipControl { - - String caption; - int channelIdx; - boolean selected; - - protected int barHeight = 4; - - /** - * - * @param container - * @param caption - * @param colorIdx Index of the channel, also the color index in the EntitySheep color table. (Always 100% opacity.) - * @param x - * @param y - * @param width - * @param height - */ - public BeefGuiRedNetChannelSelector(BeefGuiBase container, String caption, int colorIdx, int x, int y, int width, int height) { - super(container, x, y, width, height); - this.caption = caption; - this.channelIdx = colorIdx; - this.selected = false; - } - - @Override - public boolean isMouseOver(int mouseX, int mouseY) { - // Only mouse over when the color or line are moused over. - if(mouseX < absoluteX+width && mouseX >= absoluteX) { - return mouseY >= absoluteY && mouseY <= absoluteY+height; - } - else if(mouseX < absoluteX+width-height && mouseX >= absoluteX+height) { - int barTop = absoluteY + height/2 - (barHeight/2-1); - return mouseY >= barTop && mouseY < barTop+barHeight; - } - return false; - } - - @Override - public String[] getTooltip() { - return new String[] { caption }; - } - - @Override - public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY) { - int barTop = absoluteY + height/2 - (barHeight/2-1); - int borderColor = 0xff000000; - if(this.selected) { - borderColor = 0xff22dd22; // bright green? - } - this.drawRect(absoluteX, absoluteY, absoluteX+height, absoluteY+height, borderColor); - this.drawRect(absoluteX+width-height, absoluteY, absoluteX+width, absoluteY+height, borderColor); - this.drawRect(absoluteX+height, barTop, absoluteX+width-height, barTop+barHeight, borderColor); - - float[] color = EntitySheep.fleeceColorTable[this.channelIdx]; - - this.drawRect(absoluteX+1, absoluteY+1, absoluteX+height-1, absoluteY+height-1, color[0], color[1], color[2], 1.0f); - this.drawRect(absoluteX+width-height+1, absoluteY+1, absoluteX+width-1, absoluteY+height-1, 0xff777777); - } - - @Override - public void drawForeground(TextureManager renderEngine, int mouseX, int mouseY) { - } - - @Override - public void onMouseClicked(int mouseX, int mouseY, int mouseButton) { - if(mouseButton == 0 && isMouseOver(mouseX, mouseY)) { - guiContainer.onControlClicked(this); - } - } - - public void setSelected(boolean selected) { - this.selected = selected; - } - - public boolean isSelected() { - return selected; - } - - public int getChannel() { - return channelIdx; - } - +public class BeefGuiRedNetChannelSelector extends BeefGuiControlBase implements IBeefGuiControl, IBeefTooltipControl { + + String caption; + int channelIdx; + boolean selected; + + protected int barHeight = 4; + + /** + * + * @param container + * @param caption + * @param colorIdx Index of the channel, also the color index in the EntitySheep color table. (Always 100% + * opacity.) + * @param x + * @param y + * @param width + * @param height + */ + public BeefGuiRedNetChannelSelector(BeefGuiBase container, String caption, int colorIdx, int x, int y, int width, + int height) { + super(container, x, y, width, height); + this.caption = caption; + this.channelIdx = colorIdx; + this.selected = false; + } + + @Override + public boolean isMouseOver(int mouseX, int mouseY) { + // Only mouse over when the color or line are moused over. + if (mouseX < absoluteX + width && mouseX >= absoluteX) { + return mouseY >= absoluteY && mouseY <= absoluteY + height; + } else if (mouseX < absoluteX + width - height && mouseX >= absoluteX + height) { + int barTop = absoluteY + height / 2 - (barHeight / 2 - 1); + return mouseY >= barTop && mouseY < barTop + barHeight; + } + return false; + } + + @Override + public String[] getTooltip() { + return new String[] { caption }; + } + + @Override + public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY) { + int barTop = absoluteY + height / 2 - (barHeight / 2 - 1); + int borderColor = 0xff000000; + if (this.selected) { + borderColor = 0xff22dd22; // bright green? + } + this.drawRect(absoluteX, absoluteY, absoluteX + height, absoluteY + height, borderColor); + this.drawRect(absoluteX + width - height, absoluteY, absoluteX + width, absoluteY + height, borderColor); + this.drawRect(absoluteX + height, barTop, absoluteX + width - height, barTop + barHeight, borderColor); + + float[] color = EntitySheep.fleeceColorTable[this.channelIdx]; + + this.drawRect( + absoluteX + 1, + absoluteY + 1, + absoluteX + height - 1, + absoluteY + height - 1, + color[0], + color[1], + color[2], + 1.0f); + this.drawRect( + absoluteX + width - height + 1, + absoluteY + 1, + absoluteX + width - 1, + absoluteY + height - 1, + 0xff777777); + } + + @Override + public void drawForeground(TextureManager renderEngine, int mouseX, int mouseY) {} + + @Override + public void onMouseClicked(int mouseX, int mouseY, int mouseButton) { + if (mouseButton == 0 && isMouseOver(mouseX, mouseY)) { + guiContainer.onControlClicked(this); + } + } + + public void setSelected(boolean selected) { + this.selected = selected; + } + + public boolean isSelected() { + return selected; + } + + public int getChannel() { + return channelIdx; + } + } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiRpmBar.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiRpmBar.java index cc94b92e..9185d70f 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiRpmBar.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiRpmBar.java @@ -1,55 +1,59 @@ package erogenousbeef.bigreactors.gui.controls; import net.minecraft.util.EnumChatFormatting; + import erogenousbeef.bigreactors.client.gui.BeefGuiBase; import erogenousbeef.bigreactors.common.multiblock.MultiblockTurbine; import erogenousbeef.bigreactors.gui.IBeefTooltipControl; -public class BeefGuiRpmBar extends BeefGuiTextureProgressBar implements - IBeefTooltipControl { - - MultiblockTurbine turbine; - String[] tooltip; - - public BeefGuiRpmBar(BeefGuiBase container, int x, int y, MultiblockTurbine turbine, String tooltipTitle, String[] extraTooltip) { - super(container, x, y); - tooltip = null; - this.turbine = turbine; - - if(extraTooltip == null || extraTooltip.length <= 0) { - tooltip = new String[2]; - } - else { - tooltip = new String[3 + extraTooltip.length]; - tooltip[2] = ""; - for(int i = 0; i < extraTooltip.length; i++) { - tooltip[i+3] = extraTooltip[i]; - } - } - tooltip[0] = EnumChatFormatting.AQUA + tooltipTitle; - tooltip[1] = ""; - } - - @Override - protected String getBackgroundTexture() { return "controls/RpmBar.png"; } - - @Override - public String[] getTooltip() { - if(turbine != null) { - tooltip[1] = String.format(" %.0f RPM", turbine.getRotorSpeed()); - } - else { - tooltip[1] = " 0 RPM"; - } - - return tooltip; - } - - @Override - protected float getProgress() { - if(turbine == null) { return 0f; } - - return Math.min(1f, turbine.getRotorSpeed() / (turbine.getMaxRotorSpeed()*1.1f)); // Give a little extra warning - } +public class BeefGuiRpmBar extends BeefGuiTextureProgressBar implements IBeefTooltipControl { + + MultiblockTurbine turbine; + String[] tooltip; + + public BeefGuiRpmBar(BeefGuiBase container, int x, int y, MultiblockTurbine turbine, String tooltipTitle, + String[] extraTooltip) { + super(container, x, y); + tooltip = null; + this.turbine = turbine; + + if (extraTooltip == null || extraTooltip.length <= 0) { + tooltip = new String[2]; + } else { + tooltip = new String[3 + extraTooltip.length]; + tooltip[2] = ""; + for (int i = 0; i < extraTooltip.length; i++) { + tooltip[i + 3] = extraTooltip[i]; + } + } + tooltip[0] = EnumChatFormatting.AQUA + tooltipTitle; + tooltip[1] = ""; + } + + @Override + protected String getBackgroundTexture() { + return "controls/RpmBar.png"; + } + + @Override + public String[] getTooltip() { + if (turbine != null) { + tooltip[1] = String.format(" %.0f RPM", turbine.getRotorSpeed()); + } else { + tooltip[1] = " 0 RPM"; + } + + return tooltip; + } + + @Override + protected float getProgress() { + if (turbine == null) { + return 0f; + } + + return Math.min(1f, turbine.getRotorSpeed() / (turbine.getMaxRotorSpeed() * 1.1f)); // Give a little extra + // warning + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiTextureProgressBar.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiTextureProgressBar.java index e3151614..370331f0 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiTextureProgressBar.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiTextureProgressBar.java @@ -3,56 +3,76 @@ import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.util.ResourceLocation; + import erogenousbeef.bigreactors.client.gui.BeefGuiBase; public abstract class BeefGuiTextureProgressBar extends BeefGuiVerticalProgressBar { - protected double barLeftU = 0.5; - protected double barRightU = 1; - - ResourceLocation barTexture; - - public BeefGuiTextureProgressBar(BeefGuiBase container, int x, int y) { - super(container, x, y); - - barLeftU = getBarLeftU(); - barRightU = getBarRightU(); - barTexture = getBarTexture(); - } - - protected double getBarLeftU() { return 0.5; } - protected double getBarRightU() { return 0.9999; } - protected ResourceLocation getBarTexture() { return this.controlResource; } - - @Override - protected double getBackgroundLeftU() { return 0; } - - @Override - protected double getBackgroundRightU() { return 0.499; } - - - @Override - protected void drawProgressBar(Tessellator tessellator, - TextureManager renderEngine, int barMinX, int barMaxX, int barMinY, - int barMaxY, int zLevel) { - - double barHeight = Math.round((getProgress() * (this.height-2))) + 2; - if(getProgress() > 0.00001) { barHeight = Math.max(getBarMinHeight(), barHeight); } - - double barMaxV = 1; - double barMinV = 1 - Math.min(1, Math.max(0, barHeight / this.height)); - - renderEngine.bindTexture(getBarTexture()); - tessellator.startDrawingQuads(); - tessellator.addVertexWithUV(this.absoluteX, this.absoluteY + this.height, zLevel, barLeftU, barMaxV); - tessellator.addVertexWithUV(this.absoluteX + this.width, this.absoluteY + this.height, zLevel, barRightU, barMaxV); - tessellator.addVertexWithUV(this.absoluteX + this.width, this.absoluteY + this.height - barHeight, zLevel, barRightU, barMinV); - tessellator.addVertexWithUV(this.absoluteX, this.absoluteY + this.height - barHeight, zLevel, barLeftU, barMinV); - tessellator.draw(); - } - - protected double getBarMinHeight() { - return 3; - } + protected double barLeftU = 0.5; + protected double barRightU = 1; + + ResourceLocation barTexture; + + public BeefGuiTextureProgressBar(BeefGuiBase container, int x, int y) { + super(container, x, y); + + barLeftU = getBarLeftU(); + barRightU = getBarRightU(); + barTexture = getBarTexture(); + } + + protected double getBarLeftU() { + return 0.5; + } + + protected double getBarRightU() { + return 0.9999; + } + + protected ResourceLocation getBarTexture() { + return this.controlResource; + } + + @Override + protected double getBackgroundLeftU() { + return 0; + } + + @Override + protected double getBackgroundRightU() { + return 0.499; + } + + @Override + protected void drawProgressBar(Tessellator tessellator, TextureManager renderEngine, int barMinX, int barMaxX, + int barMinY, int barMaxY, int zLevel) { + + double barHeight = Math.round((getProgress() * (this.height - 2))) + 2; + if (getProgress() > 0.00001) { + barHeight = Math.max(getBarMinHeight(), barHeight); + } + + double barMaxV = 1; + double barMinV = 1 - Math.min(1, Math.max(0, barHeight / this.height)); + + renderEngine.bindTexture(getBarTexture()); + tessellator.startDrawingQuads(); + tessellator.addVertexWithUV(this.absoluteX, this.absoluteY + this.height, zLevel, barLeftU, barMaxV); + tessellator + .addVertexWithUV(this.absoluteX + this.width, this.absoluteY + this.height, zLevel, barRightU, barMaxV); + tessellator.addVertexWithUV( + this.absoluteX + this.width, + this.absoluteY + this.height - barHeight, + zLevel, + barRightU, + barMinV); + tessellator + .addVertexWithUV(this.absoluteX, this.absoluteY + this.height - barHeight, zLevel, barLeftU, barMinV); + tessellator.draw(); + } + + protected double getBarMinHeight() { + return 3; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiVerticalProgressBar.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiVerticalProgressBar.java index bfca33ed..75399477 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiVerticalProgressBar.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/BeefGuiVerticalProgressBar.java @@ -11,85 +11,112 @@ import erogenousbeef.bigreactors.gui.BeefGuiControlBase; public abstract class BeefGuiVerticalProgressBar extends BeefGuiControlBase { - private final static int controlWidth = 20; - private final static int controlHeight = 64; - - protected ResourceLocation controlResource; - - private double backgroundLeftU = 0; - private double backgroundRightU = 0.32; - - private double gradationLeftU = 0.77; - private double gradationRightU = 1; - - protected float barAbsoluteMaxHeight; - - public BeefGuiVerticalProgressBar(BeefGuiBase container, int x, int y) { - super(container, x, y, controlWidth, controlHeight); - - controlResource = new ResourceLocation(BigReactors.GUI_DIRECTORY + getBackgroundTexture()); - - backgroundLeftU = getBackgroundLeftU(); - backgroundRightU = getBackgroundRightU(); - gradationLeftU = getGradationLeftU(); - gradationRightU = getGradationRightU(); - - barAbsoluteMaxHeight = this.height - 1; - - } - - protected boolean drawGradationMarks() { return false; } - protected String getBackgroundTexture() { return "controls/FluidTank.png"; } - - protected abstract float getProgress(); - protected abstract void drawProgressBar(Tessellator tessellator, TextureManager renderEngine, int barMinX, int barMaxX, int barMinY, int barMaxY, int zLevel); - - protected double getBackgroundLeftU() { return 0; } - protected double getBackgroundRightU() { return 0.32; } - protected double getGradationLeftU() { return 0.77; } - protected double getGradationRightU() { return 1; } - - @Override - public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY) { - if(!this.visible) { return; } - - // Draw the background - GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - renderEngine.bindTexture(controlResource); - Tessellator tessellator = Tessellator.instance; - tessellator.startDrawingQuads(); - tessellator.addVertexWithUV(this.absoluteX, this.absoluteY + this.height, 0, backgroundLeftU, 1.0); - tessellator.addVertexWithUV(this.absoluteX + this.width, this.absoluteY + this.height, 0, backgroundRightU, 1.0); - tessellator.addVertexWithUV(this.absoluteX + this.width, this.absoluteY, 0, backgroundRightU, 0); - tessellator.addVertexWithUV(this.absoluteX, this.absoluteY, 0, backgroundLeftU, 0); - tessellator.draw(); - - float progress = getProgress(); - // Draw the bar itself, on top of the background - if(progress > 0.0) { - int barHeight = Math.max(1, (int)Math.floor(progress * barAbsoluteMaxHeight)); - int barMinX = this.absoluteX + 1; - int barMaxX = this.absoluteX + this.width - 4; - int barMinY = this.absoluteY + this.height - barHeight; - int barMaxY = this.absoluteY + this.height - 1; - - this.drawProgressBar(tessellator, renderEngine, barMinX, barMaxX, barMinY, barMaxY, 1); - } - - if(drawGradationMarks()) { - GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - renderEngine.bindTexture(controlResource); - tessellator.startDrawingQuads(); - tessellator.addVertexWithUV(this.absoluteX, this.absoluteY + this.height, 2, gradationLeftU, 1.0); - tessellator.addVertexWithUV(this.absoluteX + this.width - 4, this.absoluteY + this.height, 2, gradationRightU, 1.0); - tessellator.addVertexWithUV(this.absoluteX + this.width - 4, this.absoluteY, 2, gradationRightU, 0); - tessellator.addVertexWithUV(this.absoluteX, this.absoluteY, 2, gradationLeftU, 0); - tessellator.draw(); - } - } - - @Override - public void drawForeground(TextureManager renderEngine, int mouseX, int mouseY) { - - } + + private final static int controlWidth = 20; + private final static int controlHeight = 64; + + protected ResourceLocation controlResource; + + private double backgroundLeftU = 0; + private double backgroundRightU = 0.32; + + private double gradationLeftU = 0.77; + private double gradationRightU = 1; + + protected float barAbsoluteMaxHeight; + + public BeefGuiVerticalProgressBar(BeefGuiBase container, int x, int y) { + super(container, x, y, controlWidth, controlHeight); + + controlResource = new ResourceLocation(BigReactors.GUI_DIRECTORY + getBackgroundTexture()); + + backgroundLeftU = getBackgroundLeftU(); + backgroundRightU = getBackgroundRightU(); + gradationLeftU = getGradationLeftU(); + gradationRightU = getGradationRightU(); + + barAbsoluteMaxHeight = this.height - 1; + + } + + protected boolean drawGradationMarks() { + return false; + } + + protected String getBackgroundTexture() { + return "controls/FluidTank.png"; + } + + protected abstract float getProgress(); + + protected abstract void drawProgressBar(Tessellator tessellator, TextureManager renderEngine, int barMinX, + int barMaxX, int barMinY, int barMaxY, int zLevel); + + protected double getBackgroundLeftU() { + return 0; + } + + protected double getBackgroundRightU() { + return 0.32; + } + + protected double getGradationLeftU() { + return 0.77; + } + + protected double getGradationRightU() { + return 1; + } + + @Override + public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY) { + if (!this.visible) { + return; + } + + // Draw the background + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + renderEngine.bindTexture(controlResource); + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + tessellator.addVertexWithUV(this.absoluteX, this.absoluteY + this.height, 0, backgroundLeftU, 1.0); + tessellator + .addVertexWithUV(this.absoluteX + this.width, this.absoluteY + this.height, 0, backgroundRightU, 1.0); + tessellator.addVertexWithUV(this.absoluteX + this.width, this.absoluteY, 0, backgroundRightU, 0); + tessellator.addVertexWithUV(this.absoluteX, this.absoluteY, 0, backgroundLeftU, 0); + tessellator.draw(); + + float progress = getProgress(); + // Draw the bar itself, on top of the background + if (progress > 0.0) { + int barHeight = Math.max(1, (int) Math.floor(progress * barAbsoluteMaxHeight)); + int barMinX = this.absoluteX + 1; + int barMaxX = this.absoluteX + this.width - 4; + int barMinY = this.absoluteY + this.height - barHeight; + int barMaxY = this.absoluteY + this.height - 1; + + this.drawProgressBar(tessellator, renderEngine, barMinX, barMaxX, barMinY, barMaxY, 1); + } + + if (drawGradationMarks()) { + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + renderEngine.bindTexture(controlResource); + tessellator.startDrawingQuads(); + tessellator.addVertexWithUV(this.absoluteX, this.absoluteY + this.height, 2, gradationLeftU, 1.0); + tessellator.addVertexWithUV( + this.absoluteX + this.width - 4, + this.absoluteY + this.height, + 2, + gradationRightU, + 1.0); + tessellator.addVertexWithUV(this.absoluteX + this.width - 4, this.absoluteY, 2, gradationRightU, 0); + tessellator.addVertexWithUV(this.absoluteX, this.absoluteY, 2, gradationLeftU, 0); + tessellator.draw(); + } + } + + @Override + public void drawForeground(TextureManager renderEngine, int mouseX, int mouseY) { + + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/GuiIconButton.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/GuiIconButton.java index 0055debd..1c19979c 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/GuiIconButton.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/GuiIconButton.java @@ -11,79 +11,90 @@ public class GuiIconButton extends GuiButton implements IBeefTooltipControl { - protected IIcon icon; - - protected String[] tooltip; - - public GuiIconButton(int buttonId, int x, int y, int width, int height) { - super(buttonId, x, y, width, height, ""); - icon = null; - tooltip = null; - } - - public GuiIconButton(int buttonId, int x, int y, int width, int height, IIcon icon) { - this(buttonId, x, y, width, height); - this.icon = icon; - tooltip = null; - } - - public GuiIconButton(int buttonId, int x, int y, int width, int height, IIcon icon, String[] tooltip) { - this(buttonId, x, y, width, height, icon); - this.tooltip = tooltip; - } - - public void setIcon(IIcon icon) { - this.icon = icon; - } + protected IIcon icon; + + protected String[] tooltip; + + public GuiIconButton(int buttonId, int x, int y, int width, int height) { + super(buttonId, x, y, width, height, ""); + icon = null; + tooltip = null; + } + + public GuiIconButton(int buttonId, int x, int y, int width, int height, IIcon icon) { + this(buttonId, x, y, width, height); + this.icon = icon; + tooltip = null; + } + + public GuiIconButton(int buttonId, int x, int y, int width, int height, IIcon icon, String[] tooltip) { + this(buttonId, x, y, width, height, icon); + this.tooltip = tooltip; + } + + public void setIcon(IIcon icon) { + this.icon = icon; + } /** * Draws this button to the screen. */ - public void drawButton(Minecraft par1Minecraft, int par2, int par3) - { - if (this.visible) - { + public void drawButton(Minecraft par1Minecraft, int par2, int par3) { + if (this.visible) { GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); // Draw the border - this.field_146123_n = par2 >= this.xPosition && par3 >= this.yPosition && par2 < this.xPosition + this.width && par3 < this.yPosition + this.height; + this.field_146123_n = par2 >= this.xPosition && par3 >= this.yPosition + && par2 < this.xPosition + this.width + && par3 < this.yPosition + this.height; int k = this.getHoverState(this.field_146123_n); int borderColor = k == 2 ? 0xFF5555AA : 0xFF000000; - drawRect(this.xPosition, this.yPosition, this.xPosition + this.width, this.yPosition + this.height, borderColor); - + drawRect( + this.xPosition, + this.yPosition, + this.xPosition + this.width, + this.yPosition + this.height, + borderColor); + this.mouseDragged(par1Minecraft, par2, par3); // Draw the icon - if(this.icon != null) { + if (this.icon != null) { GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); par1Minecraft.renderEngine.bindTexture(TextureMap.locationBlocksTexture); - this.drawTexturedModelRectFromIcon(this.xPosition + 1, this.yPosition + 1, this.icon, this.width-2, this.height-2); + this.drawTexturedModelRectFromIcon( + this.xPosition + 1, + this.yPosition + 1, + this.icon, + this.width - 2, + this.height - 2); } } } - @Override - public boolean isMouseOver(int mouseX, int mouseY) { - if(mouseX < xPosition || mouseX > xPosition+width || mouseY < yPosition || mouseY > yPosition+height) { return false; } - return true; - } - - public void setTooltip(String[] tooltip) { - this.tooltip = tooltip; - } - - @Override - public String[] getTooltip() { - if(this.visible) { - return tooltip; - } - else { - return null; - } - } - - @Override - public boolean isVisible() { - return visible; - } + @Override + public boolean isMouseOver(int mouseX, int mouseY) { + if (mouseX < xPosition || mouseX > xPosition + width || mouseY < yPosition || mouseY > yPosition + height) { + return false; + } + return true; + } + + public void setTooltip(String[] tooltip) { + this.tooltip = tooltip; + } + + @Override + public String[] getTooltip() { + if (this.visible) { + return tooltip; + } else { + return null; + } + } + + @Override + public boolean isVisible() { + return visible; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/GuiSelectableButton.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/GuiSelectableButton.java index 17c57c59..89556a21 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/GuiSelectableButton.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/GuiSelectableButton.java @@ -12,66 +12,86 @@ public class GuiSelectableButton extends GuiButton implements IBeefTooltipControl { - private boolean selected; - private int selectedColor; - private IIcon icon; - - private BeefGuiBase window; - - public GuiSelectableButton(int id, int x, int y, IIcon icon, int selectedColor, BeefGuiBase containingWindow) { - super(id, x, y, 24, 24, ""); - selected = false; - this.icon = icon; - this.selectedColor = selectedColor; - window = containingWindow; - } - - public void setSelected(boolean selected) { - this.selected = selected; - } - - public boolean isSelected() { return this.selected; } - - @Override - public void drawButton(Minecraft minecraft, int par2, int par3) { - if (this.visible) - { - minecraft.getTextureManager().bindTexture(TextureMap.locationBlocksTexture); - this.field_146123_n = par2 >= this.xPosition && par3 >= this.yPosition && par2 < this.xPosition + this.width && par3 < this.yPosition + this.height; - + private boolean selected; + private int selectedColor; + private IIcon icon; + + private BeefGuiBase window; + + public GuiSelectableButton(int id, int x, int y, IIcon icon, int selectedColor, BeefGuiBase containingWindow) { + super(id, x, y, 24, 24, ""); + selected = false; + this.icon = icon; + this.selectedColor = selectedColor; + window = containingWindow; + } + + public void setSelected(boolean selected) { + this.selected = selected; + } + + public boolean isSelected() { + return this.selected; + } + + @Override + public void drawButton(Minecraft minecraft, int par2, int par3) { + if (this.visible) { + minecraft.getTextureManager() + .bindTexture(TextureMap.locationBlocksTexture); + this.field_146123_n = par2 >= this.xPosition && par3 >= this.yPosition + && par2 < this.xPosition + this.width + && par3 < this.yPosition + this.height; + int k = this.getHoverState(this.field_146123_n); int borderColor = this.selected ? this.selectedColor : 0xFF000000; int bgColor = 0xFF565656; // disabled - if(k == 1) { - bgColor = 0xFF999999; // enabled - } - else if(k == 2) { - bgColor = 0xFF9999CC; // hovered - borderColor = this.selected ? this.selectedColor : 0xFF5555AA; + if (k == 1) { + bgColor = 0xFF999999; // enabled + } else if (k == 2) { + bgColor = 0xFF9999CC; // hovered + borderColor = this.selected ? this.selectedColor : 0xFF5555AA; } - this.drawRect(this.xPosition, this.yPosition, this.xPosition+this.width, this.yPosition+this.height, borderColor); - this.drawRect(this.xPosition+1, this.yPosition+1, this.xPosition+this.width-1, this.yPosition+this.height-1, bgColor); + this.drawRect( + this.xPosition, + this.yPosition, + this.xPosition + this.width, + this.yPosition + this.height, + borderColor); + this.drawRect( + this.xPosition + 1, + this.yPosition + 1, + this.xPosition + this.width - 1, + this.yPosition + this.height - 1, + bgColor); GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); - this.drawTexturedModelRectFromIcon(this.xPosition+1, this.yPosition+1, this.icon, this.width-2, this.height-2); - + this.drawTexturedModelRectFromIcon( + this.xPosition + 1, + this.yPosition + 1, + this.icon, + this.width - 2, + this.height - 2); + this.mouseDragged(minecraft, par2, par3); } - } - - @Override - public boolean isMouseOver(int mouseX, int mouseY) { - if(mouseX < xPosition || mouseX > xPosition+width || mouseY < yPosition || mouseY > yPosition+height) { return false; } - return true; - } - - @Override - public String[] getTooltip() { - return new String[] { this.displayString }; - } - - @Override - public boolean isVisible() { - return visible; - } + } + + @Override + public boolean isMouseOver(int mouseX, int mouseY) { + if (mouseX < xPosition || mouseX > xPosition + width || mouseY < yPosition || mouseY > yPosition + height) { + return false; + } + return true; + } + + @Override + public String[] getTooltip() { + return new String[] { this.displayString }; + } + + @Override + public boolean isVisible() { + return visible; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/BeefGuiGrabSource.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/BeefGuiGrabSource.java index 574a9df3..a1c4c505 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/BeefGuiGrabSource.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/BeefGuiGrabSource.java @@ -14,53 +14,64 @@ */ public class BeefGuiGrabSource extends BeefGuiControlBase implements IBeefTooltipControl { - protected static final int defaultHoverColor = 0x33ffffff; // 20% alpha white - - protected IBeefGuiGrabbable grabbable; - protected int hoverColor; - - public BeefGuiGrabSource(BeefGuiBase container, int x, int y, IBeefGuiGrabbable grabbable) { - super(container, x, y, 16, 16); - this.grabbable = grabbable; - hoverColor = defaultHoverColor; - } + protected static final int defaultHoverColor = 0x33ffffff; // 20% alpha white - @Override - public void drawForeground(TextureManager renderEngine, int mouseX, int mouseY) { - if(this.grabbable != null) { - renderEngine.bindTexture( TextureMap.locationBlocksTexture ); - GL11.glColor4f(1f, 1f, 1f, 1f); - this.guiContainer.drawTexturedModelRectFromIcon(relativeX, relativeY, grabbable.getIcon(), width, height); - } - else { - this.drawRect(this.relativeX, this.relativeY, this.relativeX+this.width, this.relativeY+this.height, 0x66ff0000); // Red error spot - } - - if(this.isMouseOver(mouseX, mouseY)) { - this.drawRect(this.relativeX, this.relativeY, this.relativeX+this.width, this.relativeY+this.height, hoverColor); - } - } - - public IBeefGuiGrabbable getGrabbable() { return grabbable; } + protected IBeefGuiGrabbable grabbable; + protected int hoverColor; - @Override - public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY) { - // Draw Border - this.drawRect(absoluteX-1, absoluteY-1, absoluteX+width+1, absoluteY+height+1, 0xff222222); - - // Draw Background - this.drawRect(absoluteX, absoluteY, absoluteX+width, absoluteY+height, 0xff777777); - } - - @Override - public void onMouseClicked(int mouseX, int mouseY, int buttonIndex) { - if(buttonIndex == 0 && isMouseOver(mouseX, mouseY)) { - this.guiContainer.setGrabbedItem(grabbable); - } - } + public BeefGuiGrabSource(BeefGuiBase container, int x, int y, IBeefGuiGrabbable grabbable) { + super(container, x, y, 16, 16); + this.grabbable = grabbable; + hoverColor = defaultHoverColor; + } - @Override - public String[] getTooltip() { - return new String[] { this.grabbable.getName() }; - } + @Override + public void drawForeground(TextureManager renderEngine, int mouseX, int mouseY) { + if (this.grabbable != null) { + renderEngine.bindTexture(TextureMap.locationBlocksTexture); + GL11.glColor4f(1f, 1f, 1f, 1f); + this.guiContainer.drawTexturedModelRectFromIcon(relativeX, relativeY, grabbable.getIcon(), width, height); + } else { + this.drawRect( + this.relativeX, + this.relativeY, + this.relativeX + this.width, + this.relativeY + this.height, + 0x66ff0000); // Red error spot + } + + if (this.isMouseOver(mouseX, mouseY)) { + this.drawRect( + this.relativeX, + this.relativeY, + this.relativeX + this.width, + this.relativeY + this.height, + hoverColor); + } + } + + public IBeefGuiGrabbable getGrabbable() { + return grabbable; + } + + @Override + public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY) { + // Draw Border + this.drawRect(absoluteX - 1, absoluteY - 1, absoluteX + width + 1, absoluteY + height + 1, 0xff222222); + + // Draw Background + this.drawRect(absoluteX, absoluteY, absoluteX + width, absoluteY + height, 0xff777777); + } + + @Override + public void onMouseClicked(int mouseX, int mouseY, int buttonIndex) { + if (buttonIndex == 0 && isMouseOver(mouseX, mouseY)) { + this.guiContainer.setGrabbedItem(grabbable); + } + } + + @Override + public String[] getTooltip() { + return new String[] { this.grabbable.getName() }; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/BeefGuiGrabTarget.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/BeefGuiGrabTarget.java index a762334e..a474dd7b 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/BeefGuiGrabTarget.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/BeefGuiGrabTarget.java @@ -10,87 +10,93 @@ public abstract class BeefGuiGrabTarget extends BeefGuiControlBase { - protected static final int hoverColor = 0x33ffffff; // 20% opacity white - protected static final int invalidHoverColor = 0x33ff9999; // 20% opacity red - - protected IBeefGuiGrabbable grabbable; - - - protected BeefGuiGrabTarget(BeefGuiBase container, int x, int y) { - super(container, x, y, 16, 16); - grabbable = null; - } - - @Override - public void drawForeground(TextureManager renderEngine, int mouseX, int mouseY) { - if(grabbable != null) { - renderEngine.bindTexture(TextureMap.locationBlocksTexture); - GL11.glColor4f(1f, 1f, 1f, 1f); - this.guiContainer.drawTexturedModelRectFromIcon(relativeX, relativeY, grabbable.getIcon(), width, height); - } - - if(this.isMouseOver(mouseX, mouseY)) { - if(this.guiContainer.getGrabbedItem() != null && isAcceptedGrab(this.guiContainer.getGrabbedItem())) { - this.drawRect(this.relativeX, this.relativeY, this.relativeX+this.width, this.relativeY+this.height, invalidHoverColor); - } - else { - this.drawRect(this.relativeX, this.relativeY, this.relativeX+this.width, this.relativeY+this.height, hoverColor); - } - } - } - - @Override - public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY) { - } - - @Override - public void onMouseClicked(int mouseX, int mouseY, int buttonIndex) { - if(isMouseOver(mouseX, mouseY)) { - if(buttonIndex == 0) { - setSlotContents(this.guiContainer.getGrabbedItem()); - this.guiContainer.setGrabbedItem(null); - } - else { - clearSlot(); - } - } - } - - private void clearSlot() { - this.grabbable = null; - this.onSlotCleared(); - } - - public void setSlotContents(IBeefGuiGrabbable grabbedItem) { - if(grabbedItem == null) { - this.clearSlot(); - } - else { - if(this.grabbable != grabbedItem) { - this.grabbable = grabbedItem; - this.onSlotSet(); - } - } - } - - /** - * Called when the grab-object is cleared from this slot, - * either by right-clicking or left-clicking with nothing selected. - */ - public abstract void onSlotCleared(); - - /** - * Called when the grab-object is set or changed in this slot. - */ - public abstract void onSlotSet(); - - /** - * Called when we're trying to determine if the grabbable item is - * compatible with this target. Return true if the user can "drop" - * the item here. - * Null is always accepted. You do not have to check for it. - * @param grabbedItem An IBeefGuiGrabbable that has been grabbed by the user. - * @return True if the user can "drop" the Grabbable here, false otherwise. - */ - public abstract boolean isAcceptedGrab(IBeefGuiGrabbable grabbedItem); + protected static final int hoverColor = 0x33ffffff; // 20% opacity white + protected static final int invalidHoverColor = 0x33ff9999; // 20% opacity red + + protected IBeefGuiGrabbable grabbable; + + protected BeefGuiGrabTarget(BeefGuiBase container, int x, int y) { + super(container, x, y, 16, 16); + grabbable = null; + } + + @Override + public void drawForeground(TextureManager renderEngine, int mouseX, int mouseY) { + if (grabbable != null) { + renderEngine.bindTexture(TextureMap.locationBlocksTexture); + GL11.glColor4f(1f, 1f, 1f, 1f); + this.guiContainer.drawTexturedModelRectFromIcon(relativeX, relativeY, grabbable.getIcon(), width, height); + } + + if (this.isMouseOver(mouseX, mouseY)) { + if (this.guiContainer.getGrabbedItem() != null && isAcceptedGrab(this.guiContainer.getGrabbedItem())) { + this.drawRect( + this.relativeX, + this.relativeY, + this.relativeX + this.width, + this.relativeY + this.height, + invalidHoverColor); + } else { + this.drawRect( + this.relativeX, + this.relativeY, + this.relativeX + this.width, + this.relativeY + this.height, + hoverColor); + } + } + } + + @Override + public void drawBackground(TextureManager renderEngine, int mouseX, int mouseY) {} + + @Override + public void onMouseClicked(int mouseX, int mouseY, int buttonIndex) { + if (isMouseOver(mouseX, mouseY)) { + if (buttonIndex == 0) { + setSlotContents(this.guiContainer.getGrabbedItem()); + this.guiContainer.setGrabbedItem(null); + } else { + clearSlot(); + } + } + } + + private void clearSlot() { + this.grabbable = null; + this.onSlotCleared(); + } + + public void setSlotContents(IBeefGuiGrabbable grabbedItem) { + if (grabbedItem == null) { + this.clearSlot(); + } else { + if (this.grabbable != grabbedItem) { + this.grabbable = grabbedItem; + this.onSlotSet(); + } + } + } + + /** + * Called when the grab-object is cleared from this slot, + * either by right-clicking or left-clicking with nothing selected. + */ + public abstract void onSlotCleared(); + + /** + * Called when the grab-object is set or changed in this slot. + */ + public abstract void onSlotSet(); + + /** + * Called when we're trying to determine if the grabbable item is + * compatible with this target. Return true if the user can "drop" + * the item here. + * Null is always accepted. You do not have to check for it. + * + * @param grabbedItem An IBeefGuiGrabbable that has been grabbed by the user. + * @return True if the user can "drop" the Grabbable here, false otherwise. + */ + public abstract boolean isAcceptedGrab(IBeefGuiGrabbable grabbedItem); } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/IBeefGuiGrabbable.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/IBeefGuiGrabbable.java index d5bfd348..288d9d7a 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/IBeefGuiGrabbable.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/IBeefGuiGrabbable.java @@ -4,6 +4,7 @@ public interface IBeefGuiGrabbable { - public IIcon getIcon(); - public String getName(); + public IIcon getIcon(); + + public String getName(); } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/RedNetConfigGrabTarget.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/RedNetConfigGrabTarget.java index af02889c..de3f8cf2 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/RedNetConfigGrabTarget.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/RedNetConfigGrabTarget.java @@ -7,53 +7,58 @@ public class RedNetConfigGrabTarget extends BeefGuiGrabTarget implements IBeefTooltipControl { - TileEntityReactorRedNetPort port; - int channel; - String tooltip; - TileEntityReactorRedNetPort.CircuitType currentCircuitType; - - public RedNetConfigGrabTarget(BeefGuiBase container, int x, int y, TileEntityReactorRedNetPort port, int channel) { - super(container, x, y); - this.port = port; - this.channel = channel; - this.tooltip = null; - currentCircuitType = port.getChannelCircuitType(channel); - } - - @Override - public void onSlotCleared() { - currentCircuitType = TileEntityReactorRedNetPort.CircuitType.DISABLED; - tooltip = null; - - if(guiContainer instanceof GuiReactorRedNetPort) { - ((GuiReactorRedNetPort)guiContainer).onChannelChanged(this.channel); - } - } - - @Override - public void onSlotSet() { - currentCircuitType = ((RedNetConfigGrabbable)this.grabbable).getCircuitType(); - tooltip = ((RedNetConfigGrabbable)this.grabbable).getName(); - - if(guiContainer instanceof GuiReactorRedNetPort) { - ((GuiReactorRedNetPort)guiContainer).onChannelChanged(this.channel); - } - } - - @Override - public boolean isAcceptedGrab(IBeefGuiGrabbable grabbedItem) { - return grabbedItem instanceof RedNetConfigGrabbable; - } - - public boolean hasChanged() { - return currentCircuitType != this.port.getChannelCircuitType(channel); - } - - public int getChannel() { return channel; } - public TileEntityReactorRedNetPort.CircuitType getCircuitType() { return this.currentCircuitType; } - - @Override - public String[] getTooltip() { - return new String[] { tooltip }; - } + TileEntityReactorRedNetPort port; + int channel; + String tooltip; + TileEntityReactorRedNetPort.CircuitType currentCircuitType; + + public RedNetConfigGrabTarget(BeefGuiBase container, int x, int y, TileEntityReactorRedNetPort port, int channel) { + super(container, x, y); + this.port = port; + this.channel = channel; + this.tooltip = null; + currentCircuitType = port.getChannelCircuitType(channel); + } + + @Override + public void onSlotCleared() { + currentCircuitType = TileEntityReactorRedNetPort.CircuitType.DISABLED; + tooltip = null; + + if (guiContainer instanceof GuiReactorRedNetPort) { + ((GuiReactorRedNetPort) guiContainer).onChannelChanged(this.channel); + } + } + + @Override + public void onSlotSet() { + currentCircuitType = ((RedNetConfigGrabbable) this.grabbable).getCircuitType(); + tooltip = ((RedNetConfigGrabbable) this.grabbable).getName(); + + if (guiContainer instanceof GuiReactorRedNetPort) { + ((GuiReactorRedNetPort) guiContainer).onChannelChanged(this.channel); + } + } + + @Override + public boolean isAcceptedGrab(IBeefGuiGrabbable grabbedItem) { + return grabbedItem instanceof RedNetConfigGrabbable; + } + + public boolean hasChanged() { + return currentCircuitType != this.port.getChannelCircuitType(channel); + } + + public int getChannel() { + return channel; + } + + public TileEntityReactorRedNetPort.CircuitType getCircuitType() { + return this.currentCircuitType; + } + + @Override + public String[] getTooltip() { + return new String[] { tooltip }; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/RedNetConfigGrabbable.java b/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/RedNetConfigGrabbable.java index 427d5b1e..718e932b 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/RedNetConfigGrabbable.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/controls/grab/RedNetConfigGrabbable.java @@ -1,38 +1,39 @@ package erogenousbeef.bigreactors.gui.controls.grab; import net.minecraft.util.IIcon; + import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorRedNetPort; public class RedNetConfigGrabbable implements IBeefGuiGrabbable { - protected String name; - protected IIcon icon; - protected TileEntityReactorRedNetPort.CircuitType circuitType; - - public RedNetConfigGrabbable(String name, IIcon icon, TileEntityReactorRedNetPort.CircuitType circuitType) { - this.name = name; - this.icon = icon; - this.circuitType = circuitType; - } - - @Override - public IIcon getIcon() { - return icon; - } - - public TileEntityReactorRedNetPort.CircuitType getCircuitType() { - return circuitType; - } - - @Override - public boolean equals(Object other) { - if(other instanceof RedNetConfigGrabbable) { - return this.circuitType == ((RedNetConfigGrabbable)other).circuitType; - } - return false; - } - - public String getName() { - return name; - } + protected String name; + protected IIcon icon; + protected TileEntityReactorRedNetPort.CircuitType circuitType; + + public RedNetConfigGrabbable(String name, IIcon icon, TileEntityReactorRedNetPort.CircuitType circuitType) { + this.name = name; + this.icon = icon; + this.circuitType = circuitType; + } + + @Override + public IIcon getIcon() { + return icon; + } + + public TileEntityReactorRedNetPort.CircuitType getCircuitType() { + return circuitType; + } + + @Override + public boolean equals(Object other) { + if (other instanceof RedNetConfigGrabbable) { + return this.circuitType == ((RedNetConfigGrabbable) other).circuitType; + } + return false; + } + + public String getName() { + return name; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/slot/SlotReactorInput.java b/src/main/java/erogenousbeef/bigreactors/gui/slot/SlotReactorInput.java index 8e6625ba..8238e604 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/slot/SlotReactorInput.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/slot/SlotReactorInput.java @@ -3,27 +3,28 @@ import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; + import erogenousbeef.bigreactors.api.registry.Reactants; public class SlotReactorInput extends Slot { - boolean fuel = true; - - public SlotReactorInput(IInventory par1iInventory, int par2, int par3, - int par4, boolean fuel) { - super(par1iInventory, par2, par3, par4); - this.fuel = fuel; - } + boolean fuel = true; + + public SlotReactorInput(IInventory par1iInventory, int par2, int par3, int par4, boolean fuel) { + super(par1iInventory, par2, par3, par4); + this.fuel = fuel; + } + + @Override + public boolean isItemValid(ItemStack stack) { + if (stack == null) { + return false; + } - @Override - public boolean isItemValid(ItemStack stack) { - if(stack == null) { return false; } - - if(fuel) { - return Reactants.isFuel(stack); - } - else { - return Reactants.isWaste(stack); - } - } + if (fuel) { + return Reactants.isFuel(stack); + } else { + return Reactants.isWaste(stack); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/slot/SlotRemoveOnly.java b/src/main/java/erogenousbeef/bigreactors/gui/slot/SlotRemoveOnly.java index 4259d136..ff4bb0a2 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/slot/SlotRemoveOnly.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/slot/SlotRemoveOnly.java @@ -6,13 +6,12 @@ public class SlotRemoveOnly extends Slot { - public SlotRemoveOnly(IInventory par1iInventory, int par2, int par3, - int par4) { - super(par1iInventory, par2, par3, par4); - } - - @Override - public boolean isItemValid(ItemStack stack) { - return false; - } + public SlotRemoveOnly(IInventory par1iInventory, int par2, int par3, int par4) { + super(par1iInventory, par2, par3, par4); + } + + @Override + public boolean isItemValid(ItemStack stack) { + return false; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/gui/slot/SlotRestrictedOreTypes.java b/src/main/java/erogenousbeef/bigreactors/gui/slot/SlotRestrictedOreTypes.java index 58ae4ba2..c0460900 100644 --- a/src/main/java/erogenousbeef/bigreactors/gui/slot/SlotRestrictedOreTypes.java +++ b/src/main/java/erogenousbeef/bigreactors/gui/slot/SlotRestrictedOreTypes.java @@ -1,38 +1,41 @@ package erogenousbeef.bigreactors.gui.slot; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; -import scala.actors.threadpool.Arrays; + import cofh.core.util.oredict.OreDictionaryArbiter; public class SlotRestrictedOreTypes extends Slot { - protected List acceptedTypes; - - public SlotRestrictedOreTypes(IInventory par1iInventory, int par2, int par3, - int par4, String[] acceptedOreDictionaryNames) { - super(par1iInventory, par2, par3, par4); - - acceptedTypes = new ArrayList(Arrays.asList(acceptedOreDictionaryNames)); - } - - @Override - public boolean isItemValid(ItemStack stack) { - if(stack == null) { return false; } - - ArrayList oreNames = OreDictionaryArbiter.getAllOreNames(stack); - if(oreNames != null) { - for(String oreName : oreNames) { - if(acceptedTypes.contains(oreName)) { - return true; - } - } - } - - return false; - } + protected List acceptedTypes; + + public SlotRestrictedOreTypes(IInventory par1iInventory, int par2, int par3, int par4, + String[] acceptedOreDictionaryNames) { + super(par1iInventory, par2, par3, par4); + + acceptedTypes = new ArrayList(Arrays.asList(acceptedOreDictionaryNames)); + } + + @Override + public boolean isItemValid(ItemStack stack) { + if (stack == null) { + return false; + } + + ArrayList oreNames = OreDictionaryArbiter.getAllOreNames(stack); + if (oreNames != null) { + for (String oreName : oreNames) { + if (acceptedTypes.contains(oreName)) { + return true; + } + } + } + + return false; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/CommonPacketHandler.java b/src/main/java/erogenousbeef/bigreactors/net/CommonPacketHandler.java index 6a650559..f088da1b 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/CommonPacketHandler.java +++ b/src/main/java/erogenousbeef/bigreactors/net/CommonPacketHandler.java @@ -27,20 +27,19 @@ public class CommonPacketHandler { - /* - * Naming Convention: - * Client >> Server - * [Machine|TileEntity]ChangeMessage -- a full state change message (for large/batch commits) - * [Machine|TileEntity]Change[Datum]Message -- a client request to change [Datum] - * - * Server >> Client - * [Machine|TileEntity]UpdateMessage -- a full state update - * [Machine|TileEntity]Update[Datum]Message -- an update for only [Datum] - * - * Generic Format: [Machine|TileEntity][Operation][Type]Message - */ - - public static final SimpleNetworkWrapper INSTANCE = NetworkRegistry.INSTANCE.newSimpleChannel(BigReactors.CHANNEL.toLowerCase()); + /* + * Naming Convention: + * Client >> Server + * [Machine|TileEntity]ChangeMessage -- a full state change message (for large/batch commits) + * [Machine|TileEntity]Change[Datum]Message -- a client request to change [Datum] + * Server >> Client + * [Machine|TileEntity]UpdateMessage -- a full state update + * [Machine|TileEntity]Update[Datum]Message -- an update for only [Datum] + * Generic Format: [Machine|TileEntity][Operation][Type]Message + */ + + public static final SimpleNetworkWrapper INSTANCE = NetworkRegistry.INSTANCE + .newSimpleChannel(BigReactors.CHANNEL.toLowerCase()); /** * Initialize the messages. Note that all messages (server>client and client>server) @@ -48,28 +47,89 @@ public class CommonPacketHandler { */ // Be careful not to reference any client code in your message handlers, such as WorldClient! public static void init() { - // Server >> Client Messages + // Server >> Client Messages INSTANCE.registerMessage(DeviceUpdateMessage.Handler.class, DeviceUpdateMessage.class, 1, Side.CLIENT); - INSTANCE.registerMessage(DeviceUpdateRotationMessage.Handler.class, DeviceUpdateRotationMessage.class, 3, Side.CLIENT); - INSTANCE.registerMessage(DeviceUpdateExposureMessage.Handler.class, DeviceUpdateExposureMessage.class, 5, Side.CLIENT); + INSTANCE.registerMessage( + DeviceUpdateRotationMessage.Handler.class, + DeviceUpdateRotationMessage.class, + 3, + Side.CLIENT); + INSTANCE.registerMessage( + DeviceUpdateExposureMessage.Handler.class, + DeviceUpdateExposureMessage.class, + 5, + Side.CLIENT); INSTANCE.registerMessage(ControlRodUpdateMessage.Handler.class, ControlRodUpdateMessage.class, 9, Side.CLIENT); INSTANCE.registerMessage(ReactorUpdateMessage.Handler.class, ReactorUpdateMessage.class, 11, Side.CLIENT); - INSTANCE.registerMessage(ReactorUpdateWasteEjectionMessage.Handler.class, ReactorUpdateWasteEjectionMessage.class, 13, Side.CLIENT); + INSTANCE.registerMessage( + ReactorUpdateWasteEjectionMessage.Handler.class, + ReactorUpdateWasteEjectionMessage.class, + 13, + Side.CLIENT); INSTANCE.registerMessage(TurbineUpdateMessage.Handler.class, TurbineUpdateMessage.class, 15, Side.CLIENT); // Client >> Server Messages - INSTANCE.registerMessage(MachineCommandActivateMessage.Handler.class, MachineCommandActivateMessage.class, 0, Side.SERVER); - INSTANCE.registerMessage(DeviceChangeExposureMessage.Handler.class, DeviceChangeExposureMessage.class, 2, Side.SERVER); - INSTANCE.registerMessage(ControlRodChangeNameMessage.Handler.class, ControlRodChangeNameMessage.class, 4, Side.SERVER); - INSTANCE.registerMessage(ControlRodChangeInsertionMessage.Handler.class, ControlRodChangeInsertionMessage.class, 6, Side.SERVER); - INSTANCE.registerMessage(ReactorRedNetPortChangeMessage.Handler.class, ReactorRedNetPortChangeMessage.class, 8, Side.SERVER); - INSTANCE.registerMessage(ReactorRedstonePortChangeMessage.Handler.class, ReactorRedstonePortChangeMessage.class, 10, Side.SERVER); - INSTANCE.registerMessage(ReactorCommandEjectMessage.Handler.class, ReactorCommandEjectMessage.class, 12, Side.SERVER); - INSTANCE.registerMessage(ReactorCommandEjectToPortMessage.Handler.class, ReactorCommandEjectToPortMessage.class, 14, Side.SERVER); - INSTANCE.registerMessage(ReactorChangeWasteEjectionMessage.Handler.class, ReactorChangeWasteEjectionMessage.class, 16, Side.SERVER); - INSTANCE.registerMessage(ReactorAccessPortChangeDirectionMessage.Handler.class, ReactorAccessPortChangeDirectionMessage.class, 18, Side.SERVER); - INSTANCE.registerMessage(TurbineChangeMaxIntakeMessage.Handler.class, TurbineChangeMaxIntakeMessage.class, 20, Side.SERVER); - INSTANCE.registerMessage(TurbineChangeVentMessage.Handler.class, TurbineChangeVentMessage.class, 22, Side.SERVER); - INSTANCE.registerMessage(TurbineChangeInductorMessage.Handler.class, TurbineChangeInductorMessage.class, 24, Side.SERVER); + INSTANCE.registerMessage( + MachineCommandActivateMessage.Handler.class, + MachineCommandActivateMessage.class, + 0, + Side.SERVER); + INSTANCE.registerMessage( + DeviceChangeExposureMessage.Handler.class, + DeviceChangeExposureMessage.class, + 2, + Side.SERVER); + INSTANCE.registerMessage( + ControlRodChangeNameMessage.Handler.class, + ControlRodChangeNameMessage.class, + 4, + Side.SERVER); + INSTANCE.registerMessage( + ControlRodChangeInsertionMessage.Handler.class, + ControlRodChangeInsertionMessage.class, + 6, + Side.SERVER); + INSTANCE.registerMessage( + ReactorRedNetPortChangeMessage.Handler.class, + ReactorRedNetPortChangeMessage.class, + 8, + Side.SERVER); + INSTANCE.registerMessage( + ReactorRedstonePortChangeMessage.Handler.class, + ReactorRedstonePortChangeMessage.class, + 10, + Side.SERVER); + INSTANCE.registerMessage( + ReactorCommandEjectMessage.Handler.class, + ReactorCommandEjectMessage.class, + 12, + Side.SERVER); + INSTANCE.registerMessage( + ReactorCommandEjectToPortMessage.Handler.class, + ReactorCommandEjectToPortMessage.class, + 14, + Side.SERVER); + INSTANCE.registerMessage( + ReactorChangeWasteEjectionMessage.Handler.class, + ReactorChangeWasteEjectionMessage.class, + 16, + Side.SERVER); + INSTANCE.registerMessage( + ReactorAccessPortChangeDirectionMessage.Handler.class, + ReactorAccessPortChangeDirectionMessage.class, + 18, + Side.SERVER); + INSTANCE.registerMessage( + TurbineChangeMaxIntakeMessage.Handler.class, + TurbineChangeMaxIntakeMessage.class, + 20, + Side.SERVER); + INSTANCE + .registerMessage(TurbineChangeVentMessage.Handler.class, TurbineChangeVentMessage.class, 22, Side.SERVER); + INSTANCE.registerMessage( + TurbineChangeInductorMessage.Handler.class, + TurbineChangeInductorMessage.class, + 24, + Side.SERVER); } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/helpers/RedNetChange.java b/src/main/java/erogenousbeef/bigreactors/net/helpers/RedNetChange.java index 7bfdd889..e0cf1c65 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/helpers/RedNetChange.java +++ b/src/main/java/erogenousbeef/bigreactors/net/helpers/RedNetChange.java @@ -1,62 +1,74 @@ package erogenousbeef.bigreactors.net.helpers; -import io.netty.buffer.ByteBuf; import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorRedNetPort.CircuitType; import erogenousbeef.core.common.CoordTriplet; +import io.netty.buffer.ByteBuf; public class RedNetChange { - int channelID; - CircuitType circuitType; - boolean pulseOrToggle; - CoordTriplet coord; - - public RedNetChange(int channelID, CircuitType circuitType, boolean pulseOrToggle, CoordTriplet coord) { - this.channelID = channelID; - this.circuitType = circuitType; - this.pulseOrToggle = pulseOrToggle; - this.coord = coord; - } - - public static RedNetChange fromBytes(ByteBuf buf) { - int channelID = buf.readInt(); - CircuitType type = CircuitType.s_Types[buf.readInt()]; - boolean pulseOrToggle = false; - - if(CircuitType.canBeToggledBetweenPulseAndNormal(type)) { - pulseOrToggle = buf.readBoolean(); - } - - CoordTriplet coord = null; - if(CircuitType.hasCoordinate(type)) { - boolean coordNull = buf.readBoolean(); - if(!coordNull) { - coord = new CoordTriplet(buf.readInt(), buf.readInt(), buf.readInt()); - } - } - - return new RedNetChange(channelID, type, pulseOrToggle, coord); - } - - public void toBytes(ByteBuf buf) { - buf.writeInt(channelID); - buf.writeInt(circuitType.ordinal()); - - if(CircuitType.canBeToggledBetweenPulseAndNormal(circuitType)) { - buf.writeBoolean(pulseOrToggle); - } - - if(CircuitType.hasCoordinate(circuitType)) { - buf.writeBoolean(coord == null); - if(coord != null) { - buf.writeInt(coord.x); - buf.writeInt(coord.y); - buf.writeInt(coord.z); - } - } - } - - public int getChannel() { return channelID; } - public CircuitType getType() { return this.circuitType; } - public CoordTriplet getCoord() { return coord; } - public boolean getPulseOrToggle() { return this.pulseOrToggle; } + + int channelID; + CircuitType circuitType; + boolean pulseOrToggle; + CoordTriplet coord; + + public RedNetChange(int channelID, CircuitType circuitType, boolean pulseOrToggle, CoordTriplet coord) { + this.channelID = channelID; + this.circuitType = circuitType; + this.pulseOrToggle = pulseOrToggle; + this.coord = coord; + } + + public static RedNetChange fromBytes(ByteBuf buf) { + int channelID = buf.readInt(); + CircuitType type = CircuitType.s_Types[buf.readInt()]; + boolean pulseOrToggle = false; + + if (CircuitType.canBeToggledBetweenPulseAndNormal(type)) { + pulseOrToggle = buf.readBoolean(); + } + + CoordTriplet coord = null; + if (CircuitType.hasCoordinate(type)) { + boolean coordNull = buf.readBoolean(); + if (!coordNull) { + coord = new CoordTriplet(buf.readInt(), buf.readInt(), buf.readInt()); + } + } + + return new RedNetChange(channelID, type, pulseOrToggle, coord); + } + + public void toBytes(ByteBuf buf) { + buf.writeInt(channelID); + buf.writeInt(circuitType.ordinal()); + + if (CircuitType.canBeToggledBetweenPulseAndNormal(circuitType)) { + buf.writeBoolean(pulseOrToggle); + } + + if (CircuitType.hasCoordinate(circuitType)) { + buf.writeBoolean(coord == null); + if (coord != null) { + buf.writeInt(coord.x); + buf.writeInt(coord.y); + buf.writeInt(coord.z); + } + } + } + + public int getChannel() { + return channelID; + } + + public CircuitType getType() { + return this.circuitType; + } + + public CoordTriplet getCoord() { + return coord; + } + + public boolean getPulseOrToggle() { + return this.pulseOrToggle; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/ControlRodChangeInsertionMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/ControlRodChangeInsertionMessage.java index 2b908220..37cabaad 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/ControlRodChangeInsertionMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/ControlRodChangeInsertionMessage.java @@ -1,53 +1,59 @@ package erogenousbeef.bigreactors.net.message; -import io.netty.buffer.ByteBuf; import net.minecraft.tileentity.TileEntity; + import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorControlRod; import erogenousbeef.bigreactors.net.message.base.WorldMessageServer; +import io.netty.buffer.ByteBuf; public class ControlRodChangeInsertionMessage extends WorldMessageServer { - protected int amount; - protected boolean changeAll; - - public ControlRodChangeInsertionMessage() { super(); amount = 0; changeAll = false; } - public ControlRodChangeInsertionMessage(int x, int y, int z, int amount, boolean all) { - super(x, y, z); - this.amount = amount; - this.changeAll = all; - } - - @Override - public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); - amount = buf.readInt(); - changeAll = buf.readBoolean(); - } - - @Override - public void toBytes(ByteBuf buf) { - super.toBytes(buf); - buf.writeInt(amount); - buf.writeBoolean(changeAll); - } - - public static class Handler extends WorldMessageServer.Handler { - @Override - protected IMessage handleMessage(ControlRodChangeInsertionMessage message, - MessageContext ctx, TileEntity te) { - if(te instanceof TileEntityReactorControlRod) { - TileEntityReactorControlRod rod = (TileEntityReactorControlRod)te; - int newInsertion = rod.getControlRodInsertion() + (short)message.amount; - if(message.changeAll && rod.getReactorController() != null) - { - rod.getReactorController().setAllControlRodInsertionValues(newInsertion); - } - else { - rod.setControlRodInsertion((short)newInsertion); - } - } - return null; - } - } + + protected int amount; + protected boolean changeAll; + + public ControlRodChangeInsertionMessage() { + super(); + amount = 0; + changeAll = false; + } + + public ControlRodChangeInsertionMessage(int x, int y, int z, int amount, boolean all) { + super(x, y, z); + this.amount = amount; + this.changeAll = all; + } + + @Override + public void fromBytes(ByteBuf buf) { + super.fromBytes(buf); + amount = buf.readInt(); + changeAll = buf.readBoolean(); + } + + @Override + public void toBytes(ByteBuf buf) { + super.toBytes(buf); + buf.writeInt(amount); + buf.writeBoolean(changeAll); + } + + public static class Handler extends WorldMessageServer.Handler { + + @Override + protected IMessage handleMessage(ControlRodChangeInsertionMessage message, MessageContext ctx, TileEntity te) { + if (te instanceof TileEntityReactorControlRod) { + TileEntityReactorControlRod rod = (TileEntityReactorControlRod) te; + int newInsertion = rod.getControlRodInsertion() + (short) message.amount; + if (message.changeAll && rod.getReactorController() != null) { + rod.getReactorController() + .setAllControlRodInsertionValues(newInsertion); + } else { + rod.setControlRodInsertion((short) newInsertion); + } + } + return null; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/ControlRodChangeNameMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/ControlRodChangeNameMessage.java index daa65230..b361d3bc 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/ControlRodChangeNameMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/ControlRodChangeNameMessage.java @@ -1,42 +1,48 @@ package erogenousbeef.bigreactors.net.message; -import io.netty.buffer.ByteBuf; import net.minecraft.tileentity.TileEntity; + import cpw.mods.fml.common.network.ByteBufUtils; import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorControlRod; import erogenousbeef.bigreactors.net.message.base.WorldMessageServer; +import io.netty.buffer.ByteBuf; public class ControlRodChangeNameMessage extends WorldMessageServer { + private String name; - public ControlRodChangeNameMessage() { super(); name = null; } - + public ControlRodChangeNameMessage() { + super(); + name = null; + } + public ControlRodChangeNameMessage(int x, int y, int z, String name) { - super(x, y, z); + super(x, y, z); this.name = name; } @Override public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); + super.fromBytes(buf); name = ByteBufUtils.readUTF8String(buf); } @Override public void toBytes(ByteBuf buf) { - super.toBytes(buf); + super.toBytes(buf); ByteBufUtils.writeUTF8String(buf, name); } public static class Handler extends WorldMessageServer.Handler { - @Override - protected IMessage handleMessage(ControlRodChangeNameMessage message, MessageContext ctx, TileEntity te) { - if(te instanceof TileEntityReactorControlRod) { - ((TileEntityReactorControlRod)te).setName(message.name); - } - return null; - } + + @Override + protected IMessage handleMessage(ControlRodChangeNameMessage message, MessageContext ctx, TileEntity te) { + if (te instanceof TileEntityReactorControlRod) { + ((TileEntityReactorControlRod) te).setName(message.name); + } + return null; + } } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/ControlRodUpdateMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/ControlRodUpdateMessage.java index 8453eb38..001c2dd0 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/ControlRodUpdateMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/ControlRodUpdateMessage.java @@ -1,40 +1,45 @@ package erogenousbeef.bigreactors.net.message; -import io.netty.buffer.ByteBuf; import net.minecraft.tileentity.TileEntity; + import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorControlRod; import erogenousbeef.bigreactors.net.message.base.WorldMessageClient; +import io.netty.buffer.ByteBuf; public class ControlRodUpdateMessage extends WorldMessageClient { + private short insertion; - public ControlRodUpdateMessage() { super(); insertion = 0; } - + public ControlRodUpdateMessage() { + super(); + insertion = 0; + } + public ControlRodUpdateMessage(int x, int y, int z, short controlRodInsertion) { - super(x, y, z); + super(x, y, z); this.insertion = controlRodInsertion; } @Override public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); + super.fromBytes(buf); insertion = buf.readShort(); } @Override public void toBytes(ByteBuf buf) { - super.toBytes(buf); + super.toBytes(buf); buf.writeShort(insertion); } - public static class Handler extends WorldMessageClient.Handler - { + public static class Handler extends WorldMessageClient.Handler { + @Override protected IMessage handleMessage(ControlRodUpdateMessage message, MessageContext ctx, TileEntity te) { - if(te instanceof TileEntityReactorControlRod) { - ((TileEntityReactorControlRod)te).onControlRodUpdate(message.insertion); + if (te instanceof TileEntityReactorControlRod) { + ((TileEntityReactorControlRod) te).onControlRodUpdate(message.insertion); } return null; } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/DeviceChangeExposureMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/DeviceChangeExposureMessage.java index 3cc6fb9f..f0ffa49a 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/DeviceChangeExposureMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/DeviceChangeExposureMessage.java @@ -1,61 +1,67 @@ package erogenousbeef.bigreactors.net.message; -import io.netty.buffer.ByteBuf; import net.minecraft.tileentity.TileEntity; + import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.BRLog; import erogenousbeef.bigreactors.common.tileentity.base.TileEntityBeefBase; import erogenousbeef.bigreactors.net.message.base.WorldMessageServer; +import io.netty.buffer.ByteBuf; /** * A message signifying that a user would like to change * the inventory/fluid exposure status of the side of a block. + * * @author Erogenous Beef * */ public class DeviceChangeExposureMessage extends WorldMessageServer { - private int side; - private boolean increment; - - public DeviceChangeExposureMessage() {} - - public DeviceChangeExposureMessage(int x, int y, int z, int side, boolean increment) { - super(x, y, z); - this.side = side; - this.increment = increment; - } - - @Override - public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); - this.side = buf.readInt(); - this.increment = buf.readBoolean(); - } - - @Override - public void toBytes(ByteBuf buf) { - super.toBytes(buf); - buf.writeInt(side); - buf.writeBoolean(increment); - } - - public static class Handler extends WorldMessageServer.Handler { - @Override - protected IMessage handleMessage(DeviceChangeExposureMessage message, MessageContext ctx, TileEntity te) { - if(te instanceof TileEntityBeefBase) { - TileEntityBeefBase beefTe = (TileEntityBeefBase)te; - if(message.increment) { - beefTe.incrSide(message.side); - } - else { - beefTe.decrSide(message.side); - } - } - else { - BRLog.warning("Received SideChangeMessage for TE at %d, %d, %d, but it was not a TE with an iterable side exposure!", te.xCoord, te.yCoord, te.zCoord); - } - return null; - } - } + + private int side; + private boolean increment; + + public DeviceChangeExposureMessage() {} + + public DeviceChangeExposureMessage(int x, int y, int z, int side, boolean increment) { + super(x, y, z); + this.side = side; + this.increment = increment; + } + + @Override + public void fromBytes(ByteBuf buf) { + super.fromBytes(buf); + this.side = buf.readInt(); + this.increment = buf.readBoolean(); + } + + @Override + public void toBytes(ByteBuf buf) { + super.toBytes(buf); + buf.writeInt(side); + buf.writeBoolean(increment); + } + + public static class Handler extends WorldMessageServer.Handler { + + @Override + protected IMessage handleMessage(DeviceChangeExposureMessage message, MessageContext ctx, TileEntity te) { + if (te instanceof TileEntityBeefBase) { + TileEntityBeefBase beefTe = (TileEntityBeefBase) te; + if (message.increment) { + beefTe.incrSide(message.side); + } else { + beefTe.decrSide(message.side); + } + } else { + BRLog.warning( + "Received SideChangeMessage for TE at %d, %d, %d, but it was not a TE with an iterable side exposure!", + te.xCoord, + te.yCoord, + te.zCoord); + } + return null; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/DeviceUpdateExposureMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/DeviceUpdateExposureMessage.java index 8bc8c89b..b2dbffeb 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/DeviceUpdateExposureMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/DeviceUpdateExposureMessage.java @@ -1,61 +1,62 @@ package erogenousbeef.bigreactors.net.message; -import io.netty.buffer.ByteBuf; import net.minecraft.tileentity.TileEntity; + import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.tileentity.base.TileEntityBeefBase; import erogenousbeef.bigreactors.net.message.base.WorldMessageClient; +import io.netty.buffer.ByteBuf; public class DeviceUpdateExposureMessage extends WorldMessageClient { - int[] exposures; - - public DeviceUpdateExposureMessage() { - super(); - exposures = null; - } - - public DeviceUpdateExposureMessage(int x, int y, int z, int[] exposures) { - super(x, y, z); - this.exposures = new int[exposures.length]; - System.arraycopy(exposures, 0, this.exposures, 0, this.exposures.length); - } - - @Override - public void toBytes(ByteBuf buf) { - super.toBytes(buf); - - buf.writeInt(exposures.length); - for(int i = 0; i < exposures.length; i++) { - buf.writeInt(exposures[i]); - } - } - - @Override - public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); - - int numExposures = buf.readInt(); - assert(numExposures > 0); - exposures = new int[numExposures]; - for(int i = 0; i < numExposures; i++) { - exposures[i] = buf.readInt(); - } - } - - public static class Handler extends WorldMessageClient.Handler { - @Override - protected IMessage handleMessage(DeviceUpdateExposureMessage message, - MessageContext ctx, TileEntity te) { - if(te instanceof TileEntityBeefBase) { - TileEntityBeefBase beefTe = (TileEntityBeefBase)te; - beefTe.setSides(message.exposures); - } - // TODO Auto-generated method stub - return null; - } - - } - + int[] exposures; + + public DeviceUpdateExposureMessage() { + super(); + exposures = null; + } + + public DeviceUpdateExposureMessage(int x, int y, int z, int[] exposures) { + super(x, y, z); + this.exposures = new int[exposures.length]; + System.arraycopy(exposures, 0, this.exposures, 0, this.exposures.length); + } + + @Override + public void toBytes(ByteBuf buf) { + super.toBytes(buf); + + buf.writeInt(exposures.length); + for (int i = 0; i < exposures.length; i++) { + buf.writeInt(exposures[i]); + } + } + + @Override + public void fromBytes(ByteBuf buf) { + super.fromBytes(buf); + + int numExposures = buf.readInt(); + assert (numExposures > 0); + exposures = new int[numExposures]; + for (int i = 0; i < numExposures; i++) { + exposures[i] = buf.readInt(); + } + } + + public static class Handler extends WorldMessageClient.Handler { + + @Override + protected IMessage handleMessage(DeviceUpdateExposureMessage message, MessageContext ctx, TileEntity te) { + if (te instanceof TileEntityBeefBase) { + TileEntityBeefBase beefTe = (TileEntityBeefBase) te; + beefTe.setSides(message.exposures); + } + // TODO Auto-generated method stub + return null; + } + + } + } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/DeviceUpdateMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/DeviceUpdateMessage.java index 50af4929..9e632106 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/DeviceUpdateMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/DeviceUpdateMessage.java @@ -1,41 +1,47 @@ package erogenousbeef.bigreactors.net.message; -import io.netty.buffer.ByteBuf; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; + import cpw.mods.fml.common.network.ByteBufUtils; import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.tileentity.base.TileEntityBeefBase; import erogenousbeef.bigreactors.net.message.base.WorldMessageClient; +import io.netty.buffer.ByteBuf; public class DeviceUpdateMessage extends WorldMessageClient { + private NBTTagCompound compound; - public DeviceUpdateMessage() { super(); compound = null; } - + public DeviceUpdateMessage() { + super(); + compound = null; + } + public DeviceUpdateMessage(int x, int y, int z, NBTTagCompound compound) { - super(x, y, z); + super(x, y, z); this.compound = compound; } @Override public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); + super.fromBytes(buf); compound = ByteBufUtils.readTag(buf); } @Override public void toBytes(ByteBuf buf) { - super.toBytes(buf); + super.toBytes(buf); ByteBufUtils.writeTag(buf, compound); } public static class Handler extends WorldMessageClient.Handler { + @Override public IMessage handleMessage(DeviceUpdateMessage message, MessageContext ctx, TileEntity te) { - if(te instanceof TileEntityBeefBase) { - ((TileEntityBeefBase)te).onReceiveUpdate(message.compound); + if (te instanceof TileEntityBeefBase) { + ((TileEntityBeefBase) te).onReceiveUpdate(message.compound); } return null; } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/DeviceUpdateRotationMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/DeviceUpdateRotationMessage.java index f87300af..1d472217 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/DeviceUpdateRotationMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/DeviceUpdateRotationMessage.java @@ -1,39 +1,45 @@ package erogenousbeef.bigreactors.net.message; -import io.netty.buffer.ByteBuf; import net.minecraft.tileentity.TileEntity; + import cofh.api.tileentity.IReconfigurableFacing; import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.net.message.base.WorldMessageClient; +import io.netty.buffer.ByteBuf; public class DeviceUpdateRotationMessage extends WorldMessageClient { + private int newOrientation; - public DeviceUpdateRotationMessage() { super(); newOrientation = 0; } - + public DeviceUpdateRotationMessage() { + super(); + newOrientation = 0; + } + public DeviceUpdateRotationMessage(int x, int y, int z, int newOrientation) { - super(x, y, z); + super(x, y, z); this.newOrientation = newOrientation; } @Override public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); + super.fromBytes(buf); newOrientation = buf.readInt(); } @Override public void toBytes(ByteBuf buf) { - super.toBytes(buf); + super.toBytes(buf); buf.writeInt(newOrientation); } public static class Handler extends WorldMessageClient.Handler { + @Override public IMessage handleMessage(DeviceUpdateRotationMessage message, MessageContext ctx, TileEntity te) { - if(te instanceof IReconfigurableFacing) { - ((IReconfigurableFacing)te).setFacing(message.newOrientation); + if (te instanceof IReconfigurableFacing) { + ((IReconfigurableFacing) te).setFacing(message.newOrientation); getWorld(ctx).markBlockForUpdate(message.x, message.y, message.z); } return null; diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/MachineCommandActivateMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/MachineCommandActivateMessage.java index 7cf1b8d6..590d20b0 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/MachineCommandActivateMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/MachineCommandActivateMessage.java @@ -1,59 +1,69 @@ package erogenousbeef.bigreactors.net.message; -import io.netty.buffer.ByteBuf; import net.minecraft.tileentity.TileEntity; + import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.BRLog; import erogenousbeef.bigreactors.common.multiblock.interfaces.IActivateable; import erogenousbeef.bigreactors.net.message.base.WorldMessageServer; import erogenousbeef.core.common.CoordTriplet; +import io.netty.buffer.ByteBuf; /** * Send a "setActive" command to any IActivateable machine. * Currently used for multiblock reactors and turbines. + * * @see erogenousbeef.bigreactors.common.multiblock.interfaces.IActivateable * @author Erogenous Beef * */ public class MachineCommandActivateMessage extends WorldMessageServer { - protected boolean setActive; - public MachineCommandActivateMessage() { super(); setActive = true; } - - protected MachineCommandActivateMessage(CoordTriplet coord, boolean setActive) { - super(coord.x, coord.y, coord.z); - this.setActive = setActive; - } - - public MachineCommandActivateMessage(IActivateable machine, boolean setActive) { - this(machine.getReferenceCoord(), setActive); - } - - @Override - public void toBytes(ByteBuf buf) { - super.toBytes(buf); - buf.writeBoolean(setActive); - } - - @Override - public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); - setActive = buf.readBoolean(); - } - - public static class Handler extends WorldMessageServer.Handler { - @Override - protected IMessage handleMessage(MachineCommandActivateMessage message, - MessageContext ctx, TileEntity te) { - if(te instanceof IActivateable) { - IActivateable machine = (IActivateable)te; - machine.setActive(message.setActive); - } - else { - BRLog.error("Received a MachineCommandActivateMessage for %d, %d, %d but found no activateable machine", message.x, message.y, message.z); - } - return null; - } - } - + + protected boolean setActive; + + public MachineCommandActivateMessage() { + super(); + setActive = true; + } + + protected MachineCommandActivateMessage(CoordTriplet coord, boolean setActive) { + super(coord.x, coord.y, coord.z); + this.setActive = setActive; + } + + public MachineCommandActivateMessage(IActivateable machine, boolean setActive) { + this(machine.getReferenceCoord(), setActive); + } + + @Override + public void toBytes(ByteBuf buf) { + super.toBytes(buf); + buf.writeBoolean(setActive); + } + + @Override + public void fromBytes(ByteBuf buf) { + super.fromBytes(buf); + setActive = buf.readBoolean(); + } + + public static class Handler extends WorldMessageServer.Handler { + + @Override + protected IMessage handleMessage(MachineCommandActivateMessage message, MessageContext ctx, TileEntity te) { + if (te instanceof IActivateable) { + IActivateable machine = (IActivateable) te; + machine.setActive(message.setActive); + } else { + BRLog.error( + "Received a MachineCommandActivateMessage for %d, %d, %d but found no activateable machine", + message.x, + message.y, + message.z); + } + return null; + } + } + } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/ReactorAccessPortChangeDirectionMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/ReactorAccessPortChangeDirectionMessage.java index 92c011e6..f6658e0d 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/ReactorAccessPortChangeDirectionMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/ReactorAccessPortChangeDirectionMessage.java @@ -1,46 +1,55 @@ package erogenousbeef.bigreactors.net.message; -import io.netty.buffer.ByteBuf; import net.minecraft.tileentity.TileEntity; + import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorAccessPort; import erogenousbeef.bigreactors.net.message.base.TileMessageServer; +import io.netty.buffer.ByteBuf; public class ReactorAccessPortChangeDirectionMessage extends TileMessageServer { - private boolean newSetting; - public ReactorAccessPortChangeDirectionMessage() { super(); newSetting = true; } - public ReactorAccessPortChangeDirectionMessage(TileEntityReactorAccessPort port, boolean inlet) { - super(port); - newSetting = inlet; - } - - @Override - public void toBytes(ByteBuf buf) { - super.toBytes(buf); - buf.writeBoolean(newSetting); - } - - @Override - public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); - newSetting = buf.readBoolean(); - } - - public static class Handler extends TileMessageServer.Handler { - @Override - protected IMessage handle(ReactorAccessPortChangeDirectionMessage message, - MessageContext ctx, TileEntityReactorAccessPort te) { - te.setInlet(message.newSetting); - return null; - } - - @Override - protected TileEntityReactorAccessPort getImpl(TileEntity te) { - if(te instanceof TileEntityReactorAccessPort) { - return (TileEntityReactorAccessPort)te; - } - return null; - } - } + + private boolean newSetting; + + public ReactorAccessPortChangeDirectionMessage() { + super(); + newSetting = true; + } + + public ReactorAccessPortChangeDirectionMessage(TileEntityReactorAccessPort port, boolean inlet) { + super(port); + newSetting = inlet; + } + + @Override + public void toBytes(ByteBuf buf) { + super.toBytes(buf); + buf.writeBoolean(newSetting); + } + + @Override + public void fromBytes(ByteBuf buf) { + super.fromBytes(buf); + newSetting = buf.readBoolean(); + } + + public static class Handler + extends TileMessageServer.Handler { + + @Override + protected IMessage handle(ReactorAccessPortChangeDirectionMessage message, MessageContext ctx, + TileEntityReactorAccessPort te) { + te.setInlet(message.newSetting); + return null; + } + + @Override + protected TileEntityReactorAccessPort getImpl(TileEntity te) { + if (te instanceof TileEntityReactorAccessPort) { + return (TileEntityReactorAccessPort) te; + } + return null; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/ReactorRedNetPortChangeMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/ReactorRedNetPortChangeMessage.java index 5ae49479..263f82f8 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/ReactorRedNetPortChangeMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/ReactorRedNetPortChangeMessage.java @@ -1,63 +1,71 @@ package erogenousbeef.bigreactors.net.message; -import io.netty.buffer.ByteBuf; import net.minecraft.tileentity.TileEntity; + import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorRedNetPort; import erogenousbeef.bigreactors.net.helpers.RedNetChange; import erogenousbeef.bigreactors.net.message.base.TileMessageServer; +import io.netty.buffer.ByteBuf; public class ReactorRedNetPortChangeMessage extends TileMessageServer { + private RedNetChange[] changes; - - public ReactorRedNetPortChangeMessage() { super(); changes = null; } - + + public ReactorRedNetPortChangeMessage() { + super(); + changes = null; + } + public ReactorRedNetPortChangeMessage(TileEntityReactorRedNetPort port, RedNetChange[] changes) { - super(port); - this.changes = changes; + super(port); + this.changes = changes; } @Override public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); - - int numChanges = buf.readInt(); - if(numChanges < 1) { return; } - - changes = new RedNetChange[numChanges]; - for(int i = 0; i < numChanges; i++) { - changes[i] = RedNetChange.fromBytes(buf); - } + super.fromBytes(buf); + + int numChanges = buf.readInt(); + if (numChanges < 1) { + return; + } + + changes = new RedNetChange[numChanges]; + for (int i = 0; i < numChanges; i++) { + changes[i] = RedNetChange.fromBytes(buf); + } } @Override public void toBytes(ByteBuf buf) { - super.toBytes(buf); - - if(changes == null || changes.length < 1) { - buf.writeInt(0); - return; - } - - buf.writeInt(changes.length); - for(int i = 0; i < changes.length; i++) { - changes[i].toBytes(buf); - } + super.toBytes(buf); + + if (changes == null || changes.length < 1) { + buf.writeInt(0); + return; + } + + buf.writeInt(changes.length); + for (int i = 0; i < changes.length; i++) { + changes[i].toBytes(buf); + } } - public static class Handler extends TileMessageServer.Handler { + public static class Handler + extends TileMessageServer.Handler { + @Override - public IMessage handle(ReactorRedNetPortChangeMessage message, MessageContext ctx, TileEntityReactorRedNetPort port) { + public IMessage handle(ReactorRedNetPortChangeMessage message, MessageContext ctx, + TileEntityReactorRedNetPort port) { port.onCircuitUpdate(message.changes); return null; } - + @Override public TileEntityReactorRedNetPort getImpl(TileEntity te) { - return te instanceof TileEntityReactorRedNetPort ? - (TileEntityReactorRedNetPort)te : null; + return te instanceof TileEntityReactorRedNetPort ? (TileEntityReactorRedNetPort) te : null; } } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/ReactorRedstonePortChangeMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/ReactorRedstonePortChangeMessage.java index bcaa7186..a651a57f 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/ReactorRedstonePortChangeMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/ReactorRedstonePortChangeMessage.java @@ -1,20 +1,25 @@ package erogenousbeef.bigreactors.net.message; -import io.netty.buffer.ByteBuf; import net.minecraft.tileentity.TileEntity; + import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorRedstonePort; import erogenousbeef.bigreactors.net.message.base.TileMessageServer; +import io.netty.buffer.ByteBuf; public class ReactorRedstonePortChangeMessage extends TileMessageServer { + private int newCircut, newLevel; private boolean newGt, pulse; - public ReactorRedstonePortChangeMessage() { super(); } - - public ReactorRedstonePortChangeMessage(TileEntityReactorRedstonePort port, int newCircut, int newLevel, boolean newGt, boolean pulse) { - super(port); + public ReactorRedstonePortChangeMessage() { + super(); + } + + public ReactorRedstonePortChangeMessage(TileEntityReactorRedstonePort port, int newCircut, int newLevel, + boolean newGt, boolean pulse) { + super(port); this.newCircut = newCircut; this.newLevel = newLevel; this.newGt = newGt; @@ -23,7 +28,7 @@ public ReactorRedstonePortChangeMessage(TileEntityReactorRedstonePort port, int @Override public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); + super.fromBytes(buf); newCircut = buf.readInt(); newLevel = buf.readInt(); newGt = buf.readBoolean(); @@ -32,25 +37,26 @@ public void fromBytes(ByteBuf buf) { @Override public void toBytes(ByteBuf buf) { - super.toBytes(buf); + super.toBytes(buf); buf.writeInt(newCircut); buf.writeInt(newLevel); buf.writeBoolean(newGt); buf.writeBoolean(pulse); } - public static class Handler extends TileMessageServer.Handler { + public static class Handler + extends TileMessageServer.Handler { + @Override - public IMessage handle(ReactorRedstonePortChangeMessage message, MessageContext ctx, TileEntityReactorRedstonePort te) { - te.onReceiveUpdatePacket(message.newCircut, message.newLevel, message.newGt, message.pulse); + public IMessage handle(ReactorRedstonePortChangeMessage message, MessageContext ctx, + TileEntityReactorRedstonePort te) { + te.onReceiveUpdatePacket(message.newCircut, message.newLevel, message.newGt, message.pulse); return null; } - + @Override public TileEntityReactorRedstonePort getImpl(TileEntity te) { - return te instanceof TileEntityReactorRedstonePort ? - (TileEntityReactorRedstonePort)te : null; + return te instanceof TileEntityReactorRedstonePort ? (TileEntityReactorRedstonePort) te : null; } } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/base/ReactorMessageClient.java b/src/main/java/erogenousbeef/bigreactors/net/message/base/ReactorMessageClient.java index 867a3829..f03ff385 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/base/ReactorMessageClient.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/base/ReactorMessageClient.java @@ -1,6 +1,7 @@ package erogenousbeef.bigreactors.net.message.base; import net.minecraft.tileentity.TileEntity; + import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.BRLog; @@ -9,35 +10,48 @@ import erogenousbeef.core.common.CoordTriplet; public abstract class ReactorMessageClient extends WorldMessageClient { - protected MultiblockReactor reactor; - - protected ReactorMessageClient() { super(); reactor = null; } - protected ReactorMessageClient(MultiblockReactor reactor, CoordTriplet referenceCoord) { - super(referenceCoord.x, referenceCoord.y, referenceCoord.z); - this.reactor = reactor; - } - protected ReactorMessageClient(MultiblockReactor reactor) { - this(reactor, reactor.getReferenceCoord()); - } - - public static abstract class Handler extends WorldMessageClient.Handler { - protected abstract IMessage handleMessage(M message, MessageContext ctx, MultiblockReactor reactor); - - @Override - protected IMessage handleMessage(M message, MessageContext ctx, TileEntity te) { - if(te instanceof TileEntityReactorPartBase) { - MultiblockReactor reactor = ((TileEntityReactorPartBase)te).getReactorController(); - if(reactor != null) { - return handleMessage(message, ctx, reactor); - } - else { - BRLog.error("Received ReactorMessageClient for a reactor part @ %d, %d, %d which has no attached reactor", te.xCoord, te.yCoord, te.zCoord); - } - } - else { - BRLog.error("Received ReactorMessageClient for a non-reactor-part block @ %d, %d, %d", message.x, message.y, message.z); - } - return null; - } - } + + protected MultiblockReactor reactor; + + protected ReactorMessageClient() { + super(); + reactor = null; + } + + protected ReactorMessageClient(MultiblockReactor reactor, CoordTriplet referenceCoord) { + super(referenceCoord.x, referenceCoord.y, referenceCoord.z); + this.reactor = reactor; + } + + protected ReactorMessageClient(MultiblockReactor reactor) { + this(reactor, reactor.getReferenceCoord()); + } + + public static abstract class Handler extends WorldMessageClient.Handler { + + protected abstract IMessage handleMessage(M message, MessageContext ctx, MultiblockReactor reactor); + + @Override + protected IMessage handleMessage(M message, MessageContext ctx, TileEntity te) { + if (te instanceof TileEntityReactorPartBase) { + MultiblockReactor reactor = ((TileEntityReactorPartBase) te).getReactorController(); + if (reactor != null) { + return handleMessage(message, ctx, reactor); + } else { + BRLog.error( + "Received ReactorMessageClient for a reactor part @ %d, %d, %d which has no attached reactor", + te.xCoord, + te.yCoord, + te.zCoord); + } + } else { + BRLog.error( + "Received ReactorMessageClient for a non-reactor-part block @ %d, %d, %d", + message.x, + message.y, + message.z); + } + return null; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/base/ReactorMessageServer.java b/src/main/java/erogenousbeef/bigreactors/net/message/base/ReactorMessageServer.java index 767217b9..0a16aeef 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/base/ReactorMessageServer.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/base/ReactorMessageServer.java @@ -1,6 +1,7 @@ package erogenousbeef.bigreactors.net.message.base; import net.minecraft.tileentity.TileEntity; + import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.BRLog; @@ -9,35 +10,48 @@ import erogenousbeef.core.common.CoordTriplet; public abstract class ReactorMessageServer extends WorldMessageServer { - MultiblockReactor reactor; - - protected ReactorMessageServer() { super(); reactor = null; } - protected ReactorMessageServer(MultiblockReactor reactor, CoordTriplet referenceCoord) { - super(referenceCoord.x, referenceCoord.y, referenceCoord.z); - this.reactor = reactor; - } - protected ReactorMessageServer(MultiblockReactor reactor) { - this(reactor, reactor.getReferenceCoord()); - } - - public static abstract class Handler extends WorldMessageServer.Handler { - protected abstract IMessage handleMessage(M message, MessageContext ctx, MultiblockReactor reactor); - - @Override - protected IMessage handleMessage(M message, MessageContext ctx, TileEntity te) { - if(te instanceof TileEntityReactorPartBase) { - MultiblockReactor reactor = ((TileEntityReactorPartBase)te).getReactorController(); - if(reactor != null) { - return handleMessage(message, ctx, reactor); - } - else { - BRLog.error("Received ReactorMessageServer for a reactor part @ %d, %d, %d which has no attached reactor", te.xCoord, te.yCoord, te.zCoord); - } - } - else { - BRLog.error("Received ReactorMessageServer for a non-reactor-part block @ %d, %d, %d", message.x, message.y, message.z); - } - return null; - } - } + + MultiblockReactor reactor; + + protected ReactorMessageServer() { + super(); + reactor = null; + } + + protected ReactorMessageServer(MultiblockReactor reactor, CoordTriplet referenceCoord) { + super(referenceCoord.x, referenceCoord.y, referenceCoord.z); + this.reactor = reactor; + } + + protected ReactorMessageServer(MultiblockReactor reactor) { + this(reactor, reactor.getReferenceCoord()); + } + + public static abstract class Handler extends WorldMessageServer.Handler { + + protected abstract IMessage handleMessage(M message, MessageContext ctx, MultiblockReactor reactor); + + @Override + protected IMessage handleMessage(M message, MessageContext ctx, TileEntity te) { + if (te instanceof TileEntityReactorPartBase) { + MultiblockReactor reactor = ((TileEntityReactorPartBase) te).getReactorController(); + if (reactor != null) { + return handleMessage(message, ctx, reactor); + } else { + BRLog.error( + "Received ReactorMessageServer for a reactor part @ %d, %d, %d which has no attached reactor", + te.xCoord, + te.yCoord, + te.zCoord); + } + } else { + BRLog.error( + "Received ReactorMessageServer for a non-reactor-part block @ %d, %d, %d", + message.x, + message.y, + message.z); + } + return null; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/base/TileMessageClient.java b/src/main/java/erogenousbeef/bigreactors/net/message/base/TileMessageClient.java index ee9b9db2..ded4eb3e 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/base/TileMessageClient.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/base/TileMessageClient.java @@ -1,34 +1,41 @@ package erogenousbeef.bigreactors.net.message.base; import net.minecraft.tileentity.TileEntity; + import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.BRLog; public class TileMessageClient extends WorldMessageClient { - protected TileMessageClient() {} - protected TileMessageClient(TE te) { - super(te.xCoord, te.yCoord, te.zCoord); - } - - protected abstract static class Handler extends WorldMessageClient.Handler { - protected abstract IMessage handle(MESSAGE message, MessageContext ctx, TE te); - protected abstract TE getImpl(TileEntity te); - - @Override - protected IMessage handleMessage(MESSAGE message, MessageContext ctx, - TileEntity te) { - TE concrete = getImpl(te); - if(concrete != null) { - return handle(message, ctx, concrete); - } - else { - BRLog.error("Received a TileMessageClient for a non-resolvable TileEntity @ %d, %d, %d", message.x, message.y, message.z); - } - return null; - } - - } - + protected TileMessageClient() {} + + protected TileMessageClient(TE te) { + super(te.xCoord, te.yCoord, te.zCoord); + } + + protected abstract static class Handler + extends WorldMessageClient.Handler { + + protected abstract IMessage handle(MESSAGE message, MessageContext ctx, TE te); + + protected abstract TE getImpl(TileEntity te); + + @Override + protected IMessage handleMessage(MESSAGE message, MessageContext ctx, TileEntity te) { + TE concrete = getImpl(te); + if (concrete != null) { + return handle(message, ctx, concrete); + } else { + BRLog.error( + "Received a TileMessageClient for a non-resolvable TileEntity @ %d, %d, %d", + message.x, + message.y, + message.z); + } + return null; + } + + } + } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/base/TileMessageServer.java b/src/main/java/erogenousbeef/bigreactors/net/message/base/TileMessageServer.java index 52fd6881..efae1494 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/base/TileMessageServer.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/base/TileMessageServer.java @@ -1,32 +1,40 @@ package erogenousbeef.bigreactors.net.message.base; import net.minecraft.tileentity.TileEntity; + import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.BRLog; public class TileMessageServer extends WorldMessageServer { - protected TileMessageServer() {} - protected TileMessageServer(TE te) { - super(te.xCoord, te.yCoord, te.zCoord); - } - - protected abstract static class Handler extends WorldMessageServer.Handler { - protected abstract IMessage handle(MESSAGE message, MessageContext ctx, TE te); - protected abstract TE getImpl(TileEntity te); - - @Override - protected IMessage handleMessage(MESSAGE message, MessageContext ctx, - TileEntity te) { - TE concrete = getImpl(te); - if(concrete != null) { - return handle(message, ctx, concrete); - } - else { - BRLog.error("Received a TileMessageServer for a non-resolvable TileEntity @ %d, %d, %d", message.x, message.y, message.z); - } - return null; - } - - } + + protected TileMessageServer() {} + + protected TileMessageServer(TE te) { + super(te.xCoord, te.yCoord, te.zCoord); + } + + protected abstract static class Handler + extends WorldMessageServer.Handler { + + protected abstract IMessage handle(MESSAGE message, MessageContext ctx, TE te); + + protected abstract TE getImpl(TileEntity te); + + @Override + protected IMessage handleMessage(MESSAGE message, MessageContext ctx, TileEntity te) { + TE concrete = getImpl(te); + if (concrete != null) { + return handle(message, ctx, concrete); + } else { + BRLog.error( + "Received a TileMessageServer for a non-resolvable TileEntity @ %d, %d, %d", + message.x, + message.y, + message.z); + } + return null; + } + + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/base/TurbineMessageClient.java b/src/main/java/erogenousbeef/bigreactors/net/message/base/TurbineMessageClient.java index a5939f9d..75513222 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/base/TurbineMessageClient.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/base/TurbineMessageClient.java @@ -1,6 +1,7 @@ package erogenousbeef.bigreactors.net.message.base; import net.minecraft.tileentity.TileEntity; + import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.BRLog; @@ -9,35 +10,48 @@ import erogenousbeef.core.common.CoordTriplet; public class TurbineMessageClient extends WorldMessageClient { - protected MultiblockTurbine turbine; - - protected TurbineMessageClient() { super(); turbine = null; } - protected TurbineMessageClient(MultiblockTurbine turbine, CoordTriplet referenceCoord) { - super(referenceCoord.x, referenceCoord.y, referenceCoord.z); - this.turbine = turbine; - } - protected TurbineMessageClient(MultiblockTurbine turbine) { - this(turbine, turbine.getReferenceCoord()); - } - - public static abstract class Handler extends WorldMessageClient.Handler { - protected abstract IMessage handleMessage(M message, MessageContext ctx, MultiblockTurbine turbine); - - @Override - protected IMessage handleMessage(M message, MessageContext ctx, TileEntity te) { - if(te instanceof TileEntityTurbinePartBase) { - MultiblockTurbine reactor = ((TileEntityTurbinePartBase)te).getTurbine(); - if(reactor != null) { - return handleMessage(message, ctx, reactor); - } - else { - BRLog.error("Received TurbineMessageClient for a turbine part @ %d, %d, %d which has no attached turbine", te.xCoord, te.yCoord, te.zCoord); - } - } - else { - BRLog.error("Received TurbineMessageClient for a non-turbine-part block @ %d, %d, %d", message.x, message.y, message.z); - } - return null; - } - } + + protected MultiblockTurbine turbine; + + protected TurbineMessageClient() { + super(); + turbine = null; + } + + protected TurbineMessageClient(MultiblockTurbine turbine, CoordTriplet referenceCoord) { + super(referenceCoord.x, referenceCoord.y, referenceCoord.z); + this.turbine = turbine; + } + + protected TurbineMessageClient(MultiblockTurbine turbine) { + this(turbine, turbine.getReferenceCoord()); + } + + public static abstract class Handler extends WorldMessageClient.Handler { + + protected abstract IMessage handleMessage(M message, MessageContext ctx, MultiblockTurbine turbine); + + @Override + protected IMessage handleMessage(M message, MessageContext ctx, TileEntity te) { + if (te instanceof TileEntityTurbinePartBase) { + MultiblockTurbine reactor = ((TileEntityTurbinePartBase) te).getTurbine(); + if (reactor != null) { + return handleMessage(message, ctx, reactor); + } else { + BRLog.error( + "Received TurbineMessageClient for a turbine part @ %d, %d, %d which has no attached turbine", + te.xCoord, + te.yCoord, + te.zCoord); + } + } else { + BRLog.error( + "Received TurbineMessageClient for a non-turbine-part block @ %d, %d, %d", + message.x, + message.y, + message.z); + } + return null; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/base/TurbineMessageServer.java b/src/main/java/erogenousbeef/bigreactors/net/message/base/TurbineMessageServer.java index 522769ce..fa7ae256 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/base/TurbineMessageServer.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/base/TurbineMessageServer.java @@ -1,6 +1,7 @@ package erogenousbeef.bigreactors.net.message.base; import net.minecraft.tileentity.TileEntity; + import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.BRLog; @@ -9,35 +10,48 @@ import erogenousbeef.core.common.CoordTriplet; public class TurbineMessageServer extends WorldMessageServer { - protected MultiblockTurbine turbine; - - protected TurbineMessageServer() { super(); turbine = null; } - protected TurbineMessageServer(MultiblockTurbine turbine, CoordTriplet referenceCoord) { - super(referenceCoord.x, referenceCoord.y, referenceCoord.z); - this.turbine = turbine; - } - protected TurbineMessageServer(MultiblockTurbine turbine) { - this(turbine, turbine.getReferenceCoord()); - } - - public static abstract class Handler extends WorldMessageServer.Handler { - protected abstract IMessage handleMessage(M message, MessageContext ctx, MultiblockTurbine turbine); - - @Override - protected IMessage handleMessage(M message, MessageContext ctx, TileEntity te) { - if(te instanceof TileEntityTurbinePartBase) { - MultiblockTurbine reactor = ((TileEntityTurbinePartBase)te).getTurbine(); - if(reactor != null) { - return handleMessage(message, ctx, reactor); - } - else { - BRLog.error("Received TurbineMessageServer for a turbine part @ %d, %d, %d which has no attached turbine", te.xCoord, te.yCoord, te.zCoord); - } - } - else { - BRLog.error("Received TurbineMessageServer for a non-turbine-part block @ %d, %d, %d", message.x, message.y, message.z); - } - return null; - } - } + + protected MultiblockTurbine turbine; + + protected TurbineMessageServer() { + super(); + turbine = null; + } + + protected TurbineMessageServer(MultiblockTurbine turbine, CoordTriplet referenceCoord) { + super(referenceCoord.x, referenceCoord.y, referenceCoord.z); + this.turbine = turbine; + } + + protected TurbineMessageServer(MultiblockTurbine turbine) { + this(turbine, turbine.getReferenceCoord()); + } + + public static abstract class Handler extends WorldMessageServer.Handler { + + protected abstract IMessage handleMessage(M message, MessageContext ctx, MultiblockTurbine turbine); + + @Override + protected IMessage handleMessage(M message, MessageContext ctx, TileEntity te) { + if (te instanceof TileEntityTurbinePartBase) { + MultiblockTurbine reactor = ((TileEntityTurbinePartBase) te).getTurbine(); + if (reactor != null) { + return handleMessage(message, ctx, reactor); + } else { + BRLog.error( + "Received TurbineMessageServer for a turbine part @ %d, %d, %d which has no attached turbine", + te.xCoord, + te.yCoord, + te.zCoord); + } + } else { + BRLog.error( + "Received TurbineMessageServer for a non-turbine-part block @ %d, %d, %d", + message.x, + message.y, + message.z); + } + return null; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/base/WorldMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/base/WorldMessage.java index 8a32273b..fbcecce8 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/base/WorldMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/base/WorldMessage.java @@ -1,12 +1,13 @@ package erogenousbeef.bigreactors.net.message.base; -import io.netty.buffer.ByteBuf; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; + import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.BRLog; +import io.netty.buffer.ByteBuf; /** * This class implements a message which is being sent to a specific location @@ -16,50 +17,55 @@ * */ public abstract class WorldMessage implements IMessage { - protected int x, y, z; - - protected WorldMessage() {} - protected WorldMessage(int x, int y, int z) { - this.x = x; - this.y = y; - this.z = z; - } - @Override - public void fromBytes(ByteBuf buf) { - x = buf.readInt(); - y = buf.readInt(); - z = buf.readInt(); - } + protected int x, y, z; + + protected WorldMessage() {} + + protected WorldMessage(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public void fromBytes(ByteBuf buf) { + x = buf.readInt(); + y = buf.readInt(); + z = buf.readInt(); + } + + @Override + public void toBytes(ByteBuf buf) { + buf.writeInt(x); + buf.writeInt(y); + buf.writeInt(z); + } + + public abstract static class Handler implements IMessageHandler { + + protected abstract World getWorld(MessageContext ctxt); - @Override - public void toBytes(ByteBuf buf) { - buf.writeInt(x); - buf.writeInt(y); - buf.writeInt(z); - } + protected abstract IMessage handleMessage(M message, MessageContext ctx, TileEntity te); - - public abstract static class Handler implements IMessageHandler { + public IMessage onMessage(WorldMessage message, MessageContext ctx) { + World world = getWorld(ctx); + if (world == null) { + BRLog.fatal("Unable to resolve world from messagecontext for WorldMessage"); + return null; + } - protected abstract World getWorld(MessageContext ctxt); - - protected abstract IMessage handleMessage(M message, MessageContext ctx, TileEntity te); - - public IMessage onMessage(WorldMessage message, MessageContext ctx) { - World world = getWorld(ctx); - if(world == null) { - BRLog.fatal("Unable to resolve world from messagecontext for WorldMessage"); - return null; - } - - TileEntity te = world.getTileEntity(message.x, message.y, message.z); - if(te == null) { - BRLog.error("Unable to find tile entity for WorldMessage at %d, %d, %d", message.x, message.y, message.z); - return null; - } + TileEntity te = world.getTileEntity(message.x, message.y, message.z); + if (te == null) { + BRLog.error( + "Unable to find tile entity for WorldMessage at %d, %d, %d", + message.x, + message.y, + message.z); + return null; + } - return handleMessage((M)message, ctx, te); - } - } + return handleMessage((M) message, ctx, te); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/base/WorldMessageClient.java b/src/main/java/erogenousbeef/bigreactors/net/message/base/WorldMessageClient.java index bbfb4e72..3f96aaa2 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/base/WorldMessageClient.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/base/WorldMessageClient.java @@ -1,6 +1,7 @@ package erogenousbeef.bigreactors.net.message.base; import net.minecraft.world.World; + import cpw.mods.fml.client.FMLClientHandler; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import cpw.mods.fml.relauncher.Side; @@ -9,19 +10,26 @@ /** * A message to a client user which is grounded in world-space. * Generally, such messages will be sent FROM the server. + * * @author Erogenous Beef */ public abstract class WorldMessageClient extends WorldMessage { - protected WorldMessageClient() { super(); } - protected WorldMessageClient(int x, int y, int z) { - super(x, y, z); - } - public abstract static class Handler extends WorldMessage.Handler { - @SideOnly(Side.CLIENT) - @Override - protected World getWorld(MessageContext ctx) { - return FMLClientHandler.instance().getClient().theWorld; - } - } + protected WorldMessageClient() { + super(); + } + + protected WorldMessageClient(int x, int y, int z) { + super(x, y, z); + } + + public abstract static class Handler extends WorldMessage.Handler { + + @SideOnly(Side.CLIENT) + @Override + protected World getWorld(MessageContext ctx) { + return FMLClientHandler.instance() + .getClient().theWorld; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/base/WorldMessageServer.java b/src/main/java/erogenousbeef/bigreactors/net/message/base/WorldMessageServer.java index b421ad2d..7f4f4d5e 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/base/WorldMessageServer.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/base/WorldMessageServer.java @@ -1,21 +1,30 @@ package erogenousbeef.bigreactors.net.message.base; import net.minecraft.world.World; + import cpw.mods.fml.common.network.simpleimpl.MessageContext; /** * A user-generated message to the server which is grounded in world-space. * Generally, such messages will be sent FROM the client. + * * @author Erogenous Beef */ public abstract class WorldMessageServer extends WorldMessage { - protected WorldMessageServer() { super(); } - protected WorldMessageServer(int x, int y, int z) { super(x, y, z); } - public abstract static class Handler extends WorldMessage.Handler { - @Override - protected World getWorld(MessageContext ctx) { - return ctx.getServerHandler().playerEntity.worldObj; - } - } + protected WorldMessageServer() { + super(); + } + + protected WorldMessageServer(int x, int y, int z) { + super(x, y, z); + } + + public abstract static class Handler extends WorldMessage.Handler { + + @Override + protected World getWorld(MessageContext ctx) { + return ctx.getServerHandler().playerEntity.worldObj; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorChangeWasteEjectionMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorChangeWasteEjectionMessage.java index 913f7f36..41dd5958 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorChangeWasteEjectionMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorChangeWasteEjectionMessage.java @@ -1,40 +1,45 @@ package erogenousbeef.bigreactors.net.message.multiblock; -import io.netty.buffer.ByteBuf; import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.multiblock.MultiblockReactor; import erogenousbeef.bigreactors.common.multiblock.MultiblockReactor.WasteEjectionSetting; import erogenousbeef.bigreactors.net.message.base.ReactorMessageServer; +import io.netty.buffer.ByteBuf; public class ReactorChangeWasteEjectionMessage extends ReactorMessageServer { - int newSetting; - public ReactorChangeWasteEjectionMessage() { super(); newSetting = 0; } - public ReactorChangeWasteEjectionMessage(MultiblockReactor reactor, WasteEjectionSetting setting) { - super(reactor); - newSetting = setting.ordinal(); - } - - @Override - public void toBytes(ByteBuf buf) { - super.toBytes(buf); - buf.writeInt(newSetting); - } - - @Override - public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); - newSetting = buf.readInt(); - } - - public static class Handler extends ReactorMessageServer.Handler { - - @Override - protected IMessage handleMessage( - ReactorChangeWasteEjectionMessage message, MessageContext ctx, - MultiblockReactor reactor) { - reactor.setWasteEjection(MultiblockReactor.s_EjectionSettings[message.newSetting]); - return null; - } - } + + int newSetting; + + public ReactorChangeWasteEjectionMessage() { + super(); + newSetting = 0; + } + + public ReactorChangeWasteEjectionMessage(MultiblockReactor reactor, WasteEjectionSetting setting) { + super(reactor); + newSetting = setting.ordinal(); + } + + @Override + public void toBytes(ByteBuf buf) { + super.toBytes(buf); + buf.writeInt(newSetting); + } + + @Override + public void fromBytes(ByteBuf buf) { + super.fromBytes(buf); + newSetting = buf.readInt(); + } + + public static class Handler extends ReactorMessageServer.Handler { + + @Override + protected IMessage handleMessage(ReactorChangeWasteEjectionMessage message, MessageContext ctx, + MultiblockReactor reactor) { + reactor.setWasteEjection(MultiblockReactor.s_EjectionSettings[message.newSetting]); + return null; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorCommandEjectMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorCommandEjectMessage.java index 4f51e89c..6c5e813c 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorCommandEjectMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorCommandEjectMessage.java @@ -1,50 +1,52 @@ package erogenousbeef.bigreactors.net.message.multiblock; -import io.netty.buffer.ByteBuf; import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.multiblock.MultiblockReactor; import erogenousbeef.bigreactors.net.message.base.ReactorMessageServer; +import io.netty.buffer.ByteBuf; public class ReactorCommandEjectMessage extends ReactorMessageServer { - protected boolean ejectFuel; - protected boolean dumpExcess; - - public ReactorCommandEjectMessage() { - super(); - ejectFuel = dumpExcess = false; - } - - public ReactorCommandEjectMessage(MultiblockReactor reactor, boolean ejectFuel, boolean dumpExcess) { - super(reactor); - this.ejectFuel = ejectFuel; - this.dumpExcess = dumpExcess; - } - - @Override - public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); - ejectFuel = buf.readBoolean(); - dumpExcess = buf.readBoolean(); - } - - @Override - public void toBytes(ByteBuf buf) { - super.toBytes(buf); - buf.writeBoolean(ejectFuel); - buf.writeBoolean(dumpExcess); - } - - public static class Handler extends ReactorMessageServer.Handler { - @Override - public IMessage handleMessage(ReactorCommandEjectMessage message, MessageContext ctx, MultiblockReactor reactor) { - if(message.ejectFuel) { - reactor.ejectFuel(message.dumpExcess, null); - } - else { - reactor.ejectWaste(message.dumpExcess, null); - } - return null; - } - } + + protected boolean ejectFuel; + protected boolean dumpExcess; + + public ReactorCommandEjectMessage() { + super(); + ejectFuel = dumpExcess = false; + } + + public ReactorCommandEjectMessage(MultiblockReactor reactor, boolean ejectFuel, boolean dumpExcess) { + super(reactor); + this.ejectFuel = ejectFuel; + this.dumpExcess = dumpExcess; + } + + @Override + public void fromBytes(ByteBuf buf) { + super.fromBytes(buf); + ejectFuel = buf.readBoolean(); + dumpExcess = buf.readBoolean(); + } + + @Override + public void toBytes(ByteBuf buf) { + super.toBytes(buf); + buf.writeBoolean(ejectFuel); + buf.writeBoolean(dumpExcess); + } + + public static class Handler extends ReactorMessageServer.Handler { + + @Override + public IMessage handleMessage(ReactorCommandEjectMessage message, MessageContext ctx, + MultiblockReactor reactor) { + if (message.ejectFuel) { + reactor.ejectFuel(message.dumpExcess, null); + } else { + reactor.ejectWaste(message.dumpExcess, null); + } + return null; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorCommandEjectToPortMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorCommandEjectToPortMessage.java index 1e8585ee..70f23c45 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorCommandEjectToPortMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorCommandEjectToPortMessage.java @@ -1,66 +1,67 @@ package erogenousbeef.bigreactors.net.message.multiblock; -import io.netty.buffer.ByteBuf; import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.multiblock.MultiblockReactor; import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorAccessPort; import erogenousbeef.bigreactors.net.message.base.ReactorMessageServer; import erogenousbeef.core.common.CoordTriplet; +import io.netty.buffer.ByteBuf; public class ReactorCommandEjectToPortMessage extends ReactorMessageServer { - protected boolean ejectFuel; - protected boolean dumpExcess; - int portX, portY, portZ; - - public ReactorCommandEjectToPortMessage() { - super(); - ejectFuel = dumpExcess = false; - portX = portY = portZ = Integer.MAX_VALUE; - } - - public ReactorCommandEjectToPortMessage(TileEntityReactorAccessPort destination, - boolean ejectFuel, - boolean dumpExcess) { - super(destination.getReactorController()); - this.portX = destination.xCoord; - this.portY = destination.yCoord; - this.portZ = destination.zCoord; - this.ejectFuel = ejectFuel; - this.dumpExcess = dumpExcess; - } - - @Override - public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); - ejectFuel = buf.readBoolean(); - dumpExcess = buf.readBoolean(); - portX = buf.readInt(); - portY = buf.readInt(); - portZ = buf.readInt(); - } - - @Override - public void toBytes(ByteBuf buf) { - super.toBytes(buf); - buf.writeBoolean(ejectFuel); - buf.writeBoolean(dumpExcess); - buf.writeInt(portX); - buf.writeInt(portY); - buf.writeInt(portZ); - } - - public static class Handler extends ReactorMessageServer.Handler { - @Override - public IMessage handleMessage(ReactorCommandEjectToPortMessage message, MessageContext ctx, MultiblockReactor reactor) { - CoordTriplet dest = new CoordTriplet(message.portX, message.portY, message.portZ); - if(message.ejectFuel) { - reactor.ejectFuel(message.dumpExcess, dest); - } - else { - reactor.ejectWaste(message.dumpExcess, dest); - } - return null; - } - } + + protected boolean ejectFuel; + protected boolean dumpExcess; + int portX, portY, portZ; + + public ReactorCommandEjectToPortMessage() { + super(); + ejectFuel = dumpExcess = false; + portX = portY = portZ = Integer.MAX_VALUE; + } + + public ReactorCommandEjectToPortMessage(TileEntityReactorAccessPort destination, boolean ejectFuel, + boolean dumpExcess) { + super(destination.getReactorController()); + this.portX = destination.xCoord; + this.portY = destination.yCoord; + this.portZ = destination.zCoord; + this.ejectFuel = ejectFuel; + this.dumpExcess = dumpExcess; + } + + @Override + public void fromBytes(ByteBuf buf) { + super.fromBytes(buf); + ejectFuel = buf.readBoolean(); + dumpExcess = buf.readBoolean(); + portX = buf.readInt(); + portY = buf.readInt(); + portZ = buf.readInt(); + } + + @Override + public void toBytes(ByteBuf buf) { + super.toBytes(buf); + buf.writeBoolean(ejectFuel); + buf.writeBoolean(dumpExcess); + buf.writeInt(portX); + buf.writeInt(portY); + buf.writeInt(portZ); + } + + public static class Handler extends ReactorMessageServer.Handler { + + @Override + public IMessage handleMessage(ReactorCommandEjectToPortMessage message, MessageContext ctx, + MultiblockReactor reactor) { + CoordTriplet dest = new CoordTriplet(message.portX, message.portY, message.portZ); + if (message.ejectFuel) { + reactor.ejectFuel(message.dumpExcess, dest); + } else { + reactor.ejectWaste(message.dumpExcess, dest); + } + return null; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorUpdateMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorUpdateMessage.java index b5c898cc..dee3c3bd 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorUpdateMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorUpdateMessage.java @@ -1,37 +1,41 @@ package erogenousbeef.bigreactors.net.message.multiblock; -import io.netty.buffer.ByteBuf; import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.multiblock.MultiblockReactor; import erogenousbeef.bigreactors.net.message.base.ReactorMessageClient; +import io.netty.buffer.ByteBuf; public class ReactorUpdateMessage extends ReactorMessageClient { - ByteBuf data; - - public ReactorUpdateMessage() { super(); } - public ReactorUpdateMessage(MultiblockReactor reactor) { - super(reactor); - } - - @Override - public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); - data = buf.readBytes(buf.readableBytes()); - } - - @Override - public void toBytes(ByteBuf buf) { - super.toBytes(buf); - reactor.serialize(buf); - } - - public static class Handler extends ReactorMessageClient.Handler { - @Override - protected IMessage handleMessage(ReactorUpdateMessage message, - MessageContext ctx, MultiblockReactor reactor) { - reactor.deserialize(message.data); - return null; - } - } + + ByteBuf data; + + public ReactorUpdateMessage() { + super(); + } + + public ReactorUpdateMessage(MultiblockReactor reactor) { + super(reactor); + } + + @Override + public void fromBytes(ByteBuf buf) { + super.fromBytes(buf); + data = buf.readBytes(buf.readableBytes()); + } + + @Override + public void toBytes(ByteBuf buf) { + super.toBytes(buf); + reactor.serialize(buf); + } + + public static class Handler extends ReactorMessageClient.Handler { + + @Override + protected IMessage handleMessage(ReactorUpdateMessage message, MessageContext ctx, MultiblockReactor reactor) { + reactor.deserialize(message.data); + return null; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorUpdateWasteEjectionMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorUpdateWasteEjectionMessage.java index d88aa399..7b801200 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorUpdateWasteEjectionMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/ReactorUpdateWasteEjectionMessage.java @@ -1,38 +1,45 @@ package erogenousbeef.bigreactors.net.message.multiblock; -import io.netty.buffer.ByteBuf; import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.multiblock.MultiblockReactor; import erogenousbeef.bigreactors.net.message.base.ReactorMessageClient; +import io.netty.buffer.ByteBuf; public class ReactorUpdateWasteEjectionMessage extends ReactorMessageClient { + private int newSetting; - - public ReactorUpdateWasteEjectionMessage() { super(); newSetting = 0; } + + public ReactorUpdateWasteEjectionMessage() { + super(); + newSetting = 0; + } public ReactorUpdateWasteEjectionMessage(MultiblockReactor reactor) { - super(reactor); - newSetting = reactor.getWasteEjection().ordinal(); + super(reactor); + newSetting = reactor.getWasteEjection() + .ordinal(); } @Override public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); + super.fromBytes(buf); newSetting = buf.readInt(); } @Override public void toBytes(ByteBuf buf) { - super.toBytes(buf); + super.toBytes(buf); buf.writeInt(newSetting); } public static class Handler extends ReactorMessageClient.Handler { + @Override - public IMessage handleMessage(ReactorUpdateWasteEjectionMessage message, MessageContext ctx, MultiblockReactor reactor) { - reactor.setWasteEjection(MultiblockReactor.s_EjectionSettings[message.newSetting]); + public IMessage handleMessage(ReactorUpdateWasteEjectionMessage message, MessageContext ctx, + MultiblockReactor reactor) { + reactor.setWasteEjection(MultiblockReactor.s_EjectionSettings[message.newSetting]); return null; - } + } } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/TurbineChangeInductorMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/TurbineChangeInductorMessage.java index 88295ecd..2b63a0a0 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/TurbineChangeInductorMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/TurbineChangeInductorMessage.java @@ -1,37 +1,44 @@ package erogenousbeef.bigreactors.net.message.multiblock; -import io.netty.buffer.ByteBuf; import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.multiblock.MultiblockTurbine; import erogenousbeef.bigreactors.net.message.base.TurbineMessageServer; +import io.netty.buffer.ByteBuf; public class TurbineChangeInductorMessage extends TurbineMessageServer { - boolean newSetting; - public TurbineChangeInductorMessage() { super(); newSetting = true; } - public TurbineChangeInductorMessage(MultiblockTurbine turbine, boolean newSetting) { - super(turbine); - this.newSetting = newSetting; - } - - @Override - public void toBytes(ByteBuf buf) { - super.toBytes(buf); - buf.writeBoolean(newSetting); - } - - @Override - public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); - newSetting = buf.readBoolean(); - } - - public static class Handler extends TurbineMessageServer.Handler { - @Override - protected IMessage handleMessage(TurbineChangeInductorMessage message, - MessageContext ctx, MultiblockTurbine turbine) { - turbine.setInductorEngaged(message.newSetting, true); - return null; - } - } + + boolean newSetting; + + public TurbineChangeInductorMessage() { + super(); + newSetting = true; + } + + public TurbineChangeInductorMessage(MultiblockTurbine turbine, boolean newSetting) { + super(turbine); + this.newSetting = newSetting; + } + + @Override + public void toBytes(ByteBuf buf) { + super.toBytes(buf); + buf.writeBoolean(newSetting); + } + + @Override + public void fromBytes(ByteBuf buf) { + super.fromBytes(buf); + newSetting = buf.readBoolean(); + } + + public static class Handler extends TurbineMessageServer.Handler { + + @Override + protected IMessage handleMessage(TurbineChangeInductorMessage message, MessageContext ctx, + MultiblockTurbine turbine) { + turbine.setInductorEngaged(message.newSetting, true); + return null; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/TurbineChangeMaxIntakeMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/TurbineChangeMaxIntakeMessage.java index eed3fccf..9daf7e3c 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/TurbineChangeMaxIntakeMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/TurbineChangeMaxIntakeMessage.java @@ -1,37 +1,44 @@ package erogenousbeef.bigreactors.net.message.multiblock; -import io.netty.buffer.ByteBuf; import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.multiblock.MultiblockTurbine; import erogenousbeef.bigreactors.net.message.base.TurbineMessageServer; +import io.netty.buffer.ByteBuf; public class TurbineChangeMaxIntakeMessage extends TurbineMessageServer { - int newSetting; - public TurbineChangeMaxIntakeMessage() { super(); newSetting = MultiblockTurbine.MAX_PERMITTED_FLOW; } - public TurbineChangeMaxIntakeMessage(MultiblockTurbine turbine, int newSetting) { - super(turbine); - this.newSetting = newSetting; - } - - @Override - public void toBytes(ByteBuf buf) { - super.toBytes(buf); - buf.writeInt(newSetting); - } - - @Override - public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); - newSetting = buf.readInt(); - } - - public static class Handler extends TurbineMessageServer.Handler { - @Override - protected IMessage handleMessage(TurbineChangeMaxIntakeMessage message, - MessageContext ctx, MultiblockTurbine turbine) { - turbine.setMaxIntakeRate(message.newSetting); - return null; - } - } + + int newSetting; + + public TurbineChangeMaxIntakeMessage() { + super(); + newSetting = MultiblockTurbine.MAX_PERMITTED_FLOW; + } + + public TurbineChangeMaxIntakeMessage(MultiblockTurbine turbine, int newSetting) { + super(turbine); + this.newSetting = newSetting; + } + + @Override + public void toBytes(ByteBuf buf) { + super.toBytes(buf); + buf.writeInt(newSetting); + } + + @Override + public void fromBytes(ByteBuf buf) { + super.fromBytes(buf); + newSetting = buf.readInt(); + } + + public static class Handler extends TurbineMessageServer.Handler { + + @Override + protected IMessage handleMessage(TurbineChangeMaxIntakeMessage message, MessageContext ctx, + MultiblockTurbine turbine) { + turbine.setMaxIntakeRate(message.newSetting); + return null; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/TurbineChangeVentMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/TurbineChangeVentMessage.java index 04f66882..7df5b4b3 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/TurbineChangeVentMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/TurbineChangeVentMessage.java @@ -1,37 +1,44 @@ package erogenousbeef.bigreactors.net.message.multiblock; -import io.netty.buffer.ByteBuf; import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.multiblock.MultiblockTurbine; import erogenousbeef.bigreactors.net.message.base.TurbineMessageServer; +import io.netty.buffer.ByteBuf; public class TurbineChangeVentMessage extends TurbineMessageServer { - int newSetting; - public TurbineChangeVentMessage() { super(); newSetting = 0; } - public TurbineChangeVentMessage(MultiblockTurbine turbine, MultiblockTurbine.VentStatus newStatus) { - super(turbine); - this.newSetting = newStatus.ordinal(); - } - - @Override - public void toBytes(ByteBuf buf) { - super.toBytes(buf); - buf.writeInt(newSetting); - } - - @Override - public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); - newSetting = buf.readInt(); - } - - public static class Handler extends TurbineMessageServer.Handler { - @Override - protected IMessage handleMessage(TurbineChangeVentMessage message, - MessageContext ctx, MultiblockTurbine turbine) { - turbine.setVentStatus(MultiblockTurbine.s_VentStatuses[message.newSetting], true); - return null; - } - } + + int newSetting; + + public TurbineChangeVentMessage() { + super(); + newSetting = 0; + } + + public TurbineChangeVentMessage(MultiblockTurbine turbine, MultiblockTurbine.VentStatus newStatus) { + super(turbine); + this.newSetting = newStatus.ordinal(); + } + + @Override + public void toBytes(ByteBuf buf) { + super.toBytes(buf); + buf.writeInt(newSetting); + } + + @Override + public void fromBytes(ByteBuf buf) { + super.fromBytes(buf); + newSetting = buf.readInt(); + } + + public static class Handler extends TurbineMessageServer.Handler { + + @Override + protected IMessage handleMessage(TurbineChangeVentMessage message, MessageContext ctx, + MultiblockTurbine turbine) { + turbine.setVentStatus(MultiblockTurbine.s_VentStatuses[message.newSetting], true); + return null; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/TurbineUpdateMessage.java b/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/TurbineUpdateMessage.java index cd86b734..c301bda5 100644 --- a/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/TurbineUpdateMessage.java +++ b/src/main/java/erogenousbeef/bigreactors/net/message/multiblock/TurbineUpdateMessage.java @@ -1,37 +1,43 @@ package erogenousbeef.bigreactors.net.message.multiblock; -import io.netty.buffer.ByteBuf; import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import erogenousbeef.bigreactors.common.multiblock.MultiblockTurbine; import erogenousbeef.bigreactors.net.message.base.TurbineMessageClient; +import io.netty.buffer.ByteBuf; public class TurbineUpdateMessage extends TurbineMessageClient { - protected ByteBuf data; - - public TurbineUpdateMessage() { super(); data = null; } - public TurbineUpdateMessage(MultiblockTurbine turbine) { - super(turbine); - data = null; - } - - @Override - public void toBytes(ByteBuf buf) { - super.toBytes(buf); - turbine.serialize(buf); - } - - @Override public void fromBytes(ByteBuf buf) { - super.fromBytes(buf); - data = buf.readBytes(buf.readableBytes()); - } - - public static class Handler extends TurbineMessageClient.Handler { - @Override - protected IMessage handleMessage(TurbineUpdateMessage message, - MessageContext ctx, MultiblockTurbine turbine) { - turbine.deserialize(message.data); - return null; - } - } + + protected ByteBuf data; + + public TurbineUpdateMessage() { + super(); + data = null; + } + + public TurbineUpdateMessage(MultiblockTurbine turbine) { + super(turbine); + data = null; + } + + @Override + public void toBytes(ByteBuf buf) { + super.toBytes(buf); + turbine.serialize(buf); + } + + @Override + public void fromBytes(ByteBuf buf) { + super.fromBytes(buf); + data = buf.readBytes(buf.readableBytes()); + } + + public static class Handler extends TurbineMessageClient.Handler { + + @Override + protected IMessage handleMessage(TurbineUpdateMessage message, MessageContext ctx, MultiblockTurbine turbine) { + turbine.deserialize(message.data); + return null; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/utils/AdjacentInventoryHelper.java b/src/main/java/erogenousbeef/bigreactors/utils/AdjacentInventoryHelper.java index 53334a12..77967e59 100644 --- a/src/main/java/erogenousbeef/bigreactors/utils/AdjacentInventoryHelper.java +++ b/src/main/java/erogenousbeef/bigreactors/utils/AdjacentInventoryHelper.java @@ -7,6 +7,7 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; + import buildcraft.api.transport.IPipeTile; import cofh.api.transport.IItemDuct; import erogenousbeef.bigreactors.utils.intermod.ModHelperBase; @@ -17,119 +18,117 @@ * tracked tile entity. * * You can then use distribute() to safely try to distribute items. + * * @author Erogenous Beef */ public class AdjacentInventoryHelper { - private ForgeDirection dir; - private TileEntity entity; - private IItemDuct duct; - private IPipeTile pipe; - private InventoryHelper inv; - - /** - * @param dir The direction away from the current tile entity which this wrapper represents. - */ - public AdjacentInventoryHelper(ForgeDirection dir) { - this.dir = dir; - entity = null; - duct = null; - pipe = null; - inv = null; - } - - /** - * Attempt to distribute an item to a cached inventory connection - * which is wrapped by this object. - * @param itemToDistribute An itemstack to distribute. - * @return An itemstack containing the remaining items, or null if all items were distributed. - */ - public ItemStack distribute(ItemStack itemToDistribute) { - if(entity == null || itemToDistribute == null) { - return itemToDistribute; - } - - if(!hasConnection()) { - return itemToDistribute; - } - - if(ModHelperBase.useCofh && duct != null) { - itemToDistribute = duct.insertItem(dir.getOpposite(), itemToDistribute); - } - else if(ModHelperBase.useBuildcraftTransport && pipe != null) { - if(pipe.isPipeConnected(dir.getOpposite())) { - itemToDistribute.stackSize -= pipe.injectItem(itemToDistribute.copy(), true, dir.getOpposite()); - - if(itemToDistribute.stackSize <= 0) { - itemToDistribute = null; - } - } - - } - else if(inv != null) { - itemToDistribute = inv.addItem(itemToDistribute); - } - - return itemToDistribute; - } - - public boolean hasConnection() { - return inv != null || pipe != null || duct != null; - } - - /** - * @param te The new tile entity for this helper to cache. - * @return True if this helper's wrapped inventory changed, false otherwise. - */ - public boolean set(TileEntity te) { - if(entity == te) { return false; } - - if(te == null) { - duct = null; - pipe = null; - inv = null; - } - else if(ModHelperBase.useCofh && te instanceof IItemDuct) { - setDuct((IItemDuct)te); - } - else if(ModHelperBase.useBuildcraftTransport && te instanceof IPipeTile) { - setPipe((IPipeTile)te); - } - else if(te instanceof IInventory) { - setInv(te); - } - - entity = te; - return true; - } - - private void setDuct(IItemDuct duct) { - this.duct = duct; - this.pipe = null; - this.inv = null; - } - - private void setPipe(IPipeTile pipe) { - this.pipe = pipe; - this.duct = null; - this.inv = null; - } - - private void setInv(TileEntity te) { - this.pipe = null; - this.duct = null; - this.inv = null; - - if(te instanceof ISidedInventory) { - this.inv = new SidedInventoryHelper((ISidedInventory)te, dir.getOpposite()); - } - else { - IInventory inv = (IInventory)te; - World world = te.getWorldObj(); - if(world.getBlock(te.xCoord, te.yCoord, te.zCoord) == Blocks.chest) { - inv = StaticUtils.Inventory.checkForDoubleChest(world, inv, te.xCoord, te.yCoord, te.zCoord); - } - this.inv = new InventoryHelper(inv); - } - } + private ForgeDirection dir; + private TileEntity entity; + private IItemDuct duct; + private IPipeTile pipe; + private InventoryHelper inv; + + /** + * @param dir The direction away from the current tile entity which this wrapper represents. + */ + public AdjacentInventoryHelper(ForgeDirection dir) { + this.dir = dir; + entity = null; + duct = null; + pipe = null; + inv = null; + } + + /** + * Attempt to distribute an item to a cached inventory connection + * which is wrapped by this object. + * + * @param itemToDistribute An itemstack to distribute. + * @return An itemstack containing the remaining items, or null if all items were distributed. + */ + public ItemStack distribute(ItemStack itemToDistribute) { + if (entity == null || itemToDistribute == null) { + return itemToDistribute; + } + + if (!hasConnection()) { + return itemToDistribute; + } + + if (ModHelperBase.useCofh && duct != null) { + itemToDistribute = duct.insertItem(dir.getOpposite(), itemToDistribute); + } else if (ModHelperBase.useBuildcraftTransport && pipe != null) { + if (pipe.isPipeConnected(dir.getOpposite())) { + itemToDistribute.stackSize -= pipe.injectItem(itemToDistribute.copy(), true, dir.getOpposite()); + + if (itemToDistribute.stackSize <= 0) { + itemToDistribute = null; + } + } + + } else if (inv != null) { + itemToDistribute = inv.addItem(itemToDistribute); + } + + return itemToDistribute; + } + + public boolean hasConnection() { + return inv != null || pipe != null || duct != null; + } + + /** + * @param te The new tile entity for this helper to cache. + * @return True if this helper's wrapped inventory changed, false otherwise. + */ + public boolean set(TileEntity te) { + if (entity == te) { + return false; + } + + if (te == null) { + duct = null; + pipe = null; + inv = null; + } else if (ModHelperBase.useCofh && te instanceof IItemDuct) { + setDuct((IItemDuct) te); + } else if (ModHelperBase.useBuildcraftTransport && te instanceof IPipeTile) { + setPipe((IPipeTile) te); + } else if (te instanceof IInventory) { + setInv(te); + } + + entity = te; + return true; + } + + private void setDuct(IItemDuct duct) { + this.duct = duct; + this.pipe = null; + this.inv = null; + } + + private void setPipe(IPipeTile pipe) { + this.pipe = pipe; + this.duct = null; + this.inv = null; + } + + private void setInv(TileEntity te) { + this.pipe = null; + this.duct = null; + this.inv = null; + + if (te instanceof ISidedInventory) { + this.inv = new SidedInventoryHelper((ISidedInventory) te, dir.getOpposite()); + } else { + IInventory inv = (IInventory) te; + World world = te.getWorldObj(); + if (world.getBlock(te.xCoord, te.yCoord, te.zCoord) == Blocks.chest) { + inv = StaticUtils.Inventory.checkForDoubleChest(world, inv, te.xCoord, te.yCoord, te.zCoord); + } + this.inv = new InventoryHelper(inv); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/utils/FloatAverager.java b/src/main/java/erogenousbeef/bigreactors/utils/FloatAverager.java index cd062da5..93a64a2d 100644 --- a/src/main/java/erogenousbeef/bigreactors/utils/FloatAverager.java +++ b/src/main/java/erogenousbeef/bigreactors/utils/FloatAverager.java @@ -1,44 +1,45 @@ package erogenousbeef.bigreactors.utils; - public class FloatAverager { - - private float[] values; - private int current; - private int size; - - public FloatAverager(int maxSize) { - size = maxSize; - values = new float[maxSize]; - for(int i = 0; i < maxSize; i++) { - values[i] = 0f; - } - } - - public FloatAverager(int maxSize, float initialValue) { - size = maxSize; - values = new float[maxSize]; - for(int i = 0; i < maxSize; i++) { - values[i] = initialValue; - } - } - - public float average() { - float accumulator = 0f; - for(int i = 0; i < size; i++) { - accumulator += values[i]; - } - return accumulator / (float)size; - } - - public void add(float value) { - values[current++] = value; - if(current >= size) { current = 0; } - } - - public void setAll(float value) { - for(int i = 0; i < size; i++) { - values[i] = value; - } - } + + private float[] values; + private int current; + private int size; + + public FloatAverager(int maxSize) { + size = maxSize; + values = new float[maxSize]; + for (int i = 0; i < maxSize; i++) { + values[i] = 0f; + } + } + + public FloatAverager(int maxSize, float initialValue) { + size = maxSize; + values = new float[maxSize]; + for (int i = 0; i < maxSize; i++) { + values[i] = initialValue; + } + } + + public float average() { + float accumulator = 0f; + for (int i = 0; i < size; i++) { + accumulator += values[i]; + } + return accumulator / (float) size; + } + + public void add(float value) { + values[current++] = value; + if (current >= size) { + current = 0; + } + } + + public void setAll(float value) { + for (int i = 0; i < size; i++) { + values[i] = value; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/utils/InventoryHelper.java b/src/main/java/erogenousbeef/bigreactors/utils/InventoryHelper.java index 91792c8d..09d8c64a 100644 --- a/src/main/java/erogenousbeef/bigreactors/utils/InventoryHelper.java +++ b/src/main/java/erogenousbeef/bigreactors/utils/InventoryHelper.java @@ -5,86 +5,90 @@ // Strongly based off Powercrystals' InventoryManager public class InventoryHelper { - private IInventory inventory; - public InventoryHelper(IInventory inventory) { - this.inventory = inventory; - } + private IInventory inventory; - protected boolean canAdd(ItemStack stack, int slot) { - if(inventory == null) { return false; } - return inventory.isItemValidForSlot(slot, stack); - } + public InventoryHelper(IInventory inventory) { + this.inventory = inventory; + } - protected boolean canRemove(ItemStack stack, int slot) { - return inventory != null; - } + protected boolean canAdd(ItemStack stack, int slot) { + if (inventory == null) { + return false; + } + return inventory.isItemValidForSlot(slot, stack); + } - /** - * Add an item to a wrapped inventory - * - * @param stack - * Item stack to place into the wrapped inventory - * @return Stack representing the remaining items - */ - public ItemStack addItem(ItemStack stack) { - if (stack == null) { - return null; - } + protected boolean canRemove(ItemStack stack, int slot) { + return inventory != null; + } - int quantitytoadd = stack.stackSize; - ItemStack remaining = stack.copy(); - int[] candidates = getSlots(); - - if(candidates.length == 0) { - return stack; - } + /** + * Add an item to a wrapped inventory + * + * @param stack + * Item stack to place into the wrapped inventory + * @return Stack representing the remaining items + */ + public ItemStack addItem(ItemStack stack) { + if (stack == null) { + return null; + } - for (int candidateSlot : candidates) { - int maxStackSize = Math.min(inventory.getInventoryStackLimit(), - stack.getMaxStackSize()); - ItemStack s = inventory.getStackInSlot(candidateSlot); - if (s == null) { - ItemStack add = stack.copy(); - add.stackSize = Math.min(quantitytoadd, maxStackSize); + int quantitytoadd = stack.stackSize; + ItemStack remaining = stack.copy(); + int[] candidates = getSlots(); - if (canAdd(add, candidateSlot)) { - quantitytoadd -= add.stackSize; - inventory.setInventorySlotContents(candidateSlot, add); - inventory.markDirty(); - } - } else if (StaticUtils.Inventory.areStacksEqual(s, stack)) { - ItemStack add = stack.copy(); - add.stackSize = Math.min(quantitytoadd, maxStackSize - - s.stackSize); + if (candidates.length == 0) { + return stack; + } - if (add.stackSize > 0 && canAdd(add, candidateSlot)) { - s.stackSize += add.stackSize; - quantitytoadd -= add.stackSize; - inventory.setInventorySlotContents(candidateSlot, s); - inventory.markDirty(); - } - } - if (quantitytoadd == 0) { - break; - } - } + for (int candidateSlot : candidates) { + int maxStackSize = Math.min(inventory.getInventoryStackLimit(), stack.getMaxStackSize()); + ItemStack s = inventory.getStackInSlot(candidateSlot); + if (s == null) { + ItemStack add = stack.copy(); + add.stackSize = Math.min(quantitytoadd, maxStackSize); - remaining.stackSize = quantitytoadd; - if (remaining.stackSize == 0) { - return null; - } else { - return remaining; - } - } + if (canAdd(add, candidateSlot)) { + quantitytoadd -= add.stackSize; + inventory.setInventorySlotContents(candidateSlot, add); + inventory.markDirty(); + } + } else if (StaticUtils.Inventory.areStacksEqual(s, stack)) { + ItemStack add = stack.copy(); + add.stackSize = Math.min(quantitytoadd, maxStackSize - s.stackSize); - private final static int[] noSlots = new int[0]; - protected int[] getSlots() { - if(inventory == null) { return noSlots; } - int[] slots = new int[inventory.getSizeInventory()]; - for (int i = 0; i < slots.length; i++) { - slots[i] = i; - } - return slots; - } + if (add.stackSize > 0 && canAdd(add, candidateSlot)) { + s.stackSize += add.stackSize; + quantitytoadd -= add.stackSize; + inventory.setInventorySlotContents(candidateSlot, s); + inventory.markDirty(); + } + } + if (quantitytoadd == 0) { + break; + } + } + + remaining.stackSize = quantitytoadd; + if (remaining.stackSize == 0) { + return null; + } else { + return remaining; + } + } + + private final static int[] noSlots = new int[0]; + + protected int[] getSlots() { + if (inventory == null) { + return noSlots; + } + int[] slots = new int[inventory.getSizeInventory()]; + for (int i = 0; i < slots.length; i++) { + slots[i] = i; + } + return slots; + } } diff --git a/src/main/java/erogenousbeef/bigreactors/utils/SidedInventoryHelper.java b/src/main/java/erogenousbeef/bigreactors/utils/SidedInventoryHelper.java index cf36b61e..c8f9e805 100644 --- a/src/main/java/erogenousbeef/bigreactors/utils/SidedInventoryHelper.java +++ b/src/main/java/erogenousbeef/bigreactors/utils/SidedInventoryHelper.java @@ -6,30 +6,29 @@ public class SidedInventoryHelper extends InventoryHelper { - private ISidedInventory sidedInventory; - private ForgeDirection side; - - public SidedInventoryHelper(ISidedInventory inventory, ForgeDirection side) { - super(inventory); - - this.sidedInventory = inventory; - this.side = side; - } - - @Override - protected boolean canAdd(ItemStack stack, int slot) { - return sidedInventory.canInsertItem(slot, stack, this.side.ordinal()); - } - - @Override - protected boolean canRemove(ItemStack stack, int slot) { - return sidedInventory.canExtractItem(slot, stack, this.side.ordinal()); - } - - @Override - public int[] getSlots() { - return sidedInventory.getAccessibleSlotsFromSide(this.side.ordinal()); - } + private ISidedInventory sidedInventory; + private ForgeDirection side; + public SidedInventoryHelper(ISidedInventory inventory, ForgeDirection side) { + super(inventory); + + this.sidedInventory = inventory; + this.side = side; + } + + @Override + protected boolean canAdd(ItemStack stack, int slot) { + return sidedInventory.canInsertItem(slot, stack, this.side.ordinal()); + } + + @Override + protected boolean canRemove(ItemStack stack, int slot) { + return sidedInventory.canExtractItem(slot, stack, this.side.ordinal()); + } + + @Override + public int[] getSlots() { + return sidedInventory.getAccessibleSlotsFromSide(this.side.ordinal()); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/utils/StaticUtils.java b/src/main/java/erogenousbeef/bigreactors/utils/StaticUtils.java index 03bf3df2..abb23a13 100644 --- a/src/main/java/erogenousbeef/bigreactors/utils/StaticUtils.java +++ b/src/main/java/erogenousbeef/bigreactors/utils/StaticUtils.java @@ -16,6 +16,7 @@ import net.minecraftforge.fluids.FluidContainerRegistry; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.IFluidHandler; + import buildcraft.api.tools.IToolWrench; import cofh.api.item.IToolHammer; import erogenousbeef.bigreactors.common.BigReactors; @@ -24,344 +25,357 @@ public class StaticUtils { - public static final ForgeDirection[] CardinalDirections = new ForgeDirection[] { ForgeDirection.NORTH, ForgeDirection.EAST, ForgeDirection.SOUTH, ForgeDirection.WEST }; - - public static final ForgeDirection neighborsBySide[][] = new ForgeDirection[][] { - {ForgeDirection.NORTH, ForgeDirection.SOUTH, ForgeDirection.WEST, ForgeDirection.EAST}, - {ForgeDirection.NORTH, ForgeDirection.SOUTH, ForgeDirection.WEST, ForgeDirection.EAST}, - {ForgeDirection.UP, ForgeDirection.DOWN, ForgeDirection.EAST, ForgeDirection.WEST}, - {ForgeDirection.UP, ForgeDirection.DOWN, ForgeDirection.WEST, ForgeDirection.EAST}, - {ForgeDirection.UP, ForgeDirection.DOWN, ForgeDirection.NORTH, ForgeDirection.SOUTH}, - {ForgeDirection.UP, ForgeDirection.DOWN, ForgeDirection.SOUTH, ForgeDirection.NORTH} - }; - - public static class Inventory { - /** - * Consume a single item from a stack of items - * @param stack The stack from which to consume - * @return The remainder of the stack, or null if the stack was fully consumed. - */ - public static ItemStack consumeItem(ItemStack stack) - { - return consumeItem(stack, 1); - } - - /** - * Consume some amount of items from a stack of items. Assumes you've already validated - * the consumption. If you try to consume more than the stack has, it will simply destroy - * the stack, as if you'd consumed all of it. - * @param stack The stack from which to consume - * @return The remainder of the stack, or null if the stack was fully consumed. - */ - public static ItemStack consumeItem(ItemStack stack, int amount) - { - if(stack == null) { return null; } - - if(stack.stackSize <= amount) - { - if(stack.getItem().hasContainerItem(stack)) - { - return stack.getItem().getContainerItem(stack); - } - else - { - return null; - } - } - else - { - stack.splitStack(amount); - return stack; - } - } - - /** - * Is this player holding a goddamn wrench? - * @return True if the player is holding a goddamn wrench. BC only, screw you. - */ - public static boolean isPlayerHoldingWrench(EntityPlayer player) { - if(player.inventory.getCurrentItem() == null) { - return false; - } - Item currentItem = player.inventory.getCurrentItem().getItem(); - return (ModHelperBase.useCofh && currentItem instanceof IToolHammer) || - (ModHelperBase.useBuildcraftTools && currentItem instanceof IToolWrench); - } - - /** - * Check to see if two stacks are equal. NBT-sensitive. - * Lifted from PowerCrystalsCore. - * @param s1 First stack to compare - * @param s2 Second stack to compare - * @return True if stacks are equal, false otherwise. - */ - public static boolean areStacksEqual(ItemStack s1, ItemStack s2) - { - return areStacksEqual(s1, s2, true); + public static final ForgeDirection[] CardinalDirections = new ForgeDirection[] { ForgeDirection.NORTH, + ForgeDirection.EAST, ForgeDirection.SOUTH, ForgeDirection.WEST }; + + public static final ForgeDirection neighborsBySide[][] = new ForgeDirection[][] { + { ForgeDirection.NORTH, ForgeDirection.SOUTH, ForgeDirection.WEST, ForgeDirection.EAST }, + { ForgeDirection.NORTH, ForgeDirection.SOUTH, ForgeDirection.WEST, ForgeDirection.EAST }, + { ForgeDirection.UP, ForgeDirection.DOWN, ForgeDirection.EAST, ForgeDirection.WEST }, + { ForgeDirection.UP, ForgeDirection.DOWN, ForgeDirection.WEST, ForgeDirection.EAST }, + { ForgeDirection.UP, ForgeDirection.DOWN, ForgeDirection.NORTH, ForgeDirection.SOUTH }, + { ForgeDirection.UP, ForgeDirection.DOWN, ForgeDirection.SOUTH, ForgeDirection.NORTH } }; + + public static class Inventory { + + /** + * Consume a single item from a stack of items + * + * @param stack The stack from which to consume + * @return The remainder of the stack, or null if the stack was fully consumed. + */ + public static ItemStack consumeItem(ItemStack stack) { + return consumeItem(stack, 1); + } + + /** + * Consume some amount of items from a stack of items. Assumes you've already validated + * the consumption. If you try to consume more than the stack has, it will simply destroy + * the stack, as if you'd consumed all of it. + * + * @param stack The stack from which to consume + * @return The remainder of the stack, or null if the stack was fully consumed. + */ + public static ItemStack consumeItem(ItemStack stack, int amount) { + if (stack == null) { + return null; + } + + if (stack.stackSize <= amount) { + if (stack.getItem() + .hasContainerItem(stack)) { + return stack.getItem() + .getContainerItem(stack); + } else { + return null; + } + } else { + stack.splitStack(amount); + return stack; + } } /** - * Check to see if two stacks are equal. Optionally NBT-sensitive. - * Lifted from PowerCrystalsCore. - * @param s1 First stack to compare - * @param s2 Second stack to compare + * Is this player holding a goddamn wrench? + * + * @return True if the player is holding a goddamn wrench. BC only, screw you. + */ + public static boolean isPlayerHoldingWrench(EntityPlayer player) { + if (player.inventory.getCurrentItem() == null) { + return false; + } + Item currentItem = player.inventory.getCurrentItem() + .getItem(); + return (ModHelperBase.useCofh && currentItem instanceof IToolHammer) + || (ModHelperBase.useBuildcraftTools && currentItem instanceof IToolWrench); + } + + /** + * Check to see if two stacks are equal. NBT-sensitive. + * Lifted from PowerCrystalsCore. + * + * @param s1 First stack to compare + * @param s2 Second stack to compare + * @return True if stacks are equal, false otherwise. + */ + public static boolean areStacksEqual(ItemStack s1, ItemStack s2) { + return areStacksEqual(s1, s2, true); + } + + /** + * Check to see if two stacks are equal. Optionally NBT-sensitive. + * Lifted from PowerCrystalsCore. + * + * @param s1 First stack to compare + * @param s2 Second stack to compare * @param nbtSensitive True if stacks' NBT tags should be checked for equality. * @return True if stacks are equal, false otherwise. */ - public static boolean areStacksEqual(ItemStack s1, ItemStack s2, boolean nbtSensitive) - { - if(s1 == null || s2 == null) return false; - if(!s1.isItemEqual(s2)) return false; - - if(nbtSensitive) - { - if(s1.getTagCompound() == null && s2.getTagCompound() == null) return true; - if(s1.getTagCompound() == null || s2.getTagCompound() == null) return false; - return s1.getTagCompound().equals(s2.getTagCompound()); + public static boolean areStacksEqual(ItemStack s1, ItemStack s2, boolean nbtSensitive) { + if (s1 == null || s2 == null) return false; + if (!s1.isItemEqual(s2)) return false; + + if (nbtSensitive) { + if (s1.getTagCompound() == null && s2.getTagCompound() == null) return true; + if (s1.getTagCompound() == null || s2.getTagCompound() == null) return false; + return s1.getTagCompound() + .equals(s2.getTagCompound()); + } + + return true; + } + + private static final ForgeDirection[] chestDirections = new ForgeDirection[] { ForgeDirection.NORTH, + ForgeDirection.SOUTH, ForgeDirection.EAST, ForgeDirection.WEST }; + + public static IInventory checkForDoubleChest(World worldObj, IInventory te, int x, int y, int z) { + for (ForgeDirection dir : chestDirections) { + if (worldObj.getBlock(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ) == Blocks.chest) { + TileEntity otherTe = worldObj.getTileEntity(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ); + if (otherTe instanceof IInventory) { + return new InventoryLargeChest("Large Chest", te, (IInventory) otherTe); + } + } + } + + // Not a large chest, so just return the single chest. + return te; + } + } + + public static class Fluids { + + /* Below stolen from COFHLib because COFHLib itself still relies on cofh.core */ + public static boolean fillTankWithContainer(World world, IFluidHandler handler, EntityPlayer player) { + + ItemStack container = player.getCurrentEquippedItem(); + FluidStack fluid = FluidContainerRegistry.getFluidForFilledItem(container); + + if (fluid != null) { + if (handler.fill(ForgeDirection.UNKNOWN, fluid, false) == fluid.amount + || player.capabilities.isCreativeMode) { + if (world.isRemote) { + return true; + } + handler.fill(ForgeDirection.UNKNOWN, fluid, true); + + if (!player.capabilities.isCreativeMode) { + player.inventory + .setInventorySlotContents(player.inventory.currentItem, Inventory.consumeItem(container)); + } + return true; + } + } + return false; + } + + public static boolean fillContainerFromTank(World world, IFluidHandler handler, EntityPlayer player, + FluidStack tankFluid) { + ItemStack container = player.getCurrentEquippedItem(); + + if (FluidContainerRegistry.isEmptyContainer(container)) { + ItemStack returnStack = FluidContainerRegistry.fillFluidContainer(tankFluid, container); + FluidStack fluid = FluidContainerRegistry.getFluidForFilledItem(returnStack); + + if (fluid == null || returnStack == null) { + return false; + } + if (!player.capabilities.isCreativeMode) { + if (container.stackSize == 1) { + container = container.copy(); + player.inventory.setInventorySlotContents(player.inventory.currentItem, returnStack); + } else if (!player.inventory.addItemStackToInventory(returnStack)) { + return false; + } + handler.drain(ForgeDirection.UNKNOWN, fluid.amount, true); + container.stackSize--; + + if (container.stackSize <= 0) { + container = null; + } + } else { + handler.drain(ForgeDirection.UNKNOWN, fluid.amount, true); } - return true; + } + return false; } + } - private static final ForgeDirection[] chestDirections = new ForgeDirection[] { ForgeDirection.NORTH, - ForgeDirection.SOUTH, - ForgeDirection.EAST, - ForgeDirection.WEST}; - - public static IInventory checkForDoubleChest(World worldObj, IInventory te, int x, int y, int z) { - for(ForgeDirection dir : chestDirections) { - if(worldObj.getBlock(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ) == Blocks.chest) { - TileEntity otherTe = worldObj.getTileEntity(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ); - if(otherTe instanceof IInventory) { - return new InventoryLargeChest("Large Chest", te, (IInventory)otherTe); - } - } - } - - // Not a large chest, so just return the single chest. - return te; - } - } - - public static class Fluids { - /* Below stolen from COFHLib because COFHLib itself still relies on cofh.core */ - public static boolean fillTankWithContainer(World world, IFluidHandler handler, EntityPlayer player) { - - ItemStack container = player.getCurrentEquippedItem(); - FluidStack fluid = FluidContainerRegistry.getFluidForFilledItem(container); - - if (fluid != null) { - if (handler.fill(ForgeDirection.UNKNOWN, fluid, false) == fluid.amount || player.capabilities.isCreativeMode) { - if (world.isRemote) { - return true; - } - handler.fill(ForgeDirection.UNKNOWN, fluid, true); - - if (!player.capabilities.isCreativeMode) { - player.inventory.setInventorySlotContents(player.inventory.currentItem, Inventory.consumeItem(container)); - } - return true; - } - } - return false; - } - - public static boolean fillContainerFromTank(World world, IFluidHandler handler, EntityPlayer player, FluidStack tankFluid) { - ItemStack container = player.getCurrentEquippedItem(); - - if (FluidContainerRegistry.isEmptyContainer(container)) { - ItemStack returnStack = FluidContainerRegistry.fillFluidContainer(tankFluid, container); - FluidStack fluid = FluidContainerRegistry.getFluidForFilledItem(returnStack); - - if (fluid == null || returnStack == null) { - return false; - } - if (!player.capabilities.isCreativeMode) { - if (container.stackSize == 1) { - container = container.copy(); - player.inventory.setInventorySlotContents(player.inventory.currentItem, returnStack); - } else if (!player.inventory.addItemStackToInventory(returnStack)) { - return false; - } - handler.drain(ForgeDirection.UNKNOWN, fluid.amount, true); - container.stackSize--; - - if (container.stackSize <= 0) { - container = null; - } - } else { - handler.drain(ForgeDirection.UNKNOWN, fluid.amount, true); - } - return true; - } - return false; - } - } - - public static class ExtraMath { - /** - * Linear interpolate between two numbers. - * @param from - * @param to - * @param modifier - * @return - */ - public static float Lerp(float from, float to, float modifier) - { - modifier = Math.min(1f, Math.max(0f, modifier)); - return from + modifier * (to - from); - } - - /** - * Calculate the volume of the cube defined by two coordinates. - * @param minimum Minimum coordinate. - * @param maximum Maximum coordinate. - * @return The cube's volume, in blocks. - */ - public static int Volume(CoordTriplet minimum, CoordTriplet maximum) { - if(minimum == null || maximum == null) { return 0; } - - int xsize = Math.abs(maximum.x - minimum.x) + 1; - int ysize = Math.abs(maximum.y - minimum.y) + 1; - int zsize = Math.abs(maximum.z - minimum.z) + 1; - return xsize * ysize * zsize; - } - } - - public static class Energy { - public static float RFPerCentigradePerUnitVolume = 10f; - - public static float getRFFromVolumeAndTemp(int volume, float temperature) { - return temperature * (float)volume * RFPerCentigradePerUnitVolume; - } - - public static float getTempFromVolumeAndRF(int volume, float rf) { - return rf / ((float)volume * RFPerCentigradePerUnitVolume); - } - } - - public static class Strings { - public static String[] sizePrefixes = {"", "Ki", "Me", "Gi", "Te", "Pe", "Ex", "Ze", "Yo", "Ho"}; - // Ho = Hojillion - - public static String formatRF(float number) { - String prefix = ""; - if(number < 0f) { - prefix = "-"; - number *= -1; - } - - if(number <= 0.00001f) { return "0.00 RF"; } - - int power = (int)Math.floor(Math.log10(number)); - - int decimalPoints = 2 - (power % 3); - int letterIdx = Math.max(0, Math.min(sizePrefixes.length, power / 3)); - double divisor = Math.pow(1000f, letterIdx); - - if(divisor > 0) { - return String.format("%s%." + Integer.toString(decimalPoints) + "f %sRF", prefix, number/divisor, sizePrefixes[letterIdx]); - } - else { - return String.format("%s%." + Integer.toString(decimalPoints) + "f RF", prefix, number); - } - } - - public static String formatMillibuckets(float number) { - String prefix = ""; - if(number < 0f) { - prefix = "-"; - number *= -1; - } - - if(number <= 0.00001f) { return "0.000 mB"; } - int power = (int)Math.floor(Math.log10(number)); - if(power < 1) { - return String.format("%.3f mB", number); - } - else if(power < 2) { - return String.format("%.2f mB", number); - } - else if(power < 3) { - return String.format("%.1f mB", number); - } - else if(power < 4) { - return String.format("%.0f mB", number); - } - else { - number /= 1000f; // Re-render into buckets - if(power < 5) { - return String.format("%.2f B", number); - } - else if(power < 6) { - return String.format("%.1f B", number); - } - else { - return String.format("%.0f B", number); - } - } - } - } - - // Mob = Mobile = Entity - public static class Mob { - /** - * @param entity The entity whose facing you wish to query. - * @return The ForgeDirection which entity is facing (north/south/east/west) - */ - protected ForgeDirection getFacingDirection(Entity entity) { - int facingAngle = (MathHelper.floor_double((entity.rotationYaw * 4F) / 360F + 0.5D) & 3); - switch(facingAngle) { - case 1: - return ForgeDirection.EAST; - case 2: - return ForgeDirection.SOUTH; - case 3: - return ForgeDirection.WEST; - default: - return ForgeDirection.NORTH; - } - } - } - - public static class TE { - public static TileEntity getTileEntityUnsafe(IBlockAccess iba, int x, int y, int z) { - TileEntity te = null; - - if(iba instanceof World) { - // We don't want to trigger tile entity loads in this method - te = getTileEntityUnsafe((World)iba, x, y, z); - } - else { - // Should never happen, generally - te = iba.getTileEntity(x, y, z); - } - - return te; - } - - public static TileEntity getTileEntityUnsafe(World world, int x, int y, int z) { - TileEntity te = null; - - Chunk chunk = world.getChunkFromBlockCoords(x, z); - if(chunk != null) { - te = chunk.getTileEntityUnsafe(x & 0x0F, y, z & 0x0F); - } - - return te; - } - } - - public static class WorldGen { - /** - * Check if a Big Reactors world generator should even bother to run - * in a given dimension. - * @param dimensionId The dimension being queried for WorldGen. - * @return True if world generation should proceed, false if it should be skipped altogether. - */ - public static boolean shouldGenerateInDimension(int dimensionId) { - return dimensionId >= 0 || BigReactors.enableWorldGenInNegativeDimensions || - BigReactors.dimensionWhitelist.contains(dimensionId); - } - } + public static class ExtraMath { + + /** + * Linear interpolate between two numbers. + * + * @param from + * @param to + * @param modifier + * @return + */ + public static float Lerp(float from, float to, float modifier) { + modifier = Math.min(1f, Math.max(0f, modifier)); + return from + modifier * (to - from); + } + + /** + * Calculate the volume of the cube defined by two coordinates. + * + * @param minimum Minimum coordinate. + * @param maximum Maximum coordinate. + * @return The cube's volume, in blocks. + */ + public static int Volume(CoordTriplet minimum, CoordTriplet maximum) { + if (minimum == null || maximum == null) { + return 0; + } + + int xsize = Math.abs(maximum.x - minimum.x) + 1; + int ysize = Math.abs(maximum.y - minimum.y) + 1; + int zsize = Math.abs(maximum.z - minimum.z) + 1; + return xsize * ysize * zsize; + } + } + + public static class Energy { + + public static float RFPerCentigradePerUnitVolume = 10f; + + public static float getRFFromVolumeAndTemp(int volume, float temperature) { + return temperature * (float) volume * RFPerCentigradePerUnitVolume; + } + + public static float getTempFromVolumeAndRF(int volume, float rf) { + return rf / ((float) volume * RFPerCentigradePerUnitVolume); + } + } + + public static class Strings { + + public static String[] sizePrefixes = { "", "Ki", "Me", "Gi", "Te", "Pe", "Ex", "Ze", "Yo", "Ho" }; + // Ho = Hojillion + + public static String formatRF(float number) { + String prefix = ""; + if (number < 0f) { + prefix = "-"; + number *= -1; + } + + if (number <= 0.00001f) { + return "0.00 RF"; + } + + int power = (int) Math.floor(Math.log10(number)); + + int decimalPoints = 2 - (power % 3); + int letterIdx = Math.max(0, Math.min(sizePrefixes.length, power / 3)); + double divisor = Math.pow(1000f, letterIdx); + + if (divisor > 0) { + return String.format( + "%s%." + Integer.toString(decimalPoints) + "f %sRF", + prefix, + number / divisor, + sizePrefixes[letterIdx]); + } else { + return String.format("%s%." + Integer.toString(decimalPoints) + "f RF", prefix, number); + } + } + + public static String formatMillibuckets(float number) { + String prefix = ""; + if (number < 0f) { + prefix = "-"; + number *= -1; + } + + if (number <= 0.00001f) { + return "0.000 mB"; + } + int power = (int) Math.floor(Math.log10(number)); + if (power < 1) { + return String.format("%.3f mB", number); + } else if (power < 2) { + return String.format("%.2f mB", number); + } else if (power < 3) { + return String.format("%.1f mB", number); + } else if (power < 4) { + return String.format("%.0f mB", number); + } else { + number /= 1000f; // Re-render into buckets + if (power < 5) { + return String.format("%.2f B", number); + } else if (power < 6) { + return String.format("%.1f B", number); + } else { + return String.format("%.0f B", number); + } + } + } + } + + // Mob = Mobile = Entity + public static class Mob { + + /** + * @param entity The entity whose facing you wish to query. + * @return The ForgeDirection which entity is facing (north/south/east/west) + */ + protected ForgeDirection getFacingDirection(Entity entity) { + int facingAngle = (MathHelper.floor_double((entity.rotationYaw * 4F) / 360F + 0.5D) & 3); + switch (facingAngle) { + case 1: + return ForgeDirection.EAST; + case 2: + return ForgeDirection.SOUTH; + case 3: + return ForgeDirection.WEST; + default: + return ForgeDirection.NORTH; + } + } + } + + public static class TE { + + public static TileEntity getTileEntityUnsafe(IBlockAccess iba, int x, int y, int z) { + TileEntity te = null; + + if (iba instanceof World) { + // We don't want to trigger tile entity loads in this method + te = getTileEntityUnsafe((World) iba, x, y, z); + } else { + // Should never happen, generally + te = iba.getTileEntity(x, y, z); + } + + return te; + } + + public static TileEntity getTileEntityUnsafe(World world, int x, int y, int z) { + TileEntity te = null; + + Chunk chunk = world.getChunkFromBlockCoords(x, z); + if (chunk != null) { + te = chunk.getTileEntityUnsafe(x & 0x0F, y, z & 0x0F); + } + + return te; + } + } + + public static class WorldGen { + + /** + * Check if a Big Reactors world generator should even bother to run + * in a given dimension. + * + * @param dimensionId The dimension being queried for WorldGen. + * @return True if world generation should proceed, false if it should be skipped altogether. + */ + public static boolean shouldGenerateInDimension(int dimensionId) { + return dimensionId >= 0 || BigReactors.enableWorldGenInNegativeDimensions + || BigReactors.dimensionWhitelist.contains(dimensionId); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/utils/intermod/IMCHelper.java b/src/main/java/erogenousbeef/bigreactors/utils/intermod/IMCHelper.java index 692ccaaa..65645fb1 100644 --- a/src/main/java/erogenousbeef/bigreactors/utils/intermod/IMCHelper.java +++ b/src/main/java/erogenousbeef/bigreactors/utils/intermod/IMCHelper.java @@ -2,6 +2,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; + import cpw.mods.fml.common.event.FMLInterModComms; /** @@ -14,40 +15,42 @@ */ public class IMCHelper { - protected static void sendInterModMessage(String to, String type, NBTTagCompound message) { - FMLInterModComms.sendMessage(to, type, message); - } - - /// MineFactory Reloaded - public static class MFR { - public static void addOreToMiningLaserFocus(ItemStack stack, int color) { - NBTTagCompound laserOreMsg = new NBTTagCompound(); - stack.writeToNBT(laserOreMsg); - laserOreMsg.setInteger("value", color); - IMCHelper.sendInterModMessage("MineFactoryReloaded", "registerLaserOre", laserOreMsg); - - } - - public static void setMiningLaserFocusPreferredOre(ItemStack stack, int color) { - - } - } - - /// Applied Energistics 2 - public static class AE2 { - public static void addGrinderRecipe(ItemStack input, ItemStack output, int turns) { - NBTTagCompound msg = new NBTTagCompound(); - NBTTagCompound in = new NBTTagCompound(); - NBTTagCompound out = new NBTTagCompound(); - - input.writeToNBT( in ); - output.writeToNBT( out ); - - msg.setTag( "in", in ); - msg.setTag( "out", out ); - msg.setInteger( "turns", turns ); - - sendInterModMessage("appliedenergistics2", "add-grindable", msg); - } - } + protected static void sendInterModMessage(String to, String type, NBTTagCompound message) { + FMLInterModComms.sendMessage(to, type, message); + } + + /// MineFactory Reloaded + public static class MFR { + + public static void addOreToMiningLaserFocus(ItemStack stack, int color) { + NBTTagCompound laserOreMsg = new NBTTagCompound(); + stack.writeToNBT(laserOreMsg); + laserOreMsg.setInteger("value", color); + IMCHelper.sendInterModMessage("MineFactoryReloaded", "registerLaserOre", laserOreMsg); + + } + + public static void setMiningLaserFocusPreferredOre(ItemStack stack, int color) { + + } + } + + /// Applied Energistics 2 + public static class AE2 { + + public static void addGrinderRecipe(ItemStack input, ItemStack output, int turns) { + NBTTagCompound msg = new NBTTagCompound(); + NBTTagCompound in = new NBTTagCompound(); + NBTTagCompound out = new NBTTagCompound(); + + input.writeToNBT(in); + output.writeToNBT(out); + + msg.setTag("in", in); + msg.setTag("out", out); + msg.setInteger("turns", turns); + + sendInterModMessage("appliedenergistics2", "add-grindable", msg); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/utils/intermod/ModHelperBase.java b/src/main/java/erogenousbeef/bigreactors/utils/intermod/ModHelperBase.java index ba4be66c..0f99e9ee 100644 --- a/src/main/java/erogenousbeef/bigreactors/utils/intermod/ModHelperBase.java +++ b/src/main/java/erogenousbeef/bigreactors/utils/intermod/ModHelperBase.java @@ -5,18 +5,18 @@ public class ModHelperBase { - public static boolean useCofh; - public static boolean useBuildcraftTools; - public static boolean useBuildcraftTransport; - - public void register() {} - - public static void detectMods() { - - useCofh = Loader.isModLoaded("CoFHCore"); - useBuildcraftTools = ModAPIManager.INSTANCE.hasAPI("BuildCraftAPI|tools"); - useBuildcraftTransport = ModAPIManager.INSTANCE.hasAPI("BuildCraftAPI|transport"); - - } + public static boolean useCofh; + public static boolean useBuildcraftTools; + public static boolean useBuildcraftTransport; + + public void register() {} + + public static void detectMods() { + + useCofh = Loader.isModLoaded("CoFHCore"); + useBuildcraftTools = ModAPIManager.INSTANCE.hasAPI("BuildCraftAPI|tools"); + useBuildcraftTransport = ModAPIManager.INSTANCE.hasAPI("BuildCraftAPI|transport"); + + } } diff --git a/src/main/java/erogenousbeef/bigreactors/utils/intermod/ModHelperComputerCraft.java b/src/main/java/erogenousbeef/bigreactors/utils/intermod/ModHelperComputerCraft.java index c40880c8..49875c58 100644 --- a/src/main/java/erogenousbeef/bigreactors/utils/intermod/ModHelperComputerCraft.java +++ b/src/main/java/erogenousbeef/bigreactors/utils/intermod/ModHelperComputerCraft.java @@ -6,10 +6,10 @@ public class ModHelperComputerCraft extends ModHelperBase { - @Optional.Method(modid = "ComputerCraft") - @Override - public void register() { - ComputerCraftAPI.registerPeripheralProvider(BigReactors.blockReactorPart); - ComputerCraftAPI.registerPeripheralProvider(BigReactors.blockTurbinePart); - } + @Optional.Method(modid = "ComputerCraft") + @Override + public void register() { + ComputerCraftAPI.registerPeripheralProvider(BigReactors.blockReactorPart); + ComputerCraftAPI.registerPeripheralProvider(BigReactors.blockTurbinePart); + } } diff --git a/src/main/java/erogenousbeef/bigreactors/utils/intermod/ModHelperMekanism.java b/src/main/java/erogenousbeef/bigreactors/utils/intermod/ModHelperMekanism.java index af792591..3a40ee7b 100644 --- a/src/main/java/erogenousbeef/bigreactors/utils/intermod/ModHelperMekanism.java +++ b/src/main/java/erogenousbeef/bigreactors/utils/intermod/ModHelperMekanism.java @@ -3,104 +3,105 @@ import java.lang.reflect.Method; import net.minecraft.item.ItemStack; + import cpw.mods.fml.common.Optional; import erogenousbeef.bigreactors.common.BigReactors; import erogenousbeef.bigreactors.common.item.ItemIngot; public class ModHelperMekanism extends ModHelperBase { - @Optional.Method(modid = "Mekanism") - @Override - public void register() { - ItemIngot ingotGeneric = ((ItemIngot)BigReactors.ingotGeneric); - - ItemStack yelloriteOre = new ItemStack(BigReactors.blockYelloriteOre, 1); - ItemStack ingotYellorium= ingotGeneric.getItemStackForType("ingotYellorium"); - ItemStack ingotCyanite = ingotGeneric.getItemStackForType("ingotCyanite"); - ItemStack ingotGraphite = ingotGeneric.getItemStackForType("ingotGraphite"); - ItemStack ingotBlutonium= ingotGeneric.getItemStackForType("ingotBlutonium"); - ItemStack dustYellorium = ingotGeneric.getItemStackForType("dustYellorium"); - ItemStack dustCyanite = ingotGeneric.getItemStackForType("dustCyanite"); - ItemStack dustGraphite = ingotGeneric.getItemStackForType("dustGraphite"); - ItemStack dustBlutonium = ingotGeneric.getItemStackForType("dustBlutonium"); + @Optional.Method(modid = "Mekanism") + @Override + public void register() { + ItemIngot ingotGeneric = ((ItemIngot) BigReactors.ingotGeneric); + + ItemStack yelloriteOre = new ItemStack(BigReactors.blockYelloriteOre, 1); + ItemStack ingotYellorium = ingotGeneric.getItemStackForType("ingotYellorium"); + ItemStack ingotCyanite = ingotGeneric.getItemStackForType("ingotCyanite"); + ItemStack ingotGraphite = ingotGeneric.getItemStackForType("ingotGraphite"); + ItemStack ingotBlutonium = ingotGeneric.getItemStackForType("ingotBlutonium"); + ItemStack dustYellorium = ingotGeneric.getItemStackForType("dustYellorium"); + ItemStack dustCyanite = ingotGeneric.getItemStackForType("dustCyanite"); + ItemStack dustGraphite = ingotGeneric.getItemStackForType("dustGraphite"); + ItemStack dustBlutonium = ingotGeneric.getItemStackForType("dustBlutonium"); + + // Some mods make me do this myself. :V + ItemStack doubledYelloriumDust = null; + if (dustYellorium != null) { + doubledYelloriumDust = dustYellorium.copy(); + doubledYelloriumDust.stackSize = 2; + } + + if (yelloriteOre != null && doubledYelloriumDust != null) { + addMekanismEnrichmentChamberRecipe(yelloriteOre.copy(), doubledYelloriumDust.copy()); + ItemStack octupledYelloriumDust = dustYellorium.copy(); + octupledYelloriumDust.stackSize = 8; + addMekanismCombinerRecipe(octupledYelloriumDust, yelloriteOre.copy()); + } + + if (ingotYellorium != null && dustYellorium != null) { + addMekanismCrusherRecipe(ingotYellorium.copy(), dustYellorium.copy()); + } - // Some mods make me do this myself. :V - ItemStack doubledYelloriumDust = null; - if(dustYellorium != null) { - doubledYelloriumDust = dustYellorium.copy(); - doubledYelloriumDust.stackSize = 2; - } + if (ingotCyanite != null && dustCyanite != null) { + addMekanismCrusherRecipe(ingotCyanite.copy(), dustCyanite.copy()); + } - if(yelloriteOre != null && doubledYelloriumDust != null) { - addMekanismEnrichmentChamberRecipe(yelloriteOre.copy(), doubledYelloriumDust.copy()); - ItemStack octupledYelloriumDust = dustYellorium.copy(); - octupledYelloriumDust.stackSize = 8; - addMekanismCombinerRecipe(octupledYelloriumDust, yelloriteOre.copy()); - } - - if(ingotYellorium != null && dustYellorium != null) { - addMekanismCrusherRecipe(ingotYellorium.copy(), dustYellorium.copy()); - } + if (ingotGraphite != null && dustGraphite != null) { + addMekanismCrusherRecipe(ingotGraphite.copy(), dustGraphite.copy()); + } - if(ingotCyanite != null && dustCyanite != null) { - addMekanismCrusherRecipe(ingotCyanite.copy(), dustCyanite.copy()); - } + if (ingotBlutonium != null && dustBlutonium != null) { + addMekanismCrusherRecipe(ingotBlutonium.copy(), dustBlutonium.copy()); + } + } - if(ingotGraphite != null && dustGraphite != null) { - addMekanismCrusherRecipe(ingotGraphite.copy(), dustGraphite.copy()); - } + /// Mekanism Compat - taken from Mekanism's API. Extracted to allow compat with last known green build. + /** + * Add an Enrichment Chamber recipe. (Ore -> 2 Dust) + * + * @param input - input ItemStack + * @param output - output ItemStack + */ + public static void addMekanismEnrichmentChamberRecipe(ItemStack input, ItemStack output) { + try { + Class recipeClass = Class.forName("mekanism.api.RecipeHelper"); + Method m = recipeClass.getMethod("addEnrichmentChamberRecipe", ItemStack.class, ItemStack.class); + m.invoke(null, input, output); + } catch (Exception e) { + System.err.println("[Mekanism] Error while adding recipe: " + e.getMessage()); + } + } - if(ingotBlutonium != null && dustBlutonium != null) { - addMekanismCrusherRecipe(ingotBlutonium.copy(), dustBlutonium.copy()); - } - } - - /// Mekanism Compat - taken from Mekanism's API. Extracted to allow compat with last known green build. - /** - * Add an Enrichment Chamber recipe. (Ore -> 2 Dust) - * @param input - input ItemStack - * @param output - output ItemStack - */ - public static void addMekanismEnrichmentChamberRecipe(ItemStack input, ItemStack output) - { - try { - Class recipeClass = Class.forName("mekanism.api.RecipeHelper"); - Method m = recipeClass.getMethod("addEnrichmentChamberRecipe", ItemStack.class, ItemStack.class); - m.invoke(null, input, output); - } catch(Exception e) { - System.err.println("[Mekanism] Error while adding recipe: " + e.getMessage()); - } - } + /** + * Add a Combiner recipe. (8 Dust + Cobble -> Ore) + * + * @param input - input ItemStack + * @param output - output ItemStack + */ + public static void addMekanismCombinerRecipe(ItemStack input, ItemStack output) { + try { + Class recipeClass = Class.forName("mekanism.api.RecipeHelper"); + Method m = recipeClass.getMethod("addCombinerRecipe", ItemStack.class, ItemStack.class); + m.invoke(null, input, output); + } catch (Exception e) { + System.err.println("[Mekanism] Error while adding recipe: " + e.getMessage()); + } + } - /** - * Add a Combiner recipe. (8 Dust + Cobble -> Ore) - * @param input - input ItemStack - * @param output - output ItemStack - */ - public static void addMekanismCombinerRecipe(ItemStack input, ItemStack output) - { - try { - Class recipeClass = Class.forName("mekanism.api.RecipeHelper"); - Method m = recipeClass.getMethod("addCombinerRecipe", ItemStack.class, ItemStack.class); - m.invoke(null, input, output); - } catch(Exception e) { - System.err.println("[Mekanism] Error while adding recipe: " + e.getMessage()); - } - } - - /** - * Add a Crusher recipe. (Ingot -> Dust) - * @param input - input ItemStack - * @param output - output ItemStack - */ - public static void addMekanismCrusherRecipe(ItemStack input, ItemStack output) - { - try { - Class recipeClass = Class.forName("mekanism.api.RecipeHelper"); - Method m = recipeClass.getMethod("addCrusherRecipe", ItemStack.class, ItemStack.class); - m.invoke(null, input, output); - } catch(Exception e) { - System.err.println("[Mekanism] Error while adding recipe: " + e.getMessage()); - } - } + /** + * Add a Crusher recipe. (Ingot -> Dust) + * + * @param input - input ItemStack + * @param output - output ItemStack + */ + public static void addMekanismCrusherRecipe(ItemStack input, ItemStack output) { + try { + Class recipeClass = Class.forName("mekanism.api.RecipeHelper"); + Method m = recipeClass.getMethod("addCrusherRecipe", ItemStack.class, ItemStack.class); + m.invoke(null, input, output); + } catch (Exception e) { + System.err.println("[Mekanism] Error while adding recipe: " + e.getMessage()); + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/world/BRSimpleOreGenerator.java b/src/main/java/erogenousbeef/bigreactors/world/BRSimpleOreGenerator.java index 80984750..6edc3e44 100644 --- a/src/main/java/erogenousbeef/bigreactors/world/BRSimpleOreGenerator.java +++ b/src/main/java/erogenousbeef/bigreactors/world/BRSimpleOreGenerator.java @@ -13,108 +13,109 @@ /** * This class handles simple ore generation. + * * @author Erogenous Beef * */ public class BRSimpleOreGenerator extends WorldGenMinable { - protected Block blockToGenerate; - protected int blockToGenerateMetadata; - protected Block blockToReplace; - - protected int minClustersPerChunk; - protected int maxClustersPerChunk; - protected int minY; - protected int maxY; - - // For now, we never generate in those dimensions. - protected Set dimensionBlacklist; - - public BRSimpleOreGenerator(Block blockToGenerate, int blockMetadata, Block blockToReplace, int clustersPerChunk, int maxY, int maxOrePerCluster) { - super(blockToGenerate, blockMetadata, maxOrePerCluster, blockToReplace); - this.minClustersPerChunk = maxClustersPerChunk = clustersPerChunk; - this.minY = 0; - this.maxY = maxY; - - // this is only used for equality checks - this.blockToGenerate = blockToGenerate; - this.blockToGenerateMetadata = blockMetadata; - this.blockToReplace = blockToReplace; - - dimensionBlacklist = new CopyOnWriteArraySet(); - } - - public BRSimpleOreGenerator(Block blockToGenerate, int blockMetadata, Block blockToReplace, int minClustersPerChunk, int maxClustersPerChunk, int minY, int maxY, int maxOrePerCluster) { - this(blockToGenerate, blockMetadata, blockToReplace, maxClustersPerChunk, maxY, maxOrePerCluster); - this.minClustersPerChunk = minClustersPerChunk; - this.minY = minY; - } - - public void blacklistDimension(int dimensionId) { - dimensionBlacklist.add(dimensionId); - } - - /** - * Call to generate in the given chunk in the given world. - * Performs no validation as to whether this generator should run (per user settings). - * @param world - * @param random - * @param chunkX - * @param chunkZ - */ - public void generateChunk(World world, Random random, int chunkX, int chunkZ) { - int clustersToGen = minClustersPerChunk; - if(maxClustersPerChunk > minClustersPerChunk) { - clustersToGen += random.nextInt(maxClustersPerChunk - minClustersPerChunk); - } - - int chunkBaseX = chunkX << 4; - int chunkBaseZ = chunkZ << 4; - int y; - - for(int i = 0; i < clustersToGen; i++) { - y = this.minY + random.nextInt(this.maxY - this.minY); - - generate(world, random, chunkBaseX, y, chunkBaseZ); - } - } - - /** - * Call to discover if this generator WISHES to generate in this world. - * @param world - * @return - */ - public boolean shouldGenerateInWorld(World world) { - IChunkProvider chunkProvider = world.getChunkProvider(); - if(dimensionBlacklist.contains(world.provider.dimensionId)) { - return false; - } - else if(chunkProvider instanceof ChunkProviderHell) { - return false; - } - else if(chunkProvider instanceof ChunkProviderEnd) { - return false; - } - - return true; - } - - @Override - public boolean equals(Object o) { - if(o instanceof BRSimpleOreGenerator) { - BRSimpleOreGenerator other = (BRSimpleOreGenerator)o; - if(this.blockToGenerate != null) { - return this.blockToGenerate == other.blockToGenerate && this.blockToGenerateMetadata == other.blockToGenerateMetadata; - } - else if(other.blockToGenerate != null) { - return false; - } - else { - return false; - } - } - else { - return false; - } - } + protected Block blockToGenerate; + protected int blockToGenerateMetadata; + protected Block blockToReplace; + + protected int minClustersPerChunk; + protected int maxClustersPerChunk; + protected int minY; + protected int maxY; + + // For now, we never generate in those dimensions. + protected Set dimensionBlacklist; + + public BRSimpleOreGenerator(Block blockToGenerate, int blockMetadata, Block blockToReplace, int clustersPerChunk, + int maxY, int maxOrePerCluster) { + super(blockToGenerate, blockMetadata, maxOrePerCluster, blockToReplace); + this.minClustersPerChunk = maxClustersPerChunk = clustersPerChunk; + this.minY = 0; + this.maxY = maxY; + + // this is only used for equality checks + this.blockToGenerate = blockToGenerate; + this.blockToGenerateMetadata = blockMetadata; + this.blockToReplace = blockToReplace; + + dimensionBlacklist = new CopyOnWriteArraySet(); + } + + public BRSimpleOreGenerator(Block blockToGenerate, int blockMetadata, Block blockToReplace, int minClustersPerChunk, + int maxClustersPerChunk, int minY, int maxY, int maxOrePerCluster) { + this(blockToGenerate, blockMetadata, blockToReplace, maxClustersPerChunk, maxY, maxOrePerCluster); + this.minClustersPerChunk = minClustersPerChunk; + this.minY = minY; + } + + public void blacklistDimension(int dimensionId) { + dimensionBlacklist.add(dimensionId); + } + + /** + * Call to generate in the given chunk in the given world. + * Performs no validation as to whether this generator should run (per user settings). + * + * @param world + * @param random + * @param chunkX + * @param chunkZ + */ + public void generateChunk(World world, Random random, int chunkX, int chunkZ) { + int clustersToGen = minClustersPerChunk; + if (maxClustersPerChunk > minClustersPerChunk) { + clustersToGen += random.nextInt(maxClustersPerChunk - minClustersPerChunk); + } + + int chunkBaseX = chunkX << 4; + int chunkBaseZ = chunkZ << 4; + int y; + + for (int i = 0; i < clustersToGen; i++) { + y = this.minY + random.nextInt(this.maxY - this.minY); + + generate(world, random, chunkBaseX, y, chunkBaseZ); + } + } + + /** + * Call to discover if this generator WISHES to generate in this world. + * + * @param world + * @return + */ + public boolean shouldGenerateInWorld(World world) { + IChunkProvider chunkProvider = world.getChunkProvider(); + if (dimensionBlacklist.contains(world.provider.dimensionId)) { + return false; + } else if (chunkProvider instanceof ChunkProviderHell) { + return false; + } else if (chunkProvider instanceof ChunkProviderEnd) { + return false; + } + + return true; + } + + @Override + public boolean equals(Object o) { + if (o instanceof BRSimpleOreGenerator) { + BRSimpleOreGenerator other = (BRSimpleOreGenerator) o; + if (this.blockToGenerate != null) { + return this.blockToGenerate == other.blockToGenerate + && this.blockToGenerateMetadata == other.blockToGenerateMetadata; + } else if (other.blockToGenerate != null) { + return false; + } else { + return false; + } + } else { + return false; + } + } } diff --git a/src/main/java/erogenousbeef/bigreactors/world/BRWorldGenerator.java b/src/main/java/erogenousbeef/bigreactors/world/BRWorldGenerator.java index 82ff963f..6dc0d3e2 100644 --- a/src/main/java/erogenousbeef/bigreactors/world/BRWorldGenerator.java +++ b/src/main/java/erogenousbeef/bigreactors/world/BRWorldGenerator.java @@ -6,41 +6,42 @@ import net.minecraft.world.World; import net.minecraft.world.chunk.IChunkProvider; + import cpw.mods.fml.common.IWorldGenerator; import erogenousbeef.bigreactors.utils.StaticUtils; public class BRWorldGenerator implements IWorldGenerator { - protected static volatile Set oreGenerators = null; - - public static void addGenerator(BRSimpleOreGenerator newGenerator) { - if(oreGenerators == null) { - oreGenerators = new CopyOnWriteArraySet(); - } - oreGenerators.add(newGenerator); - } - - @Override - public void generate(Random random, int chunkX, int chunkZ, World world, - IChunkProvider chunkGenerator, IChunkProvider chunkProvider) { - generateChunk(random, chunkX, chunkZ, world); - } - - public void generateChunk(Random random, int chunkX, int chunkZ, World world) { - if(oreGenerators == null) { - return; - } - - // Ignore negative dimension IDs if we're disallowing negative dimensions - // OR if this dimensionID is not on the whitelist. - if(!StaticUtils.WorldGen.shouldGenerateInDimension(world.provider.dimensionId)) { - return; - } - - for(BRSimpleOreGenerator generator : oreGenerators) { - if(generator.shouldGenerateInWorld(world)) { - generator.generateChunk(world, random, chunkX, chunkZ); - } - } - } + protected static volatile Set oreGenerators = null; + + public static void addGenerator(BRSimpleOreGenerator newGenerator) { + if (oreGenerators == null) { + oreGenerators = new CopyOnWriteArraySet(); + } + oreGenerators.add(newGenerator); + } + + @Override + public void generate(Random random, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, + IChunkProvider chunkProvider) { + generateChunk(random, chunkX, chunkZ, world); + } + + public void generateChunk(Random random, int chunkX, int chunkZ, World world) { + if (oreGenerators == null) { + return; + } + + // Ignore negative dimension IDs if we're disallowing negative dimensions + // OR if this dimensionID is not on the whitelist. + if (!StaticUtils.WorldGen.shouldGenerateInDimension(world.provider.dimensionId)) { + return; + } + + for (BRSimpleOreGenerator generator : oreGenerators) { + if (generator.shouldGenerateInWorld(world)) { + generator.generateChunk(world, random, chunkX, chunkZ); + } + } + } } diff --git a/src/main/java/erogenousbeef/core/common/BeefCoreLog.java b/src/main/java/erogenousbeef/core/common/BeefCoreLog.java new file mode 100644 index 00000000..69c5cd4c --- /dev/null +++ b/src/main/java/erogenousbeef/core/common/BeefCoreLog.java @@ -0,0 +1,38 @@ +package erogenousbeef.core.common; + +import org.apache.logging.log4j.Level; + +import cpw.mods.fml.common.FMLLog; + +public class BeefCoreLog { + + private static final String CHANNEL = "BeefCore"; + + public static void log(Level level, String format, Object... data) { + FMLLog.log(level, format, data); + } + + public static void fatal(String format, Object... data) { + log(Level.FATAL, format, data); + } + + public static void error(String format, Object... data) { + log(Level.ERROR, format, data); + } + + public static void warning(String format, Object... data) { + log(Level.WARN, format, data); + } + + public static void info(String format, Object... data) { + log(Level.INFO, format, data); + } + + public static void debug(String format, Object... data) { + log(Level.DEBUG, format, data); + } + + public static void trace(String format, Object... data) { + log(Level.TRACE, format, data); + } +} diff --git a/src/main/java/erogenousbeef/core/common/CoordTriplet.java b/src/main/java/erogenousbeef/core/common/CoordTriplet.java new file mode 100644 index 00000000..cce44138 --- /dev/null +++ b/src/main/java/erogenousbeef/core/common/CoordTriplet.java @@ -0,0 +1,163 @@ +package erogenousbeef.core.common; + +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraftforge.common.util.ForgeDirection; + +/* + * Simple wrapper class for XYZ coordinates. + */ +public class CoordTriplet implements Comparable { + + public int x, y, z; + + public CoordTriplet(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public int getChunkX() { + return x >> 4; + } + + public int getChunkZ() { + return z >> 4; + } + + public long getChunkXZHash() { + return ChunkCoordIntPair.chunkXZ2Int(x >> 4, z >> 4); + } + + @Override + public boolean equals(Object other) { + if (other == null) { + return false; + } else if (other instanceof CoordTriplet) { + CoordTriplet otherTriplet = (CoordTriplet) other; + return this.x == otherTriplet.x && this.y == otherTriplet.y && this.z == otherTriplet.z; + } else { + return false; + } + } + + public void translate(ForgeDirection dir) { + this.x += dir.offsetX; + this.y += dir.offsetY; + this.z += dir.offsetZ; + } + + public boolean equals(int x, int y, int z) { + return this.x == x && this.y == y && this.z == z; + } + + // Suggested implementation from NetBeans 7.1 + public int hashCode() { + int hash = 7; + hash = 71 * hash + this.x; + hash = 71 * hash + this.y; + hash = 71 * hash + this.z; + return hash; + } + + public CoordTriplet copy() { + return new CoordTriplet(x, y, z); + } + + public void copy(CoordTriplet other) { + this.x = other.x; + this.y = other.y; + this.z = other.z; + } + + public CoordTriplet[] getNeighbors() { + return new CoordTriplet[] { new CoordTriplet(x + 1, y, z), new CoordTriplet(x - 1, y, z), + new CoordTriplet(x, y + 1, z), new CoordTriplet(x, y - 1, z), new CoordTriplet(x, y, z + 1), + new CoordTriplet(x, y, z - 1) }; + } + + ///// IComparable + + @Override + public int compareTo(Object o) { + if (o instanceof CoordTriplet) { + CoordTriplet other = (CoordTriplet) o; + if (this.x < other.x) { + return -1; + } else if (this.x > other.x) { + return 1; + } else if (this.y < other.y) { + return -1; + } else if (this.y > other.y) { + return 1; + } else if (this.z < other.z) { + return -1; + } else if (this.z > other.z) { + return 1; + } else { + return 0; + } + } + return 0; + } + + ///// Really confusing code that should be cleaned up + + public ForgeDirection getDirectionFromSourceCoords(int x, int y, int z) { + if (this.x < x) { + return ForgeDirection.WEST; + } else if (this.x > x) { + return ForgeDirection.EAST; + } else if (this.y < y) { + return ForgeDirection.DOWN; + } else if (this.y > y) { + return ForgeDirection.UP; + } else if (this.z < z) { + return ForgeDirection.SOUTH; + } else if (this.z > z) { + return ForgeDirection.NORTH; + } else { + return ForgeDirection.UNKNOWN; + } + } + + public ForgeDirection getOppositeDirectionFromSourceCoords(int x, int y, int z) { + if (this.x < x) { + return ForgeDirection.EAST; + } else if (this.x > x) { + return ForgeDirection.WEST; + } else if (this.y < y) { + return ForgeDirection.UP; + } else if (this.y > y) { + return ForgeDirection.DOWN; + } else if (this.z < z) { + return ForgeDirection.NORTH; + } else if (this.z > z) { + return ForgeDirection.SOUTH; + } else { + return ForgeDirection.UNKNOWN; + } + } + + @Override + public String toString() { + return String.format("(%d, %d, %d)", this.x, this.y, this.z); + } + + public int compareTo(int xCoord, int yCoord, int zCoord) { + if (this.x < xCoord) { + return -1; + } else if (this.x > xCoord) { + return 1; + } else if (this.y < yCoord) { + return -1; + } else if (this.y > yCoord) { + return 1; + } else if (this.z < zCoord) { + return -1; + } else if (this.z > zCoord) { + return 1; + } else { + return 0; + } + } +} diff --git a/src/main/java/erogenousbeef/core/multiblock/BlockMultiblockBase.java b/src/main/java/erogenousbeef/core/multiblock/BlockMultiblockBase.java new file mode 100644 index 00000000..8b3010f3 --- /dev/null +++ b/src/main/java/erogenousbeef/core/multiblock/BlockMultiblockBase.java @@ -0,0 +1,15 @@ +package erogenousbeef.core.multiblock; + +import net.minecraft.block.BlockContainer; +import net.minecraft.block.material.Material; + +/* + * Base class for multiblock-capable blocks. This is only a reference implementation + * and can be safely ignored. + */ +public abstract class BlockMultiblockBase extends BlockContainer { + + protected BlockMultiblockBase(Material material) { + super(material); + } +} diff --git a/src/main/java/erogenousbeef/core/multiblock/IMultiblockPart.java b/src/main/java/erogenousbeef/core/multiblock/IMultiblockPart.java new file mode 100644 index 00000000..14b00c65 --- /dev/null +++ b/src/main/java/erogenousbeef/core/multiblock/IMultiblockPart.java @@ -0,0 +1,205 @@ +package erogenousbeef.core.multiblock; + +import java.util.Set; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; + +import erogenousbeef.core.common.CoordTriplet; + +/** + * Basic interface for a multiblock machine part. This is defined as an abstract class + * as we need the basic functionality of a TileEntity as well. + * Preferably, you should derive from MultiblockTileEntityBase, + * which does all the hard work for you. + * + * {@link erogenousbeef.core.multiblock.MultiblockTileEntityBase} + */ +public abstract class IMultiblockPart extends TileEntity { + + public static final int INVALID_DISTANCE = Integer.MAX_VALUE; + + /** + * @return True if this block is connected to a multiblock controller. False otherwise. + */ + public abstract boolean isConnected(); + + /** + * @return The attached multiblock controller for this tile entity. + */ + public abstract MultiblockControllerBase getMultiblockController(); + + /** + * Returns the location of this tile entity in the world, in CoordTriplet form. + * + * @return A CoordTriplet with its x,y,z members set to the location of this tile entity in the world. + */ + public abstract CoordTriplet getWorldLocation(); + + // Multiblock connection-logic callbacks + + /** + * Called after this block has been attached to a new multiblock controller. + * + * @param newController The new multiblock controller to which this tile entity is attached. + */ + public abstract void onAttached(MultiblockControllerBase newController); + + /** + * Called after this block has been detached from a multiblock controller. + * + * @param multiblockController The multiblock controller that no longer controls this tile entity. + */ + public abstract void onDetached(MultiblockControllerBase multiblockController); + + /** + * Called when this block is being orphaned. Use this to copy game-data values that + * should persist despite a machine being broken. + * This should NOT mark the part as disconnected. onDetached will be called immediately afterwards. + * + * @see #onDetached(MultiblockControllerBase) + * @param oldController The controller which is orphaning this block. + * @param oldControllerSize The number of connected blocks in the controller prior to shedding orphans. + * @param newControllerSize The number of connected blocks in the controller after shedding orphans. + */ + public abstract void onOrphaned(MultiblockControllerBase oldController, int oldControllerSize, + int newControllerSize); + + // Multiblock fuse/split helper methods. Here there be dragons. + /** + * Factory method. Creates a new multiblock controller and returns it. + * Does not attach this tile entity to it. + * Override this in your game code! + * + * @return A new Multiblock Controller, derived from MultiblockControllerBase. + */ + public abstract MultiblockControllerBase createNewMultiblock(); + + /** + * Retrieve the type of multiblock controller which governs this part. + * Used to ensure that incompatible multiblocks are not merged. + * + * @return The class/type of the multiblock controller which governs this type of part. + */ + public abstract Class getMultiblockControllerType(); + + /** + * Called when this block is moved from its current controller into a new controller. + * A special case of attach/detach, done here for efficiency to avoid triggering + * lots of recalculation logic. + * + * @param newController The new controller into which this tile entity is being merged. + */ + public abstract void onAssimilated(MultiblockControllerBase newController); + + // Multiblock connection data access. + // You generally shouldn't toy with these! + // They're for use by Multiblock Controllers. + + /** + * Set that this block has been visited by your validation algorithms. + */ + public abstract void setVisited(); + + /** + * Set that this block has not been visited by your validation algorithms; + */ + public abstract void setUnvisited(); + + /** + * @return True if this block has been visited by your validation algorithms since the last reset. + */ + public abstract boolean isVisited(); + + /** + * Called when this block becomes the designated block for saving data and + * transmitting data across the wire. + */ + public abstract void becomeMultiblockSaveDelegate(); + + /** + * Called when this block is no longer the designated block for saving data + * and transmitting data across the wire. + */ + public abstract void forfeitMultiblockSaveDelegate(); + + /** + * Is this block the designated save/load & network delegate? + */ + public abstract boolean isMultiblockSaveDelegate(); + + /** + * Returns an array containing references to neighboring IMultiblockPart tile entities. + * Primarily a utility method. Only works after tileentity construction, so it cannot be used in + * MultiblockControllerBase::attachBlock. + * + * This method is chunk-safe on the server; it will not query for parts in chunks that are unloaded. + * Note that no method is chunk-safe on the client, because ChunkProviderClient is stupid. + * + * @return An array of references to neighboring IMultiblockPart tile entities. + */ + public abstract IMultiblockPart[] getNeighboringParts(); + + // Multiblock business-logic callbacks - implement these! + /** + * Called when a machine is fully assembled from the disassembled state, meaning + * it was broken by a player/entity action, not by chunk unloads. + * Note that, for non-square machines, the min/max coordinates may not actually be part + * of the machine! They form an outer bounding box for the whole machine itself. + * + * @param multiblockControllerBase The controller to which this part is being assembled. + */ + public abstract void onMachineAssembled(MultiblockControllerBase multiblockControllerBase); + + /** + * Called when the machine is broken for game reasons, e.g. a player removed a block + * or an explosion occurred. + */ + public abstract void onMachineBroken(); + + /** + * Called when the user activates the machine. This is not called by default, but is included + * as most machines have this game-logical concept. + */ + public abstract void onMachineActivated(); + + /** + * Called when the user deactivates the machine. This is not called by default, but is included + * as most machines have this game-logical concept. + */ + public abstract void onMachineDeactivated(); + + // Block events + /** + * Called when this part should check its neighbors. + * This method MUST NOT cause additional chunks to load. + * ALWAYS check to see if a chunk is loaded before querying for its tile entity + * This part should inform the controller that it is attaching at this time. + * + * @return A Set of multiblock controllers to which this object would like to attach. It should have attached to one + * of the controllers in this list. Return null if there are no compatible controllers nearby. + */ + public abstract Set attachToNeighbors(); + + /** + * Assert that this part is detached. If not, log a warning and set the part's controller to null. + * Do NOT fire the full disconnection logic. + */ + public abstract void assertDetached(); + + /** + * @return True if a part has multiblock game-data saved inside it. + */ + public abstract boolean hasMultiblockSaveData(); + + /** + * @return The part's saved multiblock game-data in NBT format, or null if there isn't any. + */ + public abstract NBTTagCompound getMultiblockSaveData(); + + /** + * Called after a block is added and the controller has incorporated the part's saved + * multiblock game-data into itself. Generally, you should clear the saved data here. + */ + public abstract void onMultiblockDataAssimilated(); +} diff --git a/src/main/java/erogenousbeef/core/multiblock/MultiblockClientTickHandler.java b/src/main/java/erogenousbeef/core/multiblock/MultiblockClientTickHandler.java new file mode 100644 index 00000000..2cf504d9 --- /dev/null +++ b/src/main/java/erogenousbeef/core/multiblock/MultiblockClientTickHandler.java @@ -0,0 +1,16 @@ +package erogenousbeef.core.multiblock; + +import net.minecraft.client.Minecraft; + +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent; + +public class MultiblockClientTickHandler { + + @SubscribeEvent + public void onClientTick(TickEvent.ClientTickEvent event) { + if (event.phase == TickEvent.Phase.START) { + MultiblockRegistry.tickStart(Minecraft.getMinecraft().theWorld); + } + } +} diff --git a/src/main/java/erogenousbeef/core/multiblock/MultiblockControllerBase.java b/src/main/java/erogenousbeef/core/multiblock/MultiblockControllerBase.java new file mode 100644 index 00000000..9d4a5cf1 --- /dev/null +++ b/src/main/java/erogenousbeef/core/multiblock/MultiblockControllerBase.java @@ -0,0 +1,1037 @@ +package erogenousbeef.core.multiblock; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Set; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.IChunkProvider; + +import erogenousbeef.core.common.BeefCoreLog; +import erogenousbeef.core.common.CoordTriplet; + +/** + * This class contains the base logic for "multiblock controllers". Conceptually, they are + * meta-TileEntities. They govern the logic for an associated group of TileEntities. + * + * Subordinate TileEntities implement the IMultiblockPart class and, generally, should not have an update() loop. + */ +public abstract class MultiblockControllerBase { + + public static final short DIMENSION_UNBOUNDED = -1; + + // Multiblock stuff - do not mess with + protected World worldObj; + + // Disassembled -> Assembled; Assembled -> Disassembled OR Paused; Paused -> Assembled + protected enum AssemblyState { + Disassembled, + Assembled, + Paused + }; + + protected AssemblyState assemblyState; + + protected HashSet connectedParts; + + /** + * This is a deterministically-picked coordinate that identifies this + * multiblock uniquely in its dimension. + * Currently, this is the coord with the lowest X, Y and Z coordinates, in that order of evaluation. + * i.e. If something has a lower X but higher Y/Z coordinates, it will still be the reference. + * If something has the same X but a lower Y coordinate, it will be the reference. Etc. + */ + private CoordTriplet referenceCoord; + + /** + * Minimum bounding box coordinate. Blocks do not necessarily exist at this coord if your machine + * is not a cube/rectangular prism. + */ + private CoordTriplet minimumCoord; + + /** + * Maximum bounding box coordinate. Blocks do not necessarily exist at this coord if your machine + * is not a cube/rectangular prism. + */ + private CoordTriplet maximumCoord; + + /** + * Set to true whenever a part is removed from this controller. + */ + private boolean shouldCheckForDisconnections; + + /** + * Set whenever we validate the multiblock + */ + private MultiblockValidationException lastValidationException; + + protected boolean debugMode; + + protected MultiblockControllerBase(World world) { + // Multiblock stuff + worldObj = world; + connectedParts = new HashSet(); + + referenceCoord = null; + assemblyState = AssemblyState.Disassembled; + + minimumCoord = null; + maximumCoord = null; + + shouldCheckForDisconnections = true; + lastValidationException = null; + + debugMode = false; + } + + public void setDebugMode(boolean active) { + debugMode = active; + } + + public boolean isDebugMode() { + return debugMode; + } + + /** + * Call when a block with cached save-delegate data is added to the multiblock. + * The part will be notified that the data has been used after this call completes. + * + * @param part The NBT tag containing this controller's data. + */ + public abstract void onAttachedPartWithMultiblockData(IMultiblockPart part, NBTTagCompound data); + + /** + * Check if a block is being tracked by this machine. + * + * @param blockCoord Coordinate to check. + * @return True if the tile entity at blockCoord is being tracked by this machine, false otherwise. + */ + public boolean hasBlock(CoordTriplet blockCoord) { + return connectedParts.contains(blockCoord); + } + + /** + * Attach a new part to this machine. + * + * @param part The part to add. + */ + public void attachBlock(IMultiblockPart part) { + IMultiblockPart candidate; + CoordTriplet coord = part.getWorldLocation(); + + if (!connectedParts.add(part)) { + BeefCoreLog.warning( + "[%s] Controller %s is double-adding part %d @ %s. This is unusual. If you encounter odd behavior, please tear down the machine and rebuild it.", + (worldObj.isRemote ? "CLIENT" : "SERVER"), + hashCode(), + part.hashCode(), + coord); + } + + part.onAttached(this); + this.onBlockAdded(part); + + if (part.hasMultiblockSaveData()) { + NBTTagCompound savedData = part.getMultiblockSaveData(); + onAttachedPartWithMultiblockData(part, savedData); + part.onMultiblockDataAssimilated(); + } + + if (this.referenceCoord == null) { + referenceCoord = coord; + part.becomeMultiblockSaveDelegate(); + } else if (coord.compareTo(referenceCoord) < 0) { + TileEntity te = this.worldObj.getTileEntity(referenceCoord.x, referenceCoord.y, referenceCoord.z); + ((IMultiblockPart) te).forfeitMultiblockSaveDelegate(); + + referenceCoord = coord; + part.becomeMultiblockSaveDelegate(); + } else { + part.forfeitMultiblockSaveDelegate(); + } + + if (minimumCoord != null) { + if (part.xCoord < minimumCoord.x) { + minimumCoord.x = part.xCoord; + } + if (part.yCoord < minimumCoord.y) { + minimumCoord.y = part.yCoord; + } + if (part.zCoord < minimumCoord.z) { + minimumCoord.z = part.zCoord; + } + } + + if (maximumCoord != null) { + if (part.xCoord > maximumCoord.x) { + maximumCoord.x = part.xCoord; + } + if (part.yCoord > maximumCoord.y) { + maximumCoord.y = part.yCoord; + } + if (part.zCoord > maximumCoord.z) { + maximumCoord.z = part.zCoord; + } + } + + MultiblockRegistry.addDirtyController(worldObj, this); + } + + /** + * Called when a new part is added to the machine. Good time to register things into lists. + * + * @param newPart The part being added. + */ + protected abstract void onBlockAdded(IMultiblockPart newPart); + + /** + * Called when a part is removed from the machine. Good time to clean up lists. + * + * @param oldPart The part being removed. + */ + protected abstract void onBlockRemoved(IMultiblockPart oldPart); + + /** + * Called when a machine is assembled from a disassembled state. + */ + protected abstract void onMachineAssembled(); + + /** + * Called when a machine is restored to the assembled state from a paused state. + */ + protected abstract void onMachineRestored(); + + /** + * Called when a machine is paused from an assembled state + * This generally only happens due to chunk-loads and other "system" events. + */ + protected abstract void onMachinePaused(); + + /** + * Called when a machine is disassembled from an assembled state. + * This happens due to user or in-game actions (e.g. explosions) + */ + protected abstract void onMachineDisassembled(); + + /** + * Callback whenever a part is removed (or will very shortly be removed) from a controller. + * Do housekeeping/callbacks, also nulls min/max coords. + * + * @param part The part being removed. + */ + private void onDetachBlock(IMultiblockPart part) { + // Strip out this part + part.onDetached(this); + this.onBlockRemoved(part); + part.forfeitMultiblockSaveDelegate(); + + minimumCoord = maximumCoord = null; + + if (referenceCoord != null && referenceCoord.equals(part.xCoord, part.yCoord, part.zCoord)) { + referenceCoord = null; + } + + shouldCheckForDisconnections = true; + } + + /** + * Call to detach a block from this machine. Generally, this should be called + * when the tile entity is being released, e.g. on block destruction. + * + * @param part The part to detach from this machine. + * @param chunkUnloading Is this entity detaching due to the chunk unloading? If true, the multiblock will be paused + * instead of broken. + */ + public void detachBlock(IMultiblockPart part, boolean chunkUnloading) { + if (chunkUnloading && this.assemblyState == AssemblyState.Assembled) { + this.assemblyState = AssemblyState.Paused; + this.onMachinePaused(); + } + + // Strip out this part + onDetachBlock(part); + if (!connectedParts.remove(part)) { + BeefCoreLog.warning( + "[%s] Double-removing part (%d) @ %d, %d, %d, this is unexpected and may cause problems. If you encounter anomalies, please tear down the reactor and rebuild it.", + worldObj.isRemote ? "CLIENT" : "SERVER", + part.hashCode(), + part.xCoord, + part.yCoord, + part.zCoord); + } + + if (connectedParts.isEmpty()) { + // Destroy/unregister + MultiblockRegistry.addDeadController(this.worldObj, this); + return; + } + + MultiblockRegistry.addDirtyController(this.worldObj, this); + + // Find new save delegate if we need to. + if (referenceCoord == null) { + selectNewReferenceCoord(); + } + } + + /** + * Helper method so we don't check for a whole machine until we have enough blocks + * to actually assemble it. This isn't as simple as xmax*ymax*zmax for non-cubic machines + * or for machines with hollow/complex interiors. + * + * @return The minimum number of blocks connected to the machine for it to be assembled. + */ + protected abstract int getMinimumNumberOfBlocksForAssembledMachine(); + + /** + * Returns the maximum X dimension size of the machine, or -1 (DIMENSION_UNBOUNDED) to disable + * dimension checking in X. (This is not recommended.) + * + * @return The maximum X dimension size of the machine, or -1 + */ + protected abstract int getMaximumXSize(); + + /** + * Returns the maximum Z dimension size of the machine, or -1 (DIMENSION_UNBOUNDED) to disable + * dimension checking in X. (This is not recommended.) + * + * @return The maximum Z dimension size of the machine, or -1 + */ + protected abstract int getMaximumZSize(); + + /** + * Returns the maximum Y dimension size of the machine, or -1 (DIMENSION_UNBOUNDED) to disable + * dimension checking in X. (This is not recommended.) + * + * @return The maximum Y dimension size of the machine, or -1 + */ + protected abstract int getMaximumYSize(); + + /** + * Returns the minimum X dimension size of the machine. Must be at least 1, because nothing else makes sense. + * + * @return The minimum X dimension size of the machine + */ + protected int getMinimumXSize() { + return 1; + } + + /** + * Returns the minimum Y dimension size of the machine. Must be at least 1, because nothing else makes sense. + * + * @return The minimum Y dimension size of the machine + */ + protected int getMinimumYSize() { + return 1; + } + + /** + * Returns the minimum Z dimension size of the machine. Must be at least 1, because nothing else makes sense. + * + * @return The minimum Z dimension size of the machine + */ + protected int getMinimumZSize() { + return 1; + } + + /** + * @return An exception representing the last error encountered when trying to assemble this + * multiblock, or null if there is no error. + */ + public MultiblockValidationException getLastValidationException() { + return lastValidationException; + } + + /** + * Checks if a machine is whole. If not, throws an exception with the reason why. + */ + protected abstract void isMachineWhole() throws MultiblockValidationException; + + /** + * Check if the machine is whole or not. + * If the machine was not whole, but now is, assemble the machine. + * If the machine was whole, but no longer is, disassemble the machine. + * + * @return + */ + public void checkIfMachineIsWhole() { + AssemblyState oldState = this.assemblyState; + boolean isWhole; + lastValidationException = null; + try { + isMachineWhole(); + isWhole = true; + } catch (MultiblockValidationException e) { + lastValidationException = e; + isWhole = false; + } + + if (isWhole) { + // This will alter assembly state + assembleMachine(oldState); + } else if (oldState == AssemblyState.Assembled) { + // This will alter assembly state + disassembleMachine(); + } + // Else Paused, do nothing + } + + /** + * Called when a machine becomes "whole" and should begin + * functioning as a game-logically finished machine. + * Calls onMachineAssembled on all attached parts. + */ + private void assembleMachine(AssemblyState oldState) { + for (IMultiblockPart part : connectedParts) { + part.onMachineAssembled(this); + } + + this.assemblyState = AssemblyState.Assembled; + if (oldState == assemblyState.Paused) { + onMachineRestored(); + } else { + onMachineAssembled(); + } + } + + /** + * Called when the machine needs to be disassembled. + * It is not longer "whole" and should not be functional, usually + * as a result of a block being removed. + * Calls onMachineBroken on all attached parts. + */ + private void disassembleMachine() { + for (IMultiblockPart part : connectedParts) { + part.onMachineBroken(); + } + + this.assemblyState = AssemblyState.Disassembled; + onMachineDisassembled(); + } + + /** + * Assimilate another controller into this controller. + * Acquire all of the other controller's blocks and attach them + * to this one. + * + * @param other The controller to merge into this one. + */ + public void assimilate(MultiblockControllerBase other) { + CoordTriplet otherReferenceCoord = other.getReferenceCoord(); + if (otherReferenceCoord != null && getReferenceCoord().compareTo(otherReferenceCoord) >= 0) { + throw new IllegalArgumentException( + "The controller with the lowest minimum-coord value must consume the one with the higher coords"); + } + + TileEntity te; + Set partsToAcquire = new HashSet(other.connectedParts); + + // releases all blocks and references gently so they can be incorporated into another multiblock + other._onAssimilated(this); + + for (IMultiblockPart acquiredPart : partsToAcquire) { + // By definition, none of these can be the minimum block. + if (acquiredPart.isInvalid()) { + continue; + } + + connectedParts.add(acquiredPart); + acquiredPart.onAssimilated(this); + this.onBlockAdded(acquiredPart); + } + + this.onAssimilate(other); + other.onAssimilated(this); + } + + /** + * Called when this machine is consumed by another controller. + * Essentially, forcibly tear down this object. + * + * @param otherController The controller consuming this controller. + */ + private void _onAssimilated(MultiblockControllerBase otherController) { + if (referenceCoord != null) { + if (worldObj.getChunkProvider() + .chunkExists(referenceCoord.getChunkX(), referenceCoord.getChunkZ())) { + TileEntity te = this.worldObj.getTileEntity(referenceCoord.x, referenceCoord.y, referenceCoord.z); + if (te instanceof IMultiblockPart) { + ((IMultiblockPart) te).forfeitMultiblockSaveDelegate(); + } + } + this.referenceCoord = null; + } + + connectedParts.clear(); + } + + /** + * Callback. Called after this controller assimilates all the blocks + * from another controller. + * Use this to absorb that controller's game data. + * + * @param assimilated The controller whose uniqueness was added to our own. + */ + protected abstract void onAssimilate(MultiblockControllerBase assimilated); + + /** + * Callback. Called after this controller is assimilated into another controller. + * All blocks have been stripped out of this object and handed over to the + * other controller. + * This is intended primarily for cleanup. + * + * @param assimilator The controller which has assimilated this controller. + */ + protected abstract void onAssimilated(MultiblockControllerBase assimilator); + + /** + * Driver for the update loop. If the machine is assembled, runs + * the game logic update method. + * + * @see erogenousbeef.core.multiblock.MultiblockControllerBase#update() //TODO Fix this Javadoc + */ + public final void updateMultiblockEntity() { + if (connectedParts.isEmpty()) { + // This shouldn't happen, but just in case... + MultiblockRegistry.addDeadController(this.worldObj, this); + return; + } + + if (this.assemblyState != AssemblyState.Assembled) { + // Not assembled - don't run game logic + return; + } + + if (worldObj.isRemote) { + updateClient(); + } else if (updateServer()) { + // If this returns true, the server has changed its internal data. + // If our chunks are loaded (they should be), we must mark our chunks as dirty. + if (minimumCoord != null && maximumCoord != null + && this.worldObj.checkChunksExist( + minimumCoord.x, + minimumCoord.y, + minimumCoord.z, + maximumCoord.x, + maximumCoord.y, + maximumCoord.z)) { + int minChunkX = minimumCoord.x >> 4; + int minChunkZ = minimumCoord.z >> 4; + int maxChunkX = maximumCoord.x >> 4; + int maxChunkZ = maximumCoord.z >> 4; + + for (int x = minChunkX; x <= maxChunkX; x++) { + for (int z = minChunkZ; z <= maxChunkZ; z++) { + // Ensure that we save our data, even if the our save delegate is in has no TEs. + Chunk chunkToSave = this.worldObj.getChunkFromChunkCoords(x, z); + chunkToSave.setChunkModified(); + } + } + } + } + // Else: Server, but no need to save data. + } + + /** + * The server-side update loop! Use this similarly to a TileEntity's update loop. + * You do not need to call your superclass' update() if you're directly + * derived from MultiblockControllerBase. This is a callback. + * Note that this will only be called when the machine is assembled. + * + * @return True if the multiblock should save data, i.e. its internal game state has changed. False otherwise. + */ + protected abstract boolean updateServer(); + + /** + * Client-side update loop. Generally, this shouldn't do anything, but if you want + * to do some interpolation or something, do it here. + */ + protected abstract void updateClient(); + + // Validation helpers + /** + * The "frame" consists of the outer edges of the machine, plus the corners. + * + * @param world World object for the world in which this controller is located. + * @param x X coordinate of the block being tested + * @param y Y coordinate of the block being tested + * @param z Z coordinate of the block being tested + * @throws MultiblockValidationException if the tested block is not allowed on the machine's frame + */ + protected void isBlockGoodForFrame(World world, int x, int y, int z) throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%d, %d, %d - Block is not valid for use in the machine's interior", x, y, z)); + } + + /** + * The top consists of the top face, minus the edges. + * + * @param world World object for the world in which this controller is located. + * @param x X coordinate of the block being tested + * @param y Y coordinate of the block being tested + * @param z Z coordinate of the block being tested + * @throws MultiblockValidationException if the tested block is not allowed on the machine's top face + */ + protected void isBlockGoodForTop(World world, int x, int y, int z) throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%d, %d, %d - Block is not valid for use in the machine's interior", x, y, z)); + } + + /** + * The bottom consists of the bottom face, minus the edges. + * + * @param world World object for the world in which this controller is located. + * @param x X coordinate of the block being tested + * @param y Y coordinate of the block being tested + * @param z Z coordinate of the block being tested + * @throws MultiblockValidationException if the tested block is not allowed on the machine's bottom face + */ + protected void isBlockGoodForBottom(World world, int x, int y, int z) throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%d, %d, %d - Block is not valid for use in the machine's interior", x, y, z)); + } + + /** + * The sides consists of the N/E/S/W-facing faces, minus the edges. + * + * @param world World object for the world in which this controller is located. + * @param x X coordinate of the block being tested + * @param y Y coordinate of the block being tested + * @param z Z coordinate of the block being tested + * @throws MultiblockValidationException if the tested block is not allowed on the machine's side faces + */ + protected void isBlockGoodForSides(World world, int x, int y, int z) throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%d, %d, %d - Block is not valid for use in the machine's interior", x, y, z)); + } + + /** + * The interior is any block that does not touch blocks outside the machine. + * + * @param world World object for the world in which this controller is located. + * @param x X coordinate of the block being tested + * @param y Y coordinate of the block being tested + * @param z Z coordinate of the block being tested + * @throws MultiblockValidationException if the tested block is not allowed in the machine's interior + */ + protected void isBlockGoodForInterior(World world, int x, int y, int z) throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%d, %d, %d - Block is not valid for use in the machine's interior", x, y, z)); + } + + /** + * @return The reference coordinate, the block with the lowest x, y, z coordinates, evaluated in that order. + */ + public CoordTriplet getReferenceCoord() { + if (referenceCoord == null) { + selectNewReferenceCoord(); + } + return referenceCoord; + } + + /** + * @return The number of blocks connected to this controller. + */ + public int getNumConnectedBlocks() { + return connectedParts.size(); + } + + public abstract void writeToNBT(NBTTagCompound data); + + public abstract void readFromNBT(NBTTagCompound data); + + /** + * Force this multiblock to recalculate its minimum and maximum coordinates + * from the list of connected parts. + */ + public void recalculateMinMaxCoords() { + minimumCoord = new CoordTriplet(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); + maximumCoord = new CoordTriplet(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); + + for (IMultiblockPart part : connectedParts) { + if (part.xCoord < minimumCoord.x) { + minimumCoord.x = part.xCoord; + } + if (part.xCoord > maximumCoord.x) { + maximumCoord.x = part.xCoord; + } + if (part.yCoord < minimumCoord.y) { + minimumCoord.y = part.yCoord; + } + if (part.yCoord > maximumCoord.y) { + maximumCoord.y = part.yCoord; + } + if (part.zCoord < minimumCoord.z) { + minimumCoord.z = part.zCoord; + } + if (part.zCoord > maximumCoord.z) { + maximumCoord.z = part.zCoord; + } + } + } + + /** + * @return The minimum bounding-box coordinate containing this machine's blocks. + */ + public CoordTriplet getMinimumCoord() { + if (minimumCoord == null) { + recalculateMinMaxCoords(); + } + return minimumCoord.copy(); + } + + /** + * @return The maximum bounding-box coordinate containing this machine's blocks. + */ + public CoordTriplet getMaximumCoord() { + if (maximumCoord == null) { + recalculateMinMaxCoords(); + } + return maximumCoord.copy(); + } + + /** + * Called when the save delegate's tile entity is being asked for its description packet + * + * @param data A fresh compound tag to write your multiblock data into + */ + public abstract void formatDescriptionPacket(NBTTagCompound data); + + /** + * Called when the save delegate's tile entity receiving a description packet + * + * @param data A compound tag containing multiblock data to import + */ + public abstract void decodeDescriptionPacket(NBTTagCompound data); + + /** + * @return True if this controller has no associated blocks, false otherwise + */ + public boolean isEmpty() { + return connectedParts.isEmpty(); + } + + /** + * Tests whether this multiblock should consume the other multiblock + * and become the new multiblock master when the two multiblocks + * are adjacent. Assumes both multiblocks are the same type. + * + * @param otherController The other multiblock controller. + * @return True if this multiblock should consume the other, false otherwise. + */ + public boolean shouldConsume(MultiblockControllerBase otherController) { + if (!otherController.getClass() + .equals(getClass())) { + throw new IllegalArgumentException( + "Attempting to merge two multiblocks with different master classes - this should never happen!"); + } + + if (otherController == this) { + return false; + } // Don't be silly, don't eat yourself. + + int res = _shouldConsume(otherController); + if (res < 0) { + return true; + } else if (res > 0) { + return false; + } else { + // Strip dead parts from both and retry + BeefCoreLog.warning( + "[%s] Encountered two controllers with the same reference coordinate. Auditing connected parts and retrying.", + worldObj.isRemote ? "CLIENT" : "SERVER"); + auditParts(); + otherController.auditParts(); + + res = _shouldConsume(otherController); + if (res < 0) { + return true; + } else if (res > 0) { + return false; + } else { + BeefCoreLog.error( + "My Controller (%d): size (%d), parts: %s", + hashCode(), + connectedParts.size(), + getPartsListString()); + BeefCoreLog.error( + "Other Controller (%d): size (%d), coords: %s", + otherController.hashCode(), + otherController.connectedParts.size(), + otherController.getPartsListString()); + throw new IllegalArgumentException( + "[" + (worldObj.isRemote ? "CLIENT" : "SERVER") + + "] Two controllers with the same reference coord that somehow both have valid parts - this should never happen!"); + } + + } + } + + private int _shouldConsume(MultiblockControllerBase otherController) { + CoordTriplet myCoord = getReferenceCoord(); + CoordTriplet theirCoord = otherController.getReferenceCoord(); + + // Always consume other controllers if their reference coordinate is null - this means they're empty and can be + // assimilated on the cheap + if (theirCoord == null) { + return -1; + } else { + return myCoord.compareTo(theirCoord); + } + } + + private String getPartsListString() { + StringBuilder sb = new StringBuilder(); + boolean first = true; + for (IMultiblockPart part : connectedParts) { + if (!first) { + sb.append(", "); + } + sb.append(String.format("(%d: %d, %d, %d)", part.hashCode(), part.xCoord, part.yCoord, part.zCoord)); + first = false; + } + + return sb.toString(); + } + + /** + * Checks all of the parts in the controller. If any are dead or do not exist in the world, they are removed. + */ + private void auditParts() { + HashSet deadParts = new HashSet(); + for (IMultiblockPart part : connectedParts) { + if (part.isInvalid() || worldObj.getTileEntity(part.xCoord, part.yCoord, part.zCoord) != part) { + onDetachBlock(part); + deadParts.add(part); + } + } + + connectedParts.removeAll(deadParts); + BeefCoreLog.warning( + "[%s] Controller found %d dead parts during an audit, %d parts remain attached", + worldObj.isRemote ? "CLIENT" : "SERVER", + deadParts.size(), + connectedParts.size()); + } + + /** + * Called when this machine may need to check for blocks that are no + * longer physically connected to the reference coordinate. + * + * @return + */ + public Set checkForDisconnections() { + if (!this.shouldCheckForDisconnections) { + return null; + } + + if (this.isEmpty()) { + MultiblockRegistry.addDeadController(worldObj, this); + return null; + } + + TileEntity te; + IChunkProvider chunkProvider = worldObj.getChunkProvider(); + + // Invalidate our reference coord, we'll recalculate it shortly + referenceCoord = null; + + // Reset visitations and find the minimum coordinate + Set deadParts = new HashSet(); + CoordTriplet c; + IMultiblockPart referencePart = null; + + int originalSize = connectedParts.size(); + + for (IMultiblockPart part : connectedParts) { + // This happens during chunk unload. + if (!chunkProvider.chunkExists(part.xCoord >> 4, part.zCoord >> 4) || part.isInvalid()) { + deadParts.add(part); + onDetachBlock(part); + continue; + } + + if (worldObj.getTileEntity(part.xCoord, part.yCoord, part.zCoord) != part) { + deadParts.add(part); + onDetachBlock(part); + continue; + } + + part.setUnvisited(); + part.forfeitMultiblockSaveDelegate(); + + c = part.getWorldLocation(); + if (referenceCoord == null) { + referenceCoord = c; + referencePart = part; + } else if (c.compareTo(referenceCoord) < 0) { + referenceCoord = c; + referencePart = part; + } + } + + connectedParts.removeAll(deadParts); + deadParts.clear(); + + if (referencePart == null || isEmpty()) { + // There are no valid parts remaining. The entire multiblock was unloaded during a chunk unload. Halt. + shouldCheckForDisconnections = false; + MultiblockRegistry.addDeadController(worldObj, this); + return null; + } else { + referencePart.becomeMultiblockSaveDelegate(); + } + + // Now visit all connected parts, breadth-first, starting from reference coord's part + IMultiblockPart part; + LinkedList partsToCheck = new LinkedList(); + IMultiblockPart[] nearbyParts = null; + int visitedParts = 0; + + partsToCheck.add(referencePart); + + while (!partsToCheck.isEmpty()) { + part = partsToCheck.removeFirst(); + part.setVisited(); + visitedParts++; + + nearbyParts = part.getNeighboringParts(); // Chunk-safe on server, but not on client + for (IMultiblockPart nearbyPart : nearbyParts) { + // Ignore different machines + if (nearbyPart.getMultiblockController() != this) { + continue; + } + + if (!nearbyPart.isVisited()) { + nearbyPart.setVisited(); + partsToCheck.add(nearbyPart); + } + } + } + + // Finally, remove all parts that remain disconnected. + Set removedParts = new HashSet(); + for (IMultiblockPart orphanCandidate : connectedParts) { + if (!orphanCandidate.isVisited()) { + deadParts.add(orphanCandidate); + orphanCandidate.onOrphaned(this, originalSize, visitedParts); + onDetachBlock(orphanCandidate); + removedParts.add(orphanCandidate); + } + } + + // Trim any blocks that were invalid, or were removed. + connectedParts.removeAll(deadParts); + + // Cleanup. Not necessary, really. + deadParts.clear(); + + // Juuuust in case. + if (referenceCoord == null) { + selectNewReferenceCoord(); + } + + // We've run the checks from here on out. + shouldCheckForDisconnections = false; + + return removedParts; + } + + /** + * Detach all parts. Return a set of all parts which still + * have a valid tile entity. Chunk-safe. + * + * @return A set of all parts which still have a valid tile entity. + */ + public Set detachAllBlocks() { + if (worldObj == null) { + return new HashSet(); + } + + IChunkProvider chunkProvider = worldObj.getChunkProvider(); + for (IMultiblockPart part : connectedParts) { + if (chunkProvider.chunkExists(part.xCoord >> 4, part.zCoord >> 4)) { + onDetachBlock(part); + } + } + + Set detachedParts = connectedParts; + connectedParts = new HashSet(); + return detachedParts; + } + + /** + * @return True if this multiblock machine is considered assembled and ready to go. + */ + public boolean isAssembled() { + return this.assemblyState == AssemblyState.Assembled; + } + + private void selectNewReferenceCoord() { + IChunkProvider chunkProvider = worldObj.getChunkProvider(); + TileEntity theChosenOne = null; + referenceCoord = null; + + for (IMultiblockPart part : connectedParts) { + if (part.isInvalid() || !chunkProvider.chunkExists(part.xCoord >> 4, part.zCoord >> 4)) { + // Chunk is unloading, skip this coord to prevent chunk thrashing + continue; + } + + if (referenceCoord == null || referenceCoord.compareTo(part.xCoord, part.yCoord, part.zCoord) > 0) { + referenceCoord = part.getWorldLocation(); + theChosenOne = part; + } + } + + if (theChosenOne != null) { + ((IMultiblockPart) theChosenOne).becomeMultiblockSaveDelegate(); + } + } + + /** + * Marks the reference coord dirty & updateable. + * + * On the server, this will mark the for a data-update, so that + * nearby clients will receive an updated description packet from the server + * after a short time. The block's chunk will also be marked dirty and the + * block's chunk will be saved to disk the next time chunks are saved. + * + * On the client, this will mark the block for a rendering update. + */ + protected void markReferenceCoordForUpdate() { + CoordTriplet rc = getReferenceCoord(); + if (worldObj != null && rc != null) { + worldObj.markBlockForUpdate(rc.x, rc.y, rc.z); + } + } + + /** + * Marks the reference coord dirty. + * + * On the server, this marks the reference coord's chunk as dirty; the block (and chunk) + * will be saved to disk the next time chunks are saved. This does NOT mark it dirty for + * a description-packet update. + * + * On the client, does nothing. + * + * @see MultiblockControllerBase#markReferenceCoordForUpdate() + */ + protected void markReferenceCoordDirty() { + if (worldObj == null || worldObj.isRemote) { + return; + } + + CoordTriplet referenceCoord = getReferenceCoord(); + if (referenceCoord == null) { + return; + } + + TileEntity saveTe = worldObj.getTileEntity(referenceCoord.x, referenceCoord.y, referenceCoord.z); + worldObj.markTileEntityChunkModified(referenceCoord.x, referenceCoord.y, referenceCoord.z, saveTe); + } + +} diff --git a/src/main/java/erogenousbeef/core/multiblock/MultiblockEventHandler.java b/src/main/java/erogenousbeef/core/multiblock/MultiblockEventHandler.java new file mode 100644 index 00000000..3b8733b0 --- /dev/null +++ b/src/main/java/erogenousbeef/core/multiblock/MultiblockEventHandler.java @@ -0,0 +1,31 @@ +package erogenousbeef.core.multiblock; + +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraftforge.event.world.ChunkEvent; +import net.minecraftforge.event.world.WorldEvent; + +import cpw.mods.fml.common.eventhandler.EventPriority; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; + +/** + * In your mod, subscribe this on both the client and server sides side to handle chunk + * load events for your multiblock machines. + * Chunks can load asynchronously in environments like MCPC+, so we cannot + * process any blocks that are in chunks which are still loading. + */ +public class MultiblockEventHandler { + + @SubscribeEvent(priority = EventPriority.NORMAL) + public void onChunkLoad(ChunkEvent.Load loadEvent) { + Chunk chunk = loadEvent.getChunk(); + World world = loadEvent.world; + MultiblockRegistry.onChunkLoaded(world, chunk.xPosition, chunk.zPosition); + } + + // Cleanup, for nice memory usageness + @SubscribeEvent(priority = EventPriority.NORMAL) + public void onWorldUnload(WorldEvent.Unload unloadWorldEvent) { + MultiblockRegistry.onWorldUnloaded(unloadWorldEvent.world); + } +} diff --git a/src/main/java/erogenousbeef/core/multiblock/MultiblockRegistry.java b/src/main/java/erogenousbeef/core/multiblock/MultiblockRegistry.java new file mode 100644 index 00000000..7ce4a045 --- /dev/null +++ b/src/main/java/erogenousbeef/core/multiblock/MultiblockRegistry.java @@ -0,0 +1,146 @@ +package erogenousbeef.core.multiblock; + +import java.util.HashMap; +import java.util.Set; + +import net.minecraft.world.World; + +import erogenousbeef.core.common.BeefCoreLog; + +/** + * This is a very static singleton registry class which directs incoming events to sub-objects, which + * actually manage each individual world's multiblocks. + * + * @author Erogenous Beef + */ +public class MultiblockRegistry { + + // World > WorldRegistry map + private static HashMap registries = new HashMap(); + + /** + * Called before Tile Entities are ticked in the world. Do bookkeeping here. + * + * @param world The world being ticked + */ + public static void tickStart(World world) { + if (registries.containsKey(world)) { + MultiblockWorldRegistry registry = registries.get(world); + registry.processMultiblockChanges(); + registry.tickStart(); + } + } + + /** + * Called when the world has finished loading a chunk. + * + * @param world The world which has finished loading a chunk + * @param chunkX The X coordinate of the chunk + * @param chunkZ The Z coordinate of the chunk + */ + public static void onChunkLoaded(World world, int chunkX, int chunkZ) { + if (registries.containsKey(world)) { + registries.get(world) + .onChunkLoaded(chunkX, chunkZ); + } + } + + /** + * Register a new part in the system. The part has been created either through user action or via a chunk loading. + * + * @param world The world into which this part is loading. + * @param part The part being loaded. + */ + public static void onPartAdded(World world, IMultiblockPart part) { + MultiblockWorldRegistry registry = getOrCreateRegistry(world); + registry.onPartAdded(part); + } + + /** + * Call to remove a part from world lists. + * + * @param world The world from which a multiblock part is being removed. + * @param part The part being removed. + */ + public static void onPartRemovedFromWorld(World world, IMultiblockPart part) { + if (registries.containsKey(world)) { + registries.get(world) + .onPartRemovedFromWorld(part); + } + + } + + /** + * Called whenever a world is unloaded. Unload the relevant registry, if we have one. + * + * @param world The world being unloaded. + */ + public static void onWorldUnloaded(World world) { + if (registries.containsKey(world)) { + registries.get(world) + .onWorldUnloaded(); + registries.remove(world); + } + } + + /** + * Call to mark a controller as dirty. Dirty means that parts have + * been added or removed this tick. + * + * @param world The world containing the multiblock + * @param controller The dirty controller + */ + public static void addDirtyController(World world, MultiblockControllerBase controller) { + if (registries.containsKey(world)) { + registries.get(world) + .addDirtyController(controller); + } else { + throw new IllegalArgumentException( + "Adding a dirty controller to a world that has no registered controllers!"); + } + } + + /** + * Call to mark a controller as dead. It should only be marked as dead + * when it has no connected parts. It will be removed after the next world tick. + * + * @param world The world formerly containing the multiblock + * @param controller The dead controller + */ + public static void addDeadController(World world, MultiblockControllerBase controller) { + if (registries.containsKey(world)) { + registries.get(world) + .addDeadController(controller); + } else { + BeefCoreLog.warning( + "Controller %d in world %s marked as dead, but that world is not tracked! Controller is being ignored.", + controller.hashCode(), + world); + } + } + + /** + * @param world The world whose controllers you wish to retrieve. + * @return An unmodifiable set of controllers active in the given world, or null if there are none. + */ + public static Set getControllersFromWorld(World world) { + if (registries.containsKey(world)) { + return registries.get(world) + .getControllers(); + } + return null; + } + + /// *** PRIVATE HELPERS *** /// + + private static MultiblockWorldRegistry getOrCreateRegistry(World world) { + if (registries.containsKey(world)) { + return registries.get(world); + } else { + MultiblockWorldRegistry newRegistry = new MultiblockWorldRegistry(world); + registries.put(world, newRegistry); + return newRegistry; + } + } + +} diff --git a/src/main/java/erogenousbeef/core/multiblock/MultiblockServerTickHandler.java b/src/main/java/erogenousbeef/core/multiblock/MultiblockServerTickHandler.java new file mode 100644 index 00000000..22066153 --- /dev/null +++ b/src/main/java/erogenousbeef/core/multiblock/MultiblockServerTickHandler.java @@ -0,0 +1,23 @@ +package erogenousbeef.core.multiblock; + +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent; + +/** + * This is a generic multiblock tick handler. If you are using this code on your own, + * you will need to register this with the Forge TickRegistry on both the + * client AND server sides. + * Note that different types of ticks run on different parts of the system. + * CLIENT ticks only run on the client, at the start/end of each game loop. + * SERVER and WORLD ticks only run on the server. + * WORLDLOAD ticks run only on the server, and only when worlds are loaded. + */ +public class MultiblockServerTickHandler { + + @SubscribeEvent + public void onWorldTick(TickEvent.WorldTickEvent event) { + if (event.phase == TickEvent.Phase.START) { + MultiblockRegistry.tickStart(event.world); + } + } +} diff --git a/src/main/java/erogenousbeef/core/multiblock/MultiblockTileEntityBase.java b/src/main/java/erogenousbeef/core/multiblock/MultiblockTileEntityBase.java new file mode 100644 index 00000000..dc28e986 --- /dev/null +++ b/src/main/java/erogenousbeef/core/multiblock/MultiblockTileEntityBase.java @@ -0,0 +1,370 @@ +package erogenousbeef.core.multiblock; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.Packet; +import net.minecraft.network.play.server.S35PacketUpdateTileEntity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.chunk.IChunkProvider; + +import erogenousbeef.core.common.BeefCoreLog; +import erogenousbeef.core.common.CoordTriplet; + +/** + * Base logic class for Multiblock-connected tile entities. Most multiblock machines + * should derive from this and implement their game logic in certain abstract methods. + */ +public abstract class MultiblockTileEntityBase extends IMultiblockPart { + + private MultiblockControllerBase controller; + private boolean visited; + + private boolean saveMultiblockData; + private NBTTagCompound cachedMultiblockData; + private boolean paused; + + public MultiblockTileEntityBase() { + super(); + controller = null; + visited = false; + saveMultiblockData = false; + paused = false; + cachedMultiblockData = null; + } + + ///// Multiblock Connection Base Logic + @Override + public Set attachToNeighbors() { + Set controllers = null; + MultiblockControllerBase bestController = null; + + // Look for a compatible controller in our neighboring parts. + IMultiblockPart[] partsToCheck = getNeighboringParts(); + for (IMultiblockPart neighborPart : partsToCheck) { + if (neighborPart.isConnected()) { + MultiblockControllerBase candidate = neighborPart.getMultiblockController(); + if (!candidate.getClass() + .equals(this.getMultiblockControllerType())) { + // Skip multiblocks with incompatible types + continue; + } + + if (controllers == null) { + controllers = new HashSet(); + bestController = candidate; + } else if (!controllers.contains(candidate) && candidate.shouldConsume(bestController)) { + bestController = candidate; + } + + controllers.add(candidate); + } + } + + // If we've located a valid neighboring controller, attach to it. + if (bestController != null) { + // attachBlock will call onAttached, which will set the controller. + this.controller = bestController; + bestController.attachBlock(this); + } + + return controllers; + } + + @Override + public void assertDetached() { + if (this.controller != null) { + BeefCoreLog.info( + "[assert] Part @ (%d, %d, %d) should be detached already, but detected that it was not. This is not a fatal error, and will be repaired, but is unusual.", + xCoord, + yCoord, + zCoord); + this.controller = null; + } + } + + ///// Overrides from base TileEntity methods + + @Override + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + + // We can't directly initialize a multiblock controller yet, so we cache the data here until + // we receive a validate() call, which creates the controller and hands off the cached data. + if (data.hasKey("multiblockData")) { + this.cachedMultiblockData = data.getCompoundTag("multiblockData"); + } + } + + @Override + public void writeToNBT(NBTTagCompound data) { + super.writeToNBT(data); + + if (isMultiblockSaveDelegate() && isConnected()) { + NBTTagCompound multiblockData = new NBTTagCompound(); + this.controller.writeToNBT(multiblockData); + data.setTag("multiblockData", multiblockData); + } + } + + /** + * Generally, TileEntities that are part of a multiblock should not subscribe to updates + * from the main game loop. Instead, you should have lists of TileEntities which need to + * be notified during an update() in your Controller and perform callbacks from there. + * + * @see net.minecraft.tileentity.TileEntity#canUpdate() + */ + @Override + public boolean canUpdate() { + return false; + } + + /** + * Called when a block is removed by game actions, such as a player breaking the block + * or the block being changed into another block. + * + * @see net.minecraft.tileentity.TileEntity#invalidate() + */ + @Override + public void invalidate() { + super.invalidate(); + detachSelf(false); + } + + /** + * Called from Minecraft's tile entity loop, after all tile entities have been ticked, + * as the chunk in which this tile entity is contained is unloading. + * Happens before the Forge TickEnd event. + * + * @see net.minecraft.tileentity.TileEntity#onChunkUnload() + */ + @Override + public void onChunkUnload() { + super.onChunkUnload(); + detachSelf(true); + } + + /** + * This is called when a block is being marked as valid by the chunk, but has not yet fully + * been placed into the world's TileEntity cache. this.worldObj, xCoord, yCoord and zCoord have + * been initialized, but any attempts to read data about the world can cause infinite loops - + * if you call getTileEntity on this TileEntity's coordinate from within validate(), you will + * blow your call stack. + * + * TL;DR: Here there be dragons. + * + * @see net.minecraft.tileentity.TileEntity#validate() + */ + @Override + public void validate() { + super.validate(); + MultiblockRegistry.onPartAdded(this.worldObj, this); + } + + // Network Communication + @Override + public Packet getDescriptionPacket() { + NBTTagCompound packetData = new NBTTagCompound(); + encodeDescriptionPacket(packetData); + return new S35PacketUpdateTileEntity(xCoord, yCoord, zCoord, 0, packetData); + } + + @Override + public void onDataPacket(NetworkManager network, S35PacketUpdateTileEntity packet) { + decodeDescriptionPacket(packet.func_148857_g()); + } + + ///// Things to override in most implementations (IMultiblockPart) + /** + * Override this to easily modify the description packet's data without having + * to worry about sending the packet itself. + * Decode this data in decodeDescriptionPacket. + * + * @param packetData An NBT compound tag into which you should write your custom description data. + * @see erogenousbeef.core.multiblock.MultiblockTileEntityBase#decodeDescriptionPacket(NBTTagCompound) + */ + protected void encodeDescriptionPacket(NBTTagCompound packetData) { + if (this.isMultiblockSaveDelegate() && isConnected()) { + NBTTagCompound tag = new NBTTagCompound(); + getMultiblockController().formatDescriptionPacket(tag); + packetData.setTag("multiblockData", tag); + } + } + + /** + * Override this to easily read in data from a TileEntity's description packet. + * Encoded in encodeDescriptionPacket. + * + * @param packetData The NBT data from the tile entity's description packet. + * @see erogenousbeef.core.multiblock.MultiblockTileEntityBase#encodeDescriptionPacket(NBTTagCompound) + */ + protected void decodeDescriptionPacket(NBTTagCompound packetData) { + if (packetData.hasKey("multiblockData")) { + NBTTagCompound tag = packetData.getCompoundTag("multiblockData"); + if (isConnected()) { + getMultiblockController().decodeDescriptionPacket(tag); + } else { + // This part hasn't been added to a machine yet, so cache the data. + this.cachedMultiblockData = tag; + } + } + } + + @Override + public boolean hasMultiblockSaveData() { + return this.cachedMultiblockData != null; + } + + @Override + public NBTTagCompound getMultiblockSaveData() { + return this.cachedMultiblockData; + } + + @Override + public void onMultiblockDataAssimilated() { + this.cachedMultiblockData = null; + } + + ///// Game logic callbacks (IMultiblockPart) + + @Override + public abstract void onMachineAssembled(MultiblockControllerBase multiblockControllerBase); + + @Override + public abstract void onMachineBroken(); + + @Override + public abstract void onMachineActivated(); + + @Override + public abstract void onMachineDeactivated(); + + ///// Miscellaneous multiblock-assembly callbacks and support methods (IMultiblockPart) + + @Override + public boolean isConnected() { + return (controller != null); + } + + @Override + public MultiblockControllerBase getMultiblockController() { + return controller; + } + + @Override + public CoordTriplet getWorldLocation() { + return new CoordTriplet(this.xCoord, this.yCoord, this.zCoord); + } + + @Override + public void becomeMultiblockSaveDelegate() { + this.saveMultiblockData = true; + } + + @Override + public void forfeitMultiblockSaveDelegate() { + this.saveMultiblockData = false; + } + + @Override + public boolean isMultiblockSaveDelegate() { + return this.saveMultiblockData; + } + + @Override + public void setUnvisited() { + this.visited = false; + } + + @Override + public void setVisited() { + this.visited = true; + } + + @Override + public boolean isVisited() { + return this.visited; + } + + @Override + public void onAssimilated(MultiblockControllerBase newController) { + assert (this.controller != newController); + this.controller = newController; + } + + @Override + public void onAttached(MultiblockControllerBase newController) { + this.controller = newController; + } + + @Override + public void onDetached(MultiblockControllerBase oldController) { + this.controller = null; + } + + @Override + public abstract MultiblockControllerBase createNewMultiblock(); + + @Override + public IMultiblockPart[] getNeighboringParts() { + CoordTriplet[] neighbors = new CoordTriplet[] { new CoordTriplet(this.xCoord - 1, this.yCoord, this.zCoord), + new CoordTriplet(this.xCoord, this.yCoord - 1, this.zCoord), + new CoordTriplet(this.xCoord, this.yCoord, this.zCoord - 1), + new CoordTriplet(this.xCoord, this.yCoord, this.zCoord + 1), + new CoordTriplet(this.xCoord, this.yCoord + 1, this.zCoord), + new CoordTriplet(this.xCoord + 1, this.yCoord, this.zCoord) }; + + TileEntity te; + List neighborParts = new ArrayList(); + IChunkProvider chunkProvider = worldObj.getChunkProvider(); + for (CoordTriplet neighbor : neighbors) { + if (!chunkProvider.chunkExists(neighbor.getChunkX(), neighbor.getChunkZ())) { + // Chunk not loaded, skip it. + continue; + } + + te = this.worldObj.getTileEntity(neighbor.x, neighbor.y, neighbor.z); + if (te instanceof IMultiblockPart) { + neighborParts.add((IMultiblockPart) te); + } + } + IMultiblockPart[] tmp = new IMultiblockPart[neighborParts.size()]; + return neighborParts.toArray(tmp); + } + + @Override + public void onOrphaned(MultiblockControllerBase controller, int oldSize, int newSize) { + this.markDirty(); + worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this); + } + + //// Helper functions for notifying neighboring blocks + protected void notifyNeighborsOfBlockChange() { + worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord, getBlockType()); + } + + protected void notifyNeighborsOfTileChange() { + worldObj.func_147453_f(xCoord, yCoord, zCoord, getBlockType()); + } + + ///// Private/Protected Logic Helpers + /* + * Detaches this block from its controller. Calls detachBlock() and clears the controller member. + */ + protected void detachSelf(boolean chunkUnloading) { + if (this.controller != null) { + // Clean part out of controller + this.controller.detachBlock(this, chunkUnloading); + + // The above should call onDetached, but, just in case... + this.controller = null; + } + + // Clean part out of lists in the registry + MultiblockRegistry.onPartRemovedFromWorld(worldObj, this); + } +} diff --git a/src/main/java/erogenousbeef/core/multiblock/MultiblockValidationException.java b/src/main/java/erogenousbeef/core/multiblock/MultiblockValidationException.java new file mode 100644 index 00000000..8c383bfb --- /dev/null +++ b/src/main/java/erogenousbeef/core/multiblock/MultiblockValidationException.java @@ -0,0 +1,14 @@ +package erogenousbeef.core.multiblock; + +/** + * An exception thrown when trying to validate a multiblock. Requires a string describing why the multiblock + * could not assemble. + * + * @author Erogenous Beef + */ +public class MultiblockValidationException extends Exception { + + public MultiblockValidationException(String reason) { + super(reason); + } +} diff --git a/src/main/java/erogenousbeef/core/multiblock/MultiblockWorldRegistry.java b/src/main/java/erogenousbeef/core/multiblock/MultiblockWorldRegistry.java new file mode 100644 index 00000000..26d215fc --- /dev/null +++ b/src/main/java/erogenousbeef/core/multiblock/MultiblockWorldRegistry.java @@ -0,0 +1,426 @@ +package erogenousbeef.core.multiblock; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.World; +import net.minecraft.world.chunk.IChunkProvider; + +import erogenousbeef.core.common.BeefCoreLog; +import erogenousbeef.core.common.CoordTriplet; + +/** + * This class manages all the multiblock controllers that exist in a given world, + * either client- or server-side. + * You must create different registries for server and client worlds. + * + * @author Erogenous Beef + */ +public class MultiblockWorldRegistry { + + private World worldObj; + + private Set controllers; // Active controllers + private Set dirtyControllers; // Controllers whose parts lists have changed + private Set deadControllers; // Controllers which are empty + + // A list of orphan parts - parts which currently have no master, but should seek one this tick + // Indexed by the hashed chunk coordinate + // This can be added-to asynchronously via chunk loads! + private Set orphanedParts; + + // A list of parts which have been detached during internal operations + private Set detachedParts; + + // A list of parts whose chunks have not yet finished loading + // They will be added to the orphan list when they are finished loading. + // Indexed by the hashed chunk coordinate + // This can be added-to asynchronously via chunk loads! + private HashMap> partsAwaitingChunkLoad; + + // Mutexes to protect lists which may be changed due to asynchronous events, such as chunk loads + private Object partsAwaitingChunkLoadMutex; + private Object orphanedPartsMutex; + + public MultiblockWorldRegistry(World world) { + worldObj = world; + + controllers = new HashSet(); + deadControllers = new HashSet(); + dirtyControllers = new HashSet(); + + detachedParts = new HashSet(); + orphanedParts = new HashSet(); + + partsAwaitingChunkLoad = new HashMap>(); + partsAwaitingChunkLoadMutex = new Object(); + orphanedPartsMutex = new Object(); + } + + /** + * Called before Tile Entities are ticked in the world. Run game logic. + */ + public void tickStart() { + if (controllers.size() > 0) { + for (MultiblockControllerBase controller : controllers) { + if (controller.worldObj == worldObj && controller.worldObj.isRemote == worldObj.isRemote) { + if (controller.isEmpty()) { + // This happens on the server when the user breaks the last block. It's fine. + // Mark 'er dead and move on. + deadControllers.add(controller); + } else { + // Run the game logic for this world + controller.updateMultiblockEntity(); + } + } + } + } + } + + /** + * Called prior to processing multiblock controllers. Do bookkeeping. + */ + public void processMultiblockChanges() { + IChunkProvider chunkProvider = worldObj.getChunkProvider(); + CoordTriplet coord; + + // Merge pools - sets of adjacent machines which should be merged later on in processing + List> mergePools = null; + if (orphanedParts.size() > 0) { + Set orphansToProcess = null; + + // Keep the synchronized block small. We can't iterate over orphanedParts directly + // because the client does not know which chunks are actually loaded, so attachToNeighbors() + // is not chunk-safe on the client, because Minecraft is stupid. + // It's possible to polyfill this, but the polyfill is too slow for comfort. + synchronized (orphanedPartsMutex) { + if (orphanedParts.size() > 0) { + orphansToProcess = orphanedParts; + orphanedParts = new HashSet(); + } + } + + if (orphansToProcess != null && orphansToProcess.size() > 0) { + Set compatibleControllers; + + // Process orphaned blocks + // These are blocks that exist in a valid chunk and require a controller + for (IMultiblockPart orphan : orphansToProcess) { + coord = orphan.getWorldLocation(); + if (!chunkProvider.chunkExists(coord.getChunkX(), coord.getChunkZ())) { + continue; + } + + // This can occur on slow machines. + if (orphan.isInvalid()) { + continue; + } + + if (worldObj.getTileEntity(coord.x, coord.y, coord.z) != orphan) { + // This block has been replaced by another. + continue; + } + + // THIS IS THE ONLY PLACE WHERE PARTS ATTACH TO MACHINES + // Try to attach to a neighbor's master controller + compatibleControllers = orphan.attachToNeighbors(); + if (compatibleControllers == null) { + // FOREVER ALONE! Create and register a new controller. + // THIS IS THE ONLY PLACE WHERE NEW CONTROLLERS ARE CREATED. + MultiblockControllerBase newController = orphan.createNewMultiblock(); + newController.attachBlock(orphan); + this.controllers.add(newController); + } else if (compatibleControllers.size() > 1) { + if (mergePools == null) { + mergePools = new ArrayList>(); + } + + // THIS IS THE ONLY PLACE WHERE MERGES ARE DETECTED + // Multiple compatible controllers indicates an impending merge. + // Locate the appropriate merge pool(s) + boolean hasAddedToPool = false; + List> candidatePools = new ArrayList>(); + for (Set candidatePool : mergePools) { + if (!Collections.disjoint(candidatePool, compatibleControllers)) { + // They share at least one element, so that means they will all touch after the merge + candidatePools.add(candidatePool); + } + } + + if (candidatePools.size() <= 0) { + // No pools nearby, create a new merge pool + mergePools.add(compatibleControllers); + } else if (candidatePools.size() == 1) { + // Only one pool nearby, simply add to that one + candidatePools.get(0) + .addAll(compatibleControllers); + } else { + // Multiple pools- merge into one, then add the compatible controllers + Set masterPool = candidatePools.get(0); + Set consumedPool; + for (int i = 1; i < candidatePools.size(); i++) { + consumedPool = candidatePools.get(i); + masterPool.addAll(consumedPool); + mergePools.remove(consumedPool); + } + masterPool.addAll(compatibleControllers); + } + } + } + } + } + + if (mergePools != null && mergePools.size() > 0) { + // Process merges - any machines that have been marked for merge should be merged + // into the "master" machine. + // To do this, we combine lists of machines that are touching one another and therefore + // should voltron the fuck up. + for (Set mergePool : mergePools) { + // Search for the new master machine, which will take over all the blocks contained in the other + // machines + MultiblockControllerBase newMaster = null; + for (MultiblockControllerBase controller : mergePool) { + if (newMaster == null || controller.shouldConsume(newMaster)) { + newMaster = controller; + } + } + + if (newMaster == null) { + BeefCoreLog.fatal( + "Multiblock system checked a merge pool of size %d, found no master candidates. This should never happen.", + mergePool.size()); + } else { + // Merge all the other machines into the master machine, then unregister them + addDirtyController(newMaster); + for (MultiblockControllerBase controller : mergePool) { + if (controller != newMaster) { + newMaster.assimilate(controller); + addDeadController(controller); + addDirtyController(newMaster); + } + } + } + } + } + + // Process splits and assembly + // Any controllers which have had parts removed must be checked to see if some parts are no longer + // physically connected to their master. + if (dirtyControllers.size() > 0) { + Set newlyDetachedParts = null; + for (MultiblockControllerBase controller : dirtyControllers) { + // Tell the machine to check if any parts are disconnected. + // It should return a set of parts which are no longer connected. + // POSTCONDITION: The controller must have informed those parts that + // they are no longer connected to this machine. + newlyDetachedParts = controller.checkForDisconnections(); + + if (!controller.isEmpty()) { + controller.recalculateMinMaxCoords(); + controller.checkIfMachineIsWhole(); + } else { + addDeadController(controller); + } + + if (newlyDetachedParts != null && newlyDetachedParts.size() > 0) { + // Controller has shed some parts - add them to the detached list for delayed processing + detachedParts.addAll(newlyDetachedParts); + } + } + + dirtyControllers.clear(); + } + + // Unregister dead controllers + if (deadControllers.size() > 0) { + for (MultiblockControllerBase controller : deadControllers) { + // Go through any controllers which have marked themselves as potentially dead. + // Validate that they are empty/dead, then unregister them. + if (!controller.isEmpty()) { + BeefCoreLog.fatal( + "Found a non-empty controller. Forcing it to shed its blocks and die. This should never happen!"); + detachedParts.addAll(controller.detachAllBlocks()); + } + + // THIS IS THE ONLY PLACE WHERE CONTROLLERS ARE UNREGISTERED. + this.controllers.remove(controller); + } + + deadControllers.clear(); + } + + // Process detached blocks + // Any blocks which have been detached this tick should be moved to the orphaned + // list, and will be checked next tick to see if their chunk is still loaded. + for (IMultiblockPart part : detachedParts) { + // Ensure parts know they're detached + part.assertDetached(); + } + + addAllOrphanedPartsThreadsafe(detachedParts); + detachedParts.clear(); + } + + /** + * Called when a multiblock part is added to the world, either via chunk-load or user action. + * If its chunk is loaded, it will be processed during the next tick. + * If the chunk is not loaded, it will be added to a list of objects waiting for a chunkload. + * + * @param part The part which is being added to this world. + */ + public void onPartAdded(IMultiblockPart part) { + CoordTriplet worldLocation = part.getWorldLocation(); + + if (!worldObj.getChunkProvider() + .chunkExists(worldLocation.getChunkX(), worldLocation.getChunkZ())) { + // Part goes into the waiting-for-chunk-load list + Set partSet; + long chunkHash = worldLocation.getChunkXZHash(); + synchronized (partsAwaitingChunkLoadMutex) { + if (!partsAwaitingChunkLoad.containsKey(chunkHash)) { + partSet = new HashSet(); + partsAwaitingChunkLoad.put(chunkHash, partSet); + } else { + partSet = partsAwaitingChunkLoad.get(chunkHash); + } + + partSet.add(part); + } + } else { + // Part goes into the orphan queue, to be checked this tick + addOrphanedPartThreadsafe(part); + } + } + + /** + * Called when a part is removed from the world, via user action or via chunk unloads. + * This part is removed from any lists in which it may be, and its machine is marked for recalculation. + * + * @param part The part which is being removed. + */ + public void onPartRemovedFromWorld(IMultiblockPart part) { + CoordTriplet coord = part.getWorldLocation(); + if (coord != null) { + long hash = coord.getChunkXZHash(); + + if (partsAwaitingChunkLoad.containsKey(hash)) { + synchronized (partsAwaitingChunkLoadMutex) { + if (partsAwaitingChunkLoad.containsKey(hash)) { + partsAwaitingChunkLoad.get(hash) + .remove(part); + if (partsAwaitingChunkLoad.get(hash) + .size() <= 0) { + partsAwaitingChunkLoad.remove(hash); + } + } + } + } + } + + detachedParts.remove(part); + if (orphanedParts.contains(part)) { + synchronized (orphanedPartsMutex) { + orphanedParts.remove(part); + } + } + + part.assertDetached(); + } + + /** + * Called when the world which this World Registry represents is fully unloaded from the system. + * Does some housekeeping just to be nice. + */ + public void onWorldUnloaded() { + controllers.clear(); + deadControllers.clear(); + dirtyControllers.clear(); + + detachedParts.clear(); + + synchronized (partsAwaitingChunkLoadMutex) { + partsAwaitingChunkLoad.clear(); + } + + synchronized (orphanedPartsMutex) { + orphanedParts.clear(); + } + + worldObj = null; + } + + /** + * Called when a chunk has finished loading. Adds all of the parts which are awaiting + * load to the list of parts which are orphans and therefore will be added to machines + * after the next world tick. + * + * @param chunkX Chunk X coordinate (world coordate >> 4) of the chunk that was loaded + * @param chunkZ Chunk Z coordinate (world coordate >> 4) of the chunk that was loaded + */ + public void onChunkLoaded(int chunkX, int chunkZ) { + long chunkHash = ChunkCoordIntPair.chunkXZ2Int(chunkX, chunkZ); + if (partsAwaitingChunkLoad.containsKey(chunkHash)) { + synchronized (partsAwaitingChunkLoadMutex) { + if (partsAwaitingChunkLoad.containsKey(chunkHash)) { + addAllOrphanedPartsThreadsafe(partsAwaitingChunkLoad.get(chunkHash)); + partsAwaitingChunkLoad.remove(chunkHash); + } + } + } + } + + /** + * Registers a controller as dead. It will be cleaned up at the end of the next world tick. + * Note that a controller must shed all of its blocks before being marked as dead, or the system + * will complain at you. + * + * @param deadController The controller which is dead. + */ + public void addDeadController(MultiblockControllerBase deadController) { + this.deadControllers.add(deadController); + } + + /** + * Registers a controller as dirty - its list of attached blocks has changed, and it + * must be re-checked for assembly and, possibly, for orphans. + * + * @param dirtyController The dirty controller. + */ + public void addDirtyController(MultiblockControllerBase dirtyController) { + this.dirtyControllers.add(dirtyController); + } + + /** + * Use this only if you know what you're doing. You should rarely need to iterate + * over all controllers in a world! + * + * @return An (unmodifiable) set of controllers which are active in this world. + */ + public Set getControllers() { + return Collections.unmodifiableSet(controllers); + } + + /* *** PRIVATE HELPERS *** */ + + private void addOrphanedPartThreadsafe(IMultiblockPart part) { + synchronized (orphanedPartsMutex) { + orphanedParts.add(part); + } + } + + private void addAllOrphanedPartsThreadsafe(Collection parts) { + synchronized (orphanedPartsMutex) { + orphanedParts.addAll(parts); + } + } + + private String clientOrServer() { + return worldObj.isRemote ? "CLIENT" : "SERVER"; + } +} diff --git a/src/main/java/erogenousbeef/core/multiblock/rectangular/PartPosition.java b/src/main/java/erogenousbeef/core/multiblock/rectangular/PartPosition.java new file mode 100644 index 00000000..deea4318 --- /dev/null +++ b/src/main/java/erogenousbeef/core/multiblock/rectangular/PartPosition.java @@ -0,0 +1,29 @@ +package erogenousbeef.core.multiblock.rectangular; + +public enum PartPosition { + + Unknown, + Interior, + FrameCorner, + Frame, + TopFace, + BottomFace, + NorthFace, + SouthFace, + EastFace, + WestFace; + + public boolean isFace(PartPosition position) { + switch (position) { + case TopFace: + case BottomFace: + case NorthFace: + case SouthFace: + case EastFace: + case WestFace: + return true; + default: + return false; + } + } +} diff --git a/src/main/java/erogenousbeef/core/multiblock/rectangular/RectangularMultiblockControllerBase.java b/src/main/java/erogenousbeef/core/multiblock/rectangular/RectangularMultiblockControllerBase.java new file mode 100644 index 00000000..b94409cc --- /dev/null +++ b/src/main/java/erogenousbeef/core/multiblock/rectangular/RectangularMultiblockControllerBase.java @@ -0,0 +1,155 @@ +package erogenousbeef.core.multiblock.rectangular; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +import erogenousbeef.core.common.CoordTriplet; +import erogenousbeef.core.multiblock.MultiblockControllerBase; +import erogenousbeef.core.multiblock.MultiblockValidationException; + +public abstract class RectangularMultiblockControllerBase extends MultiblockControllerBase { + + protected RectangularMultiblockControllerBase(World world) { + super(world); + } + + /** + * @return True if the machine is "whole" and should be assembled. False otherwise. + */ + protected void isMachineWhole() throws MultiblockValidationException { + if (connectedParts.size() < getMinimumNumberOfBlocksForAssembledMachine()) { + throw new MultiblockValidationException("Machine is too small."); + } + + CoordTriplet maximumCoord = getMaximumCoord(); + CoordTriplet minimumCoord = getMinimumCoord(); + + // Quickly check for exceeded dimensions + int deltaX = maximumCoord.x - minimumCoord.x + 1; + int deltaY = maximumCoord.y - minimumCoord.y + 1; + int deltaZ = maximumCoord.z - minimumCoord.z + 1; + + int maxX = getMaximumXSize(); + int maxY = getMaximumYSize(); + int maxZ = getMaximumZSize(); + int minX = getMinimumXSize(); + int minY = getMinimumYSize(); + int minZ = getMinimumZSize(); + + if (maxX > 0 && deltaX > maxX) { + throw new MultiblockValidationException( + String.format("Machine is too large, it may be at most %d blocks in the X dimension", maxX)); + } + if (maxY > 0 && deltaY > maxY) { + throw new MultiblockValidationException( + String.format("Machine is too large, it may be at most %d blocks in the Y dimension", maxY)); + } + if (maxZ > 0 && deltaZ > maxZ) { + throw new MultiblockValidationException( + String.format("Machine is too large, it may be at most %d blocks in the Z dimension", maxZ)); + } + if (deltaX < minX) { + throw new MultiblockValidationException( + String.format("Machine is too small, it must be at least %d blocks in the X dimension", minX)); + } + if (deltaY < minY) { + throw new MultiblockValidationException( + String.format("Machine is too small, it must be at least %d blocks in the Y dimension", minY)); + } + if (deltaZ < minZ) { + throw new MultiblockValidationException( + String.format("Machine is too small, it must be at least %d blocks in the Z dimension", minZ)); + } + + // Now we run a simple check on each block within that volume. + // Any block deviating = NO DEAL SIR + TileEntity te; + RectangularMultiblockTileEntityBase part; + Class myClass = this.getClass(); + + for (int x = minimumCoord.x; x <= maximumCoord.x; x++) { + for (int y = minimumCoord.y; y <= maximumCoord.y; y++) { + for (int z = minimumCoord.z; z <= maximumCoord.z; z++) { + // Okay, figure out what sort of block this should be. + + te = this.worldObj.getTileEntity(x, y, z); + if (te instanceof RectangularMultiblockTileEntityBase) { + part = (RectangularMultiblockTileEntityBase) te; + + // Ensure this part should actually be allowed within a cube of this controller's type + if (!myClass.equals(part.getMultiblockControllerType())) { + throw new MultiblockValidationException( + String.format( + "Part @ %d, %d, %d is incompatible with machines of type %s", + x, + y, + z, + myClass.getSimpleName())); + } + } else { + // This is permitted so that we can incorporate certain non-multiblock parts inside interiors + part = null; + } + + // Validate block type against both part-level and material-level validators. + int extremes = 0; + if (x == minimumCoord.x) { + extremes++; + } + if (y == minimumCoord.y) { + extremes++; + } + if (z == minimumCoord.z) { + extremes++; + } + + if (x == maximumCoord.x) { + extremes++; + } + if (y == maximumCoord.y) { + extremes++; + } + if (z == maximumCoord.z) { + extremes++; + } + + if (extremes >= 2) { + if (part != null) { + part.isGoodForFrame(); + } else { + isBlockGoodForFrame(this.worldObj, x, y, z); + } + } else if (extremes == 1) { + if (y == maximumCoord.y) { + if (part != null) { + part.isGoodForTop(); + } else { + isBlockGoodForTop(this.worldObj, x, y, z); + } + } else if (y == minimumCoord.y) { + if (part != null) { + part.isGoodForBottom(); + } else { + isBlockGoodForBottom(this.worldObj, x, y, z); + } + } else { + // Side + if (part != null) { + part.isGoodForSides(); + } else { + isBlockGoodForSides(this.worldObj, x, y, z); + } + } + } else { + if (part != null) { + part.isGoodForInterior(); + } else { + isBlockGoodForInterior(this.worldObj, x, y, z); + } + } + } + } + } + } + +} diff --git a/src/main/java/erogenousbeef/core/multiblock/rectangular/RectangularMultiblockTileEntityBase.java b/src/main/java/erogenousbeef/core/multiblock/rectangular/RectangularMultiblockTileEntityBase.java new file mode 100644 index 00000000..6f05cfa3 --- /dev/null +++ b/src/main/java/erogenousbeef/core/multiblock/rectangular/RectangularMultiblockTileEntityBase.java @@ -0,0 +1,109 @@ +package erogenousbeef.core.multiblock.rectangular; + +import net.minecraftforge.common.util.ForgeDirection; + +import erogenousbeef.core.common.CoordTriplet; +import erogenousbeef.core.multiblock.MultiblockControllerBase; +import erogenousbeef.core.multiblock.MultiblockTileEntityBase; +import erogenousbeef.core.multiblock.MultiblockValidationException; + +public abstract class RectangularMultiblockTileEntityBase extends MultiblockTileEntityBase { + + PartPosition position; + ForgeDirection outwards; + + public RectangularMultiblockTileEntityBase() { + super(); + + position = PartPosition.Unknown; + outwards = ForgeDirection.UNKNOWN; + } + + // Positional Data + public ForgeDirection getOutwardsDir() { + return outwards; + } + + public PartPosition getPartPosition() { + return position; + } + + // Handlers from MultiblockTileEntityBase + @Override + public void onAttached(MultiblockControllerBase newController) { + super.onAttached(newController); + recalculateOutwardsDirection(newController.getMinimumCoord(), newController.getMaximumCoord()); + } + + @Override + public void onMachineAssembled(MultiblockControllerBase controller) { + CoordTriplet maxCoord = controller.getMaximumCoord(); + CoordTriplet minCoord = controller.getMinimumCoord(); + + // Discover where I am on the reactor + recalculateOutwardsDirection(minCoord, maxCoord); + } + + @Override + public void onMachineBroken() { + position = PartPosition.Unknown; + outwards = ForgeDirection.UNKNOWN; + } + + // Positional helpers + public void recalculateOutwardsDirection(CoordTriplet minCoord, CoordTriplet maxCoord) { + outwards = ForgeDirection.UNKNOWN; + position = PartPosition.Unknown; + + int facesMatching = 0; + if (maxCoord.x == this.xCoord || minCoord.x == this.xCoord) { + facesMatching++; + } + if (maxCoord.y == this.yCoord || minCoord.y == this.yCoord) { + facesMatching++; + } + if (maxCoord.z == this.zCoord || minCoord.z == this.zCoord) { + facesMatching++; + } + + if (facesMatching <= 0) { + position = PartPosition.Interior; + } else if (facesMatching >= 3) { + position = PartPosition.FrameCorner; + } else if (facesMatching == 2) { + position = PartPosition.Frame; + } else { + // 1 face matches + if (maxCoord.x == this.xCoord) { + position = PartPosition.EastFace; + outwards = ForgeDirection.EAST; + } else if (minCoord.x == this.xCoord) { + position = PartPosition.WestFace; + outwards = ForgeDirection.WEST; + } else if (maxCoord.z == this.zCoord) { + position = PartPosition.SouthFace; + outwards = ForgeDirection.SOUTH; + } else if (minCoord.z == this.zCoord) { + position = PartPosition.NorthFace; + outwards = ForgeDirection.NORTH; + } else if (maxCoord.y == this.yCoord) { + position = PartPosition.TopFace; + outwards = ForgeDirection.UP; + } else { + position = PartPosition.BottomFace; + outwards = ForgeDirection.DOWN; + } + } + } + + ///// Validation Helpers (IMultiblockPart) + public abstract void isGoodForFrame() throws MultiblockValidationException; + + public abstract void isGoodForSides() throws MultiblockValidationException; + + public abstract void isGoodForTop() throws MultiblockValidationException; + + public abstract void isGoodForBottom() throws MultiblockValidationException; + + public abstract void isGoodForInterior() throws MultiblockValidationException; +} diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index 4f38376d..8ba2e765 100644 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -1,18 +1,21 @@ -[ { - "modid": "BigReactors", - "name": "Big Reactors", - "description": "Adds large, multiblock power generation machines to Minecraft. Compatible with Redstone Flux (RF) power.", - "version": "${version}", - "mcversion": "${mcversion}", - "url": "http://www.big-reactors.com", - "updateUrl": "", - "authorList": ["ErogenousBeef"], - "credits": "powercrystals, skyboy, King_Lemming, & Calclavia for example code", - "logoFile": "", - "screenshots": [], - "dependencies": [ - "MinecraftForge", "CoFHCore" - ] + "modListVersion": 2, + "modList": [{ + "modid": "${modId}", + "name": "${modName}", + "description": "Adds large, multiblock power generation machines to Minecraft. Compatible with Redstone Flux (RF) power.", + "version": "${modVersion}", + "mcversion": "${minecraftVersion}", + "url": "https://github.com/LITW-Refined-New-Stories/MyMod", + "updateUrl": "", + "authorList": ["Pilzinsel64", "ErogenousBeef"], + "credits": "powercrystals, skyboy, King_Lemming, & Calclavia for example code", + "logoFile": "", + "screenshots": [], + "parent": "", + "requiredMods": [], + "dependencies": [], + "dependants": [], + "useDependencyInformation": false + }] } -]