Compare commits

...

97 Commits

Author SHA1 Message Date
Sebastian Hartte 5da5315a5b Post-merge fixes. Reformat. Optimize Imports. 2020-09-20 14:47:25 +02:00
Sebastian Hartte f3c44c64c2 Merge remote-tracking branch 'origin/master' into fabric/master
# Conflicts:
#	build.gradle
#	gradle.properties
#	src/api/java/appeng/api/util/DimensionalCoord.java
#	src/main/java/appeng/block/paint/PaintSplotchesBakedModel.java
#	src/main/java/appeng/bootstrap/BlockDefinitionBuilder.java
#	src/main/java/appeng/client/gui/AEBaseScreen.java
#	src/main/java/appeng/client/gui/implementations/CraftAmountScreen.java
#	src/main/java/appeng/client/gui/implementations/CraftConfirmScreen.java
#	src/main/java/appeng/client/gui/implementations/CraftingStatusScreen.java
#	src/main/java/appeng/client/gui/implementations/InterfaceScreen.java
#	src/main/java/appeng/client/gui/implementations/InterfaceTerminalScreen.java
#	src/main/java/appeng/client/gui/implementations/LevelEmitterScreen.java
#	src/main/java/appeng/client/gui/implementations/NumberEntryWidget.java
#	src/main/java/appeng/client/gui/implementations/PriorityScreen.java
#	src/main/java/appeng/client/gui/widgets/IconButton.java
#	src/main/java/appeng/client/gui/widgets/NumberBox.java
#	src/main/java/appeng/client/gui/widgets/SettingToggleButton.java
#	src/main/java/appeng/client/gui/widgets/TabButton.java
#	src/main/java/appeng/client/render/DelegateBakedModel.java
#	src/main/java/appeng/client/render/DummyFluidDispatcherBakedModel.java
#	src/main/java/appeng/client/render/FacadeBakedItemModel.java
#	src/main/java/appeng/client/render/FacadeDispatcherBakedModel.java
#	src/main/java/appeng/client/render/cablebus/P2PTunnelFrequencyBakedModel.java
#	src/main/java/appeng/client/render/crafting/EncodedPatternBakedModel.java
#	src/main/java/appeng/client/render/model/AutoRotatingBakedModel.java
#	src/main/java/appeng/client/render/model/BiometricCardBakedModel.java
#	src/main/java/appeng/client/render/model/ColorApplicatorBakedModel.java
#	src/main/java/appeng/client/render/model/GlassBakedModel.java
#	src/main/java/appeng/client/render/model/MemoryCardBakedModel.java
#	src/main/java/appeng/client/render/model/SkyCompassBakedModel.java
#	src/main/java/appeng/client/render/tesr/ChestTileEntityRenderer.java
#	src/main/java/appeng/container/AEBaseContainer.java
#	src/main/java/appeng/container/ContainerLocator.java
#	src/main/java/appeng/container/guisync/SyncData.java
#	src/main/java/appeng/container/implementations/CellWorkbenchContainer.java
#	src/main/java/appeng/container/implementations/CondenserContainer.java
#	src/main/java/appeng/container/implementations/ContainerHelper.java
#	src/main/java/appeng/container/implementations/CraftConfirmContainer.java
#	src/main/java/appeng/container/implementations/CraftingCPUContainer.java
#	src/main/java/appeng/container/implementations/CraftingCPURecord.java
#	src/main/java/appeng/container/implementations/CraftingStatusContainer.java
#	src/main/java/appeng/container/implementations/IOPortContainer.java
#	src/main/java/appeng/container/implementations/InscriberContainer.java
#	src/main/java/appeng/container/implementations/InterfaceTerminalContainer.java
#	src/main/java/appeng/container/implementations/LevelEmitterContainer.java
#	src/main/java/appeng/container/implementations/MEMonitorableContainer.java
#	src/main/java/appeng/container/implementations/MolecularAssemblerContainer.java
#	src/main/java/appeng/container/implementations/PatternTermContainer.java
#	src/main/java/appeng/container/implementations/PriorityContainer.java
#	src/main/java/appeng/container/implementations/QuartzKnifeContainer.java
#	src/main/java/appeng/container/implementations/SpatialIOPortContainer.java
#	src/main/java/appeng/container/implementations/VibrationChamberContainer.java
#	src/main/java/appeng/container/implementations/WirelessTermContainer.java
#	src/main/java/appeng/core/AEConfig.java
#	src/main/java/appeng/core/AppEngBootstrap.java
#	src/main/java/appeng/core/Registration.java
#	src/main/java/appeng/core/api/definitions/ApiItems.java
#	src/main/java/appeng/core/features/registries/WorldGenRegistry.java
#	src/main/java/appeng/core/sync/network/NetworkHandler.java
#	src/main/java/appeng/core/worlddata/WorldData.java
#	src/main/java/appeng/datagen/providers/loot/BlockDropProvider.java
#	src/main/java/appeng/debug/ChunkLoaderBlockEntity.java
#	src/main/java/appeng/debug/ReplicatorCardItem.java
#	src/main/java/appeng/entity/GrowingCrystalEntity.java
#	src/main/java/appeng/fluids/client/gui/FluidLevelEmitterScreen.java
#	src/main/java/appeng/fluids/client/gui/FluidTerminalScreen.java
#	src/main/java/appeng/fluids/container/FluidConfigurableContainer.java
#	src/main/java/appeng/fluids/container/FluidInterfaceContainer.java
#	src/main/java/appeng/fluids/container/FluidLevelEmitterContainer.java
#	src/main/java/appeng/fluids/container/FluidTerminalContainer.java
#	src/main/java/appeng/fluids/util/AEFluidInventory.java
#	src/main/java/appeng/items/misc/CrystalSeedItem.java
#	src/main/java/appeng/items/misc/CrystalSeedRendering.java
#	src/main/java/appeng/items/storage/SpatialStorageCellItem.java
#	src/main/java/appeng/me/cluster/implementations/QuantumCluster.java
#	src/main/java/appeng/mixins/feature/ConfiguredFeaturesAccessor.java
#	src/main/java/appeng/mixins/spatial/BiomesMixin.java
#	src/main/java/appeng/mixins/spatial/DimensionTypeMixin.java
#	src/main/java/appeng/mixins/spatial/EntityMixin.java
#	src/main/java/appeng/mixins/spatial/SkyRenderMixin.java
#	src/main/java/appeng/mixins/structure/BiomeAccessor.java
#	src/main/java/appeng/mixins/structure/GenerationSettingsAccessor.java
#	src/main/java/appeng/parts/automation/FormationPlanePart.java
#	src/main/java/appeng/parts/automation/PlaneBakedModel.java
#	src/main/java/appeng/server/subcommands/SpatialStorageCommand.java
#	src/main/java/appeng/server/subcommands/TestMeteoritesCommand.java
#	src/main/java/appeng/server/subcommands/TestOreGenCommand.java
#	src/main/java/appeng/spatial/SpatialStorageBiome.java
#	src/main/java/appeng/spatial/SpatialStorageChunkGenerator.java
#	src/main/java/appeng/spatial/SpatialStorageDimensionIds.java
#	src/main/java/appeng/spatial/SpatialStorageHelper.java
#	src/main/java/appeng/util/Platform.java
#	src/main/java/appeng/worldgen/BiomeModifier.java
#	src/main/java/appeng/worldgen/meteorite/MeteoriteStructureStart.java
#	src/main/java/appeng/worldgen/meteorite/fallout/FalloutCopy.java
#	src/main/resources/assets/appliedenergistics2/textures/guis/states.png
2020-09-20 14:11:22 +02:00
Sebastian Hartte b8f48407cd Fix tooltip rendering. 2020-09-20 01:06:53 +02:00
Sebastian Hartte 489b0f635e Merge remote-tracking branch 'origin/8.0.x-1.16.1' 2020-09-20 00:42:52 +02:00
shartte e6fb553a53 Fixes #4741: Rework Crafting CPU cycling and extract commonalities into a separate class. (#4742)
Also Fixes:
- Enter key confirms the "Confirm Crafting" dialog again
- Right Mouse Button correctly cycles backwards through CPUs, while left mouse button forward
- Fixes an internal problem with syncing CPU names
- Naming of unnamed CPUs begins at #1 now
2020-09-20 00:26:34 +02:00
Sebastian Hartte cacd824db3 Remove unused field indicating availability of client classes. 2020-09-19 18:20:11 +02:00
yueh 876bb52087 Update forge mappings to 20200916-1.16.2 (#4749) 2020-09-19 17:32:23 +02:00
Sebastian Hartte 1b4969c8e7 Formatting fixes. 2020-09-19 16:58:37 +02:00
Sebastian Hartte f2427ee347 Fixes #4747: The chunk unload event was triggering before the chunk was actually saved to disk, which means disconnecting grid connections at that point led to grid nodes not saving their data to the chunk. 2020-09-19 16:54:30 +02:00
Sebastian Hartte 4aa9c92a68 Fixes #4747: Server unload event was destroying grids before the associated nodes were saved, leading to player ids not being saved correctly when quitting the server. 2020-09-19 16:49:44 +02:00
shartte 971a9d22e8 Improvements to the usability of the number entry widgets (Priority, Level Emitter, Craft Amount): (#4737)
- Fixed tab order
- Introduced focus state for corner buttons
- Allowed the player to enter any text, but add validation that only persist it if it is a valid number
- Enter will now confirm these dialogs and return to the previous dialog
- The text field is automatically focused and its contents are selected
2020-09-19 16:27:29 +02:00
Sebastian Hartte b5a90357c0 Fix ME Chest attributes being exposed on the wrong side. 2020-09-19 13:59:09 +02:00
Sebastian Hartte 5be0adbc89 Fixed Mixins that were targeting the wrong class/methods. 2020-09-19 02:48:59 +02:00
Sebastian Hartte d8e5f4fed5 Fixed formatating after migrating mappings. 2020-09-19 02:41:53 +02:00
Sebastian Hartte 47dfc19b7c Renamed mixin after mapping update. 2020-09-19 02:40:51 +02:00
Sebastian Hartte 45f5851079 Updated versions, and mappings. 2020-09-19 02:40:35 +02:00
Sebastian Hartte 76efe6026d Add an indicator that shows the number of active crafting jobs. 2020-09-18 21:34:42 +02:00
yueh 4e03cbd356 Simply build all branches 2020-09-18 10:32:06 +02:00
Sebastian Hartte ce058b006c Fixes #4748: badly filtered inventory leads to crashes, also expose the ME storage again. 2020-09-18 03:11:33 +02:00
yueh 9005db6f1c Fix yaml syntax 2020-09-17 21:42:20 +02:00
yueh 58afe755b8 Build PRs for all release branches (#4746) 2020-09-17 21:37:53 +02:00
Sebastian Hartte f368f9dac2 Fixes #4697: Show number of required items in condenser tooltips. 2020-09-17 14:33:43 +02:00
Sebastian Hartte e5b45d51cc Minor style fixes. 2020-09-17 11:43:29 +02:00
shartte 5a1d5356d1 Fixes #4733: Fix a crash bug when an external machine tries draining fluids from a fluid interface without a filter. (#4738) 2020-09-16 23:13:18 +02:00
Sebastian Hartte 5aef82b9ef Optimized Imports 2020-09-16 21:35:47 +02:00
Sebastian Hartte 483f93f977 Post-merge fixes and item generator fix. 2020-09-16 20:12:38 +02:00
Sebastian Hartte 1759f92164 Prevent FG from force-exiting the daemon if runData is used. 2020-09-16 19:51:22 +02:00
Sebastian Hartte e50c13e570 Rolled back the memory change since it'll cause a daemon to launch even during a CI build. 2020-09-16 19:29:47 +02:00
Sebastian Hartte c0575e11b0 Merge remote-tracking branch 'origin/master' into fabric/master
# Conflicts:
#	build.gradle
#	gradle.properties
#	gradle/scripts/artifacts.gradle
#	gradle/scripts/curseforge.gradle
#	gradle/wrapper/gradle-wrapper.jar
#	gradle/wrapper/gradle-wrapper.properties
#	src/main/java/appeng/block/networking/CableBusBlock.java
#	src/main/java/appeng/client/gui/AEBaseScreen.java
#	src/main/java/appeng/client/gui/implementations/InterfaceTerminalScreen.java
#	src/main/java/appeng/client/gui/widgets/Scrollbar.java
#	src/main/java/appeng/core/sync/packets/JEIRecipePacket.java
#	src/main/java/appeng/tile/AEBaseBlockEntity.java
#	src/main/resources/META-INF/mods.toml
2020-09-16 18:57:15 +02:00
Sebastian Hartte 749dd35f88 Updated forge and increased memory for IDE-sync daemon. 2020-09-16 18:18:22 +02:00
Sebastian Hartte ca79a377bd Merge remote-tracking branch 'origin/8.0.x-1.16.1'
# Conflicts:
#	gradle/scripts/dependencies.gradle
2020-09-16 17:49:59 +02:00
Sebastian Hartte 475c8ff5a1 Adapt the same sorting logic used for items stored in the network for items obtained from patterns, which fixes items from patterns not being able to be shift-clicked into new patterns. 2020-09-16 17:44:49 +02:00
yueh 5b3ccf26d0 Merge all gradle files (#4732)
* Merge all gradle files

The specific build files are now much smaller, so a single one is mostly acceptable now.
Also updates Gradle to 5.6.3

* Disable the Mixin annotation processor when importing this project into IntelliJ since it should only be needed to generate refmaps on an actual build.

* Removed Sonarqube and JaCoCo plugins.

Co-authored-by: Sebastian Hartte <sebastian@hartte.de>
2020-09-14 14:14:00 +02:00
Sebastian Hartte e73dbe4891 Updated Forge / MC to 1.16.3
Keep Mappings
Allow higher range for MC + Forge versions
2020-09-14 02:02:59 +02:00
Sebastian Hartte 38244000c9 Fixes #4731: Take the position where the user clicked the handle into account when calculating the new scrollbar position.
Also fixes: The scrollbar did not subtract the handle height when determining the available space for moving the handle, thus introducing drift the further down a user scrolled.
Also fixes: The scrollbar did not resize it's trackbar when the ME inventory screens were resized and the number of rows changed, same for craft confirm.
2020-09-13 23:12:59 +02:00
Sebastian Hartte d87ff9d1e7 Formatting fixes. 2020-09-13 22:18:38 +02:00
Sebastian Hartte 4ba97ec899 Remove unnecessary debug prints, and rename methods. 2020-09-13 22:11:40 +02:00
Sebastian Hartte 0147e1ddfb Fixes #4730 and also introduces repeat-pageup/pagedown when holding the mouse on the area above or below the scrollbar handle. 2020-09-13 22:09:47 +02:00
yueh 621d2ee715 Fixes #4728: Mark all offloading threads as daemons (#4729) 2020-09-13 11:55:18 +02:00
Sebastian Hartte 31ecdfbe0a Use the correct method to update an entities position forcefully. 2020-09-11 18:04:17 +02:00
Sebastian Hartte f0bfbfec48 Should also actually _use_ the fixed invoker... 2020-09-11 17:25:39 +02:00
Sebastian Hartte 06a8843a65 Fix a Mixin bug that causes an Invoker conflict with Patchouli.
See https://github.com/SpongePowered/Mixin/issues/430
2020-09-11 17:20:20 +02:00
shartte d07937fa93 Render Performance Improvements (#4721)
* Return a fixed bounding box for frustrum culling of AE tile entity renderers to prevent Forge from re-retrieving the TE from the world and calculating the collision box (very costly for cables).

* Changed dynamic cable bus lighting to be based on block states to improved rendering speed and fix optifine issues. (Potential fix for #4716).
2020-09-10 22:56:50 +02:00
shartte 65f58913a4 Make players assume ownership of networks when they place security stations onto unsecured ones (#4714)
* Fixes #4712: When a security station is placed onto an unsecured network, the placer assumes ownership of the entire network. Otherwise the contiguous network would not necessarily reconnect in the same way when the chunk is reloaded due to differing player-ids throughout the network.
In addition, changes to the node's owner were not being persisted due to the host never being marked as dirty.

* Fix formatting
2020-09-10 22:34:16 +02:00
Sebastian Hartte 2bca23d75d Rebuilt the recipe transfer after upstream changes. 2020-09-10 22:05:06 +02:00
Sebastian Hartte b47543d166 Merge remote-tracking branch 'origin/master' into fabric/master
# Conflicts:
#	gradle.properties
#	src/main/java/appeng/core/Registration.java
#	src/main/java/appeng/core/sync/packets/JEIRecipePacket.java
#	src/main/java/appeng/entity/TinyTNTPrimedEntity.java
#	src/main/java/appeng/fluids/client/gui/widgets/FluidSlotWidget.java
#	src/main/java/appeng/fluids/container/FluidConfigurableContainer.java
#	src/main/java/appeng/integration/modules/jei/FacadeRegistryPlugin.java
#	src/main/java/appeng/integration/modules/jei/JEIPlugin.java
#	src/main/java/appeng/integration/modules/jei/RecipeTransferHandler.java
#	src/main/java/appeng/mixins/structure/BiomeAccessor.java
#	src/main/java/appeng/parts/automation/AnnihilationPlanePart.java
#	src/main/java/appeng/parts/automation/FormationPlanePart.java
2020-09-10 19:20:58 +02:00
Sebastian Hartte a340925d98 Fix Wireless screen translated text. 2020-09-10 19:06:00 +02:00
yueh b8e53adf40 Fixes #4719: Take the entity size into account when spawning item entities (#4720) 2020-09-10 17:54:02 +02:00
yueh 44544c598f Fixes #4253: Just transfer the recipe id instead of every ingredient. (#4689)
* Fixes #4253: Just transfer the recipe id instead of every ingredient.
* If possible handle any IRecipe for processing mode
* Improvements and support for AE2 facades.
* Switched to using JEI's displayed stacks (which means we can remove the shapeless variant).

Co-authored-by: Sebastian Hartte <sebastian@hartte.de>
2020-09-09 14:08:24 +02:00
Sebastian Hartte 0be7322c2c Formatting Fixes. 2020-09-09 02:27:12 +02:00
Sebastian Hartte a521e827db Merge remote-tracking branch 'origin/master' into fabric/master
# Conflicts:
#	src/main/java/appeng/core/api/definitions/ApiItems.java
2020-09-09 02:25:15 +02:00
Sebastian Hartte bcee2ec427 Slightly increased the height of the item hitbox for crystals to make their pickup by annihilation planes less "clippy". 2020-09-09 02:23:58 +02:00
Sebastian Hartte 17648633fe Merge fixes. 2020-09-09 02:23:14 +02:00
Sebastian Hartte fcbebd4ffc Merge remote-tracking branch 'origin/master' into fabric/master
# Conflicts:
#	gradle.properties
#	src/api/java/appeng/api/implementations/items/IGrowableCrystal.java
#	src/main/java/appeng/core/AEConfig.java
#	src/main/java/appeng/core/api/definitions/ApiBlocks.java
#	src/main/java/appeng/core/features/registries/LocatableRegistry.java
#	src/main/java/appeng/decorative/solid/QuartzGlassBlock.java
#	src/main/java/appeng/decorative/solid/SkyStoneBlock.java
#	src/main/java/appeng/entity/GrowingCrystalEntity.java
#	src/main/java/appeng/fluids/parts/FluidImportBusPart.java
#	src/main/java/appeng/items/misc/CrystalSeedItem.java
#	src/main/java/appeng/items/tools/powered/ColorApplicatorItem.java
#	src/main/java/appeng/me/cluster/implementations/QuantumCluster.java
#	src/main/java/appeng/parts/CableBusContainer.java
#	src/main/java/appeng/tile/AEBaseBlockEntity.java
2020-09-09 01:41:49 +02:00
Sebastian Hartte 9e41d543f5 Merge remote-tracking branch 'origin/8.0.x-1.16.1' 2020-09-09 00:59:58 +02:00
Sebastian Hartte 81cc0b804d Fixes #4699: AE's glass should only hide it's sides adjacent to other AE glass.
Also disables spawn on AE's glass same as Vanilla glass.
2020-09-09 00:58:14 +02:00
Sebastian Hartte e1fc9908b3 Fixes #4693: Fix color applicator not working on cable-buses. 2020-09-09 00:51:45 +02:00
shartte 9ed1535477 Fixes #4661: Do not update a tile entity when it's in an unloaded chunk (i.e. during chunk unloading) (#4708) 2020-09-08 22:28:30 +02:00
Sebastian Hartte 1ef345d4a4 Formatting fixes. 2020-09-08 22:24:27 +02:00
Sebastian Hartte ff7d1b9719 Fixes #4704: QNB is not finding a registered QNB because it believes the chunk to be unloaded.
Also adds debug logging to the locatable registry to better debug this issues in the future.
2020-09-08 22:20:33 +02:00
shartte 88c9370e4f Crystal Growth Refactor (#4702)
* Refactored crystal in-world purification:
- Removed iterative formula
- Set the default growth factor to 1 rather than 0.5 to simplify settings
- Made the growth-tick-progress-per-tick a configuration setting for 0-6 accelerators
- Unfinished seeds now slowly sink when ejected by an annihilation plane or other system (emulates a player throwing it in)
- Instead of checking for "isLiquid", we now check for a new tag (appliedenergistics2:crystal_purification_medium) to check if the crystal is submerged in an allowed fluid for growth, defaults to #minecraft:water.

* Removed configuration options for changing how accelerators work,
replaced with improved fluid tag option with a clamped multiplier [1,10].
2020-09-08 18:10:45 +02:00
Sebastian Hartte f2aae3ef0f Added a global Voxelshape cache for cable bus voxel shapes, since combining voxel shapes turns out to be an extremely expensive process (i.e. 1.7s for 10000x5 shapes). 2020-09-08 17:56:02 +02:00
Sebastian Hartte 12739f1e66 Remove unneeded cable-bus inventory-model, which caused the part models to be loaded twice leading to unnecessary memory-usage. 2020-09-08 17:53:14 +02:00
shartte 81d2170ada Implemented a cache with maximum quad-count it will cache for the cable bus, (#4670)
which also fixes concurrent access to the hashmap.

(cherry picked from commit b756d68be1)
2020-09-08 14:28:08 +02:00
Sebastian Hartte 0f469e9df6 Bumped Forge version. 2020-09-07 23:34:56 +02:00
Sebastian Hartte 0f34f09b32 Remove object-scanning subscriptions and remove unused test-file. 2020-09-06 20:59:37 +02:00
Sebastian Hartte 8e54a8fed9 Fixes a problem where tile entities would become unremovable (well, one more of these at least),
because they would reset their block state upon removal and loss of power.
2020-09-06 20:59:19 +02:00
Sebastian Hartte ca007a3737 Fix compatibility with fabric-api 0.20 2020-09-05 19:30:00 +02:00
Sebastian Hartte 92b6650022 Reformat. 2020-09-05 19:22:21 +02:00
Sebastian Hartte e1cd3bba25 Improved logging and slight refactor. 2020-09-05 19:22:05 +02:00
Sebastian Hartte 689bf6e8d9 Removed unused worldgen registry,
added biome blacklists for meteorites and quartz ore, and
also fixed adding meteorite/quartz to biomes that are
registered after AE2 initializes.
2020-09-05 19:15:45 +02:00
Sebastian Hartte c8a5049d71 Fix path to AE2 logo in mod json. 2020-09-03 23:33:48 +02:00
Sebastian Hartte 10a1a6d855 Fixes #4674: Facade quads should not keep their original cull-faces if they're moved away
from the block face.
2020-09-03 17:54:23 +02:00
Sebastian Hartte d9bb81a00f Fixes #4680: Facade advancement is showing an untextured facade. 2020-09-03 17:36:20 +02:00
yueh 39e038d916 Fixes #4683: Hopefully LazyOptional works as advertised (#4684) 2020-09-02 21:36:40 +02:00
Sebastian Hartte 575a625f75 Also update the layer-map, even though the spatial biome should never show up in any vanilla layering. 2020-09-02 19:44:37 +02:00
Sebastian Hartte 89ea923c43 Merge fixes 2020-09-02 19:41:44 +02:00
Sebastian Hartte 5d818eb03e Merge remote-tracking branch 'origin/master' into fabric/master 2020-09-02 02:55:39 +02:00
Sebastian Hartte 12ca8d109a Merge remote-tracking branch 'origin/8.0.x-1.16.1' 2020-09-02 02:55:12 +02:00
Sebastian Hartte e34126458b Merge remote-tracking branch 'origin/master' into fabric/master
# Conflicts:
#	gradle.properties
#	src/main/java/appeng/client/gui/Size1Slot.java
#	src/main/java/appeng/client/me/SlotFluidME.java
#	src/main/java/appeng/client/me/SlotME.java
#	src/main/java/appeng/client/render/cablebus/CableBusBakedModel.java
#	src/main/java/appeng/client/render/cablebus/CableBusModelLoader.java
#	src/main/java/appeng/core/sync/packets/MEFluidInventoryUpdatePacket.java
#	src/main/java/appeng/core/sync/packets/MEInterfaceUpdatePacket.java
#	src/main/java/appeng/core/sync/packets/MEInventoryUpdatePacket.java
#	src/main/java/appeng/datagen/providers/loot/BlockDropProvider.java
#	src/main/java/appeng/fluids/client/gui/widgets/FluidSlotWidget.java
#	src/main/java/appeng/fluids/container/FluidConfigurableContainer.java
#	src/main/java/appeng/fluids/helper/FluidCellConfig.java
#	src/main/resources/META-INF/mods.toml
2020-09-02 02:45:31 +02:00
Sebastian Hartte 0ac918c363 Fixed exclusion zones for many screens. 2020-09-02 02:37:47 +02:00
Sebastian Hartte b6160e40bc Fixes #4671: Use other Ingredient method which is not client-only. 2020-09-02 01:49:24 +02:00
Sebastian Hartte cf103b06c1 Fixes #4677: Stackoverflow when crafting with the quartz knife. 2020-09-02 00:12:20 +02:00
yueh f0d0595c8f Fixes #4669: Take NBT into account for comparing. (#4675)
This only covers combining different items together.
Fuzzy filtering is still a bit too fuzzy for corner cases.
2020-09-01 21:59:08 +02:00
shartte b756d68be1 Implemented a cache with maximum quad-count it will cache for the cable bus, (#4670)
which also fixes concurrent access to the hashmap.
2020-09-01 18:20:51 +02:00
Sebastian Hartte 60b07e5ca5 Merge branch '8.0.x-1.16.1' 2020-09-01 01:07:47 +02:00
shartte 7c99fca789 Fixes removal of facades not invalidating the cached server-side collision boxes. (#4663)
(cherry picked from commit 957bc4c5cc)
2020-09-01 01:07:30 +02:00
yueh ab393b0ed1 Serialize the complete NBT data to avoid mismatches (#4665)
This might increase the network traffic a bit, but the amount of mods actually using the share tag seems to be very limited.
For now it is worth the risk as it solves the problem. In case we run into actual issues, there might still be other solutions, which will be way more complex and can potentially introduce additional problems.

(cherry picked from commit e90dd2f9c6)
2020-09-01 01:07:28 +02:00
shartte 957bc4c5cc Fixes removal of facades not invalidating the cached server-side collision boxes. (#4663) 2020-08-31 23:10:25 +02:00
yueh 133ed1f09d Remove GZipStreams from packets. (#4664)
This should now be handled by the normal network manager (hopefully).
Also renamed the `CompressedNBTPacket` to `MEInterfaceUpdatePacket` as that is the only use case.
2020-08-31 23:09:28 +02:00
yueh e90dd2f9c6 Serialize the complete NBT data to avoid mismatches (#4665)
This might increase the network traffic a bit, but the amount of mods actually using the share tag seems to be very limited.
For now it is worth the risk as it solves the problem. In case we run into actual issues, there might still be other solutions, which will be way more complex and can potentially introduce additional problems.
2020-08-31 23:09:14 +02:00
Sebastian Hartte 9719c7ffc3 Bump to Forge 33.0.22 2020-08-29 23:13:29 +02:00
Sebastian Hartte 319d92a371 Merge branch '8.0.x-1.16.1' 2020-08-29 22:18:12 +02:00
shartte db9ec2b070 Remove the use of SlotItemHandler since we are only faking an inventory-backed slot, (#4654)
we might as well use what we had used pre-2017, which is simply extending a normal Slot.
This should also fix #4652.
2020-08-29 22:03:35 +02:00
Sebastian Hartte 5d33005aaf Added back dynamic cable bus lighting. 2020-08-29 01:02:32 +02:00
Sebastian Hartte 87cf070b33 Fixes #4657: Remove usage of an implementation class and just copy the needed values into arrays. 2020-08-29 00:45:01 +02:00
Masakitenchi 3a0552c56e Update zh_cn.json (#4653) 2020-08-28 10:49:11 +02:00
163 changed files with 3062 additions and 3283 deletions
+2 -1
View File
@@ -2,7 +2,8 @@ name: 'Build PRs'
on:
pull_request:
branches: [ master ]
branches:
- '*'
jobs:
build:
+178 -48
View File
@@ -47,6 +47,47 @@ repositories {
}
}
dependencies {
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
//Fabric api
modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}"
modImplementation "alexiil.mc.lib:libblockattributes-core:${libblockattributes_version}"
modImplementation "alexiil.mc.lib:libblockattributes-items:${libblockattributes_version}"
modImplementation "alexiil.mc.lib:libblockattributes-fluids:${libblockattributes_version}"
include "alexiil.mc.lib:libblockattributes-core:${libblockattributes_version}"
include "alexiil.mc.lib:libblockattributes-items:${libblockattributes_version}"
include "alexiil.mc.lib:libblockattributes-fluids:${libblockattributes_version}"
// Energy API
modApi "teamreborn:energy:${tr_energy_version}"
include "teamreborn:energy:${tr_energy_version}"
modCompileOnly("me.shedaniel:RoughlyEnoughItems:${rei_version}") {
exclude group: "net.fabricmc.fabric-api"
}
modCompileOnly("mcp.mobius.waila:Hwyla:1.16.1-1.9.22-75") {
exclude group: "net.fabricmc.fabric-api"
}
modRuntime("me.shedaniel:RoughlyEnoughItems:${rei_version}") {
exclude group: "net.fabricmc.fabric-api"
}
modRuntime("TechReborn:TechReborn-1.16:3.5.1+build.101") {
exclude group: "net.fabricmc.fabric-api"
}
// modRuntimeOnly "mcp.mobius.waila:Hwyla:1.16.1-1.9.22-75"
implementation 'com.google.code.findbugs:jsr305:3.0.2'
// unit test dependencies
testCompile "junit:junit:4.13"
}
group = artifact_group
archivesBaseName = artifact_basename
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8
compileJava {
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8
@@ -59,7 +100,9 @@ tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
// Create version number
///////////////////
// Version Number
ext.pr = System.getenv('PR_NUMBER') ?: ""
if (ext.pr) {
version = version + "+pr." + ext.pr
@@ -81,9 +124,8 @@ if (ext.tag && ext.tag.startsWith("fabric/v")) {
}
}
// Maven group and artifact name
group = artifact_group
archivesBaseName = artifact_basename
ext.isAlpha = project.version.contains("alpha")
ext.isBeta = project.version.contains("beta")
sourceSets {
api
@@ -119,51 +161,12 @@ configurations {
siteexportRuntime.extendsFrom(runtimeClasspath)
}
apply from: 'gradle/scripts/spotless.gradle'
////////////////////
// Forge/Minecraft
minecraft {
accessWidener "src/main/resources/appliedenergistics2.accesswidener"
}
dependencies {
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
//Fabric api
modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}"
modImplementation "alexiil.mc.lib:libblockattributes-core:${libblockattributes_version}"
modImplementation "alexiil.mc.lib:libblockattributes-items:${libblockattributes_version}"
modImplementation "alexiil.mc.lib:libblockattributes-fluids:${libblockattributes_version}"
include "alexiil.mc.lib:libblockattributes-core:${libblockattributes_version}"
include "alexiil.mc.lib:libblockattributes-items:${libblockattributes_version}"
include "alexiil.mc.lib:libblockattributes-fluids:${libblockattributes_version}"
// Energy API
modApi "teamreborn:energy:${tr_energy_version}"
include "teamreborn:energy:${tr_energy_version}"
modCompileOnly("me.shedaniel:RoughlyEnoughItems:5.0.2-unstable") {
exclude group: "net.fabricmc.fabric-api"
}
modCompileOnly("mcp.mobius.waila:Hwyla:1.16.1-1.9.22-75") {
exclude group: "net.fabricmc.fabric-api"
}
modRuntime("me.shedaniel:RoughlyEnoughItems:5.0.2-unstable") {
exclude group: "net.fabricmc.fabric-api"
}
modRuntime("TechReborn:TechReborn-1.16:3.5.1+build.101") {
exclude group: "net.fabricmc.fabric-api"
}
// modRuntimeOnly "mcp.mobius.waila:Hwyla:1.16.1-1.9.22-75"
implementation 'com.google.code.findbugs:jsr305:3.0.2'
// unit test dependencies
testCompile "junit:junit:4.13"
}
processResources {
inputs.property "version", project.version
@@ -177,10 +180,76 @@ processResources {
}
}
apply from: 'gradle/scripts/artifacts.gradle'
apply from: 'gradle/scripts/curseforge.gradle'
//////////////
// Aritfacts
processResources {
exclude '.cache'
}
// configure the maven publication
jar {
finalizedBy 'remapJar'
from sourceSets.main.output.classesDirs
from sourceSets.api.output.classesDirs
from sourceSets.main.output.resourcesDir
from sourceSets.api.output.resourcesDir
manifest {
attributes([
"Specification-Title": "Applied Energistics 2",
"Specification-Vendor": "TeamAppliedEnergistics",
"Specification-Version": "${project.version}",
"Implementation-Title": "${project.name}",
"Implementation-Version": "${project.version}",
"Implementation-Vendor" :"TeamAppliedEnergistics",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
"MixinConfigs": "appliedenergistics2.mixins.json"
])
}
}
task javadocs(type: Javadoc) {
classpath = sourceSets.main.compileClasspath
source = sourceSets.api.java
include "appeng/api/**"
options.addStringOption('Xdoclint:none', '-quiet')
options.encoding = 'UTF-8'
options.charSet = 'UTF-8'
}
task javadocJar(type: Jar, dependsOn: javadocs) {
classifier = "javadoc"
from javadoc.destinationDir
}
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
// if it is present.
// If you remove this task, sources will not be generated.
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = "sources"
from sourceSets.main.allSource
from sourceSets.api.allSource
}
task apiJar(type: Jar) {
classifier = "api"
from sourceSets.api.output
include "appeng/api/**"
// TODO: when FG bug is fixed, remove allJava from the api jar.
// https://github.com/MinecraftForge/ForgeGradle/issues/369
// Gradle should be able to pull them from the -sources jar.
from sourceSets.api.allJava
}
artifacts {
archives javadocJar
archives sourcesJar
archives apiJar
}
//////////////////
// Maven publish
publishing {
if (!version.endsWith("-SNAPSHOT")) {
publications {
@@ -239,3 +308,64 @@ task runSiteExport(type: RunClientTask, dependsOn: downloadAssets, group: "ae2",
classpath sourceSets.main.output
classpath sourceSets.siteexport.output
}
/////////////
// Spotless
spotless {
java {
target 'src/*/java/appeng/**/*.java'
indentWithSpaces()
eclipse().configFile 'codeformat/codeformat.xml'
importOrderFile 'codeformat/ae2.importorder'
}
format 'json', {
target 'src/*/resources/**/*.json'
targetExclude 'src/generated/resources/**'
prettier().config(['parser': 'json'])
}
}
////////////////
// Curse Forge
if (System.getenv("CURSEFORGE") && !version.endsWith("-SNAPSHOT")) {
def cfReleaseType = "release"
if (ext.isAlpha) {
cfReleaseType = "alpha"
} else if (ext.isBeta) {
cfReleaseType = "beta"
}
curseforge {
apiKey = System.getenv("CURSEFORGE")
project {
id = project.curseforge_project
changelogType = "markdown"
changelog = System.getenv("CHANGELOG") ?: "Please visit our [releases](https://github.com/AppliedEnergistics/Applied-Energistics-2/releases) for a changelog"
releaseType = cfReleaseType
addGameVersion project.minecraft_version
addGameVersion "Fabric"
mainArtifact(remapJar.archiveFile) {
displayName = "${project.version} [FABRIC]"
}
}
options {
forgeGradleIntegration = false
}
afterEvaluate {
tasks.getByName("curseforge${project.curseforge_project}").dependsOn remapJar
}
}
}
////////////////
// IntelliJ Project Import
// The Mixin annotation process does not have an obfuscation source when running through the IntelliJ compiler,
// thus we have to prevent it from being activated as part of importing this Gradle project into IntelliJ.
if (System.getProperty("idea.sync.active") == "true") {
afterEvaluate {
tasks.withType(JavaCompile).all {
it.options.annotationProcessorPath = files()
}
}
}
+6 -10
View File
@@ -3,28 +3,24 @@ version=0.0.0-SNAPSHOT
artifact_group=appeng
artifact_basename=appliedenergistics2-fabric
kotlin.code.style=official
org.gradle.jvmargs=-Xmx2G
# Fabric Properties
# Check these on https://modmuss50.me/fabric.html
minecraft_version=1.16.2
yarn_mappings=1.16.2+build.6
loader_version=0.9.2+build.206
minecraft_version=1.16.3
yarn_mappings=1.16.3+build.11
loader_version=0.9.3+build.207
#Fabric api
fabric_version=0.17.2+build.396-1.16
fabric_version=0.21.0+build.407-1.16
loom_version=0.4-SNAPSHOT
# Kotlin
kotlin_version=1.3.61
fabric_kotlin_version=1.3.61+build.1
loom_version=0.5-SNAPSHOT
# Dependencies
libblockattributes_version=0.8.0
tr_energy_version=0.1.0
rei_version=5.2.10
#########################################################
# Deployment #
-78
View File
@@ -1,78 +0,0 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
processResources {
exclude '.cache'
}
jar {
finalizedBy 'remapJar'
from sourceSets.main.output.classesDirs
from sourceSets.api.output.classesDirs
from sourceSets.main.output.resourcesDir
from sourceSets.api.output.resourcesDir
manifest {
attributes([
"Specification-Title": "Applied Energistics 2",
"Specification-Vendor": "TeamAppliedEnergistics",
"Specification-Version": "${project.version}",
"Implementation-Title": "${project.name}",
"Implementation-Version": "${project.version}",
"Implementation-Vendor" :"TeamAppliedEnergistics",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
])
}
}
task javadocs(type: Javadoc) {
classpath = sourceSets.main.compileClasspath
source = sourceSets.api.java
include "appeng/api/**"
options.addStringOption('Xdoclint:none', '-quiet')
options.encoding = 'UTF-8'
options.charSet = 'UTF-8'
}
task javadocJar(type: Jar, dependsOn: javadocs) {
classifier = "javadoc"
from javadoc.destinationDir
}
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
// if it is present.
// If you remove this task, sources will not be generated.
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = "sources"
from sourceSets.main.allSource
from sourceSets.api.allSource
}
task apiJar(type: Jar) {
classifier = "api"
from sourceSets.api.output
include "appeng/api/**"
}
artifacts {
archives javadocJar
archives sourcesJar
archives apiJar
}
-50
View File
@@ -1,50 +0,0 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2020, TeamAppliedEnergistics, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*g GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
def isAlpha = project.version.contains("alpha")
def isBeta = project.version.contains("beta")
def cfReleaseType = "release"
if (isAlpha) {
cfReleaseType = "alpha"
} else if (isBeta) {
cfReleaseType = "beta"
}
if (System.getenv("CURSEFORGE") && !version.endsWith("-SNAPSHOT")) {
curseforge {
apiKey = System.getenv("CURSEFORGE")
project {
id = project.curseforge_project
changelogType = "markdown"
changelog = System.getenv("CHANGELOG") ?: "Please visit our [releases](https://github.com/AppliedEnergistics/Applied-Energistics-2/releases) for a changelog"
releaseType = cfReleaseType
addGameVersion project.minecraft_version
addGameVersion "Fabric"
mainArtifact(remapJar.archiveFile) {
displayName = "${project.version} [FABRIC]"
}
}
options {
forgeGradleIntegration = false
}
afterEvaluate {
tasks.getByName("curseforge${project.curseforge_project}").dependsOn remapJar
}
}
}
-42
View File
@@ -1,42 +0,0 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
repositories {
mavenLocal()
maven { // modmaven, maven proxy
name 'modmaven'
url "https://modmaven.k-4u.nl/"
}
}
dependencies {
minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}"
// compile against provided APIs
compileOnly "mezz.jei:jei-${jei_minecraft_version}:${jei_version}:api"
compileOnly "mcjty.theoneprobe:TheOneProbe-${minecraft_release}:${minecraft_release}-${top_version}:api"
// Runtime, Mods
runtimeOnly fg.deobf("mezz.jei:jei-${jei_minecraft_version}:${jei_version}")
runtimeOnly fg.deobf("mcjty.theoneprobe:TheOneProbe-${minecraft_release}:${minecraft_release}-${top_version}")
//runtimeOnly fg.deobf("team.chisel.ctm:CTM:${ctm_version}")
// unit test dependencies
testCompile "junit:junit:4.13"
}
-32
View File
@@ -1,32 +0,0 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2020, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*g GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
spotless {
java {
target 'src/*/java/appeng/**/*.java'
indentWithSpaces()
eclipse().configFile 'codeformat/codeformat.xml'
importOrderFile 'codeformat/ae2.importorder'
}
format 'json', {
target 'src/*/resources/**/*.json'
targetExclude 'src/generated/resources/**'
prettier().config(['parser': 'json'])
}
}
-1
View File
@@ -10,7 +10,6 @@ pluginManagement {
plugins {
id "fabric-loom" version loom_version
id "org.jetbrains.kotlin.jvm" version kotlin_version
}
}
@@ -53,10 +53,10 @@ public interface ICraftingHelper {
* @param stack If null, a new item will be created to hold the encoded pattern.
* Otherwise the given item must already contains an encoded
* pattern that will be overwritten.
* @throws IllegalArgumentException If either in or out contain only empty
* ItemStacks.
* @return A new encoded pattern, or the given stack with the pattern encoded in
* it.
* @throws IllegalArgumentException If either in or out contain only empty
* ItemStacks.
*/
ItemStack encodeProcessingPattern(@Nullable ItemStack stack, ItemStack[] in, ItemStack[] out);
@@ -82,11 +82,6 @@ public interface IRegistryContainer {
*/
IPlayerRegistry players();
/**
* get access to the world-gen api.
*/
IWorldGen worldgen();
/**
* Register your IPart models before using them.
*/
@@ -1,40 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2013 AlgorithmX2
*
* 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.
*/
package appeng.api.features;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier;
public interface IWorldGen {
void enableWorldGenForDimension(WorldGenType type, Identifier dimID);
void disableWorldGenForDimension(WorldGenType type, Identifier dimID);
boolean isWorldGenEnabled(WorldGenType type, ServerWorld w);
enum WorldGenType {
CERTUS_QUARTZ, CHARGED_CERTUS_QUARTZ, METEORITES
}
}
@@ -23,13 +23,23 @@
package appeng.api.implementations.items;
import net.minecraft.block.Block;
import net.minecraft.block.Material;
import javax.annotation.Nullable;
import net.minecraft.block.BlockState;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public interface IGrowableCrystal {
ItemStack triggerGrowth(ItemStack is);
float getMultiplier(Block blk, Material mat);
/**
* Gets the crystal growth multiplier based on the material it is submerged in.
*
* @param state The blockstate of the block the crystal is currently in.
* @return The multiplier for the growth tick progress. Zero if the crystal
* cannot grow in the current material.
*/
float getMultiplier(BlockState state, @Nullable World world, @Nullable BlockPos pos);
}
@@ -28,4 +28,9 @@ public enum GridNotification {
* the visible connections for this node have changed, useful for cable.
*/
CONNECTIONS_CHANGED,
/**
* the owner of the grid node has changed, and the node needs to be re-saved
*/
OWNER_CHANGED
}
@@ -87,7 +87,8 @@ public interface IGridBlock {
AEColor getGridColor();
/**
* Notifies your IGridBlock that changes were made to your connections
* Called by the {@link IGridNode} to notify its {@link IGridBlock} about
* events.
*/
void onGridNotification(@Nonnull GridNotification notification);
@@ -41,6 +41,8 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.item.ItemStack;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.IntProperty;
import net.minecraft.util.ActionResult;
import net.minecraft.util.DyeColor;
import net.minecraft.util.Hand;
@@ -80,8 +82,12 @@ public class CableBusBlock extends AEBaseTileBlock<CableBusBlockEntity> implemen
private static final ICableBusContainer NULL_CABLE_BUS = new NullCableBusContainer();
private static final IntProperty LIGHT_LEVEL = IntProperty.of("light_level", 0, 15);
public CableBusBlock() {
super(defaultProps(AEMaterials.GLASS).nonOpaque().dropsNothing().dynamicBounds());
super(defaultProps(AEMaterials.GLASS).nonOpaque().dropsNothing().dynamicBounds()
.luminance(state -> state.get(LIGHT_LEVEL)));
setDefaultState(getDefaultState().with(LIGHT_LEVEL, 0));
}
static {
@@ -134,16 +140,13 @@ public class CableBusBlock extends AEBaseTileBlock<CableBusBlockEntity> implemen
// OPPOSITE!?
}
// FIXME Dynamic light seems unsupported (?) Must maybe use blockstates... :|
// FIXME FABRIC @Override
// FIXME FABRIC public int getLightValue(final BlockState state, final BlockView world, final BlockPos pos) {
// FIXME FABRIC if (state.getBlock() != this) {
// FIXME FABRIC return state.getLuminance();
// FIXME FABRIC }
// FIXME FABRIC return this.cb(world, pos).getLightValue();
// FIXME FABRIC }
@Override
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
super.appendProperties(builder);
builder.add(LIGHT_LEVEL);
}
// FIXME: Must hook isClimbing ourselves
// FIXME: Must hook isClimbing ourselves
// FIXME FABRIC @Override
// FIXME FABRIC public boolean isLadder(BlockState state, WorldView world, BlockPos pos, LivingEntity entity) {
// FIXME FABRIC return this.cb(world, pos).isLadder(entity);
@@ -399,4 +402,13 @@ public class CableBusBlock extends AEBaseTileBlock<CableBusBlockEntity> implemen
}
}
@Override
protected BlockState updateBlockStateFromTileEntity(BlockState currentState, CableBusBlockEntity te) {
if (currentState.getBlock() != this) {
return currentState;
}
int lightLevel = te.getCableBus().getLightValue();
return super.updateBlockStateFromTileEntity(currentState, te).with(LIGHT_LEVEL, lightLevel);
}
}
@@ -38,11 +38,11 @@ import appeng.helpers.Splotch;
*/
class PaintSplotchesBakedModel implements BakedModel, FabricBakedModel {
private static final SpriteIdentifier TEXTURE_PAINT1 = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
private static final SpriteIdentifier TEXTURE_PAINT1 = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "block/paint1"));
private static final SpriteIdentifier TEXTURE_PAINT2 = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
private static final SpriteIdentifier TEXTURE_PAINT2 = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "block/paint2"));
private static final SpriteIdentifier TEXTURE_PAINT3 = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
private static final SpriteIdentifier TEXTURE_PAINT3 = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "block/paint3"));
private final Sprite[] textures;
@@ -36,18 +36,18 @@ import appeng.core.AppEng;
class QnbFormedBakedModel implements BakedModel, FabricBakedModel {
private static final SpriteIdentifier TEXTURE_LINK = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
private static final SpriteIdentifier TEXTURE_LINK = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "block/quantum_link"));
private static final SpriteIdentifier TEXTURE_RING = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
private static final SpriteIdentifier TEXTURE_RING = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "block/quantum_ring"));
private static final SpriteIdentifier TEXTURE_RING_LIGHT = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
new Identifier(AppEng.MOD_ID, "block/quantum_ring_light"));
private static final SpriteIdentifier TEXTURE_RING_LIGHT = new SpriteIdentifier(
SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new Identifier(AppEng.MOD_ID, "block/quantum_ring_light"));
private static final SpriteIdentifier TEXTURE_RING_LIGHT_CORNER = new SpriteIdentifier(
SpriteAtlasTexture.BLOCK_ATLAS_TEX, new Identifier(AppEng.MOD_ID, "block/quantum_ring_light_corner"));
private static final SpriteIdentifier TEXTURE_CABLE_GLASS = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
new Identifier(AppEng.MOD_ID, "part/cable/glass/transparent"));
SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new Identifier(AppEng.MOD_ID, "block/quantum_ring_light_corner"));
private static final SpriteIdentifier TEXTURE_CABLE_GLASS = new SpriteIdentifier(
SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new Identifier(AppEng.MOD_ID, "part/cable/glass/transparent"));
private static final SpriteIdentifier TEXTURE_COVERED_CABLE = new SpriteIdentifier(
SpriteAtlasTexture.BLOCK_ATLAS_TEX, new Identifier(AppEng.MOD_ID, "part/cable/covered/transparent"));
SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new Identifier(AppEng.MOD_ID, "part/cable/covered/transparent"));
private static final float DEFAULT_RENDER_MIN = 2.0f;
private static final float DEFAULT_RENDER_MAX = 14.0f;
@@ -28,6 +28,7 @@ import java.util.stream.Collectors;
import com.google.common.base.Preconditions;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import com.mojang.blaze3d.systems.RenderSystem;
import org.lwjgl.glfw.GLFW;
@@ -58,6 +59,7 @@ import net.minecraft.util.Identifier;
import alexiil.mc.lib.attributes.fluid.render.FluidRenderFace;
import alexiil.mc.lib.attributes.fluid.render.FluidVolumeRenderer;
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
import me.shedaniel.math.Rectangle;
import appeng.api.storage.data.IAEFluidStack;
import appeng.api.storage.data.IAEItemStack;
@@ -104,6 +106,7 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
private Stopwatch dbl_clickTimer = Stopwatch.createStarted();
private ItemStack dbl_whichItem = ItemStack.EMPTY;
private Slot bl_clicked;
private boolean handlingRightClick;
protected final List<CustomSlotWidget> guiSlots = new ArrayList<>();
public AEBaseScreen(T container, PlayerInventory playerInventory, Text title) {
@@ -282,12 +285,18 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
public boolean mouseClicked(final double xCoord, final double yCoord, final int btn) {
this.drag_click.clear();
// Forward right-clicks as-if they were left-clicks
if (btn == 1) {
for (final Object o : this.buttons) {
final AbstractButtonWidget widget = (AbstractButtonWidget) o;
if (widget.isMouseOver(xCoord, yCoord)) {
return super.mouseClicked(xCoord, yCoord, 0);
handlingRightClick = true;
try {
for (final Object o : this.buttons) {
final AbstractButtonWidget widget = (AbstractButtonWidget) o;
if (widget.isMouseOver(xCoord, yCoord)) {
return super.mouseClicked(xCoord, yCoord, 0);
}
}
} finally {
handlingRightClick = false;
}
}
@@ -298,22 +307,36 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
}
}
if (this.getScrollBar() != null) {
this.getScrollBar().click(xCoord - this.x, yCoord - this.y);
// Forward left mouse button down events to the scrollbar
if (btn == 0 && this.getScrollBar() != null) {
if (this.getScrollBar().mouseDown(xCoord - this.x, yCoord - this.y)) {
return true;
}
}
return super.mouseClicked(xCoord, yCoord, btn);
}
@Override
public boolean mouseDragged(double mouseX, double mouseY, int mouseButton, double dragX, double dragY) {
public boolean mouseReleased(double mouseX, double mouseY, int button) {
// Forward left mouse button up events to the scrollbar
if (button == 0 && this.getScrollBar() != null) {
if (this.getScrollBar().mouseUp(mouseX - this.x, mouseY - this.y)) {
return true;
}
}
return super.mouseReleased(mouseX, mouseY, button);
}
@Override
public boolean mouseDragged(double mouseX, double mouseY, int mouseButton, double dragX, double dragY) {
final Slot slot = this.getSlot((int) mouseX, (int) mouseY);
final ItemStack itemstack = getPlayer().inventory.getCursorStack();
if (this.getScrollBar() != null) {
// FIXME: Coordinate system of mouseX/mouseY is unclear
this.getScrollBar().click((int) mouseX - this.x, (int) mouseY - this.y);
this.getScrollBar().mouseDragged((int) mouseX - this.x, (int) mouseY - this.y);
}
if (slot instanceof FakeSlot && !itemstack.isEmpty()) {
@@ -620,15 +643,7 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
}
protected Text getGuiDisplayName(final Text in) {
return this.hasCustomInventoryName() ? new LiteralText(this.getInventoryName()) : in;
}
private boolean hasCustomInventoryName() {
return this.handler.getCustomName() != null;
}
private String getInventoryName() {
return this.handler.getCustomName();
return title.getString().isEmpty() ? in : title;
}
/**
@@ -796,6 +811,11 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
public void tick() {
super.tick();
if (this.getScrollBar() != null) {
this.getScrollBar().tick();
}
for (Element child : children) {
if (child instanceof ITickingWidget) {
((ITickingWidget) child).tick();
@@ -803,4 +823,15 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
}
}
/**
* Returns true while the current event being handled is a click of the right
* mouse button.
*/
public boolean isHandlingRightClick() {
return handlingRightClick;
}
public List<Rectangle> getExclusionZones() {
return Lists.newArrayList(new Rectangle(x, y, backgroundWidth, backgroundHeight));
}
}
@@ -12,8 +12,6 @@ import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
import net.minecraft.util.Identifier;
import appeng.client.me.SlotME;
/**
* A proxy for a slot that will always return an itemstack with size 1, if there
* is an item in the slot. Used to prevent the default item count from
@@ -21,9 +19,9 @@ import appeng.client.me.SlotME;
*/
class Size1Slot extends Slot {
private final SlotME delegate;
private final Slot delegate;
public Size1Slot(SlotME delegate) {
public Size1Slot(Slot delegate) {
super(delegate.inventory, -1, delegate.x, delegate.y);
this.delegate = delegate;
}
@@ -46,22 +46,28 @@ public class CraftAmountScreen extends AEBaseScreen<CraftAmountContainer> {
public void init() {
super.init();
this.amountToCraft = new NumberEntryWidget(this, 20, 30, 138, 62, NumberEntryType.CRAFT_ITEM_COUNT, value -> {
});
this.amountToCraft = new NumberEntryWidget(this, 20, 30, 138, 62, NumberEntryType.CRAFT_ITEM_COUNT);
this.amountToCraft.setValue(1);
this.amountToCraft.setTextFieldBounds(62, 57, 50);
this.amountToCraft.setMinValue(1);
this.amountToCraft.setHideValidationIcon(true);
this.amountToCraft.addButtons(children::add, this::addButton);
this.next = this
.addButton(new ButtonWidget(this.x + 128, this.y + 51, 38, 20, GuiText.Next.text(), this::confirm));
this.amountToCraft.setOnConfirm(() -> this.confirm(this.next));
subGui.addBackButton(this::addButton, 154, 0);
changeFocus(true);
}
private void confirm(ButtonWidget button) {
NetworkHandler.instance()
.sendToServer(new CraftRequestPacket((int) this.amountToCraft.getValue(), hasShiftDown()));
int amount = this.amountToCraft.getIntValue().orElse(0);
if (amount <= 0) {
return;
}
NetworkHandler.instance().sendToServer(new CraftRequestPacket(amount, hasShiftDown()));
}
@Override
@@ -77,23 +83,9 @@ public class CraftAmountScreen extends AEBaseScreen<CraftAmountContainer> {
this.bindTexture("guis/craft_amt.png");
drawTexture(matrices, offsetX, offsetY, 0, 0, this.backgroundWidth, this.backgroundHeight);
this.next.active = this.amountToCraft.getValue() > 0;
this.next.active = this.amountToCraft.getIntValue().orElse(0) > 0;
this.amountToCraft.render(matrices, offsetX, offsetY, partialTicks);
}
@Override
public boolean keyPressed(int keyCode, int scanCode, int p_keyPressed_3_) {
if (keyCode == 28) {
this.next.onPress();
return true;
} else {
return super.keyPressed(keyCode, scanCode, p_keyPressed_3_);
}
}
protected String getBackground() {
return "guis/craftAmt.png";
}
}
@@ -25,6 +25,8 @@ import java.util.List;
import com.mojang.blaze3d.systems.RenderSystem;
import org.lwjgl.glfw.GLFW;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerInventory;
@@ -73,10 +75,6 @@ public class CraftConfirmScreen extends AEBaseScreen<CraftConfirmContainer> {
this.setScrollBar(scrollbar);
}
boolean isAutoStart() {
return this.handler.isAutoStart();
}
@Override
public void init() {
super.init();
@@ -87,12 +85,14 @@ public class CraftConfirmScreen extends AEBaseScreen<CraftConfirmContainer> {
this.addButton(this.start);
this.selectCPU = new ButtonWidget(this.x + (219 - 180) / 2, this.y + this.backgroundHeight - 68, 180, 20,
GuiText.CraftingCPU.withSuffix(": ").append(GuiText.Automatic.text()), btn -> selectNextCpu());
getNextCpuButtonLabel(), btn -> selectNextCpu());
this.selectCPU.active = false;
this.addButton(this.selectCPU);
addButton(new ButtonWidget(this.x + 6, this.y + this.backgroundHeight - 25, 50, 20, GuiText.Cancel.text(),
btn -> subGui.goBack()));
this.setScrollBar();
}
@Override
@@ -133,22 +133,22 @@ public class CraftConfirmScreen extends AEBaseScreen<CraftConfirmContainer> {
}
private void updateCPUButtonText() {
Text btnTextText = GuiText.CraftingCPU.withSuffix(": ").append(GuiText.Automatic.text());
if (this.handler.getSelectedCpu() >= 0)// && status.selectedCpu < status.cpus.size() )
{
if (this.handler.getName() != null) {
final String name = this.handler.getName().asTruncatedString(20);
btnTextText = GuiText.CraftingCPU.withSuffix(": " + name);
} else {
btnTextText = GuiText.CraftingCPU.withSuffix(": #" + this.handler.getSelectedCpu());
}
}
this.selectCPU.setMessage(getNextCpuButtonLabel());
}
private Text getNextCpuButtonLabel() {
if (this.handler.hasNoCPU()) {
btnTextText = GuiText.NoCraftingCPUs.text();
return GuiText.NoCraftingCPUs.text();
}
this.selectCPU.setMessage(btnTextText);
Text cpuName;
if (this.handler.cpuName == null) {
cpuName = GuiText.Automatic.text();
} else {
cpuName = this.handler.cpuName;
}
return GuiText.CraftingCPU.withSuffix(": ").append(cpuName);
}
private boolean isSimulation() {
@@ -440,7 +440,7 @@ public class CraftConfirmScreen extends AEBaseScreen<CraftConfirmContainer> {
@Override
public boolean keyPressed(int keyCode, int scanCode, int p_keyPressed_3_) {
if (!this.checkHotbarKeys(keyCode, scanCode)) {
if (keyCode == 28) {
if (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_KP_ENTER) {
this.start();
return true;
}
@@ -449,7 +449,7 @@ public class CraftConfirmScreen extends AEBaseScreen<CraftConfirmContainer> {
}
private void selectNextCpu() {
final boolean backwards = getClient().mouse.wasRightButtonClicked();
final boolean backwards = isHandlingRightClick();
NetworkHandler.instance().sendToServer(new ConfigValuePacket("Terminal.Cpu", backwards ? "Prev" : "Next"));
}
@@ -44,12 +44,12 @@ public class CraftingStatusScreen extends CraftingCPUScreen<CraftingStatusContai
super.init();
this.selectCPU = new ButtonWidget(this.x + 8, this.y + this.backgroundHeight - 25, 150, 20,
GuiText.CraftingCPU.withSuffix(": ").append(GuiText.NoCraftingCPUs.text()), btn -> selectNextCpu());
getNextCpuButtonLabel(), btn -> selectNextCpu());
this.addButton(this.selectCPU);
subGui.addBackButton(btn -> {
addButton(btn);
btn.setHideEdge(13);
btn.setHideEdge(true);
}, 213, -4);
}
@@ -60,23 +60,14 @@ public class CraftingStatusScreen extends CraftingCPUScreen<CraftingStatusContai
}
private void updateCPUButtonText() {
Text btnTextText = GuiText.NoCraftingJobs.text();
if (this.handler.selectedCpu >= 0)// && status.selectedCpu < status.cpus.size() )
{
if (this.handler.myName != null) {
final String name = this.handler.myName.asTruncatedString(20);
btnTextText = GuiText.CPUs.withSuffix(": " + name);
} else {
btnTextText = GuiText.CPUs.withSuffix(": #" + this.handler.selectedCpu);
}
}
this.selectCPU.setMessage(getNextCpuButtonLabel());
}
private Text getNextCpuButtonLabel() {
if (this.handler.noCPU) {
btnTextText = GuiText.NoCraftingJobs.text();
return GuiText.NoCraftingJobs.text();
}
this.selectCPU.setMessage(btnTextText);
return GuiText.CraftingCPU.withSuffix(": ").append(handler.cpuName);
}
@Override
@@ -84,9 +75,8 @@ public class CraftingStatusScreen extends CraftingCPUScreen<CraftingStatusContai
return in; // the cup name is on the button
}
// FIXME: Extract to separate class? Shared with GuiCraftConfirm
private void selectNextCpu() {
final boolean backwards = client.mouse.wasRightButtonClicked();
final boolean backwards = isHandlingRightClick();
NetworkHandler.instance().sendToServer(new ConfigValuePacket("Terminal.Cpu", backwards ? "Prev" : "Next"));
}
@@ -87,7 +87,7 @@ public class InterfaceScreen extends UpgradeableScreen<InterfaceContainer> {
}
private void selectNextInterfaceMode() {
final boolean backwards = getClient().mouse.wasRightButtonClicked();
final boolean backwards = isHandlingRightClick();
NetworkHandler.instance().sendToServer(new ConfigButtonPacket(Settings.INTERFACE_TERMINAL, backwards));
}
@@ -70,8 +70,7 @@ public class InterfaceTerminalScreen extends AEBaseScreen<InterfaceTerminalConta
public InterfaceTerminalScreen(InterfaceTerminalContainer container, PlayerInventory playerInventory, Text title) {
super(container, playerInventory, title);
final Scrollbar scrollbar = new Scrollbar();
this.setScrollBar(scrollbar);
this.setScrollBar(new Scrollbar().setLeft(175).setTop(18).setHeight(106));
this.backgroundWidth = 195;
this.backgroundHeight = 222;
}
@@ -80,10 +79,6 @@ public class InterfaceTerminalScreen extends AEBaseScreen<InterfaceTerminalConta
public void init() {
super.init();
this.getScrollBar().setLeft(175);
this.getScrollBar().setHeight(106);
this.getScrollBar().setTop(18);
this.searchField = new AETextField(this.textRenderer, this.x + 104, this.y + 4, 65, 12);
this.searchField.setHasBorder(false);
this.searchField.setMaxLength(25);
@@ -34,8 +34,6 @@ import appeng.client.gui.widgets.ServerSettingToggleButton;
import appeng.client.gui.widgets.SettingToggleButton;
import appeng.container.implementations.LevelEmitterContainer;
import appeng.core.localization.GuiText;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.ConfigValuePacket;
public class LevelEmitterScreen extends UpgradeableScreen<LevelEmitterContainer> {
@@ -51,15 +49,18 @@ public class LevelEmitterScreen extends UpgradeableScreen<LevelEmitterContainer>
public void init() {
super.init();
this.level = new NumberEntryWidget(this, 20, 17, 138, 62, NumberEntryType.LEVEL_ITEM_COUNT,
this::onLevelChange);
this.level = new NumberEntryWidget(this, 20, 17, 138, 62, NumberEntryType.LEVEL_ITEM_COUNT);
this.level.setTextFieldBounds(25, 44, 75);
this.level.addButtons(children::add, this::addButton);
handler.setTextField(this.level);
this.level.setValue(handler.getReportingValue());
this.level.setOnChange(this::saveReportingValue);
this.level.setOnConfirm(this::onClose);
this.changeFocus(true);
}
private void onLevelChange(long level) {
NetworkHandler.instance().sendToServer(new ConfigValuePacket("LevelEmitter.Value", String.valueOf(level)));
private void saveReportingValue() {
this.level.getLongValue().ifPresent(handler::setReportingValue);
}
@Override
@@ -26,8 +26,11 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import me.shedaniel.math.Rectangle;
import appeng.api.config.SearchBoxMode;
import appeng.api.config.Settings;
import appeng.api.config.SortDir;
@@ -49,6 +52,7 @@ import appeng.client.gui.widgets.SettingToggleButton;
import appeng.client.gui.widgets.TabButton;
import appeng.client.me.InternalSlotME;
import appeng.client.me.ItemRepo;
import appeng.client.render.StackSizeRenderer;
import appeng.container.implementations.CraftingStatusContainer;
import appeng.container.implementations.MEMonitorableContainer;
import appeng.container.slot.AppEngSlot;
@@ -235,7 +239,7 @@ public class MEMonitorableScreen<T extends MEMonitorableContainer> extends AEBas
if (this.viewCell || this instanceof WirelessTermScreen) {
this.craftingStatusBtn = this.addButton(new TabButton(this.x + 170, this.y - 4, 2 + 11 * 16,
GuiText.CraftingStatus.text(), this.itemRenderer, btn -> showCraftingStatus()));
this.craftingStatusBtn.setHideEdge(13);
this.craftingStatusBtn.setHideEdge(true);
}
this.isAutoFocus = SearchBoxMode.AUTOSEARCH == searchMode || SearchBoxMode.JEI_AUTOSEARCH == searchMode
@@ -281,6 +285,8 @@ public class MEMonitorableScreen<T extends MEMonitorableContainer> extends AEBas
craftingGridOffsetX -= 25;
craftingGridOffsetY -= 6;
this.setScrollBar();
}
@Override
@@ -290,6 +296,16 @@ public class MEMonitorableScreen<T extends MEMonitorableContainer> extends AEBas
this.currentMouseX = mouseX;
this.currentMouseY = mouseY;
// Show the number of active crafting jobs
if (this.craftingStatusBtn != null && handler.activeCraftingJobs != -1) {
// The stack size renderer expects a 16x16 slot, while the button is normally
// bigger
int x = this.craftingStatusBtn.x + (this.craftingStatusBtn.getWidth() - 16) / 2;
int y = this.craftingStatusBtn.y + (this.craftingStatusBtn.getHeight() - 16) / 2;
StackSizeRenderer.renderSizeLabel(textRenderer, x - this.x, y - this.y,
new LiteralText(String.valueOf(handler.activeCraftingJobs)));
}
}
@Override
@@ -354,6 +370,7 @@ public class MEMonitorableScreen<T extends MEMonitorableContainer> extends AEBas
if (this.searchField != null) {
this.searchField.render(matrices, mouseX, mouseY, partialTicks);
}
}
protected String getBackground() {
@@ -519,4 +536,14 @@ public class MEMonitorableScreen<T extends MEMonitorableContainer> extends AEBas
this.init();
}
@Override
public List<Rectangle> getExclusionZones() {
List<Rectangle> zones = super.getExclusionZones();
// Button toolbar on the left
zones.add(new Rectangle(x - 18, y + 8, 18, 160));
// View-cells on the right
zones.add(new Rectangle(x + 197, y, 46, 128));
return zones;
}
}
@@ -2,41 +2,58 @@ package appeng.client.gui.implementations;
import java.util.ArrayList;
import java.util.List;
import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.function.Consumer;
import java.util.function.LongConsumer;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import appeng.client.gui.AEBaseScreen;
import appeng.client.gui.NumberEntryType;
import appeng.client.gui.widgets.ITickingWidget;
import appeng.client.gui.widgets.NumberBox;
import appeng.client.gui.widgets.ConfirmableTextField;
import appeng.client.gui.widgets.ValidationIcon;
import appeng.core.AEConfig;
/**
* A utility widget that consists of a text-field to enter a number with
* attached buttons to increment/decrement the number in fixed intervals.
*/
public class NumberEntryWidget implements ITickingWidget {
public class NumberEntryWidget extends DrawableHelper {
private static final Text INVALID_NUMBER = new TranslatableText("gui.appliedenergistics2.validation.InvalidNumber");
private static final String NUMBER_LESS_THAN_MIN_VALUE = "gui.appliedenergistics2.validation.NumberLessThanMinValue";
private static final Text PLUS = Text.of("+");
private static final Text MINUS = Text.of("-");
private static final int TEXT_COLOR_ERROR = 0xFF1900;
private static final int TEXT_COLOR_NORMAL = 0xFFFFFF;
private final AEBaseScreen<?> parent;
private final int x;
private final int y;
private final NumberBox level;
private final ConfirmableTextField textField;
private final NumberEntryType type;
private List<ButtonWidget> buttons;
private long minValue;
private ValidationIcon validationIcon;
public NumberEntryWidget(AEBaseScreen<?> parent, int x, int y, int width, int height, NumberEntryType type,
LongConsumer changeListener) {
// Called when the value changes
private Runnable onChange;
// Called when the user presses enter while there's a valid number in the field
private Runnable onConfirm;
private boolean hideValidationIcon;
public NumberEntryWidget(AEBaseScreen<?> parent, int x, int y, int width, int height, NumberEntryType type) {
this.parent = parent;
this.x = x;
this.y = y;
@@ -45,27 +62,50 @@ public class NumberEntryWidget implements ITickingWidget {
TextRenderer font = parent.getClient().textRenderer;
int inputX = parent.getX() + x;
int inputY = parent.getY() + y;
this.level = new NumberBox(font, inputX, inputY, width, font.fontHeight, type.getInputType(), changeListener);
this.level.setHasBorder(false);
this.level.setMaxLength(16);
this.level.setEditableColor(0xFFFFFF);
this.level.setVisible(true);
parent.setInitialFocus(this.level);
this.textField = new ConfirmableTextField(font, inputX, inputY, width, font.fontHeight, LiteralText.EMPTY);
this.textField.setHasBorder(false);
this.textField.setMaxLength(16);
this.textField.setEditableColor(TEXT_COLOR_NORMAL);
this.textField.setVisible(true);
this.textField.setSelected(true);
parent.setInitialFocus(this.textField);
this.textField.setChangedListener(text -> {
validate();
if (onChange != null) {
this.onChange.run();
}
});
this.textField.setOnConfirm(() -> {
// Only confirm if it's actually valid
if (this.onConfirm != null && getLongValue().isPresent()) {
this.onConfirm.run();
}
});
validate();
}
public void setOnConfirm(Runnable callback) {
this.onConfirm = callback;
}
public void setOnChange(Runnable callback) {
this.onChange = callback;
}
public void setActive(boolean active) {
this.level.active = active;
this.textField.active = active;
this.buttons.forEach(b -> b.active = active);
}
public void setTextFieldBounds(int x, int y, int width) {
this.level.x = parent.getX() + x;
this.level.y = parent.getY() + y;
this.level.setWidth(width);
this.textField.x = parent.getX() + x;
this.textField.y = parent.getY() + y;
this.textField.setWidth(width);
}
public void setMinValue(long minValue) {
this.level.setMinValue(minValue);
this.minValue = minValue;
validate();
}
public void addButtons(Consumer<Element> addChildren, Consumer<ButtonWidget> addButton) {
@@ -78,54 +118,116 @@ public class NumberEntryWidget implements ITickingWidget {
int left = parent.getX() + x;
int top = parent.getY() + y;
List<ButtonWidget> buttons = new ArrayList<>(8);
List<ButtonWidget> buttons = new ArrayList<>(9);
buttons.add(new ButtonWidget(left, top, 22, 20, makeLabel(PLUS, a), btn -> addQty(a)));
buttons.add(new ButtonWidget(left + 28, top, 28, 20, makeLabel(PLUS, b), btn -> addQty(b)));
buttons.add(new ButtonWidget(left + 62, top, 32, 20, makeLabel(PLUS, c), btn -> addQty(c)));
buttons.add(new ButtonWidget(left + 100, top, 38, 20, makeLabel(PLUS, d), btn -> addQty(d)));
// Need to add these now for sensible tab-order
buttons.forEach(addButton);
// Placing this here will give a sensible tab order
addChildren.accept(this.level);
addChildren.accept(this.textField);
buttons.add(new ButtonWidget(left, top + 42, 22, 20, makeLabel(MINUS, a), btn -> addQty(-a)));
buttons.add(new ButtonWidget(left + 28, top + 42, 28, 20, makeLabel(MINUS, b), btn -> addQty(-b)));
buttons.add(new ButtonWidget(left + 62, top + 42, 32, 20, makeLabel(MINUS, c), btn -> addQty(-c)));
buttons.add(new ButtonWidget(left + 100, top + 42, 38, 20, makeLabel(MINUS, d), btn -> addQty(-d)));
// This element is not focusable
if (!hideValidationIcon) {
this.validationIcon = new ValidationIcon(left + 104, top + 27);
buttons.add(this.validationIcon);
}
// Add the rest to the tab order
buttons.subList(4, buttons.size()).forEach(addButton);
this.buttons = buttons;
this.buttons.forEach(addButton);
// we need to re-validate because the icon may now be present and needs it's
// initial state
this.validate();
}
private void addQty(final long i) {
long currentValue = this.level.getValue();
long minValue = this.level.getMinValue();
this.level.setText(String.valueOf(Math.max(minValue, currentValue + i)));
/**
* Returns the integer value currently in the text-field, if it is a valid
* number and is within the allowed min/max value.
*/
public OptionalInt getIntValue() {
String text = textField.getText().trim();
try {
int value = Integer.parseInt(text, 10);
if (value < minValue) {
return OptionalInt.empty();
}
return OptionalInt.of(value);
} catch (NumberFormatException ignored) {
return OptionalInt.empty();
}
}
public void render(MatrixStack matrices, int mouseX, int mouseY, float partialTicks) {
this.level.render(matrices, mouseX, mouseY, partialTicks);
}
public void setValue(long value, boolean skipNotify) {
this.level.setValue(value, skipNotify);
/**
* Returns the long value currently in the text-field, if it is a valid number
* and is within the allowed min/max value.
*/
public OptionalLong getLongValue() {
String text = textField.getText().trim();
try {
long value = Long.parseLong(text, 10);
if (value < minValue) {
return OptionalLong.empty();
}
return OptionalLong.of(value);
} catch (NumberFormatException ignored) {
return OptionalLong.empty();
}
}
public void setValue(long value) {
setValue(value, false);
this.textField.setText(String.valueOf(Math.max(minValue, value)));
this.textField.setCursorToEnd();
this.textField.setSelectionStart(0);
validate();
}
public long getValue() {
return level.getValue();
private void addQty(final long i) {
getLongValue().ifPresent(currentValue -> setValue(currentValue + i));
}
@Override
public void tick() {
this.level.tick();
public void render(MatrixStack matrices, int mouseX, int mouseY, float partialTicks) {
this.textField.render(matrices, mouseX, mouseY, partialTicks);
}
private void validate() {
List<Text> validationErrors = new ArrayList<>();
String text = textField.getText().trim();
try {
long value = Long.parseLong(text, 10);
if (value < minValue) {
validationErrors.add(new TranslatableText(NUMBER_LESS_THAN_MIN_VALUE, minValue));
}
} catch (NumberFormatException ignored) {
validationErrors.add(INVALID_NUMBER);
}
boolean valid = validationErrors.isEmpty();
this.textField.setEditableColor(valid ? TEXT_COLOR_NORMAL : TEXT_COLOR_ERROR);
if (this.validationIcon != null) {
this.validationIcon.setValid(valid);
this.validationIcon.setTooltip(validationErrors);
}
}
private Text makeLabel(Text prefix, int amount) {
return prefix.copy().append(String.valueOf(amount));
}
public void setHideValidationIcon(boolean hideValidationIcon) {
this.hideValidationIcon = hideValidationIcon;
}
}
@@ -18,6 +18,8 @@
package appeng.client.gui.implementations;
import java.util.OptionalInt;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text;
@@ -26,8 +28,6 @@ import appeng.client.gui.AEBaseScreen;
import appeng.client.gui.NumberEntryType;
import appeng.container.implementations.PriorityContainer;
import appeng.core.localization.GuiText;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.ConfigValuePacket;
public class PriorityScreen extends AEBaseScreen<PriorityContainer> {
@@ -38,24 +38,38 @@ public class PriorityScreen extends AEBaseScreen<PriorityContainer> {
public PriorityScreen(PriorityContainer container, PlayerInventory playerInventory, Text title) {
super(container, playerInventory, title);
this.subGui = new AESubScreen(this, container.getPriorityHost());
// This is the effective size of the background image
backgroundWidth = 175;
backgroundHeight = 128;
}
@Override
public void init() {
super.init();
this.priority = new NumberEntryWidget(this, 20, 30, 138, 62, NumberEntryType.PRIORITY, this::onPriorityChange);
this.priority = new NumberEntryWidget(this, 20, 30, 138, 62, NumberEntryType.PRIORITY);
this.priority.setTextFieldBounds(62, 57, 50);
this.priority.setMinValue(Integer.MIN_VALUE);
handler.setTextField(this.priority);
this.priority.setValue(this.handler.getPriorityValue());
this.priority.addButtons(children::add, this::addButton);
this.subGui.addBackButton(this::addButton, 154, 0);
this.priority.setOnChange(this::savePriority);
this.priority.setOnConfirm(() -> {
savePriority();
this.subGui.goBack();
});
changeFocus(true);
}
private void onPriorityChange(long priority) {
NetworkHandler.instance()
.sendToServer(new ConfigValuePacket("PriorityHost.Priority", String.valueOf(priority)));
private void savePriority() {
OptionalInt priority = this.priority.getIntValue();
if (priority.isPresent()) {
handler.setPriority(priority.getAsInt());
}
}
@Override
@@ -66,13 +80,10 @@ public class PriorityScreen extends AEBaseScreen<PriorityContainer> {
@Override
public void drawBG(MatrixStack matrices, final int offsetX, final int offsetY, final int mouseX, final int mouseY,
float partialTicks) {
this.bindTexture(getBackground());
this.bindTexture("guis/priority.png");
drawTexture(matrices, offsetX, offsetY, 0, 0, this.backgroundWidth, this.backgroundHeight);
this.priority.render(matrices, mouseX, mouseY, partialTicks);
}
protected String getBackground() {
return "guis/priority.png";
}
}
@@ -18,10 +18,14 @@
package appeng.client.gui.implementations;
import java.util.List;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text;
import me.shedaniel.math.Rectangle;
import appeng.api.config.FuzzyMode;
import appeng.api.config.RedstoneMode;
import appeng.api.config.SchedulingMode;
@@ -146,4 +150,11 @@ public class UpgradeableScreen<T extends UpgradeableContainer> extends AEBaseScr
return this.bc instanceof ImportBusPart ? GuiText.ImportBus : GuiText.ExportBus;
}
@Override
public List<Rectangle> getExclusionZones() {
List<Rectangle> zones = super.getExclusionZones();
zones.add(new Rectangle(x - 18, y + 8, 18, 60));
return zones;
}
}
@@ -48,9 +48,9 @@ public class WirelessScreen extends AEBaseScreen<WirelessContainer> {
this.textRenderer.draw(matrices, GuiText.inventory.text(), 8, this.backgroundHeight - 96 + 3, 4210752);
if (handler.getRange() > 0) {
final String firstMessage = GuiText.Range.text() + ": " + (handler.getRange() / 10.0) + " m";
final String secondMessage = GuiText.PowerUsageRate.text() + ": "
+ Platform.formatPowerLong(handler.getDrain(), true);
final Text firstMessage = GuiText.Range.withSuffix(": " + (handler.getRange() / 10.0) + " m");
final Text secondMessage = GuiText.PowerUsageRate
.withSuffix(": " + Platform.formatPowerLong(handler.getDrain(), true));
final int strWidth = Math.max(this.textRenderer.getWidth(firstMessage),
this.textRenderer.getWidth(secondMessage));
@@ -0,0 +1,51 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.client.gui.widgets;
import org.lwjgl.glfw.GLFW;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.text.Text;
public class ConfirmableTextField extends TextFieldWidget {
private Runnable onConfirm;
public ConfirmableTextField(TextRenderer fontRenderer, int x, int y, int width, int height, Text text) {
super(fontRenderer, x, y, width, height, text);
}
@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
if (isActive() && (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_KP_ENTER)) {
if (this.onConfirm != null) {
this.onConfirm.run();
}
return true;
}
return super.keyPressed(keyCode, scanCode, modifiers);
}
public void setOnConfirm(Runnable onConfirm) {
this.onConfirm = onConfirm;
}
}
@@ -0,0 +1,96 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.client.gui.widgets;
import java.time.Duration;
/**
* This class can be used to implement repeating events such as holding down a
* button to fire an event repeatedly while the button is still being held, or
* repeatedly scrolling down a page, while the mouse is held down on the
* scrollbar.
*/
public class EventRepeater {
/**
* -1 if no repeat event is scheduled. Otherwise contains the
* {@link System#nanoTime()} at which the next event should occur.
*/
private long nextEventTime = -1;
private EventCallback eventCallback = null;
private final long eventDelay; // In nanoseconds
private final long eventInterval; // In nanoseconds
public EventRepeater(Duration delay, Duration interval) {
this.eventDelay = delay.toNanos();
this.eventInterval = interval.toNanos();
}
public void tick() {
if (this.eventCallback == null) {
return; // No event scheduled
}
// Use nanoTime here because it is monotonically increasing, while
// System.currentTimeMillis is not
long nanoTime = System.nanoTime();
if (nanoTime < this.nextEventTime) {
return; // Event time not reached
}
// Before triggering, recompute the next event, since
// the event callback itself may reschedule/cancel, and
// we should not overwrite that
this.nextEventTime = nanoTime + this.eventInterval;
this.eventCallback.trigger();
}
/**
* Schedule the given callback to be called after a given initial delay, and
* then after the given interval repeatedly.
*
* <p>
* Replaces any previously queued callback.
*/
public void repeat(EventCallback callback) {
long time = System.nanoTime();
this.eventCallback = callback;
this.nextEventTime = time + eventDelay;
}
public boolean isRepeating() {
return this.eventCallback != null;
}
/**
* Stop repeating the event.
*/
public void stop() {
this.eventCallback = null;
}
@FunctionalInterface
public interface EventCallback {
void trigger();
}
}
@@ -22,6 +22,7 @@ import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.sound.SoundManager;
import net.minecraft.client.texture.TextureManager;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
@@ -33,6 +34,10 @@ public abstract class IconButton extends ButtonWidget implements ITooltip {
private boolean halfSize = false;
private boolean disableClickSound = false;
private boolean disableBackground = false;
public IconButton(final int x, final int y, PressAction onPress) {
super(x, y, 16, 16, LiteralText.EMPTY, onPress);
}
@@ -42,6 +47,13 @@ public abstract class IconButton extends ButtonWidget implements ITooltip {
this.active = vis;
}
@Override
public void playDownSound(SoundManager soundManager) {
if (!disableClickSound) {
super.playDownSound(soundManager);
}
}
@Override
public void renderButton(MatrixStack matrices, final int mouseX, final int mouseY, float partial) {
@@ -72,7 +84,9 @@ public abstract class IconButton extends ButtonWidget implements ITooltip {
final int uv_y = iconIndex / 16;
final int uv_x = iconIndex - uv_y * 16;
drawTexture(matrices, 0, 0, 256 - 16, 256 - 16, 16, 16);
if (!disableBackground) {
drawTexture(matrices, 0, 0, 256 - 16, 256 - 16, 16, 16);
}
drawTexture(matrices, 0, 0, uv_x * 16, uv_y * 16, 16, 16);
RenderSystem.popMatrix();
} else {
@@ -85,12 +99,18 @@ public abstract class IconButton extends ButtonWidget implements ITooltip {
final int uv_y = iconIndex / 16;
final int uv_x = iconIndex - uv_y * 16;
drawTexture(matrices, this.x, this.y, 256 - 16, 256 - 16, 16, 16);
if (!disableBackground) {
drawTexture(matrices, this.x, this.y, 256 - 16, 256 - 16, 16, 16);
}
drawTexture(matrices, this.x, this.y, uv_x * 16, uv_y * 16, 16, 16);
}
RenderSystem.enableDepthTest();
RenderSystem.color4f(1.0f, 1.0f, 1.0f, 1.0f);
if (isHovered()) {
renderToolTip(matrices, mouseX, mouseY);
}
}
RenderSystem.color4f(1.0f, 1.0f, 1.0f, 1.0f);
}
protected abstract int getIconIndex();
@@ -133,4 +153,20 @@ public abstract class IconButton extends ButtonWidget implements ITooltip {
this.halfSize = halfSize;
}
public boolean isDisableClickSound() {
return disableClickSound;
}
public void setDisableClickSound(boolean disableClickSound) {
this.disableClickSound = disableClickSound;
}
public boolean isDisableBackground() {
return disableBackground;
}
public void setDisableBackground(boolean disableBackground) {
this.disableBackground = disableBackground;
}
}
@@ -1,153 +0,0 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.client.gui.widgets;
import java.util.function.LongConsumer;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.text.LiteralText;
public class NumberBox extends TextFieldWidget {
private final LongConsumer changeListener;
private long lastValue;
private long minValue = 0;
private long maxValue;
public NumberBox(final TextRenderer fontRenderer, final int x, final int y, final int width, final int height,
final Class<?> type, LongConsumer changeListener) {
super(fontRenderer, x, y, width, height, new LiteralText("0"));
this.setText("0");
setChangedListener(this::handleTextChanged);
this.lastValue = 0;
this.changeListener = changeListener;
if (type == int.class || type == Integer.class) {
maxValue = Integer.MAX_VALUE;
} else {
maxValue = Long.MAX_VALUE;
}
}
// NOTE: This method MUST NOT BE NAMED like a method in the superclass because
// of a ForgeGradle remapping bug
// since it'll not remap this method's name, but it will remap the name of the
// method reference above.
private void handleTextChanged(String text) {
if (text.isEmpty()) {
setText("0"); // Will call onTextChanged recursively
return;
}
boolean canBeNegative = canBeNegative();
if (canBeNegative && text.equals("-")) {
// Allow this as a special case to make typing in a negative number easier
return;
}
StringBuilder sanitized = new StringBuilder(text);
boolean encounteredNonZero = false;
for (int i = 0; i < sanitized.length(); i++) {
char ch = sanitized.charAt(i);
if (canBeNegative && i == 0 && ch == '-') {
continue; // Allow leading minus sign
}
if (ch >= '1' && ch <= '9') {
encounteredNonZero = true;
continue;
}
if (ch != '0' || !encounteredNonZero) {
sanitized.deleteCharAt(i--);
}
}
if (sanitized.length() == 0) {
sanitized.append('0');
}
String sanitizedStr = sanitized.toString();
if (!sanitizedStr.equals(text)) {
setText(sanitizedStr); // Will call onTextChanged recursively
return;
}
if (getValue() < minValue) {
setText(String.valueOf(minValue)); // Will call onTextChanged recursively
return;
}
if (getValue() > maxValue) {
setText(String.valueOf(maxValue)); // Will call onTextChanged recursively
return;
}
reportChange();
}
private void reportChange() {
long value = getValue();
if (value != lastValue) {
lastValue = value;
changeListener.accept(value);
}
}
public void setValue(long value, boolean skipNotify) {
// This check avoid changing the cursor position needlessly
if (value == this.getValue()) {
return;
}
if (skipNotify) {
lastValue = value;
}
setText(String.valueOf(value));
}
public long getValue() {
if (getText().equals("-") && canBeNegative()) {
return lastValue; // Allow this as a special case to type in a negative number more easily
}
return Long.parseLong(getText());
}
@Override
public boolean keyPressed(int p_keyPressed_1_, int p_keyPressed_2_, int p_keyPressed_3_) {
if (super.keyPressed(p_keyPressed_1_, p_keyPressed_2_, p_keyPressed_3_)) {
return true;
}
// Swallow key presses for numbers because they would otherwise trigger the
// hotbar swapping unintentionally
return isFocused() && p_keyPressed_1_ >= '0' && p_keyPressed_1_ <= '9';
}
public void setMinValue(long minValue) {
this.minValue = minValue;
}
public long getMinValue() {
return minValue;
}
private boolean canBeNegative() {
return minValue < 0;
}
}
@@ -18,18 +18,74 @@
package appeng.client.gui.widgets;
import com.mojang.blaze3d.systems.RenderSystem;
import java.time.Duration;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.util.Rect2i;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import appeng.client.gui.AEBaseScreen;
public class Scrollbar implements IScrollSource {
/**
* Implements a vertical scrollbar using Vanilla's scrollbar handle texture from
* the creative tab.
* <p>
* It is expected that the background of the UI contains a pre-baked scrollbar
* track border, and that the exact rectangle of that track is set on this
* object via {@link #setLeft(int)}, {@link #setTop(int)} and
* {@link #setHeight(int)}. While the width of the track can also be set, the
* drawn handle will use vanilla's sprite width (see {@link #HANDLE_WIDTH}.
*/
public class Scrollbar extends DrawableHelper implements IScrollSource {
/**
* Width of the scrollbar handle sprite in the source texture.
*/
private static final int HANDLE_WIDTH = 12;
/**
* Height of the scrollbar handle sprite in the source texture.
*/
private static final int HANDLE_HEIGHT = 15;
/**
* Texture containing the scrollbar handle sprites.
*/
private static final Identifier TEXTURE = new Identifier("minecraft",
"textures/gui/container/creative_inventory/tabs.png");
/**
* Rectangle in the source texture that contains the sprite for an enabled
* handle.
*/
private static final Rect2i ENABLED = new Rect2i(232, 0, HANDLE_WIDTH, HANDLE_HEIGHT);
/**
* Rectangle in the source texture that contains the sprite for a disabled
* handle.
*/
private static final Rect2i DISABLED = new Rect2i(232 + HANDLE_WIDTH, 0, HANDLE_WIDTH, HANDLE_HEIGHT);
/**
* The screen x-coordinate of the scrollbar's inner track.
*/
private int displayX = 0;
/**
* The screen y-coordinate of the scrollbar's inner track.
*/
private int displayY = 0;
private int width = 12;
/**
* The inner width of the scrollbar track.
*/
private int width = HANDLE_WIDTH;
/**
* The inner height of the scrollbar track.
*/
private int height = 16;
private int pageSize = 1;
@@ -37,20 +93,58 @@ public class Scrollbar implements IScrollSource {
private int minScroll = 0;
private int currentScroll = 0;
private final DrawableHelper drawable = new DrawableHelper() {
};
/**
* True if the scrollbar's handle is currently being dragged.
*/
private boolean dragging;
/**
* The y-coordinate relative to the upper edge of the scrollbar handle, where
* the user pressed the mouse button to drag. While dragging, this is applied as
* an offset to the effective scrollbar position.
*/
private int dragYOffset;
private final EventRepeater eventRepeater = new EventRepeater(Duration.ofMillis(250), Duration.ofMillis(150));
/**
* Draws the handle of the scrollbar.
* <p>
* The GUI is assumed to already contain a prebaked scrollbar track in its
* background.
*/
public void draw(MatrixStack matrices, final AEBaseScreen<?> g) {
g.bindTexture("minecraft", "gui/container/creative_inventory/tabs.png");
RenderSystem.color4f(1.0f, 1.0f, 1.0f, 1.0f);
setZOffset(g.getZOffset());
drawable.setZOffset(g.getZOffset());
// Draw the track (nice for debugging)
// fill(matrices, displayX, displayY, this.displayX + width, this.displayY +
// height, 0xffff0000);
g.bindTexture(TEXTURE);
int yOffset;
Rect2i sourceRect;
if (this.getRange() == 0) {
drawable.drawTexture(matrices, this.displayX, this.displayY, 232 + this.width, 0, this.width, 15);
yOffset = 0;
sourceRect = DISABLED;
} else {
final int offset = (this.currentScroll - this.minScroll) * (this.height - 15) / this.getRange();
drawable.drawTexture(matrices, this.displayX, offset + this.displayY, 232, 0, this.width, 15);
yOffset = getHandleYOffset();
sourceRect = ENABLED;
}
drawTexture(matrices, this.displayX, this.displayY + yOffset, sourceRect.getX(), sourceRect.getY(),
sourceRect.getWidth(), sourceRect.getHeight());
}
/**
* Returns the y-position of the scrollbar handle in relation to the upper edge
* of the scrollbar's track.
*/
private int getHandleYOffset() {
if (getRange() == 0) {
return 0;
}
int availableHeight = this.height - HANDLE_HEIGHT;
return (this.currentScroll - this.minScroll) * availableHeight / this.getRange();
}
private int getRange() {
@@ -114,24 +208,96 @@ public class Scrollbar implements IScrollSource {
return this.currentScroll;
}
public void click(final double x, final double y) {
if (this.getRange() == 0) {
public boolean mouseDown(double x, double y) {
this.dragging = false;
// Clicks to the left or right of the scrollbar don't do anything
if (x < displayX || x >= displayX + width) {
return false;
}
// Clicks to the top or bottom don't do anything either
int relY = (int) Math.round(y - displayY);
if (relY < 0 || relY >= height) {
return false;
}
// Do nothing when there's no range, but swallow the event
if (getRange() == 0) {
return true;
}
int handleYOffset = getHandleYOffset();
if (relY < handleYOffset) {
// Clicks above the handle will page up, repeatedly
pageUp();
eventRepeater.repeat(this::pageUp);
} else if (relY < handleYOffset + HANDLE_HEIGHT) {
// Clicks on the handle will initiate dragging it
this.dragging = true;
this.dragYOffset = relY - handleYOffset;
} else {
// Clicks below the handle will page down, repeatedly
pageDown();
eventRepeater.repeat(this::pageDown);
}
return true;
}
public boolean mouseUp(double x, double y) {
this.dragging = false;
this.eventRepeater.stop();
return false;
}
public void mouseDragged(double x, double y) {
if (this.getRange() == 0 || !this.dragging || this.eventRepeater.isRepeating()) {
return;
}
if (x > this.displayX && x <= this.displayX + this.width) {
if (y > this.displayY && y <= this.displayY + this.height) {
this.currentScroll = (int) (y - this.displayY);
this.currentScroll = this.minScroll + ((this.currentScroll * 2 * this.getRange() / this.height));
this.currentScroll = (this.currentScroll + 1) >> 1;
this.applyRange();
}
}
// Compute the position of the mouse (adjusted for where it grabbed the handle,
// so as if it grabbed
// the upper edge of it) within the scrollable area of the track (minus the
// handle height).
double handleUpperEdgeY = y - this.displayY - this.dragYOffset;
double availableHeight = this.height - HANDLE_HEIGHT;
double position = MathHelper.clamp(handleUpperEdgeY / availableHeight, 0.0, 1.0);
this.currentScroll = this.minScroll + (int) Math.round(position * this.getRange());
this.applyRange();
}
public void wheel(double delta) {
// Do nothing when there's no range
if (getRange() == 0) {
return;
}
delta = Math.max(Math.min(-delta, 1), -1);
this.currentScroll += delta * this.pageSize;
this.applyRange();
}
/**
* Ticks the scrollbar for the purposes of input-repeats (since mouse-downs are
* not repeat-triggered), used to repeatedly page-up or page-down when the mouse
* is held in the area above or below the scrollbar handle.
*/
public void tick() {
this.eventRepeater.tick();
}
private void pageUp() {
this.currentScroll -= this.pageSize;
this.applyRange();
}
private void pageDown() {
this.currentScroll += this.pageSize;
this.applyRange();
}
}
@@ -25,6 +25,7 @@ import java.util.function.Predicate;
import java.util.regex.Pattern;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
@@ -47,6 +48,7 @@ import appeng.api.config.StorageFilter;
import appeng.api.config.TerminalStyle;
import appeng.api.config.ViewItems;
import appeng.api.config.YesNo;
import appeng.client.gui.AEBaseScreen;
import appeng.core.localization.ButtonToolTips;
import appeng.util.EnumCycler;
@@ -89,9 +91,11 @@ public class SettingToggleButton<T extends Enum<T>> extends IconButton {
registerApp(16 * 7, Settings.CONDENSER_OUTPUT, CondenserOutput.TRASH, ButtonToolTips.CondenserOutput,
ButtonToolTips.Trash);
registerApp(16 * 7 + 1, Settings.CONDENSER_OUTPUT, CondenserOutput.MATTER_BALLS,
ButtonToolTips.CondenserOutput, ButtonToolTips.MatterBalls);
ButtonToolTips.CondenserOutput,
ButtonToolTips.MatterBalls.text(CondenserOutput.MATTER_BALLS.requiredPower));
registerApp(16 * 7 + 2, Settings.CONDENSER_OUTPUT, CondenserOutput.SINGULARITY,
ButtonToolTips.CondenserOutput, ButtonToolTips.Singularity);
ButtonToolTips.CondenserOutput,
ButtonToolTips.Singularity.text(CondenserOutput.SINGULARITY.requiredPower));
registerApp(16 * 9 + 1, Settings.ACCESS, AccessRestriction.READ, ButtonToolTips.IOMode,
ButtonToolTips.Read);
@@ -230,7 +234,13 @@ public class SettingToggleButton<T extends Enum<T>> extends IconButton {
}
private void triggerPress() {
boolean backwards = MinecraftClient.getInstance().mouse.wasRightButtonClicked();
boolean backwards = false;
// This isn't great, but we don't get any information about right-clicks
// otherwise
Screen currentScreen = MinecraftClient.getInstance().currentScreen;
if (currentScreen instanceof AEBaseScreen) {
backwards = ((AEBaseScreen<?>) currentScreen).isHandlingRightClick();
}
onPress.handle(this, backwards);
}
@@ -31,7 +31,7 @@ import net.minecraft.util.Identifier;
public class TabButton extends ButtonWidget implements ITooltip {
public static final Identifier TEXTURE_STATES = new Identifier("appliedenergistics2", "textures/guis/states.png");
private final ItemRenderer itemRenderer;
private int hideEdge = 0;
private boolean hideEdge;
private int myIcon = -1;
private ItemStack myItem;
@@ -69,14 +69,17 @@ public class TabButton extends ButtonWidget implements ITooltip {
RenderSystem.enableAlphaTest();
int uv_x = (this.hideEdge > 0 ? 11 : 13);
// Selects the button border from the sprite-sheet, where each type occupies a
// 2x2 slot
int uv_x = 8 + (this.hideEdge ? 0 : 2);
int uv_y = 12 + (this.isFocused() ? 2 : 0);
final int offsetX = this.hideEdge > 0 ? 1 : 0;
final int offsetX = this.hideEdge ? 1 : 0;
drawTexture(matrices, this.x, this.y, uv_x * 16, 0, 25, 22);
drawTexture(matrices, this.x, this.y, uv_x * 16, uv_y * 16, 25, 22);
if (this.myIcon >= 0) {
final int uv_y = this.myIcon / 16;
uv_y = this.myIcon / 16;
uv_x = this.myIcon - uv_y * 16;
drawTexture(matrices, offsetX + this.x + 3, this.y + 3, uv_x * 16, uv_y * 16, 16, 16);
@@ -122,11 +125,11 @@ public class TabButton extends ButtonWidget implements ITooltip {
return this.visible;
}
public int getHideEdge() {
public boolean getHideEdge() {
return this.hideEdge;
}
public void setHideEdge(final int hideEdge) {
public void setHideEdge(final boolean hideEdge) {
this.hideEdge = hideEdge;
}
}
@@ -0,0 +1,64 @@
package appeng.client.gui.widgets;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
/**
* Displays a small icon that shows validation errors for some input control.
*/
public class ValidationIcon extends IconButton {
private final List<Text> tooltip = new ArrayList<>();
private boolean valid;
public ValidationIcon(int x, int y) {
super(x, y, btn -> {
});
setDisableBackground(true);
setDisableClickSound(true);
setHalfSize(true);
}
public void setValid(boolean valid) {
setVisibility(!valid);
if (valid) {
this.tooltip.clear();
}
}
public void setTooltip(List<Text> lines) {
this.tooltip.clear();
this.tooltip.addAll(lines);
}
@Override
protected int getIconIndex() {
return 16 * 8;
}
@Override
public boolean changeFocus(boolean flag) {
return false; // Cannot focus this element
}
@Override
public void renderToolTip(MatrixStack matrices, int mouseX, int mouseY) {
if (this.tooltip.isEmpty()) {
return;
}
MinecraftClient client = MinecraftClient.getInstance();
Screen screen = client.currentScreen;
if (screen == null) {
return;
}
screen.renderTooltip(matrices, this.tooltip, x, y);
}
}
@@ -41,11 +41,6 @@ import appeng.fluids.util.FluidSorters;
import appeng.util.Platform;
import appeng.util.prioritylist.IPartitionList;
/**
* @author BrockWS
* @version rv6 - 22/05/2018
* @since rv6 22/05/2018
*/
public class FluidRepo {
private final IItemList<IAEFluidStack> list = Api.instance().storage().getStorageChannel(IFluidStorageChannel.class)
.createList();
@@ -21,23 +21,22 @@ package appeng.client.me;
import javax.annotation.Nonnull;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.SimpleInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
import appeng.api.storage.data.IAEFluidStack;
import appeng.fluids.container.slots.IMEFluidSlot;
/**
* @author BrockWS
* @version rv6 - 22/05/2018
* @since rv6 22/05/2018
*/
public class SlotFluidME extends Slot implements IMEFluidSlot {
private static final Inventory EMPTY_INVENTORY = new SimpleInventory(0);
private final InternalFluidSlotME slot;
public SlotFluidME(InternalFluidSlotME slot) {
super(null, 0, slot.getxPosition(), slot.getyPosition());
super(EMPTY_INVENTORY, 0, slot.getxPosition(), slot.getyPosition());
this.slot = slot;
}
@@ -69,7 +68,7 @@ public class SlotFluidME extends Slot implements IMEFluidSlot {
}
@Override
public void setStack(final ItemStack par1ItemStack) {
public void setStack(final ItemStack stack) {
}
@@ -85,7 +84,7 @@ public class SlotFluidME extends Slot implements IMEFluidSlot {
}
@Override
public boolean canTakeItems(final PlayerEntity par1PlayerEntity) {
public boolean canTakeItems(final PlayerEntity player) {
return false;
}
}
+13 -9
View File
@@ -19,6 +19,8 @@
package appeng.client.me;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.SimpleInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
@@ -26,16 +28,18 @@ import appeng.api.storage.data.IAEItemStack;
public class SlotME extends Slot {
private final InternalSlotME mySlot;
private static final Inventory EMPTY_INVENTORY = new SimpleInventory(0);
public SlotME(final InternalSlotME me) {
super(null, 0, me.getxPosition(), me.getyPosition());
this.mySlot = me;
private final InternalSlotME slot;
public SlotME(final InternalSlotME slot) {
super(EMPTY_INVENTORY, 0, slot.getxPosition(), slot.getyPosition());
this.slot = slot;
}
public IAEItemStack getAEStack() {
if (this.mySlot.hasPower()) {
return this.mySlot.getAEStack();
if (this.slot.hasPower()) {
return this.slot.getAEStack();
}
return null;
}
@@ -47,15 +51,15 @@ public class SlotME extends Slot {
@Override
public ItemStack getStack() {
if (this.mySlot.hasPower()) {
return this.mySlot.getStack();
if (this.slot.hasPower()) {
return this.slot.getStack();
}
return ItemStack.EMPTY;
}
@Override
public boolean hasStack() {
if (this.mySlot.hasPower()) {
if (this.slot.hasPower()) {
return !this.getStack().isEmpty();
}
return false;
@@ -104,7 +104,7 @@ class CableBuilder {
throw new IllegalStateException("Cable type " + cableType + " does not support connections.");
}
return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, textureFolder + color.name().toLowerCase(Locale.ROOT)));
}
@@ -20,7 +20,6 @@ package appeng.client.render.cablebus;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -30,6 +29,10 @@ import java.util.function.Supplier;
import javax.annotation.Nullable;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.renderer.v1.Renderer;
@@ -61,10 +64,15 @@ import appeng.api.util.AEColor;
@Environment(EnvType.CLIENT)
public class CableBusBakedModel implements BakedModel, FabricBakedModel {
private static final Mesh EMPTY_MESH = consumer -> {
};
private static final Renderer RENDERER = RendererAccess.INSTANCE.getRenderer();
// FIXME: This entire cache seems dumb as shit
private static final Map<CableBusRenderState, Mesh> CABLE_MODEL_CACHE = new HashMap<>();
// The number of meshes overall that will be cached
private static final int CACHE_MESH_COUNT = 100;
private final LoadingCache<CableBusRenderState, Mesh> cableModelCache;
private final CableBuilder cableBuilder;
@@ -80,6 +88,15 @@ public class CableBusBakedModel implements BakedModel, FabricBakedModel {
this.facadeBuilder = facadeBuilder;
this.partModels = partModels;
this.particleTexture = particleTexture;
this.cableModelCache = CacheBuilder.newBuilder()//
.maximumSize(CACHE_MESH_COUNT)//
.build(new CacheLoader<CableBusRenderState, Mesh>() {
@Override
public Mesh load(CableBusRenderState renderState) {
Mesh mesh = buildCableModel(renderState);
return mesh != null ? mesh : EMPTY_MESH;
}
});
}
@Override
@@ -109,8 +126,8 @@ public class CableBusBakedModel implements BakedModel, FabricBakedModel {
}
// First, handle the cable at the center of the cable bus
final Mesh cableModel = CABLE_MODEL_CACHE.computeIfAbsent(renderState, this::buildCableModel);
if (cableModel != null) {
final Mesh cableModel = cableModelCache.getUnchecked(renderState);
if (cableModel != EMPTY_MESH) {
context.meshConsumer().accept(cableModel);
}
@@ -359,10 +376,6 @@ public class CableBusBakedModel implements BakedModel, FabricBakedModel {
return ModelOverrideList.EMPTY;
}
public static void clearCache() {
CABLE_MODEL_CACHE.clear();
}
@Override
public boolean isVanillaAdapter() {
return false;
@@ -23,7 +23,6 @@ public class CableBusModelLoader implements ModelResourceProvider {
public UnbakedModel loadModelResource(Identifier resourceId, ModelProviderContext context)
throws ModelProviderException {
if (CABLE_BUS_MODEL.equals(resourceId)) {
CableBusBakedModel.clearCache();
return new CableBusModel(partModels);
} else {
return null;
@@ -74,7 +74,7 @@ public enum CableCoreType {
}
public SpriteIdentifier getTexture(AEColor color) {
return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, this.textureFolder + "/" + color.name().toLowerCase(Locale.ROOT)));
}
@@ -258,7 +258,9 @@ public class FacadeBuilder {
for (Box box : holeStrips) {
emitter.fromVanilla(quad.getVertexData(), 0, false);
emitter.cullFace(cullFace);
// Keep the cull-face for faces that are flush with the outer block-face on the
// side the facade is attached to, but clear it for anything that faces inwards
emitter.cullFace(cullFace == side ? side : null);
emitter.nominalFace(quad.getFace());
interpolator.setInputQuad(emitter);
@@ -18,7 +18,7 @@ import appeng.core.AppEng;
public class P2PTunnelFrequencyModel implements BasicUnbakedModel {
private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "part/p2p_tunnel_frequency"));
@Nullable
@@ -24,7 +24,6 @@ import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl;
import net.minecraft.client.util.math.Vector3f;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Quaternion;
@@ -93,10 +92,6 @@ public class QuadRotator implements RenderContext.QuadTransform {
}
}
// FIXME FABRIC: Wait for Grondags response about this one
MutableQuadViewImpl quadImpl = (MutableQuadViewImpl) quad;
quadImpl.lightFace(rotation.rotate(quad.lightFace()));
// Transform the nominal face, setting the cull face will also overwrite the
// nominialFace,
// hence saving both first and the order here.
@@ -47,7 +47,8 @@ public class SmartCableTextures {
new Identifier(AppEng.MOD_ID, "part/cable/smart/channels_12"), //
new Identifier(AppEng.MOD_ID, "part/cable/smart/channels_13"), //
new Identifier(AppEng.MOD_ID, "part/cable/smart/channels_14")//
}).map(e -> new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, e)).toArray(SpriteIdentifier[]::new);
}).map(e -> new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, e))
.toArray(SpriteIdentifier[]::new);
// Textures used to display channels on smart cables. There's two sets of 5
// textures each, and
@@ -115,7 +115,7 @@ public class CraftingCubeModel implements BasicUnbakedModel {
}
private static SpriteIdentifier texture(String name) {
return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "block/crafting/" + name));
}
}
@@ -25,7 +25,7 @@ import appeng.core.AppEng;
public class BiometricCardModel implements BasicUnbakedModel {
public static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "item/biometric_card_base");
private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "item/biometric_card_hash"));
@Override
@@ -26,11 +26,11 @@ public class ColorApplicatorModel implements BasicUnbakedModel {
private static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "item/color_applicator_colored");
private static final SpriteIdentifier TEXTURE_DARK = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
private static final SpriteIdentifier TEXTURE_DARK = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "item/color_applicator_tip_dark"));
private static final SpriteIdentifier TEXTURE_MEDIUM = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
private static final SpriteIdentifier TEXTURE_MEDIUM = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "item/color_applicator_tip_medium"));
private static final SpriteIdentifier TEXTURE_BRIGHT = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
private static final SpriteIdentifier TEXTURE_BRIGHT = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "item/color_applicator_tip_bright"));
@Override
@@ -62,13 +62,13 @@ class GlassBakedModel implements BakedModel, FabricBakedModel {
private static final byte[][][] OFFSETS = generateOffsets();
// Alternating textures based on position
static final SpriteIdentifier TEXTURE_A = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
static final SpriteIdentifier TEXTURE_A = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier("appliedenergistics2:block/glass/quartz_glass_a"));
static final SpriteIdentifier TEXTURE_B = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
static final SpriteIdentifier TEXTURE_B = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier("appliedenergistics2:block/glass/quartz_glass_b"));
static final SpriteIdentifier TEXTURE_C = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
static final SpriteIdentifier TEXTURE_C = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier("appliedenergistics2:block/glass/quartz_glass_c"));
static final SpriteIdentifier TEXTURE_D = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
static final SpriteIdentifier TEXTURE_D = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier("appliedenergistics2:block/glass/quartz_glass_d"));
// Frame texture
@@ -81,7 +81,7 @@ class GlassBakedModel implements BakedModel, FabricBakedModel {
private static SpriteIdentifier[] generateTexturesFrame() {
return IntStream.range(1, 16).mapToObj(Integer::toBinaryString).map(s -> Strings.padStart(s, 4, '0'))
.map(s -> new Identifier("appliedenergistics2:block/glass/quartz_glass_frame" + s))
.map(rl -> new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, rl))
.map(rl -> new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, rl))
.toArray(SpriteIdentifier[]::new);
}
@@ -25,7 +25,7 @@ import appeng.core.AppEng;
public class MemoryCardModel implements BasicUnbakedModel {
public static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "item/memory_card_base");
private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "item/memory_card_hash"));
@Override
@@ -59,7 +59,7 @@ public class SpatialPylonModel implements BasicUnbakedModel {
}
private static SpriteIdentifier getTexturePath(SpatialPylonTextureType type) {
return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "block/spatial_pylon/" + type.name().toLowerCase(Locale.ROOT)));
}
@@ -38,7 +38,7 @@ public final class InscriberTESR extends BlockEntityRenderer<InscriberBlockEntit
private static final float ITEM_RENDER_SCALE = 1.0f / 1.2f;
private static final SpriteIdentifier TEXTURE_INSIDE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
private static final SpriteIdentifier TEXTURE_INSIDE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE,
new Identifier(AppEng.MOD_ID, "block/inscriber_inside"));
public static final ImmutableList<SpriteIdentifier> SPRITES = ImmutableList.of(TEXTURE_INSIDE);
@@ -66,10 +66,8 @@ import appeng.container.slot.PlayerInvSlot;
import appeng.core.AELog;
import appeng.core.Api;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.ConfigValuePacket;
import appeng.core.sync.packets.InventoryActionPacket;
import appeng.core.sync.packets.TargetItemStackPacket;
import appeng.helpers.ICustomNameObject;
import appeng.helpers.InventoryAction;
import appeng.me.helpers.PlayerSource;
import appeng.mixins.ScreenHandlerListeners;
@@ -88,11 +86,9 @@ public abstract class AEBaseContainer extends ScreenHandler {
private final IGuiItemObject obj;
private final HashMap<Integer, SyncData> syncData = new HashMap<>();
private boolean isContainerValid = true;
private String customName;
private ContainerLocator locator;
private IMEInventoryHandler<IAEItemStack> cellInv;
private IEnergySource powerSrc;
private boolean sentCustomName;
private int ticksSinceCheck = 900;
private IAEItemStack clientRequestedTargetItem = null;
@@ -317,9 +313,7 @@ public abstract class AEBaseContainer extends ScreenHandler {
@Override
public void sendContentUpdates() {
this.sendCustomName();
if (Platform.isServer()) {
if (isServer()) {
if (this.tileEntity != null
&& this.tileEntity.getWorld().getBlockEntity(this.tileEntity.getPos()) != this.tileEntity) {
this.setValidContainer(false);
@@ -886,43 +880,6 @@ public abstract class AEBaseContainer extends ScreenHandler {
this.sendContentUpdates();
}
private void sendCustomName() {
// FIXME: Trash this, this is handled by NamedContainerProvider now
if (!this.sentCustomName) {
this.sentCustomName = true;
if (Platform.isServer()) {
ICustomNameObject name = null;
if (this.part instanceof ICustomNameObject) {
name = (ICustomNameObject) this.part;
}
if (this.tileEntity instanceof ICustomNameObject) {
name = (ICustomNameObject) this.tileEntity;
}
if (this.obj instanceof ICustomNameObject) {
name = (ICustomNameObject) this.obj;
}
if (this instanceof ICustomNameObject) {
name = (ICustomNameObject) this;
}
if (name != null) {
if (name.hasCustomInventoryName()) {
this.setCustomName(name.getCustomInventoryName().getString());
}
if (this.getCustomName() != null) {
NetworkHandler.instance().sendTo(new ConfigValuePacket("CustomName", this.getCustomName()),
(ServerPlayerEntity) this.getPlayerInventory().player);
}
}
}
}
}
public void swapSlotContents(final int slotA, final int slotB) {
final Slot a = this.getSlot(slotA);
final Slot b = this.getSlot(slotB);
@@ -1012,14 +969,6 @@ public abstract class AEBaseContainer extends ScreenHandler {
this.cellInv = cellInv;
}
public String getCustomName() {
return this.customName;
}
public void setCustomName(final String customName) {
this.customName = customName;
}
public PlayerInventory getPlayerInventory() {
return this.invPlayer;
}
@@ -1048,4 +997,18 @@ public abstract class AEBaseContainer extends ScreenHandler {
this.powerSrc = powerSrc;
}
/**
* Returns whether this container instance lives on the client.
*/
protected boolean isClient() {
return invPlayer.player.getEntityWorld().isClient();
}
/**
* Returns whether this container instance lives on the server.
*/
protected boolean isServer() {
return !isClient();
}
}
@@ -89,6 +89,8 @@ public class SyncData {
NetworkHandler.instance().sendTo(new ConfigValuePacket("SyncDat." + this.channel, json),
(ServerPlayerEntity) o);
}
this.clientVersion = val;
return;
}
// Types other than Text must be non-null
@@ -50,7 +50,6 @@ import appeng.container.slot.RestrictedInputSlot;
import appeng.core.Api;
import appeng.tile.misc.CellWorkbenchBlockEntity;
import appeng.util.EnumCycler;
import appeng.util.Platform;
import appeng.util.helpers.ItemHandlerUtil;
import appeng.util.inv.WrapperSupplierItemHandler;
import appeng.util.iterators.NullIterator;
@@ -143,7 +142,7 @@ public class CellWorkbenchContainer extends UpgradeableContainer {
@Override
public void sendContentUpdates() {
final ItemStack is = this.workBench.getInventoryByName("cell").getInvStack(0);
if (Platform.isServer()) {
if (isServer()) {
for (final ScreenHandlerListener listener : this.getListeners()) {
if (this.prevStack != is) {
// if the bars changed an item was probably made, so just send shit!
@@ -34,7 +34,6 @@ import appeng.container.interfaces.IProgressProvider;
import appeng.container.slot.OutputSlot;
import appeng.container.slot.RestrictedInputSlot;
import appeng.tile.misc.CondenserBlockEntity;
import appeng.util.Platform;
public class CondenserContainer extends AEBaseContainer implements IProgressProvider {
@@ -76,13 +75,13 @@ public class CondenserContainer extends AEBaseContainer implements IProgressProv
@Override
public void sendContentUpdates() {
if (Platform.isServer()) {
if (isServer()) {
final double maxStorage = this.condenser.getStorage();
final double requiredEnergy = this.condenser.getRequiredPower();
this.requiredEnergy = requiredEnergy == 0 ? (int) maxStorage : (int) Math.min(requiredEnergy, maxStorage);
this.storedPower = (int) this.condenser.getStoredPower();
this.setOutput((CondenserOutput) this.condenser.getConfigManager().getSetting(Settings.CONDENSER_OUTPUT));
this.output = (CondenserOutput) this.condenser.getConfigManager().getSetting(Settings.CONDENSER_OUTPUT);
}
super.sendContentUpdates();
@@ -102,7 +101,4 @@ public class CondenserContainer extends AEBaseContainer implements IProgressProv
return this.output;
}
private void setOutput(final CondenserOutput output) {
this.output = output;
}
}
@@ -1,5 +1,7 @@
package appeng.container.implementations;
import java.util.function.Function;
import javax.annotation.Nullable;
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory;
@@ -12,9 +14,7 @@ import net.minecraft.screen.ScreenHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import appeng.api.config.SecurityPermissions;
import appeng.api.features.IWirelessTermHandler;
@@ -44,6 +44,8 @@ public final class ContainerHelper<C extends AEBaseContainer, I> {
private final SecurityPermissions requiredPermission;
private Function<I, Text> containerTitleStrategy = this::getDefaultContainerTitle;
public ContainerHelper(ContainerFactory<C, I> factory, Class<I> interfaceClass) {
this(factory, interfaceClass, null);
}
@@ -55,19 +57,47 @@ public final class ContainerHelper<C extends AEBaseContainer, I> {
this.factory = factory;
}
/**
* Specifies a custom strategy for obtaining a custom container name.
* <p>
* The stratgy should return {@link LiteralText#EMPTY} if there's no custom
* name.
*/
public ContainerHelper<C, I> withContainerTitle(Function<I, Text> containerTitleStrategy) {
this.containerTitleStrategy = containerTitleStrategy;
return this;
}
/**
* Opens a container that is based around a single block entity. The tile
* entity's position is encoded in the packet buffer.
*/
public C fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf packetBuf) {
return fromNetwork(windowId, inv, packetBuf, (accessObj, container, buffer) -> {
});
}
/**
* Same as {@link #open}, but allows or additional data to be read from the
* packet, and passed onto the container.
*/
public C fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf packetBuf,
InitialDataDeserializer<C, I> initialDataDeserializer) {
I host = getHostFromLocator(inv.player, ContainerLocator.read(packetBuf));
if (host != null) {
return factory.create(windowId, inv, host);
C container = factory.create(windowId, inv, host);
initialDataDeserializer.deserializeInitialData(host, container, packetBuf);
return container;
}
return null;
}
public boolean open(PlayerEntity player, ContainerLocator locator) {
return open(player, locator, (accessObj, buffer) -> {
});
}
public boolean open(PlayerEntity player, ContainerLocator locator, InitialDataSerializer<I> initialDataSerializer) {
if (!(player instanceof ServerPlayerEntity)) {
// Cannot open containers on the client or for non-players
// FIXME logging?
@@ -84,9 +114,9 @@ public final class ContainerHelper<C extends AEBaseContainer, I> {
return false;
}
Text title = findContainerTitle(player.world, locator, accessInterface);
Text title = containerTitleStrategy.apply(accessInterface);
player.openHandledScreen(new HandlerFactory(locator, title, accessInterface));
player.openHandledScreen(new HandlerFactory(locator, title, accessInterface, initialDataSerializer));
return true;
}
@@ -99,15 +129,20 @@ public final class ContainerHelper<C extends AEBaseContainer, I> {
private final Text title;
public HandlerFactory(ContainerLocator locator, Text title, I accessInterface) {
private final InitialDataSerializer<I> initialDataSerializer;
public HandlerFactory(ContainerLocator locator, Text title, I accessInterface,
InitialDataSerializer<I> initialDataSerializer) {
this.locator = locator;
this.title = title;
this.accessInterface = accessInterface;
this.initialDataSerializer = initialDataSerializer;
}
@Override
public void writeScreenOpeningData(ServerPlayerEntity player, PacketByteBuf buf) {
locator.write(buf);
initialDataSerializer.serializeInitialData(accessInterface, buf);
}
@Override
@@ -127,28 +162,6 @@ public final class ContainerHelper<C extends AEBaseContainer, I> {
}
private Text findContainerTitle(World world, ContainerLocator locator, I accessInterface) {
if (accessInterface instanceof ICustomNameObject) {
ICustomNameObject customNameObject = (ICustomNameObject) accessInterface;
if (customNameObject.hasCustomInventoryName()) {
return customNameObject.getCustomInventoryName();
}
}
// Use block name at position
// FIXME: this is not right, we'd need to check the part's item stack, or custom
// naming interface impl
// FIXME: Should move this up, because at this point, it's hard to know where
// the terminal host came from (part or tile)
if (locator.hasBlockPos()) {
return new TranslatableText(world.getBlockState(locator.getBlockPos()).getBlock().getTranslationKey());
}
return new LiteralText("Unknown");
}
private I getHostFromLocator(PlayerEntity player, ContainerLocator locator) {
if (locator.hasItemIndex()) {
return getHostFromPlayerInventory(player, locator);
@@ -225,6 +238,24 @@ public final class ContainerHelper<C extends AEBaseContainer, I> {
C create(int windowId, PlayerInventory playerInv, I accessObj);
}
/**
* Strategy used to serialize initial data for opening the container on the
* client-side into the packet that is sent to the client.
*/
@FunctionalInterface
public interface InitialDataSerializer<I> {
void serializeInitialData(I host, PacketByteBuf buffer);
}
/**
* Strategy used to deserialize initial data for opening the container on the
* client-side from the packet received by the server.
*/
@FunctionalInterface
public interface InitialDataDeserializer<C, I> {
void deserializeInitialData(I host, C container, PacketByteBuf buffer);
}
private boolean checkPermission(PlayerEntity player, Object accessInterface) {
if (requiredPermission != null) {
@@ -235,4 +266,15 @@ public final class ContainerHelper<C extends AEBaseContainer, I> {
}
private Text getDefaultContainerTitle(I accessInterface) {
if (accessInterface instanceof ICustomNameObject) {
ICustomNameObject customNameObject = (ICustomNameObject) accessInterface;
if (customNameObject.hasCustomInventoryName()) {
return customNameObject.getCustomInventoryName();
}
}
return LiteralText.EMPTY;
}
}
@@ -19,14 +19,8 @@
package appeng.container.implementations;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.Future;
import javax.annotation.Nullable;
import com.google.common.collect.ImmutableSet;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.network.PacketByteBuf;
@@ -66,9 +60,8 @@ import appeng.me.helpers.PlayerSource;
import appeng.parts.reporting.CraftingTerminalPart;
import appeng.parts.reporting.PatternTerminalPart;
import appeng.parts.reporting.TerminalPart;
import appeng.util.Platform;
public class CraftConfirmContainer extends AEBaseContainer {
public class CraftConfirmContainer extends AEBaseContainer implements CraftingCPUCyclingContainer {
public static ScreenHandlerType<CraftConfirmContainer> TYPE;
@@ -83,98 +76,51 @@ public class CraftConfirmContainer extends AEBaseContainer {
return helper.open(player, locator);
}
private final ArrayList<CraftingCPURecord> cpus = new ArrayList<>();
private final CraftingCPUCycler cpuCycler;
private ICraftingCPU selectedCpu;
private Future<ICraftingJob> job;
private ICraftingJob result;
@GuiSync(0)
public long bytesUsed;
@GuiSync(1)
public long cpuBytesAvail;
@GuiSync(2)
public int cpuCoProcessors;
@GuiSync(3)
public boolean autoStart = false;
@GuiSync(4)
public boolean simulation = true;
@GuiSync(5)
public int selectedCpu = -1;
// Indicates whether any CPUs are available
@GuiSync(6)
public boolean noCPU = true;
// Properties of the currently selected crafting CPU, this can be null
// if no CPUs are available, or if an automatic one is selected
@GuiSync(1)
public long cpuBytesAvail;
@GuiSync(2)
public int cpuCoProcessors;
@GuiSync(7)
public Text myName;
public Text cpuName;
public CraftConfirmContainer(int id, PlayerInventory ip, ITerminalHost te) {
super(TYPE, id, ip, te);
this.cpuCycler = new CraftingCPUCycler(this::cpuMatches, this::onCPUSelectionChanged);
// A player can select no crafting CPU to use a suitable one automatically
this.cpuCycler.setAllowNoSelection(true);
}
public void cycleCpu(final boolean next) {
if (next) {
this.setSelectedCpu(this.getSelectedCpu() + 1);
} else {
this.setSelectedCpu(this.getSelectedCpu() - 1);
}
if (this.getSelectedCpu() < -1) {
this.setSelectedCpu(this.cpus.size() - 1);
} else if (this.getSelectedCpu() >= this.cpus.size()) {
this.setSelectedCpu(-1);
}
if (this.getSelectedCpu() == -1) {
this.setCpuAvailableBytes(0);
this.setCpuCoProcessors(0);
this.setName(null);
} else {
CraftingCPURecord cpu = this.cpus.get(this.getSelectedCpu());
this.setName(cpu.getName());
this.setCpuAvailableBytes(cpu.getSize());
this.setCpuCoProcessors(cpu.getProcessors());
}
@Override
public void cycleSelectedCPU(final boolean next) {
this.cpuCycler.cycleCpu(next);
}
@Override
public void sendContentUpdates() {
if (Platform.isClient()) {
if (isClient()) {
return;
}
final ICraftingGrid cc = this.getGrid().getCache(ICraftingGrid.class);
final ImmutableSet<ICraftingCPU> cpuSet = cc.getCpus();
int matches = 0;
boolean changed = false;
for (final ICraftingCPU c : cpuSet) {
boolean found = false;
for (final CraftingCPURecord ccr : this.cpus) {
if (ccr.getCpu() == c) {
found = true;
break;
}
}
final boolean matched = this.cpuMatches(c);
if (matched) {
matches++;
}
if (found == !matched) {
changed = true;
}
}
if (changed || this.cpus.size() != matches) {
this.cpus.clear();
for (final ICraftingCPU c : cpuSet) {
if (this.cpuMatches(c)) {
this.cpus.add(new CraftingCPURecord(c.getAvailableStorage(), c.getCoProcessors(), c));
}
}
this.sendCPUs();
}
this.setNoCPU(this.cpus.isEmpty());
this.cpuCycler.detectAndSendChanges(this.getGrid());
super.sendContentUpdates();
@@ -277,22 +223,6 @@ public class CraftConfirmContainer extends AEBaseContainer {
return c.getAvailableStorage() >= this.getUsedBytes() && !c.isBusy();
}
private void sendCPUs() {
Collections.sort(this.cpus);
if (this.getSelectedCpu() >= this.cpus.size()) {
this.setSelectedCpu(-1);
this.setCpuAvailableBytes(0);
this.setCpuCoProcessors(0);
this.setName(null);
} else if (this.getSelectedCpu() != -1) {
CraftingCPURecord cpu = this.cpus.get(this.getSelectedCpu());
this.setName(cpu.getName());
this.setCpuAvailableBytes(cpu.getSize());
this.setCpuCoProcessors(cpu.getProcessors());
}
}
public void startJob() {
ScreenHandlerType<?> originalGui = null;
@@ -315,9 +245,7 @@ public class CraftConfirmContainer extends AEBaseContainer {
if (this.result != null && !this.isSimulation()) {
final ICraftingGrid cc = this.getGrid().getCache(ICraftingGrid.class);
final ICraftingLink g = cc.submitJob(this.result, null,
this.getSelectedCpu() == -1 ? null : this.cpus.get(this.getSelectedCpu()).getCpu(), true,
this.getActionSrc());
final ICraftingLink g = cc.submitJob(this.result, null, this.selectedCpu, true, this.getActionSrc());
this.setAutoStart(false);
if (g != null && originalGui != null && this.getLocator() != null) {
ContainerOpener.openContainer(originalGui, getPlayerInventory().player, getLocator());
@@ -347,6 +275,22 @@ public class CraftConfirmContainer extends AEBaseContainer {
}
}
private void onCPUSelectionChanged(CraftingCPURecord cpuRecord, boolean cpusAvailable) {
noCPU = !cpusAvailable;
if (cpuRecord == null) {
cpuBytesAvail = 0;
cpuCoProcessors = 0;
cpuName = null;
selectedCpu = null;
} else {
cpuBytesAvail = cpuRecord.getSize();
cpuCoProcessors = cpuRecord.getProcessors();
cpuName = cpuRecord.getName();
selectedCpu = cpuRecord.getCpu();
}
}
public World getWorld() {
return this.getPlayerInv().player.world;
}
@@ -371,42 +315,18 @@ public class CraftConfirmContainer extends AEBaseContainer {
return this.cpuBytesAvail;
}
private void setCpuAvailableBytes(final long cpuBytesAvail) {
this.cpuBytesAvail = cpuBytesAvail;
}
public int getCpuCoProcessors() {
return this.cpuCoProcessors;
}
private void setCpuCoProcessors(final int cpuCoProcessors) {
this.cpuCoProcessors = cpuCoProcessors;
}
public int getSelectedCpu() {
return this.selectedCpu;
}
private void setSelectedCpu(final int selectedCpu) {
this.selectedCpu = selectedCpu;
}
public Text getName() {
return this.myName;
}
private void setName(@Nullable final Text myName) {
this.myName = myName;
return this.cpuName;
}
public boolean hasNoCPU() {
return this.noCPU;
}
private void setNoCPU(final boolean noCPU) {
this.noCPU = noCPU;
}
public boolean isSimulation() {
return this.simulation;
}
@@ -26,7 +26,7 @@ import net.minecraft.network.PacketByteBuf;
import net.minecraft.screen.ScreenHandlerListener;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.text.LiteralText;
import appeng.api.config.SecurityPermissions;
import appeng.api.networking.IGrid;
@@ -46,24 +46,28 @@ import appeng.core.Api;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.ConfigValuePacket;
import appeng.core.sync.packets.MEInventoryUpdatePacket;
import appeng.helpers.ICustomNameObject;
import appeng.me.cluster.implementations.CraftingCPUCluster;
import appeng.tile.crafting.CraftingBlockEntity;
import appeng.util.Platform;
public class CraftingCPUContainer extends AEBaseContainer
implements IMEMonitorHandlerReceiver<IAEItemStack>, ICustomNameObject {
public class CraftingCPUContainer extends AEBaseContainer implements IMEMonitorHandlerReceiver<IAEItemStack> {
public static ScreenHandlerType<CraftingCPUContainer> TYPE;
private static final ContainerHelper<CraftingCPUContainer, CraftingBlockEntity> helper = new ContainerHelper<>(
CraftingCPUContainer::new, CraftingBlockEntity.class, SecurityPermissions.CRAFT);
CraftingCPUContainer::new, CraftingBlockEntity.class, SecurityPermissions.CRAFT)
.withContainerTitle(craftingTileEntity -> {
// Use the cluster's custom name instead of the right-clicked block entities one
CraftingCPUCluster cluster = craftingTileEntity.getCluster();
if (cluster != null && cluster.getName() != null) {
return cluster.getName();
}
return LiteralText.EMPTY;
});
private final IItemList<IAEItemStack> list = Api.instance().storage().getStorageChannel(IItemStorageChannel.class)
.createList();
private IGrid network;
private final IGrid network;
private CraftingCPUCluster monitor = null;
private Text cpuName = null;
@GuiSync(0)
public long eta = -1;
@@ -77,14 +81,16 @@ public class CraftingCPUContainer extends AEBaseContainer
final IActionHost host = (IActionHost) (te instanceof IActionHost ? te : null);
if (host != null && host.getActionableNode() != null) {
this.setNetwork(host.getActionableNode().getGrid());
this.network = host.getActionableNode().getGrid();
} else {
this.network = null;
}
if (te instanceof CraftingBlockEntity) {
this.setCPU(((CraftingBlockEntity) te).getCluster());
}
if (this.getNetwork() == null && Platform.isServer()) {
if (this.getNetwork() == null && isServer()) {
this.setValidContainer(false);
}
}
@@ -114,15 +120,13 @@ public class CraftingCPUContainer extends AEBaseContainer
}
if (c instanceof CraftingCPUCluster) {
this.cpuName = c.getName();
this.setMonitor((CraftingCPUCluster) c);
this.monitor = (CraftingCPUCluster) c;
this.list.resetStatus();
this.getMonitor().getListOfItem(this.list, CraftingItemList.ALL);
this.getMonitor().addListener(this, null);
this.setEstimatedTime(0);
} else {
this.setMonitor(null);
this.cpuName = null;
this.monitor = null;
this.setEstimatedTime(-1);
}
}
@@ -153,7 +157,7 @@ public class CraftingCPUContainer extends AEBaseContainer
@Override
public void sendContentUpdates() {
if (Platform.isServer() && this.getMonitor() != null && !this.list.isEmpty()) {
if (isServer() && this.getMonitor() != null && !this.list.isEmpty()) {
try {
if (this.getEstimatedTime() >= 0) {
final long elapsedTime = this.getMonitor().getElapsedTime();
@@ -218,16 +222,6 @@ public class CraftingCPUContainer extends AEBaseContainer
}
@Override
public Text getCustomInventoryName() {
return this.cpuName;
}
@Override
public boolean hasCustomInventoryName() {
return this.cpuName != null;
}
public long getEstimatedTime() {
return this.eta;
}
@@ -240,15 +234,8 @@ public class CraftingCPUContainer extends AEBaseContainer
return this.monitor;
}
private void setMonitor(final CraftingCPUCluster monitor) {
this.monitor = monitor;
}
IGrid getNetwork() {
return this.network;
}
private void setNetwork(final IGrid network) {
this.network = network;
}
}
@@ -0,0 +1,131 @@
package appeng.container.implementations;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import com.google.common.collect.ImmutableSet;
import net.minecraft.text.LiteralText;
import appeng.api.networking.IGrid;
import appeng.api.networking.crafting.ICraftingCPU;
import appeng.api.networking.crafting.ICraftingGrid;
/**
* Utility class for dialogs that can cycle through crafting CPUs
*/
class CraftingCPUCycler {
@FunctionalInterface
public interface ChangeListener {
void onChange(CraftingCPURecord selectedCpu, boolean cpusAvailable);
}
private final Predicate<ICraftingCPU> cpuFilter;
private final ChangeListener changeListener;
private final List<CraftingCPURecord> cpus = new ArrayList<>();
private int selectedCpu = -1;
private boolean initialDataSent = false;
private boolean allowNoSelection;
public CraftingCPUCycler(Predicate<ICraftingCPU> cpuFilter, ChangeListener changeListener) {
this.cpuFilter = cpuFilter;
this.changeListener = changeListener;
}
public void detectAndSendChanges(IGrid network) {
final ICraftingGrid cc = network.getCache(ICraftingGrid.class);
final ImmutableSet<ICraftingCPU> cpuSet = cc.getCpus();
int matches = 0;
boolean changed = !initialDataSent;
initialDataSent = true;
for (final ICraftingCPU c : cpuSet) {
boolean found = false;
for (final CraftingCPURecord ccr : this.cpus) {
if (ccr.getCpu() == c) {
found = true;
break;
}
}
final boolean matched = this.cpuFilter.test(c);
if (matched) {
matches++;
}
if (found == !matched) {
changed = true;
}
}
if (changed || this.cpus.size() != matches) {
this.cpus.clear();
for (final ICraftingCPU c : cpuSet) {
if (this.cpuFilter.test(c)) {
this.cpus.add(new CraftingCPURecord(c.getAvailableStorage(), c.getCoProcessors(), c));
}
}
// Sort and assign numeric IDs in case they have no names
Collections.sort(this.cpus);
for (int i = 0; i < this.cpus.size(); i++) {
CraftingCPURecord cpu = cpus.get(i);
if (cpu.getName() == null) {
cpu.setName(new LiteralText("#" + (i + 1)));
}
}
this.notifyListener();
}
}
public void cycleCpu(final boolean next) {
if (next) {
this.selectedCpu++;
} else {
this.selectedCpu--;
}
// If "no CPU" is a valid selection, then -1 is the first potential item
int lowerLimit = this.allowNoSelection ? -1 : 0;
if (this.selectedCpu < lowerLimit) {
this.selectedCpu = this.cpus.size() - 1;
} else if (this.selectedCpu >= this.cpus.size()) {
this.selectedCpu = lowerLimit;
}
this.notifyListener();
}
public boolean isAllowNoSelection() {
return allowNoSelection;
}
public void setAllowNoSelection(boolean allowNoSelection) {
this.allowNoSelection = allowNoSelection;
}
private void notifyListener() {
if (this.selectedCpu >= this.cpus.size()) {
this.selectedCpu = -1;
}
// Force the selected CPU to the first available CPU unless no-selection is
// explicitly allowed
if (!this.allowNoSelection && this.selectedCpu == -1 && !this.cpus.isEmpty()) {
this.selectedCpu = 0;
}
if (this.selectedCpu != -1) {
this.changeListener.onChange(this.cpus.get(this.selectedCpu), true);
} else {
this.changeListener.onChange(null, !this.cpus.isEmpty());
}
}
}
@@ -0,0 +1,12 @@
package appeng.container.implementations;
/**
* Implemented on screens that show information about a crafting CPU and allow
* the CPU to be cycled. Is triggered by receiving a config value packet with
* name <code>Terminal.Cpu</code>.
*/
public interface CraftingCPUCyclingContainer {
void cycleSelectedCPU(boolean forward);
}
@@ -25,16 +25,16 @@ import net.minecraft.text.Text;
import appeng.api.networking.crafting.ICraftingCPU;
public class CraftingCPURecord implements Comparable<CraftingCPURecord> {
private final Text myName;
private final ICraftingCPU cpu;
private final long size;
private final int processors;
private Text name;
public CraftingCPURecord(final long size, final int coProcessors, final ICraftingCPU server) {
this.size = size;
this.processors = coProcessors;
this.cpu = server;
this.myName = server.getName();
this.name = server.getName();
}
@Override
@@ -50,10 +50,6 @@ public class CraftingCPURecord implements Comparable<CraftingCPURecord> {
return this.cpu;
}
Text getName() {
return this.myName;
}
int getProcessors() {
return this.processors;
}
@@ -61,4 +57,13 @@ public class CraftingCPURecord implements Comparable<CraftingCPURecord> {
long getSize() {
return this.size;
}
public Text getName() {
return name;
}
public void setName(Text name) {
this.name = name;
}
}
@@ -18,12 +18,6 @@
package appeng.container.implementations;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.google.common.collect.ImmutableSet;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.network.PacketByteBuf;
@@ -31,14 +25,13 @@ import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.text.Text;
import appeng.api.config.SecurityPermissions;
import appeng.api.networking.IGrid;
import appeng.api.networking.crafting.ICraftingCPU;
import appeng.api.networking.crafting.ICraftingGrid;
import appeng.api.storage.ITerminalHost;
import appeng.container.ContainerLocator;
import appeng.container.guisync.GuiSync;
import appeng.util.Platform;
public class CraftingStatusContainer extends CraftingCPUContainer {
public class CraftingStatusContainer extends CraftingCPUContainer implements CraftingCPUCyclingContainer {
public static ScreenHandlerType<CraftingStatusContainer> TYPE;
@@ -53,13 +46,13 @@ public class CraftingStatusContainer extends CraftingCPUContainer {
return helper.open(player, locator);
}
private final List<CraftingCPURecord> cpus = new ArrayList<>();
@GuiSync(5)
public int selectedCpu = -1;
private final CraftingCPUCycler cpuCycler = new CraftingCPUCycler(this::cpuMatches, this::onCPUSelectionChanged);
@GuiSync(6)
public boolean noCPU = true;
@GuiSync(7)
public Text myName;
public Text cpuName;
public CraftingStatusContainer(int id, final PlayerInventory ip, final ITerminalHost te) {
super(TYPE, id, ip, te);
@@ -67,43 +60,9 @@ public class CraftingStatusContainer extends CraftingCPUContainer {
@Override
public void sendContentUpdates() {
if (Platform.isServer() && this.getNetwork() != null) {
final ICraftingGrid cc = this.getNetwork().getCache(ICraftingGrid.class);
final ImmutableSet<ICraftingCPU> cpuSet = cc.getCpus();
int matches = 0;
boolean changed = false;
for (final ICraftingCPU c : cpuSet) {
boolean found = false;
for (final CraftingCPURecord ccr : this.cpus) {
if (ccr.getCpu() == c) {
found = true;
}
}
final boolean matched = this.cpuMatches(c);
if (matched) {
matches++;
}
if (found == !matched) {
changed = true;
}
}
if (changed || this.cpus.size() != matches) {
this.cpus.clear();
for (final ICraftingCPU c : cpuSet) {
if (this.cpuMatches(c)) {
this.cpus.add(new CraftingCPURecord(c.getAvailableStorage(), c.getCoProcessors(), c));
}
}
this.sendCPUs();
}
this.noCPU = this.cpus.isEmpty();
IGrid network = this.getNetwork();
if (isServer() && network != null) {
cpuCycler.detectAndSendChanges(network);
}
super.sendContentUpdates();
@@ -113,52 +72,20 @@ public class CraftingStatusContainer extends CraftingCPUContainer {
return c.isBusy();
}
private void sendCPUs() {
Collections.sort(this.cpus);
if (this.selectedCpu >= this.cpus.size()) {
this.selectedCpu = -1;
this.myName = null;
} else if (this.selectedCpu != -1) {
this.myName = this.cpus.get(this.selectedCpu).getName();
}
if (this.selectedCpu == -1 && this.cpus.size() > 0) {
this.selectedCpu = 0;
}
if (this.selectedCpu != -1) {
if (this.cpus.get(this.selectedCpu).getCpu() != this.getMonitor()) {
this.setCPU(this.cpus.get(this.selectedCpu).getCpu());
}
private void onCPUSelectionChanged(CraftingCPURecord cpuRecord, boolean cpusAvailable) {
noCPU = !cpusAvailable;
if (cpuRecord == null) {
cpuName = null;
setCPU(null);
} else {
this.setCPU(null);
cpuName = cpuRecord.getName();
setCPU(cpuRecord.getCpu());
}
}
public void cycleCpu(final boolean next) {
if (next) {
this.selectedCpu++;
} else {
this.selectedCpu--;
}
if (this.selectedCpu < -1) {
this.selectedCpu = this.cpus.size() - 1;
} else if (this.selectedCpu >= this.cpus.size()) {
this.selectedCpu = -1;
}
if (this.selectedCpu == -1 && this.cpus.size() > 0) {
this.selectedCpu = 0;
}
if (this.selectedCpu == -1) {
this.myName = null;
this.setCPU(null);
} else {
this.myName = this.cpus.get(this.selectedCpu).getName();
this.setCPU(this.cpus.get(this.selectedCpu).getCpu());
}
@Override
public void cycleSelectedCPU(boolean forward) {
this.cpuCycler.cycleCpu(forward);
}
}
@@ -36,7 +36,6 @@ import appeng.container.slot.FakeTypeOnlySlot;
import appeng.container.slot.OptionalTypeOnlyFakeSlot;
import appeng.container.slot.RestrictedInputSlot;
import appeng.parts.automation.FormationPlanePart;
import appeng.util.Platform;
public class FormationPlaneContainer extends UpgradeableContainer {
@@ -108,7 +107,7 @@ public class FormationPlaneContainer extends UpgradeableContainer {
public void sendContentUpdates() {
this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) {
if (isServer()) {
this.setFuzzyMode((FuzzyMode) this.getUpgradeable().getConfigManager().getSetting(Settings.FUZZY_MODE));
this.setPlaceMode((YesNo) this.getUpgradeable().getConfigManager().getSetting(Settings.PLACE_BLOCK));
}
@@ -35,7 +35,6 @@ import appeng.container.guisync.GuiSync;
import appeng.container.slot.OutputSlot;
import appeng.container.slot.RestrictedInputSlot;
import appeng.tile.storage.IOPortBlockEntity;
import appeng.util.Platform;
public class IOPortContainer extends UpgradeableContainer {
@@ -112,7 +111,7 @@ public class IOPortContainer extends UpgradeableContainer {
public void sendContentUpdates() {
this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) {
if (isServer()) {
this.setOperationMode(
(OperationMode) this.getUpgradeable().getConfigManager().getSetting(Settings.OPERATION_MODE));
this.setFullMode(
@@ -36,7 +36,6 @@ import appeng.container.slot.RestrictedInputSlot;
import appeng.core.Api;
import appeng.tile.misc.InscriberBlockEntity;
import appeng.tile.misc.InscriberRecipes;
import appeng.util.Platform;
/**
* @author AlgorithmX2
@@ -120,7 +119,7 @@ public class InscriberContainer extends UpgradeableContainer implements IProgres
public void sendContentUpdates() {
this.standardDetectAndSendChanges();
if (Platform.isServer()) {
if (isServer()) {
this.maxProcessingTime = this.ti.getMaxProcessingTime();
this.processingTime = this.ti.getProcessingTime();
}
@@ -45,7 +45,7 @@ import appeng.api.networking.security.IActionHost;
import appeng.container.AEBaseContainer;
import appeng.container.ContainerLocator;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.CompressedNBTPacket;
import appeng.core.sync.packets.MEInterfaceUpdatePacket;
import appeng.helpers.DualityInterface;
import appeng.helpers.IInterfaceHost;
import appeng.helpers.InventoryAction;
@@ -55,7 +55,6 @@ import appeng.parts.reporting.InterfaceTerminalPart;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.tile.misc.InterfaceBlockEntity;
import appeng.util.InventoryAdaptor;
import appeng.util.Platform;
import appeng.util.helpers.ItemHandlerUtil;
import appeng.util.inv.AdaptorFixedInv;
import appeng.util.inv.WrapperCursorItemHandler;
@@ -88,7 +87,7 @@ public final class InterfaceTerminalContainer extends AEBaseContainer {
public InterfaceTerminalContainer(int id, final PlayerInventory ip, final InterfaceTerminalPart anchor) {
super(TYPE, id, ip, anchor);
if (Platform.isServer()) {
if (isServer()) {
this.grid = anchor.getActionableNode().getGrid();
}
@@ -97,7 +96,7 @@ public final class InterfaceTerminalContainer extends AEBaseContainer {
@Override
public void sendContentUpdates() {
if (Platform.isClient()) {
if (isClient()) {
return;
}
@@ -177,7 +176,7 @@ public final class InterfaceTerminalContainer extends AEBaseContainer {
if (!this.data.isEmpty()) {
try {
NetworkHandler.instance().sendTo(new CompressedNBTPacket(this.data),
NetworkHandler.instance().sendTo(new MEInterfaceUpdatePacket(this.data),
(ServerPlayerEntity) this.getPlayerInv().player);
} catch (final IOException e) {
// :P
@@ -18,8 +18,6 @@
package appeng.container.implementations;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.network.PacketByteBuf;
@@ -33,13 +31,13 @@ import appeng.api.config.RedstoneMode;
import appeng.api.config.SecurityPermissions;
import appeng.api.config.Settings;
import appeng.api.config.YesNo;
import appeng.client.gui.implementations.NumberEntryWidget;
import appeng.container.ContainerLocator;
import appeng.container.guisync.GuiSync;
import appeng.container.slot.FakeTypeOnlySlot;
import appeng.container.slot.RestrictedInputSlot;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.ConfigValuePacket;
import appeng.parts.automation.LevelEmitterPart;
import appeng.util.Platform;
public class LevelEmitterContainer extends UpgradeableContainer {
@@ -49,38 +47,46 @@ public class LevelEmitterContainer extends UpgradeableContainer {
LevelEmitterContainer::new, LevelEmitterPart.class, SecurityPermissions.BUILD);
public static LevelEmitterContainer fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf buf) {
return helper.fromNetwork(windowId, inv, buf);
return helper.fromNetwork(windowId, inv, buf, (host, container, buffer) -> {
container.reportingValue = buffer.readVarLong();
});
}
public static boolean open(PlayerEntity player, ContainerLocator locator) {
return helper.open(player, locator);
return helper.open(player, locator, (host, buffer) -> {
buffer.writeVarLong(host.getReportingValue());
});
}
private final LevelEmitterPart lvlEmitter;
@Environment(EnvType.CLIENT)
private NumberEntryWidget textField;
@GuiSync(2)
public LevelType lvType;
@GuiSync(3)
public long EmitterValue = -1;
@GuiSync(4)
public YesNo cmType;
// Only synced once on container-open, and only used on client
private long reportingValue;
public LevelEmitterContainer(int id, final PlayerInventory ip, final LevelEmitterPart te) {
super(TYPE, id, ip, te);
this.lvlEmitter = te;
}
@Environment(EnvType.CLIENT)
public void setTextField(final NumberEntryWidget level) {
this.textField = level;
this.textField.setValue(this.EmitterValue);
public long getReportingValue() {
return reportingValue;
}
public void setLevel(final long l, final PlayerEntity player) {
this.lvlEmitter.setReportingValue(l);
this.EmitterValue = l;
public void setReportingValue(long reportingValue) {
if (isClient()) {
if (reportingValue != this.reportingValue) {
this.reportingValue = reportingValue;
NetworkHandler.instance()
.sendToServer(new ConfigValuePacket("LevelEmitter.Value", String.valueOf(reportingValue)));
}
} else {
this.lvlEmitter.setReportingValue(reportingValue);
}
}
@Override
@@ -116,7 +122,6 @@ public class LevelEmitterContainer extends UpgradeableContainer {
@Override
public int availableUpgrades() {
return 1;
}
@@ -124,8 +129,7 @@ public class LevelEmitterContainer extends UpgradeableContainer {
public void sendContentUpdates() {
this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) {
this.EmitterValue = this.lvlEmitter.getReportingValue();
if (isServer()) {
this.setCraftingMode(
(YesNo) this.getUpgradeable().getConfigManager().getSetting(Settings.CRAFT_VIA_REDSTONE));
this.setLevelMode((LevelType) this.getUpgradeable().getConfigManager().getSetting(Settings.LEVEL_TYPE));
@@ -137,15 +141,6 @@ public class LevelEmitterContainer extends UpgradeableContainer {
this.standardDetectAndSendChanges();
}
@Override
public void onUpdate(final String field, final Object oldValue, final Object newValue) {
if (field.equals("EmitterValue")) {
if (this.textField != null) {
this.textField.setValue(this.EmitterValue);
}
}
}
@Override
public YesNo getCraftingMode() {
return this.cmType;
@@ -163,4 +158,5 @@ public class LevelEmitterContainer extends UpgradeableContainer {
private void setLevelMode(final LevelType lvType) {
this.lvType = lvType;
}
}
@@ -46,6 +46,8 @@ import appeng.api.implementations.tiles.IViewCellStorage;
import appeng.api.networking.IGrid;
import appeng.api.networking.IGridHost;
import appeng.api.networking.IGridNode;
import appeng.api.networking.crafting.ICraftingCPU;
import appeng.api.networking.crafting.ICraftingGrid;
import appeng.api.networking.energy.IEnergyGrid;
import appeng.api.networking.energy.IEnergySource;
import appeng.api.networking.security.IActionHost;
@@ -73,7 +75,6 @@ import appeng.core.sync.packets.MEInventoryUpdatePacket;
import appeng.me.helpers.ChannelPowerSrc;
import appeng.util.ConfigManager;
import appeng.util.IConfigManagerHost;
import appeng.util.Platform;
public class MEMonitorableContainer extends AEBaseContainer
implements IConfigManagerHost, IConfigurableObject, IMEMonitorHandlerReceiver<IAEItemStack> {
@@ -101,6 +102,13 @@ public class MEMonitorableContainer extends AEBaseContainer
public boolean canAccessViewCells = false;
@GuiSync(98)
public boolean hasPower = false;
/**
* The number of active crafting jobs in the network. -1 means unknown and will
* hide the label on the screen.
*/
@GuiSync(100)
public int activeCraftingJobs = -1;
private IConfigManagerHost gui;
private IConfigManager serverCM;
private IGridNode networkNode;
@@ -122,7 +130,7 @@ public class MEMonitorableContainer extends AEBaseContainer
this.clientCM.registerSetting(Settings.VIEW_MODE, ViewItems.ALL);
this.clientCM.registerSetting(Settings.SORT_DIRECTION, SortDir.ASCENDING);
if (Platform.isServer()) {
if (isServer()) {
this.serverCM = monitorable.getConfigManager();
this.monitor = monitorable
@@ -183,12 +191,14 @@ public class MEMonitorableContainer extends AEBaseContainer
@Override
public void sendContentUpdates() {
if (Platform.isServer()) {
if (isServer()) {
if (this.monitor != this.host
.getInventory(Api.instance().storage().getStorageChannel(IItemStorageChannel.class))) {
this.setValidContainer(false);
}
this.updateActiveCraftingJobs();
for (final Settings set : this.serverCM.getSettings()) {
final Enum<?> sideLocal = this.serverCM.getSetting(set);
final Enum<?> sideRemote = this.clientCM.getSetting(set);
@@ -286,8 +296,38 @@ public class MEMonitorableContainer extends AEBaseContainer
this.queueInventory(c);
}
private void updateActiveCraftingJobs() {
IGridNode hostNode = networkNode;
if (hostNode == null) {
// Wireless terminals do not directly expose the target grid (even though they
// have one)
if (host instanceof IActionHost) {
hostNode = ((IActionHost) host).getActionableNode();
}
}
IGrid grid = null;
if (hostNode != null) {
grid = hostNode.getGrid();
}
if (grid == null) {
// No grid to query crafting jobs from
this.activeCraftingJobs = -1;
return;
}
int activeJobs = 0;
ICraftingGrid craftingGrid = grid.getCache(ICraftingGrid.class);
for (ICraftingCPU cpus : craftingGrid.getCpus()) {
if (cpus.isBusy()) {
activeJobs++;
}
}
this.activeCraftingJobs = activeJobs;
}
private void queueInventory(final ScreenHandlerListener c) {
if (Platform.isServer() && c instanceof PlayerEntity && this.monitor != null) {
if (isServer() && c instanceof PlayerEntity && this.monitor != null) {
try {
MEInventoryUpdatePacket piu = new MEInventoryUpdatePacket();
final IItemList<IAEItemStack> monitorCache = this.monitor.getStorageList();
@@ -356,7 +396,7 @@ public class MEMonitorableContainer extends AEBaseContainer
@Override
public IConfigManager getConfigManager() {
if (Platform.isServer()) {
if (isServer()) {
return this.serverCM;
}
return this.clientCM;
@@ -42,7 +42,6 @@ import appeng.container.slot.RestrictedInputSlot;
import appeng.core.Api;
import appeng.items.misc.EncodedPatternItem;
import appeng.tile.crafting.MolecularAssemblerBlockEntity;
import appeng.util.Platform;
public class MolecularAssemblerContainer extends UpgradeableContainer implements IProgressProvider {
@@ -148,7 +147,7 @@ public class MolecularAssemblerContainer extends UpgradeableContainer implements
public void sendContentUpdates() {
this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) {
if (isServer()) {
this.setRedStoneMode(
(RedstoneMode) this.getUpgradeable().getConfigManager().getSetting(Settings.REDSTONE_CONTROLLED));
}
@@ -43,7 +43,6 @@ import appeng.container.guisync.GuiSync;
import appeng.core.Api;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.MEInventoryUpdatePacket;
import appeng.util.Platform;
import appeng.util.item.AEItemStack;
public class NetworkStatusContainer extends AEBaseContainer {
@@ -83,7 +82,7 @@ public class NetworkStatusContainer extends AEBaseContainer {
}
}
if (this.network == null && Platform.isServer()) {
if (this.network == null && isServer()) {
this.setValidContainer(false);
}
}
@@ -100,7 +99,7 @@ public class NetworkStatusContainer extends AEBaseContainer {
@Override
public void sendContentUpdates() {
this.delay++;
if (Platform.isServer() && this.delay > 15 && this.network != null) {
if (isServer() && this.delay > 15 && this.network != null) {
this.delay = 0;
final IEnergyGrid eg = this.network.getCache(IEnergyGrid.class);
@@ -297,9 +297,9 @@ public class PatternTermContainer extends MEMonitorableContainer
@Override
public boolean isSlotEnabled(final int idx) {
if (idx == 1) {
return Platform.isServer() ? !this.getPatternTerminal().isCraftingRecipe() : !this.isCraftingMode();
return isServer() ? !this.getPatternTerminal().isCraftingRecipe() : !this.isCraftingMode();
} else if (idx == 2) {
return Platform.isServer() ? this.getPatternTerminal().isCraftingRecipe() : this.isCraftingMode();
return isServer() ? this.getPatternTerminal().isCraftingRecipe() : this.isCraftingMode();
} else {
return false;
}
@@ -401,7 +401,7 @@ public class PatternTermContainer extends MEMonitorableContainer
@Override
public void sendContentUpdates() {
super.sendContentUpdates();
if (Platform.isServer()) {
if (isServer()) {
if (this.isCraftingMode() != this.getPatternTerminal().isCraftingRecipe()) {
this.setCraftingMode(this.getPatternTerminal().isCraftingRecipe());
this.updateOrderOfOutputSlots();
@@ -423,7 +423,7 @@ public class PatternTermContainer extends MEMonitorableContainer
@Override
public void onSlotChange(final Slot s) {
if (s == this.patternSlotOUT && Platform.isServer()) {
if (s == this.patternSlotOUT && isServer()) {
for (final ScreenHandlerListener listener : this.getListeners()) {
for (int i = 0; i < this.slots.size(); i++) {
Slot slot = this.slots.get(i);
@@ -438,7 +438,7 @@ public class PatternTermContainer extends MEMonitorableContainer
this.sendContentUpdates();
}
if (s == this.craftSlot && Platform.isClient()) {
if (s == this.craftSlot && isClient()) {
this.getAndUpdateOutput();
}
}
@@ -18,8 +18,6 @@
package appeng.container.implementations;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
@@ -28,12 +26,11 @@ import net.minecraft.screen.ScreenHandlerType;
import appeng.api.config.SecurityPermissions;
import appeng.api.parts.IPart;
import appeng.client.gui.implementations.NumberEntryWidget;
import appeng.container.AEBaseContainer;
import appeng.container.ContainerLocator;
import appeng.container.guisync.GuiSync;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.ConfigValuePacket;
import appeng.helpers.IPriorityHost;
import appeng.util.Platform;
public class PriorityContainer extends AEBaseContainer {
@@ -43,59 +40,53 @@ public class PriorityContainer extends AEBaseContainer {
PriorityContainer::new, IPriorityHost.class, SecurityPermissions.BUILD);
public static PriorityContainer fromNetwork(int windowId, PlayerInventory inv, PacketByteBuf buf) {
return helper.fromNetwork(windowId, inv, buf);
return helper.fromNetwork(windowId, inv, buf, (host, container, buffer) -> {
container.priorityValue = buffer.readVarInt();
});
}
public static boolean open(PlayerEntity player, ContainerLocator locator) {
return helper.open(player, locator);
return helper.open(player, locator, (host, buffer) -> buffer.writeVarInt(host.getPriority()));
}
private final IPriorityHost priHost;
@Environment(EnvType.CLIENT)
private NumberEntryWidget textField;
@GuiSync(2)
public long PriorityValue = -1;
private int priorityValue;
public PriorityContainer(int id, final PlayerInventory ip, final IPriorityHost te) {
super(TYPE, id, ip, (BlockEntity) (te instanceof BlockEntity ? te : null),
(IPart) (te instanceof IPart ? te : null));
this.priHost = te;
this.priorityValue = te.getPriority();
}
@Environment(EnvType.CLIENT)
public void setTextField(final NumberEntryWidget level) {
this.textField = level;
this.textField.setValue(this.PriorityValue, true);
}
public void setPriority(final int newValue, final PlayerEntity player) {
this.priHost.setPriority(newValue);
this.PriorityValue = newValue;
public void setPriority(final int newValue) {
if (newValue != priorityValue) {
if (isClient()) {
// If for whatever reason the client enters the value first, do not update based
// on incoming server data
this.priorityValue = newValue;
NetworkHandler.instance()
.sendToServer(new ConfigValuePacket("PriorityHost.Priority", String.valueOf(newValue)));
} else {
this.priHost.setPriority(newValue);
this.priorityValue = newValue;
}
}
}
@Override
public void sendContentUpdates() {
super.sendContentUpdates();
this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) {
this.PriorityValue = this.priHost.getPriority();
}
}
@Override
public void onUpdate(final String field, final Object oldValue, final Object newValue) {
if (field.equals("PriorityValue")) {
if (this.textField != null) {
this.textField.setValue(this.PriorityValue, true);
}
}
super.onUpdate(field, oldValue, newValue);
public int getPriorityValue() {
return priorityValue;
}
public IPriorityHost getPriorityHost() {
return this.priHost;
}
}
@@ -37,7 +37,6 @@ import appeng.core.Api;
import appeng.items.contents.QuartzKnifeObj;
import appeng.items.materials.MaterialItem;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.util.Platform;
public class QuartzKnifeContainer extends AEBaseContainer {
@@ -142,10 +141,12 @@ public class QuartzKnifeContainer extends AEBaseContainer {
}
private void makePlate() {
if (Platform.isServer()) {
if (!this.takeStack(1).isEmpty()) {
if (isServer()) {
if (!inSlot.getSlot(0).extract(1).isEmpty()) {
final ItemStack item = QuartzKnifeContainer.this.toolInv.getItemStack();
final ItemStack before = item.copy();
// FIXME FABRIC: Quartz Knife currently is not damageable due to recipe
// remainder concerns
item.damage(1, QuartzKnifeContainer.this.getPlayerInv().player, p -> {
QuartzKnifeContainer.this.getPlayerInv()
.setStack(QuartzKnifeContainer.this.getPlayerInv().selectedSlot, ItemStack.EMPTY);
@@ -35,7 +35,6 @@ import appeng.container.guisync.GuiSync;
import appeng.container.slot.OutputSlot;
import appeng.container.slot.RestrictedInputSlot;
import appeng.tile.spatial.SpatialIOPortBlockEntity;
import appeng.util.Platform;
public class SpatialIOPortContainer extends AEBaseContainer {
@@ -65,7 +64,7 @@ public class SpatialIOPortContainer extends AEBaseContainer {
public SpatialIOPortContainer(int id, final PlayerInventory ip, final SpatialIOPortBlockEntity spatialIOPort) {
super(TYPE, id, ip, spatialIOPort, null);
if (Platform.isServer()) {
if (isServer()) {
this.network = spatialIOPort.getGridNode(AEPartLocation.INTERNAL).getGrid();
}
@@ -89,7 +88,7 @@ public class SpatialIOPortContainer extends AEBaseContainer {
public void sendContentUpdates() {
this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) {
if (isServer()) {
this.delay++;
if (this.delay > 15 && this.network != null) {
this.delay = 0;
@@ -45,7 +45,6 @@ import appeng.container.slot.OptionalTypeOnlyFakeSlot;
import appeng.container.slot.RestrictedInputSlot;
import appeng.core.Api;
import appeng.parts.misc.StorageBusPart;
import appeng.util.Platform;
import appeng.util.helpers.ItemHandlerUtil;
import appeng.util.iterators.NullIterator;
@@ -125,7 +124,7 @@ public class StorageBusContainer extends UpgradeableContainer {
public void sendContentUpdates() {
this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) {
if (isServer()) {
this.setFuzzyMode((FuzzyMode) this.getUpgradeable().getConfigManager().getSetting(Settings.FUZZY_MODE));
this.setReadWriteMode(
(AccessRestriction) this.getUpgradeable().getConfigManager().getSetting(Settings.ACCESS));
@@ -52,7 +52,6 @@ import appeng.container.slot.RestrictedInputSlot;
import appeng.items.contents.NetworkToolViewer;
import appeng.items.tools.NetworkToolItem;
import appeng.parts.automation.ExportBusPart;
import appeng.util.Platform;
public class UpgradeableContainer extends AEBaseContainer implements IOptionalSlotHost {
@@ -200,7 +199,7 @@ public class UpgradeableContainer extends AEBaseContainer implements IOptionalSl
public void sendContentUpdates() {
this.verifyPermissions(SecurityPermissions.BUILD, false);
if (Platform.isServer()) {
if (isServer()) {
final IConfigManager cm = this.getUpgradeable().getConfigManager();
this.loadSettingsFromHost(cm);
}
@@ -29,7 +29,6 @@ import appeng.container.guisync.GuiSync;
import appeng.container.interfaces.IProgressProvider;
import appeng.container.slot.RestrictedInputSlot;
import appeng.tile.misc.VibrationChamberBlockEntity;
import appeng.util.Platform;
public class VibrationChamberContainer extends AEBaseContainer implements IProgressProvider {
@@ -65,7 +64,7 @@ public class VibrationChamberContainer extends AEBaseContainer implements IProgr
@Override
public void sendContentUpdates() {
if (Platform.isServer()) {
if (isServer()) {
this.remainingBurnTime = this.vibrationChamber.getMaxBurnTime() <= 0 ? 0
: (int) (100.0 * this.vibrationChamber.getBurnTime() / this.vibrationChamber.getMaxBurnTime());
this.burnSpeed = this.remainingBurnTime <= 0 ? 0 : this.vibrationChamber.getBurnSpeed();
@@ -28,7 +28,6 @@ import appeng.container.ContainerLocator;
import appeng.core.AEConfig;
import appeng.core.localization.PlayerMessages;
import appeng.helpers.WirelessTerminalGuiObject;
import appeng.util.Platform;
public class WirelessTermContainer extends MEPortableCellContainer {
@@ -57,7 +56,7 @@ public class WirelessTermContainer extends MEPortableCellContainer {
super.sendContentUpdates();
if (!this.wirelessTerminalGUIObject.rangeCheck()) {
if (Platform.isServer() && this.isValidContainer()) {
if (isServer() && this.isValidContainer()) {
this.getPlayerInv().player.sendSystemMessage(PlayerMessages.OutOfRange.get(), Util.NIL_UUID);
}
+45 -12
View File
@@ -25,14 +25,14 @@ import java.util.Collection;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.DoubleSupplier;
import java.util.stream.Collectors;
import net.minecraft.world.dimension.DimensionType;
import javax.annotation.Nullable;
import com.google.common.base.Strings;
import appeng.api.config.CondenserOutput;
import appeng.api.config.PowerMultiplier;
@@ -50,6 +50,7 @@ import appeng.core.config.DoubleOption;
import appeng.core.config.EnumOption;
import appeng.core.config.IntegerOption;
import appeng.core.config.StringListOption;
import appeng.core.config.StringOption;
import appeng.core.settings.TickRates;
import appeng.util.EnumCycler;
@@ -81,6 +82,13 @@ public final class AEConfig {
result.save(); // Save a default file
} else {
result.load();
// Re-save immediately to write-out new defaults
try {
result.save();
} catch (Exception e) {
AELog.warn(e);
}
}
return result;
}
@@ -137,7 +145,6 @@ public final class AEConfig {
// Meteors
private int meteoriteMaximumSpawnHeight;
private Set<String> meteoriteDimensionWhitelist;
// Wireless
private double wirelessBaseCost;
@@ -175,7 +182,6 @@ public final class AEConfig {
this.oreDoublePercentage = (float) commonConfig.oreDoublePercentage.get();
this.meteoriteMaximumSpawnHeight = commonConfig.meteoriteMaximumSpawnHeight.get();
this.meteoriteDimensionWhitelist = new HashSet<>(commonConfig.meteoriteDimensionWhitelist.get());
this.wirelessBaseCost = commonConfig.wirelessBaseCost.get();
this.wirelessCostMultiplier = commonConfig.wirelessCostMultiplier.get();
@@ -389,8 +395,21 @@ public final class AEConfig {
return this.meteoriteMaximumSpawnHeight;
}
public Set<String> getMeteoriteDimensionWhitelist() {
return this.meteoriteDimensionWhitelist;
public List<String> getMeteoriteBiomeBlacklist() {
return commonConfig.meteoriteBiomeBlacklist.get();
}
public List<String> getQuartzOreBiomeBlacklist() {
return commonConfig.quartzOreBiomeBlacklist.get();
}
@Nullable
public String getImprovedFluidTag() {
return Strings.emptyToNull(commonConfig.improvedFluidTag.get());
}
public float getImprovedFluidMultiplier() {
return (float) commonConfig.improvedFluidMultiplier.get();
}
// Setters keep visibility as low as possible.
@@ -478,10 +497,11 @@ public final class AEConfig {
public final DoubleOption spawnChargedChance;
public final IntegerOption quartzOresPerCluster;
public final IntegerOption quartzOresClusterAmount;
public final StringListOption quartzOreBiomeBlacklist;
// Meteors
public final IntegerOption meteoriteMaximumSpawnHeight;
public final StringListOption meteoriteDimensionWhitelist;
public final StringListOption meteoriteBiomeBlacklist;
// Wireless
public final DoubleOption wirelessBaseCost;
@@ -504,6 +524,11 @@ public final class AEConfig {
public final IntegerOption condenserMatterBallsPower;
public final IntegerOption condenserSingularityPower;
// In-World Purification
// Settings for improved speed depending on fluid the crystal is in
public final StringOption improvedFluidTag;
public final DoubleOption improvedFluidMultiplier;
public final Map<TickRates, IntegerOption> tickRateMin = new HashMap<>();
public final Map<TickRates, IntegerOption> tickRateMax = new HashMap<>();
@@ -562,13 +587,13 @@ public final class AEConfig {
this.spawnChargedChance = worldGen.addDouble("spawnChargedChance", 0.08, 0.0, 1.0);
this.meteoriteMaximumSpawnHeight = worldGen.addInt("meteoriteMaximumSpawnHeight", 180);
List<String> defaultDimensionWhitelist = new ArrayList<>();
defaultDimensionWhitelist.add(DimensionType.OVERWORLD_REGISTRY_KEY.getValue().toString());
this.meteoriteDimensionWhitelist = worldGen.addStringList("meteoriteDimensionWhitelist",
defaultDimensionWhitelist);
this.meteoriteBiomeBlacklist = worldGen.addStringList("meteoriteBiomeBlacklist", new ArrayList<>(),
"Biome IDs in which meteorites should NOT be generated (i.e. minecraft:plains).");
this.quartzOresPerCluster = worldGen.addInt("quartzOresPerCluster", 4);
this.quartzOresClusterAmount = worldGen.addInt("quartzOresClusterAmount", 20);
this.quartzOreBiomeBlacklist = worldGen.addStringList("quartzOreBiomeBlacklist", new ArrayList<>(),
"Biome IDs in which quartz ores should NOT be generated (i.e. minecraft:plains).");
ConfigSection wireless = root.subsection("wireless");
this.wirelessBaseCost = wireless.addDouble("wirelessBaseCost", 8.0);
@@ -598,6 +623,14 @@ public final class AEConfig {
tickRateMin.put(tickRate, tickrates.addInt(tickRate.name() + "Min", tickRate.getDefaultMin()));
tickRateMax.put(tickRate, tickrates.addInt(tickRate.name() + "Max", tickRate.getDefaultMax()));
}
ConfigSection inWorldPurification = root.subsection("inWorldPurification",
"Settings for in-world purification of crystals.");
improvedFluidTag = inWorldPurification.addString("improvedFluidTag", "",
"A fluid tag that identifies fluids that improve crystal purification speed. Does not affect purification with water/lava.");
improvedFluidMultiplier = inWorldPurification.addDouble("improvedFluidMultiplier", 2.0, 1.0, 10.0,
"The speed multiplier to use when the crystals are submerged in the improved fluid.");
}
}
-24
View File
@@ -30,14 +30,8 @@ import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.World;
import net.minecraft.world.dimension.DimensionType;
import team.reborn.energy.Energy;
import team.reborn.energy.EnergyHandler;
import team.reborn.energy.EnergyHolder;
import appeng.api.config.Upgrades;
import appeng.api.definitions.IBlocks;
@@ -45,8 +39,6 @@ import appeng.api.definitions.IItems;
import appeng.api.definitions.IParts;
import appeng.api.features.IRegistryContainer;
import appeng.api.features.IWirelessTermHandler;
import appeng.api.features.IWorldGen;
import appeng.api.implementations.items.IAEItemPowerStorage;
import appeng.api.movable.IMovableRegistry;
import appeng.api.networking.IGridCacheRegistry;
import appeng.api.networking.crafting.ICraftingGrid;
@@ -57,7 +49,6 @@ import appeng.api.networking.spatial.ISpatialCache;
import appeng.api.networking.storage.IStorageGrid;
import appeng.api.networking.ticking.ITickManager;
import appeng.api.parts.CableRenderMode;
import appeng.block.AEBaseBlockItemChargeable;
import appeng.bootstrap.IBootstrapComponent;
import appeng.bootstrap.components.ITileEntityRegistrationComponent;
import appeng.client.render.effects.ParticleTypes;
@@ -351,21 +342,6 @@ public abstract class AppEngBase implements AppEng {
*/
mr.whiteListBlockEntity(AEBaseBlockEntity.class);
/*
* world gen
*/
for (final IWorldGen.WorldGenType type : IWorldGen.WorldGenType.values()) {
// FIXME: registries.worldgen().disableWorldGenForProviderID( type,
// StorageWorldProvider.class );
registries.worldgen().disableWorldGenForDimension(type, DimensionType.THE_NETHER_REGISTRY_KEY.getValue());
}
// whitelist from config
for (final String dimension : AEConfig.instance().getMeteoriteDimensionWhitelist()) {
registries.worldgen().enableWorldGenForDimension(IWorldGen.WorldGenType.METEORITES,
new Identifier(dimension));
}
}
protected void registerParticleTypes() {
+43 -9
View File
@@ -1,9 +1,16 @@
package appeng.core;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.block.BlockState;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.decorator.Decorator;
@@ -54,11 +61,21 @@ public final class AppEngBootstrap {
ConfiguredFeature<?, ?> quartzOreFeature = registerQuartzOreFeature();
ConfiguredFeature<?, ?> chargedQuartzOreFeature = registerChargedQuartzOreFeature();
// add to all standard biomes
// TODO: This means we'll not add these things to newly created biomes
BuiltinRegistries.BIOME.forEach(b -> {
addMeteoriteWorldGen(b);
addQuartzWorldGen(b, quartzOreFeature, chargedQuartzOreFeature);
Set<String> meteoriteBiomeBlacklist = new HashSet<>(AEConfig.instance().getMeteoriteBiomeBlacklist());
Set<String> quartzOreBiomeBlacklist = new HashSet<>(AEConfig.instance().getQuartzOreBiomeBlacklist());
// Add features to all existing biomes
for (Map.Entry<RegistryKey<Biome>, Biome> entry : BuiltinRegistries.BIOME.getEntries()) {
Identifier id = entry.getKey().getValue();
Biome b = entry.getValue();
addMeteoriteWorldGen(id, b, meteoriteBiomeBlacklist);
addQuartzWorldGen(id, b, quartzOreFeature, chargedQuartzOreFeature, quartzOreBiomeBlacklist);
}
// Listen to added biomes for post-processing
RegistryEntryAddedCallback.event(BuiltinRegistries.BIOME).register((i, id, biome) -> {
addMeteoriteWorldGen(id, biome, meteoriteBiomeBlacklist);
addQuartzWorldGen(id, biome, quartzOreFeature, chargedQuartzOreFeature, quartzOreBiomeBlacklist);
});
registerDimension();
@@ -78,12 +95,19 @@ public final class AppEngBootstrap {
MeteoriteStructure.CONFIGURED_INSTANCE);
}
private static void addMeteoriteWorldGen(Biome b) {
private static void addMeteoriteWorldGen(Identifier id, Biome b, Set<String> biomeBlacklist) {
if (!AEConfig.instance().isFeatureEnabled(AEFeature.METEORITE_WORLD_GEN)) {
AELog.debug("Not generating meteorites in %s because the feature is disabled", id);
return;
}
if (b.getCategory() == Biome.Category.THEEND || b.getCategory() == Biome.Category.NETHER) {
AELog.debug("Not generating meteorites in %s because it's of category %s", id, b.getCategory());
return;
}
if (biomeBlacklist.contains(id.toString())) {
AELog.debug("Not generating meteorites in %s because the biome is blacklisted in the config", id);
return;
}
@@ -91,14 +115,24 @@ public final class AppEngBootstrap {
modifier.addStructureFeature(MeteoriteStructure.CONFIGURED_INSTANCE);
}
private static void addQuartzWorldGen(Biome b, ConfiguredFeature<?, ?> quartzOre,
ConfiguredFeature<?, ?> chargedQuartz) {
private static void addQuartzWorldGen(Identifier id, Biome b, ConfiguredFeature<?, ?> quartzOre,
ConfiguredFeature<?, ?> chargedQuartz, Set<String> biomeBlacklist) {
if (!AEConfig.instance().isFeatureEnabled(AEFeature.CERTUS_QUARTZ_WORLD_GEN)) {
AELog.debug("Not generating quartz-ore in %s because the feature is disabled", id);
return;
}
if (b.getCategory() == Biome.Category.THEEND || b.getCategory() == Biome.Category.NETHER) {
AELog.debug("Not generating quartz ore in %s because it's of category %s", id, b.getCategory());
return;
}
if (biomeBlacklist.contains(id.toString())) {
AELog.debug("Not generating quartz-ore in %s because the biome is blacklisted in the config", id);
return;
}
BiomeModifier modifier = new BiomeModifier(b);
modifier.addFeature(GenerationStep.Feature.UNDERGROUND_ORES, quartzOre);
if (AEConfig.instance().isFeatureEnabled(AEFeature.CHARGED_CERTUS_ORE)) {
@@ -30,6 +30,7 @@ import net.minecraft.block.Material;
import net.minecraft.block.SlabBlock;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.SpawnGroup;
import net.minecraft.sound.BlockSoundGroup;
@@ -267,17 +268,19 @@ public final class ApiBlocks implements IBlocks {
this.chiseledQuartzBlock = deco.block("chiseled_quartz_block", () -> new AEDecorativeBlock(QUARTZ_PROPERTIES))
.build();
this.quartzGlass = registry.features(AEFeature.QUARTZ_GLASS)
.block("quartz_glass", () -> new QuartzGlassBlock(glassProps()))
.rendering(new BlockRenderingCustomizer() {
@Override
@Environment(EnvType.CLIENT)
public void customize(IBlockRendering rendering, IItemRendering itemRendering) {
rendering.renderType(RenderLayer.getCutout());
}
}).build();
AbstractBlock.TypedContextPredicate<EntityType<?>> neverAllowSpawn = (p1, p2, p3, p4) -> false;
this.quartzGlass = registry.features(AEFeature.QUARTZ_GLASS).block("quartz_glass", () -> {
return new QuartzGlassBlock(glassProps().allowsSpawning(neverAllowSpawn));
}).rendering(new BlockRenderingCustomizer() {
@Override
@Environment(EnvType.CLIENT)
public void customize(IBlockRendering rendering, IItemRendering itemRendering) {
rendering.renderType(RenderLayer.getCutout());
}
}).build();
this.quartzVibrantGlass = deco
.block("quartz_vibrant_glass", () -> new QuartzLampBlock(glassProps().lightLevel(15)))
.block("quartz_vibrant_glass",
() -> new QuartzLampBlock(glassProps().lightLevel(15).allowsSpawning(neverAllowSpawn)))
.addFeatures(AEFeature.DECORATIVE_LIGHTS, AEFeature.QUARTZ_GLASS)
.rendering(new BlockRenderingCustomizer() {
@Override
@@ -318,7 +318,7 @@ public final class ApiItems implements IItems {
GrowingCrystalEntity.TYPE = registry
.<GrowingCrystalEntity>entity("growing_crystal", GrowingCrystalEntity::new, SpawnGroup.MISC)
.customize(builder -> builder.dimensions(EntityDimensions.fixed(0.25F, 0.25F))).build();
.customize(builder -> builder.dimensions(EntityDimensions.fixed(0.25F, 0.4F))).build();
// rv1
this.encodedPattern = registry.item("encoded_pattern", EncodedPatternItem::new)
@@ -58,6 +58,14 @@ public class ConfigSection {
return option;
}
public StringOption addString(String id, String defaultValue) {
return addString(id, defaultValue, comment);
}
public StringOption addString(String id, String defaultValue, String comment) {
return addOption(new StringOption(this, id, comment, defaultValue));
}
public IntegerOption addInt(String id, int defaultValue) {
return addInt(id, defaultValue, comment);
}
@@ -0,0 +1,63 @@
package appeng.core.config;
import com.google.common.base.Preconditions;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
public class StringOption extends BaseOption {
private final String defaultValue;
private String currentValue;
public StringOption(ConfigSection parent, String id, String comment, String defaultValue) {
super(parent, id, comment);
this.defaultValue = defaultValue;
this.currentValue = this.defaultValue;
}
public String get() {
return currentValue;
}
public void set(String value) {
Preconditions.checkNotNull(value);
if (value.equals(currentValue)) {
return;
}
currentValue = value;
parent.markDirty();
}
@Override
protected JsonElement write() {
return new JsonPrimitive(currentValue);
}
@Override
protected void read(JsonElement element) {
if (!element.isJsonPrimitive()) {
throw new ConfigValidationException(this, "Expected a JSON primitive: " + element);
}
JsonPrimitive primitive = element.getAsJsonPrimitive();
if (!primitive.isString()) {
throw new ConfigValidationException(this, "Expected a JSON string, but found: " + primitive);
}
this.currentValue = primitive.getAsString();
}
@Override
public boolean isDifferentFromDefault() {
return !currentValue.equals(defaultValue);
}
@Override
public String getDefaultAsString() {
return defaultValue;
}
@Override
public String getCurrentValueAsString() {
return currentValue;
}
}
@@ -25,6 +25,7 @@ import appeng.api.events.LocatableEventAnnounce;
import appeng.api.events.LocatableEventAnnounce.LocatableEvent;
import appeng.api.features.ILocatable;
import appeng.api.features.ILocatableRegistry;
import appeng.core.AELog;
import appeng.util.Platform;
public final class LocatableRegistry implements ILocatableRegistry {
@@ -39,8 +40,10 @@ public final class LocatableRegistry implements ILocatableRegistry {
}
if (change == LocatableEvent.REGISTER) {
AELog.debug("Registering locatable %s: %s", target.getLocatableSerial(), target);
this.set.put(target.getLocatableSerial(), target);
} else if (change == LocatableEvent.UNREGISTER) {
AELog.debug("Unregistering locatable %s: %s", target.getLocatableSerial(), target);
this.set.remove(target.getLocatableSerial());
}
});
@@ -25,7 +25,6 @@ import appeng.api.features.IP2PTunnelRegistry;
import appeng.api.features.IPlayerRegistry;
import appeng.api.features.IRegistryContainer;
import appeng.api.features.IWirelessTermRegistry;
import appeng.api.features.IWorldGen;
import appeng.api.movable.IMovableRegistry;
import appeng.api.networking.IGridCacheRegistry;
import appeng.api.parts.IPartModels;
@@ -99,11 +98,6 @@ public class RegistryContainer implements IRegistryContainer {
return this.playerRegistry;
}
@Override
public IWorldGen worldgen() {
return WorldGenRegistry.INSTANCE;
}
@Override
public IPartModels partModels() {
return this.partModels;
@@ -1,89 +0,0 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.core.features.registries;
import java.util.HashSet;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier;
import appeng.api.features.IWorldGen;
public final class WorldGenRegistry implements IWorldGen {
public static final WorldGenRegistry INSTANCE = new WorldGenRegistry();
private final TypeSet[] types;
private WorldGenRegistry() {
this.types = new TypeSet[WorldGenType.values().length];
for (final WorldGenType type : WorldGenType.values()) {
this.types[type.ordinal()] = new TypeSet();
}
}
@Override
public void enableWorldGenForDimension(final WorldGenType type, final Identifier dimensionID) {
if (type == null) {
throw new IllegalArgumentException("Bad Type Passed");
}
this.types[type.ordinal()].enabledDimensions.add(dimensionID);
}
@Override
public void disableWorldGenForDimension(final WorldGenType type, final Identifier dimensionID) {
if (type == null) {
throw new IllegalArgumentException("Bad Type Passed");
}
this.types[type.ordinal()].badDimensions.add(dimensionID);
}
@Override
public boolean isWorldGenEnabled(final WorldGenType type, final ServerWorld w) {
if (type == null) {
throw new IllegalArgumentException("Bad Type Passed");
}
if (w == null) {
throw new IllegalArgumentException("Bad Provider Passed");
}
Identifier id = w.getRegistryKey().getValue();
final boolean isBadDimension = this.types[type.ordinal()].badDimensions.contains(id);
final boolean isGoodDimension = this.types[type.ordinal()].enabledDimensions.contains(id);
if (isBadDimension) {
return false;
}
if (!isGoodDimension && type == WorldGenType.METEORITES) {
return false;
}
return true;
}
private static class TypeSet {
final HashSet<Identifier> badDimensions = new HashSet<>();
final HashSet<Identifier> enabledDimensions = new HashSet<>();
}
}
@@ -34,7 +34,7 @@ import appeng.core.sync.network.INetworkInfo;
public abstract class BasePacket {
/**
* Sadly {@link PacketBuffer#readString()} gets inlined by Proguard which means
* Sadly {@link PacketByteBuf#readString()} gets inlined by Proguard which means
* it's not available on the Server. This field has the default string length
* that is used for writeString, which then also should be used for readString
* when it has no special length requirements.
@@ -29,7 +29,6 @@ import appeng.core.sync.packets.BlockTransitionEffectPacket;
import appeng.core.sync.packets.ClickPacket;
import appeng.core.sync.packets.CompassRequestPacket;
import appeng.core.sync.packets.CompassResponsePacket;
import appeng.core.sync.packets.CompressedNBTPacket;
import appeng.core.sync.packets.ConfigButtonPacket;
import appeng.core.sync.packets.ConfigValuePacket;
import appeng.core.sync.packets.CraftRequestPacket;
@@ -39,6 +38,7 @@ import appeng.core.sync.packets.ItemTransitionEffectPacket;
import appeng.core.sync.packets.JEIRecipePacket;
import appeng.core.sync.packets.LightningPacket;
import appeng.core.sync.packets.MEFluidInventoryUpdatePacket;
import appeng.core.sync.packets.MEInterfaceUpdatePacket;
import appeng.core.sync.packets.MEInventoryUpdatePacket;
import appeng.core.sync.packets.MatterCannonPacket;
import appeng.core.sync.packets.PaintedEntityPacket;
@@ -99,7 +99,7 @@ public class BasePacketHandler {
PACKET_ASSEMBLER_ANIMATION(AssemblerAnimationPacket.class, AssemblerAnimationPacket::new),
PACKET_COMPRESSED_NBT(CompressedNBTPacket.class, CompressedNBTPacket::new),
PACKET_ME_INTERFACE_UPDATE(MEInterfaceUpdatePacket.class, MEInterfaceUpdatePacket::new),
PACKET_PAINTED_ENTITY(PaintedEntityPacket.class, PaintedEntityPacket::new),
@@ -37,7 +37,7 @@ import appeng.container.AEBaseContainer;
import appeng.container.implementations.CellWorkbenchContainer;
import appeng.container.implementations.CraftConfirmContainer;
import appeng.container.implementations.CraftingCPUContainer;
import appeng.container.implementations.CraftingStatusContainer;
import appeng.container.implementations.CraftingCPUCyclingContainer;
import appeng.container.implementations.LevelEmitterContainer;
import appeng.container.implementations.NetworkToolContainer;
import appeng.container.implementations.PatternTermContainer;
@@ -97,12 +97,9 @@ public class ConfigValuePacket extends BasePacket {
final ItemStack is = player.getStackInHand(hand);
final IMouseWheelItem si = (IMouseWheelItem) is.getItem();
si.onWheel(is, this.Value.equals("WheelUp"));
} else if (this.Name.equals("Terminal.Cpu") && c instanceof CraftingStatusContainer) {
final CraftingStatusContainer qk = (CraftingStatusContainer) c;
qk.cycleCpu(this.Value.equals("Next"));
} else if (this.Name.equals("Terminal.Cpu") && c instanceof CraftConfirmContainer) {
final CraftConfirmContainer qk = (CraftConfirmContainer) c;
qk.cycleCpu(this.Value.equals("Next"));
} else if (this.Name.equals("Terminal.Cpu") && c instanceof CraftingCPUCyclingContainer) {
final CraftingCPUCyclingContainer qk = (CraftingCPUCyclingContainer) c;
qk.cycleSelectedCPU(this.Value.equals("Next"));
} else if (this.Name.equals("Terminal.Start") && c instanceof CraftConfirmContainer) {
final CraftConfirmContainer qk = (CraftConfirmContainer) c;
qk.startJob();
@@ -117,13 +114,13 @@ public class ConfigValuePacket extends BasePacket {
sc.toggleSetting(this.Value, player);
} else if (this.Name.equals("PriorityHost.Priority") && c instanceof PriorityContainer) {
final PriorityContainer pc = (PriorityContainer) c;
pc.setPriority(Integer.parseInt(this.Value), player);
pc.setPriority(Integer.parseInt(this.Value));
} else if (this.Name.equals("LevelEmitter.Value") && c instanceof LevelEmitterContainer) {
final LevelEmitterContainer lvc = (LevelEmitterContainer) c;
lvc.setLevel(Long.parseLong(this.Value), player);
lvc.setReportingValue(Long.parseLong(this.Value));
} else if (this.Name.equals("FluidLevelEmitter.Value") && c instanceof FluidLevelEmitterContainer) {
final FluidLevelEmitterContainer lvc = (FluidLevelEmitterContainer) c;
lvc.setLevel(Long.parseLong(this.Value), player);
lvc.setReportingValue(Long.parseLong(this.Value));
} else if (this.Name.startsWith("PatternTerminal.") && c instanceof PatternTermContainer) {
final PatternTermContainer cpt = (PatternTermContainer) c;
if (this.Name.equals("PatternTerminal.CraftMode")) {
@@ -191,9 +188,7 @@ public class ConfigValuePacket extends BasePacket {
public void clientPacketData(final INetworkInfo network, final PlayerEntity player) {
final ScreenHandler c = player.currentScreenHandler;
if (this.Name.equals("CustomName") && c instanceof AEBaseContainer) {
((AEBaseContainer) c).setCustomName(this.Value);
} else if (this.Name.startsWith("SyncDat.")) {
if (this.Name.startsWith("SyncDat.")) {
((AEBaseContainer) c).stringSync(Integer.parseInt(this.Name.substring(8)), this.Value);
} else if (this.Name.equals("CraftingStatus") && this.Value.equals("Clear")) {
final Screen gs = MinecraftClient.getInstance().currentScreen;
@@ -18,15 +18,27 @@
package appeng.core.sync.packets;
import java.util.Arrays;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import com.google.common.base.Preconditions;
import com.mojang.datafixers.util.Pair;
import io.netty.buffer.Unpooled;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.recipe.Ingredient;
import net.minecraft.recipe.Recipe;
import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.ShapedRecipe;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.Identifier;
import net.minecraft.util.collection.DefaultedList;
import alexiil.mc.lib.attributes.item.FixedItemInv;
@@ -41,11 +53,14 @@ import appeng.api.networking.storage.IStorageGrid;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.container.implementations.PatternTermContainer;
import appeng.core.Api;
import appeng.core.sync.BasePacket;
import appeng.core.sync.BasePacketHandler;
import appeng.core.sync.network.INetworkInfo;
import appeng.helpers.IContainerCraftingPacket;
import appeng.items.storage.ViewCellItem;
import appeng.mixins.IngredientAccessor;
import appeng.util.Platform;
import appeng.util.helpers.ItemHandlerUtil;
import appeng.util.inv.AdaptorFixedInv;
@@ -55,151 +70,312 @@ import appeng.util.prioritylist.IPartitionList;
public class JEIRecipePacket extends BasePacket {
private ItemStack[][] recipe;
/**
* Transmit only a recipe ID.
*/
private static final int INLINE_RECIPE_NONE = 1;
/**
* Transmit the information about the recipe we actually need. This is
* explicitly limited since this is untrusted client->server info.
*/
private static final int INLINE_RECIPE_SHAPED = 2;
private Identifier recipeId;
/**
* This is optional, in case the client already knows it could not resolve the
* recipe id.
*/
@Nullable
private Recipe<?> recipe;
private boolean crafting;
public JEIRecipePacket(final PacketByteBuf stream) {
final CompoundTag comp = stream.readCompoundTag();
if (comp != null) {
this.recipe = new ItemStack[9][];
for (int x = 0; x < this.recipe.length; x++) {
final ListTag list = comp.getList("#" + x, 10);
if (list.size() > 0) {
this.recipe[x] = new ItemStack[list.size()];
for (int y = 0; y < list.size(); y++) {
this.recipe[x][y] = ItemStack.fromTag(list.getCompound(y));
}
}
}
}
}
this.crafting = stream.readBoolean();
final String id = stream.readString(Short.MAX_VALUE);
this.recipeId = new Identifier(id);
// api
public JEIRecipePacket(final CompoundTag recipe) {
final PacketByteBuf data = new PacketByteBuf(Unpooled.buffer());
data.writeInt(this.getPacketID());
data.writeCompoundTag(recipe);
this.configureWrite(data);
}
@Override
public void serverPacketData(final INetworkInfo manager, final PlayerEntity player) {
final ServerPlayerEntity pmp = (ServerPlayerEntity) player;
final ScreenHandler con = pmp.currentScreenHandler;
if (!(con instanceof IContainerCraftingPacket)) {
return;
}
final IContainerCraftingPacket cct = (IContainerCraftingPacket) con;
final IGridNode node = cct.getNetworkNode();
if (node == null) {
return;
}
final IGrid grid = node.getGrid();
if (grid == null) {
return;
}
final IStorageGrid inv = grid.getCache(IStorageGrid.class);
final IEnergyGrid energy = grid.getCache(IEnergyGrid.class);
final ISecurityGrid security = grid.getCache(ISecurityGrid.class);
final ICraftingGrid crafting = grid.getCache(ICraftingGrid.class);
final FixedItemInv craftMatrix = cct.getInventoryByName("crafting");
final FixedItemInv playerInventory = cct.getInventoryByName("player");
if (inv != null && this.recipe != null && security != null) {
final IMEMonitor<IAEItemStack> storage = inv
.getInventory(Api.instance().storage().getStorageChannel(IItemStorageChannel.class));
final IPartitionList<IAEItemStack> filter = ViewCellItem.createFilter(cct.getViewCells());
for (int x = 0; x < craftMatrix.getSlotCount(); x++) {
ItemStack currentItem = craftMatrix.getInvStack(x);
// prepare slots
if (!currentItem.isEmpty()) {
// already the correct item?
ItemStack newItem = this.canUseInSlot(x, currentItem);
// put away old item
if (newItem != currentItem && security.hasPermission(player, SecurityPermissions.INJECT)) {
final IAEItemStack in = AEItemStack.fromItemStack(currentItem);
final IAEItemStack out = cct.useRealItems()
? Platform.poweredInsert(energy, storage, in, cct.getActionSource())
: null;
if (out != null) {
currentItem = out.createItemStack();
} else {
currentItem = ItemStack.EMPTY;
}
}
}
if (currentItem.isEmpty() && this.recipe[x] != null) {
// for each variant
for (int y = 0; y < this.recipe[x].length && currentItem.isEmpty(); y++) {
final IAEItemStack request = AEItemStack.fromItemStack(this.recipe[x][y]);
if (request != null) {
// try ae
if ((filter == null || filter.isListed(request))
&& security.hasPermission(player, SecurityPermissions.EXTRACT)) {
request.setStackSize(1);
IAEItemStack out;
if (cct.useRealItems()) {
out = Platform.poweredExtraction(energy, storage, request, cct.getActionSource());
} else {
// Query the crafting grid if there is a pattern providing the item
if (!crafting.getCraftingFor(request, null, 0, null).isEmpty()) {
out = request;
} else {
// Fall back using an existing item
out = storage.extractItems(request, Actionable.SIMULATE, cct.getActionSource());
}
}
if (out != null) {
currentItem = out.createItemStack();
}
}
// try inventory
if (currentItem.isEmpty()) {
AdaptorFixedInv ad = new AdaptorFixedInv(playerInventory);
if (cct.useRealItems()) {
currentItem = ad.removeItems(1, this.recipe[x][y], null);
} else {
currentItem = ad.simulateRemove(1, this.recipe[x][y], null);
}
}
}
}
}
ItemHandlerUtil.setStackInSlot(craftMatrix, x, currentItem);
}
con.onContentChanged(new WrapperInvItemHandler(craftMatrix));
int inlineRecipeType = stream.readVarInt();
switch (inlineRecipeType) {
case INLINE_RECIPE_NONE:
break;
case INLINE_RECIPE_SHAPED:
recipe = RecipeSerializer.SHAPED.read(this.recipeId, stream);
break;
default:
throw new IllegalArgumentException("Invalid inline recipe type.");
}
}
/**
* @param slot
* @param is itemstack
* @return is if it can be used, else EMPTY
* Sends a recipe identified by the given recipe ID to the server for either
* filling a crafting grid or a pattern.
*/
private ItemStack canUseInSlot(int slot, ItemStack is) {
if (this.recipe[slot] != null) {
for (ItemStack option : this.recipe[slot]) {
if (is.isItemEqual(option)) {
return is;
public JEIRecipePacket(final Identifier recipeId, final boolean crafting) {
PacketByteBuf data = createCommonHeader(recipeId, crafting, INLINE_RECIPE_NONE);
this.configureWrite(data);
}
/**
* Sends a recipe to the server for either filling a crafting grid or a pattern.
* <p>
* Prefer the id-based constructor above whereever possible.
*/
public JEIRecipePacket(final ShapedRecipe recipe, final boolean crafting) {
PacketByteBuf data = createCommonHeader(recipe.getId(), crafting, INLINE_RECIPE_SHAPED);
RecipeSerializer.SHAPED.write(data, recipe);
this.configureWrite(data);
}
private PacketByteBuf createCommonHeader(Identifier recipeId, boolean crafting, int inlineRecipeType) {
final PacketByteBuf data = new PacketByteBuf(Unpooled.buffer());
data.writeInt(this.getPacketID());
data.writeBoolean(crafting);
data.writeIdentifier(recipeId);
data.writeVarInt(inlineRecipeType);
return data;
}
/**
* Servside handler for this packet.
* <p>
* Makes use of {@link Preconditions#checkArgument(boolean)} as the
* {@link BasePacketHandler} is catching them and in general these cases should
* never happen except in an error case and should be logged then.
*/
@Override
public void serverPacketData(final INetworkInfo manager, final PlayerEntity player) {
// Setup and verification
final ServerPlayerEntity pmp = (ServerPlayerEntity) player;
final ScreenHandler con = pmp.currentScreenHandler;
Preconditions.checkArgument(con instanceof IContainerCraftingPacket);
Recipe<?> recipe = player.getEntityWorld().getRecipeManager().get(this.recipeId).orElse(null);
if (recipe == null && this.recipe != null) {
// Certain recipes (i.e. AE2 facades) are represented in JEI as ShapedRecipe's,
// while in reality they
// are special recipes. Those recipes are sent across the wire...
recipe = this.recipe;
}
Preconditions.checkArgument(recipe != null);
final IContainerCraftingPacket cct = (IContainerCraftingPacket) con;
final IGridNode node = cct.getNetworkNode();
Preconditions.checkArgument(node != null);
final IGrid grid = node.getGrid();
Preconditions.checkArgument(grid != null);
final IStorageGrid inv = grid.getCache(IStorageGrid.class);
Preconditions.checkArgument(inv != null);
final ISecurityGrid security = grid.getCache(ISecurityGrid.class);
Preconditions.checkArgument(security != null);
final IEnergyGrid energy = grid.getCache(IEnergyGrid.class);
final ICraftingGrid crafting = grid.getCache(ICraftingGrid.class);
final FixedItemInv craftMatrix = cct.getInventoryByName("crafting");
final FixedItemInv playerInventory = cct.getInventoryByName("player");
final IMEMonitor<IAEItemStack> storage = inv
.getInventory(Api.instance().storage().getStorageChannel(IItemStorageChannel.class));
final IPartitionList<IAEItemStack> filter = ViewCellItem.createFilter(cct.getViewCells());
final DefaultedList<Ingredient> ingredients = this.ensure3by3CraftingMatrix(recipe);
// Handle each slot
for (int x = 0; x < craftMatrix.getSlotCount(); x++) {
ItemStack currentItem = craftMatrix.getInvStack(x);
Ingredient ingredient = ingredients.get(x);
// prepare slots
if (!currentItem.isEmpty()) {
// already the correct item? True, skip everything else
ItemStack newItem = this.canUseInSlot(ingredient, currentItem);
// put away old item, if not correct
if (newItem != currentItem && security.hasPermission(player, SecurityPermissions.INJECT)) {
final IAEItemStack in = AEItemStack.fromItemStack(currentItem);
final IAEItemStack out = cct.useRealItems()
? Platform.poweredInsert(energy, storage, in, cct.getActionSource())
: null;
if (out != null) {
currentItem = out.createItemStack();
} else {
currentItem = ItemStack.EMPTY;
}
}
}
// Find item or pattern from the network
if (currentItem.isEmpty() && security.hasPermission(player, SecurityPermissions.EXTRACT)) {
IAEItemStack out;
if (cct.useRealItems()) {
IAEItemStack request = findBestMatchingItemStack(ingredient, filter, storage, cct);
out = request != null
? Platform.poweredExtraction(energy, storage, request.setStackSize(1),
cct.getActionSource())
: null;
} else {
out = findBestMatchingPattern(ingredient, filter, crafting, storage, cct);
if (out == null) {
out = findBestMatchingItemStack(ingredient, filter, storage, cct);
}
if (out == null && getMatchingStacks(ingredient).length > 0) {
out = AEItemStack.fromItemStack(getMatchingStacks(ingredient)[0]);
}
}
if (out != null) {
currentItem = out.createItemStack();
}
}
// If still nothing, search the player inventory.
if (currentItem.isEmpty()) {
ItemStack[] matchingStacks = getMatchingStacks(ingredient);
for (ItemStack matchingStack : matchingStacks) {
if (currentItem.isEmpty()) {
AdaptorFixedInv ad = new AdaptorFixedInv(playerInventory);
if (cct.useRealItems()) {
currentItem = ad.removeItems(1, matchingStack, null);
} else {
currentItem = ad.simulateRemove(1, matchingStack, null);
}
}
}
}
ItemHandlerUtil.setStackInSlot(craftMatrix, x, currentItem);
}
if (!this.crafting) {
this.handleProcessing(con, cct, recipe);
}
con.onContentChanged(new WrapperInvItemHandler(craftMatrix));
}
@SuppressWarnings("ConstantConditions")
private static ItemStack[] getMatchingStacks(Ingredient ingredient) {
IngredientAccessor accessor = (IngredientAccessor) (Object) ingredient;
accessor.appeng_cacheMatchingStacks();
if (ingredient.isEmpty()) {
return new ItemStack[0];
}
ItemStack[] stacks = accessor.getMatchingStacks();
if (stacks.length == 1 && stacks[0].isEmpty()) {
return new ItemStack[0];
}
return stacks;
}
/**
* Expand any recipe to a 3x3 matrix.
* <p>
* Will throw an {@link IllegalArgumentException} in case it has more than 9 or
* a shaped recipe is either wider or higher than 3. ingredients.
*/
private DefaultedList<Ingredient> ensure3by3CraftingMatrix(Recipe<?> recipe) {
DefaultedList<Ingredient> ingredients = recipe.getPreviewInputs();
DefaultedList<Ingredient> expandedIngredients = DefaultedList.ofSize(9, Ingredient.EMPTY);
Preconditions.checkArgument(ingredients.size() <= 9);
// shaped recipes can be smaller than 3x3, expand to 3x3 to match the crafting
// matrix
if (recipe instanceof ShapedRecipe) {
ShapedRecipe shapedRecipe = (ShapedRecipe) recipe;
int width = shapedRecipe.getWidth();
int height = shapedRecipe.getHeight();
Preconditions.checkArgument(width <= 3 && height <= 3);
for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++) {
int source = w + h * width;
int target = w + h * 3;
Ingredient i = ingredients.get(source);
expandedIngredients.set(target, i);
}
}
}
return ItemStack.EMPTY;
// Anything else should be a flat list
else {
for (int i = 0; i < ingredients.size(); i++) {
expandedIngredients.set(i, ingredients.get(i));
}
}
return expandedIngredients;
}
/**
* @param is itemstack
* @return is if it can be used, else EMPTY
*/
private ItemStack canUseInSlot(Ingredient ingredient, ItemStack is) {
return Arrays.stream(getMatchingStacks(ingredient)).filter(p -> p.isItemEqual(is)).findFirst()
.orElse(ItemStack.EMPTY);
}
/**
* Finds the first matching itemstack with the highest stored amount.
*/
private IAEItemStack findBestMatchingItemStack(Ingredient ingredients, IPartitionList<IAEItemStack> filter,
IMEMonitor<IAEItemStack> storage, IContainerCraftingPacket cct) {
Stream<AEItemStack> stacks = Arrays.stream(getMatchingStacks(ingredients))//
.map(AEItemStack::fromItemStack) //
.filter(r -> r != null && (filter == null || filter.isListed(r)));
return getMostStored(stacks, storage, cct);
}
/**
* This tries to find the first pattern matching the list of ingredients.
* <p>
* As additional condition, it sorts by the stored amount to return the one with
* the highest stored amount.
*/
private IAEItemStack findBestMatchingPattern(Ingredient ingredients, IPartitionList<IAEItemStack> filter,
ICraftingGrid crafting, IMEMonitor<IAEItemStack> storage, IContainerCraftingPacket cct) {
Stream<IAEItemStack> stacks = Arrays.stream(getMatchingStacks(ingredients))//
.map(AEItemStack::fromItemStack)//
.filter(r -> r != null && (filter == null || filter.isListed(r)))//
.map(s -> s.setCraftable(!crafting.getCraftingFor(s, null, 0, null).isEmpty()))//
.filter(IAEItemStack::isCraftable);
return getMostStored(stacks, storage, cct);
}
/**
* From a stream of AE item stacks, pick the one with the highest available
* amount in the network. Returns null if the stream is empty.
*/
private static IAEItemStack getMostStored(Stream<? extends IAEItemStack> stacks, IMEMonitor<IAEItemStack> storage,
IContainerCraftingPacket cct) {
return stacks//
.map(s -> {
// Determine the stored count
IAEItemStack stored = storage.extractItems(s.copy().setStackSize(Long.MAX_VALUE),
Actionable.SIMULATE, cct.getActionSource());
return Pair.of(s, stored != null ? stored.getStackSize() : 0);
})//
.min((left, right) -> Long.compare(right.getSecond(), left.getSecond()))//
.map(Pair::getFirst)//
.orElse(null);
}
private void handleProcessing(ScreenHandler con, IContainerCraftingPacket cct, Recipe<?> recipe) {
if (con instanceof PatternTermContainer) {
PatternTermContainer patternTerm = (PatternTermContainer) con;
if (!patternTerm.craftingMode) {
final FixedItemInv output = cct.getInventoryByName("output");
ItemHandlerUtil.setStackInSlot(output, 0, recipe.getOutput());
ItemHandlerUtil.setStackInSlot(output, 1, ItemStack.EMPTY);
ItemHandlerUtil.setStackInSlot(output, 2, ItemStack.EMPTY);
}
}
}
}
@@ -19,13 +19,9 @@
package appeng.core.sync.packets;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.BufferOverflowException;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import javax.annotation.Nullable;
@@ -41,7 +37,6 @@ import net.minecraft.network.Packet;
import net.minecraft.network.PacketByteBuf;
import appeng.api.storage.data.IAEFluidStack;
import appeng.core.AELog;
import appeng.core.sync.BasePacket;
import appeng.core.sync.network.INetworkInfo;
import appeng.fluids.client.gui.FluidTerminalScreen;
@@ -55,8 +50,6 @@ import appeng.fluids.util.AEFluidStack;
public class MEFluidInventoryUpdatePacket extends BasePacket {
private static final int UNCOMPRESSED_PACKET_BYTE_LIMIT = 16 * 1024 * 1024;
private static final int OPERATION_BYTE_LIMIT = 2 * 1024;
private static final int TEMP_BUFFER_SIZE = 1024;
private static final int STREAM_MASK = 0xff;
// input.
@Nullable
@@ -66,47 +59,18 @@ public class MEFluidInventoryUpdatePacket extends BasePacket {
@Nullable
private final PacketByteBuf data;
@Nullable
private final GZIPOutputStream compressFrame;
private int writtenBytes = 0;
private boolean empty = true;
public MEFluidInventoryUpdatePacket(final PacketByteBuf stream) {
this.data = null;
this.compressFrame = null;
this.list = new LinkedList<>();
this.ref = stream.readByte();
try (final GZIPInputStream gzReader = new GZIPInputStream(new InputStream() {
@Override
public int read() {
if (stream.readableBytes() <= 0) {
return -1;
}
return stream.readByte() & STREAM_MASK;
}
})) {
final PacketByteBuf uncompressed = new PacketByteBuf(Unpooled.buffer(stream.readableBytes()));
final byte[] tmp = new byte[TEMP_BUFFER_SIZE];
while (gzReader.available() != 0) {
final int bytes = gzReader.read(tmp);
if (bytes > 0) {
uncompressed.writeBytes(tmp, 0, bytes);
}
}
while (uncompressed.readableBytes() > 0) {
this.list.add(AEFluidStack.fromPacket(uncompressed));
}
} catch (IOException e) {
throw new RuntimeException("Failed to decompress packet.", e);
while (stream.readableBytes() > 0) {
this.list.add(AEFluidStack.fromPacket(stream));
}
this.empty = this.list.isEmpty();
}
@@ -121,14 +85,6 @@ public class MEFluidInventoryUpdatePacket extends BasePacket {
this.data = new PacketByteBuf(Unpooled.buffer(OPERATION_BYTE_LIMIT));
this.data.writeInt(this.getPacketID());
this.data.writeByte(this.ref);
this.compressFrame = new GZIPOutputStream(new OutputStream() {
@Override
public void write(final int value) {
MEFluidInventoryUpdatePacket.this.data.writeByte(value);
}
});
this.list = null;
}
@@ -145,28 +101,19 @@ public class MEFluidInventoryUpdatePacket extends BasePacket {
@Nullable
@Override
public Packet<?> toPacket(NetworkSide direction) {
try {
this.compressFrame.close();
this.configureWrite(this.data);
return super.toPacket(direction);
} catch (final IOException e) {
AELog.debug(e);
}
return null;
this.configureWrite(this.data);
return super.toPacket(direction);
}
public void appendFluid(final IAEFluidStack fs) throws IOException, BufferOverflowException {
final PacketByteBuf tmp = new PacketByteBuf(Unpooled.buffer(OPERATION_BYTE_LIMIT));
fs.writeToPacket(tmp);
this.compressFrame.flush();
if (this.writtenBytes + tmp.readableBytes() > UNCOMPRESSED_PACKET_BYTE_LIMIT) {
throw new BufferOverflowException();
} else {
this.writtenBytes += tmp.readableBytes();
this.compressFrame.write(tmp.array(), 0, tmp.readableBytes());
this.data.writeBytes(tmp.array(), 0, tmp.readableBytes());
this.empty = false;
}
}
@@ -18,13 +18,7 @@
package appeng.core.sync.packets;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import io.netty.buffer.Unpooled;
@@ -34,62 +28,30 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtIo;
import net.minecraft.network.PacketByteBuf;
import appeng.client.gui.implementations.InterfaceTerminalScreen;
import appeng.core.sync.BasePacket;
import appeng.core.sync.network.INetworkInfo;
//TODO, this is pointless, NBT is already compressed when written to a PacketBuffer.
public class CompressedNBTPacket extends BasePacket {
public class MEInterfaceUpdatePacket extends BasePacket {
// input.
private final CompoundTag in;
// output...
private final PacketByteBuf data;
private final GZIPOutputStream compressFrame;
public CompressedNBTPacket(final PacketByteBuf stream) {
public MEInterfaceUpdatePacket(final PacketByteBuf stream) {
this.data = null;
this.compressFrame = null;
try (DataInputStream inStream = new DataInputStream(new GZIPInputStream(new InputStream() {
@Override
public int read() {
if (stream.readableBytes() <= 0) {
return -1;
}
return stream.readByte() & 0xff;
}
}))) {
this.in = NbtIo.read(inStream);
} catch (IOException e) {
throw new RuntimeException("Failed to decompress packet.", e);
}
this.in = stream.readCompoundTag();
}
// api
public CompressedNBTPacket(final CompoundTag din) throws IOException {
public MEInterfaceUpdatePacket(final CompoundTag din) throws IOException {
this.in = null;
this.data = new PacketByteBuf(Unpooled.buffer(2048));
this.data.writeInt(this.getPacketID());
this.in = din;
this.compressFrame = new GZIPOutputStream(new OutputStream() {
@Override
public void write(final int value) {
CompressedNBTPacket.this.data.writeByte(value);
}
});
NbtIo.write(din, new DataOutputStream(this.compressFrame));
this.compressFrame.close();
this.data.writeCompoundTag(din);
this.configureWrite(this.data);
}
@@ -19,13 +19,9 @@
package appeng.core.sync.packets;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.BufferOverflowException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import javax.annotation.Nullable;
@@ -45,7 +41,6 @@ import appeng.client.gui.implementations.CraftConfirmScreen;
import appeng.client.gui.implementations.CraftingCPUScreen;
import appeng.client.gui.implementations.MEMonitorableScreen;
import appeng.client.gui.implementations.NetworkStatusScreen;
import appeng.core.AELog;
import appeng.core.sync.BasePacket;
import appeng.core.sync.network.INetworkInfo;
import appeng.util.item.AEItemStack;
@@ -53,8 +48,6 @@ import appeng.util.item.AEItemStack;
public class MEInventoryUpdatePacket extends BasePacket {
private static final int UNCOMPRESSED_PACKET_BYTE_LIMIT = 16 * 1024 * 1024;
private static final int OPERATION_BYTE_LIMIT = 2 * 1024;
private static final int TEMP_BUFFER_SIZE = 1024;
private static final int STREAM_MASK = 0xff;
// input.
@Nullable
@@ -64,48 +57,18 @@ public class MEInventoryUpdatePacket extends BasePacket {
@Nullable
private final PacketByteBuf data;
@Nullable
private final GZIPOutputStream compressFrame;
private int writtenBytes = 0;
private boolean empty = true;
public MEInventoryUpdatePacket(final PacketByteBuf stream) {
this.data = null;
this.compressFrame = null;
this.list = new ArrayList<>();
this.ref = stream.readByte();
// int originalBytes = stream.readableBytes();
try (GZIPInputStream gzReader = new GZIPInputStream(new InputStream() {
@Override
public int read() {
if (stream.readableBytes() <= 0) {
return -1;
}
return stream.readByte() & STREAM_MASK;
}
})) {
final PacketByteBuf uncompressed = new PacketByteBuf(Unpooled.buffer(stream.readableBytes()));
final byte[] tmp = new byte[TEMP_BUFFER_SIZE];
while (gzReader.available() != 0) {
final int bytes = gzReader.read(tmp);
if (bytes > 0) {
uncompressed.writeBytes(tmp, 0, bytes);
}
}
while (uncompressed.readableBytes() > 0) {
this.list.add(AEItemStack.fromPacket(uncompressed));
}
} catch (IOException e) {
throw new RuntimeException("Failed to decompress packet.", e);
while (stream.readableBytes() > 0) {
this.list.add(AEItemStack.fromPacket(stream));
}
this.empty = this.list.isEmpty();
}
@@ -120,14 +83,6 @@ public class MEInventoryUpdatePacket extends BasePacket {
this.data = new PacketByteBuf(Unpooled.buffer(OPERATION_BYTE_LIMIT));
this.data.writeInt(this.getPacketID());
this.data.writeByte(this.ref);
this.compressFrame = new GZIPOutputStream(new OutputStream() {
@Override
public void write(final int value) {
MEInventoryUpdatePacket.this.data.writeByte(value);
}
});
this.list = null;
}
@@ -156,28 +111,19 @@ public class MEInventoryUpdatePacket extends BasePacket {
@Nullable
@Override
public Packet<?> toPacket(NetworkSide direction) {
try {
this.compressFrame.close();
this.configureWrite(this.data);
return super.toPacket(direction);
} catch (final IOException e) {
AELog.debug(e);
}
return null;
this.configureWrite(this.data);
return super.toPacket(direction);
}
public void appendItem(final IAEItemStack is) throws IOException, BufferOverflowException {
final PacketByteBuf tmp = new PacketByteBuf(Unpooled.buffer(OPERATION_BYTE_LIMIT));
is.writeToPacket(tmp);
this.compressFrame.flush();
if (this.writtenBytes + tmp.readableBytes() > UNCOMPRESSED_PACKET_BYTE_LIMIT) {
throw new BufferOverflowException();
} else {
this.writtenBytes += tmp.readableBytes();
this.compressFrame.write(tmp.array(), 0, tmp.readableBytes());
this.data.writeBytes(tmp.array(), 0, tmp.readableBytes());
this.empty = false;
}
}

Some files were not shown because too many files have changed in this diff Show More