diff options
author | BlueWeabo <ilia.iliev2005@gmail.com> | 2024-01-06 00:41:00 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-05 23:41:00 +0100 |
commit | 02bedd5c0a96a654c6692edd1b7f2765fd9c46b4 (patch) | |
tree | 57dd675f658dda3caba629f15d4708247e702f88 /src/main/java/gregtech/api | |
parent | fc63cee4c0284635c601889ce49a892cf73082ff (diff) | |
download | GT5-Unofficial-02bedd5c0a96a654c6692edd1b7f2765fd9c46b4.tar.gz GT5-Unofficial-02bedd5c0a96a654c6692edd1b7f2765fd9c46b4.tar.bz2 GT5-Unofficial-02bedd5c0a96a654c6692edd1b7f2765fd9c46b4.zip |
Merge MuTEMaster into Master (#2431)
* Fix MuTE structure check and power intake (#1975)
* Fixed casing lists being cleared for every checked structure piece
* Fixed power being taken from any side BUT the right one
* ACP Structure - Rebased (#1978)
* Added 2nd structure tier to ACR and make complex parallels depend on it
* Added tier 3 to 8 structure pieces to ACR
* Added disclaimer
* Renamed ACR to ACP because MV CR already is named ACR
* Add autopush functionality to MuTE (#1976) - fix conflict
* Working auto push
* Revert wildcard import
* Addresssed reviews
* Fix reference issue
* Minor MuTE fixes - Rebased (#1983)
* Fixed ACP recipe map
* Fixed controller side being used instead of part side when accessing tanks
* Fix Structure not forming (#1984)
* fix cables not connecting
* fix structure and don't store controller
* Add missing tooltips (#1981)
* Add missing tooltips
* Address blue's change
* Distillation MuTE (#1989)
* Started work on DT MuTE
* Renamed methods so they also make sense when used horizontally
* MuTE Upgrade Casings - Rebased (#1988) - fix conflict
* Added cleanroom upgrade casing
* Added inventory and tank upgrades
* Added tooltips to mute casings
* Added power upgrades
* Set player UUID when placing MuTE
* MuTE fixes (#1991)
* Fixed pipes not connectable to MuTE casings
* Fixed not all things being renamed to ACP
* Fix running in obf
* fix for real yo
* Add a Generic Processing Logic and extract methods - Rebased (#1992)
* add a generic processing logic
* calculate tier in another method
* calculate power logic in another method
* Add Layered Coke Foundry (#1995)
* Add the Foundry class and call it
* Foundry name correction
* Buildable stackable structure
* Fixed min stacks and added motor casings
* checkMachine override for custom checking
* Working checkMachine for all stacks, and recipes
* Fix getOutputFluids
* Change recipe processing to GenericProcessingLogic
* Change inventoryName to protected for override
* Override checkRecipe for multis that consume EU
* Rename class and add inner walls to multi
* Structure update and other fixes
* Fix processing logic being static
* MuTE inventory upgrade logic (#2082)
* Catch potential NPE
* Don't load name when it doesn't exist
* Potentially cause weird non-replicatable issue where registry ends up with different key
* Use proper block removal method
* Validate index before using it
* Don't open controller GUI from inventory upgrade
* semi-working concept
* sync the ID of the inventory upgrade to correctly remove it later
* remove unneeded boolean
---------
Co-authored-by: BlueWeabo <76872108+BlueWeabo@users.noreply.github.com>
* fixed layeredCokeBattery checkMachine to prevent 'already in building state' (#2099)
* MuTE casing structure element (#2105) - fix conflict
* Added class containing MuTE relevant structure elements
* Migrate MuTE to new structure element
* Formatting fix
* Use int array instead of int hashmap, since its expected these arrays will never get long enough to be faster as hashmap
* Delete old code
* Cache MuTEs for non-instance specific actions (#2109)
* Introduce map of cached TEs, which are used to perform actions that don't require a specific instance of the TE. This prevents constant creation of new TEs
* Remove static modifier from map of cached TEs
* First Modular Upgrade Casings Implementation (#2142)
* Base support for Heater MUCs
- Define Heater upgrade casings;
- Create the 5 tiers of Heaters;
- Add method to increase and decrease count.
* Refactor the cache of MUCs in structure
- Change the way that each MUC is counted: since there will be several types, the integer that counted heaters is now a hashmap that divides all MUCs based on their type and tier, to be counted separately from each other.
* Add Insulator MUC
- Add second MUC type (insulator) to test alongside heaters on the Layered Coke Battery.
* Fix MUC count reset
* Refactor MUC implementation into subclass
- Move the new methods and hashmap away from the base classes, and onto a s specific one that won't be used by unrelated multiblocks.
* Remove empty lines
* Refactor MUC implementations into subclasses
* Requested fixes in StackableModularController
* Change hashmap keys to an enum
* Hashmap getter for load order purposes
- Added a getter that generates the default value for the hashmap if it is null, due to problems with load order;
* Apply spotless
* NotNull annotations
* More Additions to MUCs and the LCB (#2215)
* Fix old LCB multi name in some locations
* Refactor mucMap and override checkRecipe
- Refactor mucMap to an array of primitive integers instead of the wrapper type, for ease of use with other methods such as stream;
- Override checkRecipe for custom recipe behavior on MUC multis, to be implemented in a future commit;
* First implementation of bonuses and MUC requirements
- Change EU/t and recipe duration of this multi based on the count of different MUCs in the multi;
- Fail the structure check based on the count of each of the allowed MUCs.
* Parallel count implementation
- Calculate parallels based on the count of base MUCs, the cheapest option amongst the possibilities, in this case heaters;
- Added more abstract methods to require specific values from the multi classes.
* Fix parallel count and processing
- Fixed the handling of parallels by pointing to the corrent maxParallel variable in ProcessingLogic.
* Test of parallels with additional amp input
* Structure fix for the intended LCB
- Changed MUC placements to match what I intended at the beginning, to better test the multi.
* One more comment
* Remove checkRecipe override
* Refactor Item and Fluid to be in separate logic classes (#2178) - fix
conflict
* basics of inventory logic
* mostly working item logic
* working nbt saving/loading
* fluid handler
* FluidSlotHandler WIP
* fluid handler mostly working
* remove fluid handler from gt5u
* prepare for conversion
* use correct imports
* spotless
* more controller logic
* spotless
* final refactor. migration next
* spotless
* add more methods to logic classes
* convert almost everything to use new Logic
* spotless
* make mute casing mode an int
* allow pump cover to work with FluidInventoryLogic
* pumps work
* spotless
* make item inventory logic work with every item input thing
* rework Fluid Inventory Logic to work with all fluid inputs
* spotless
* address annotation reviews
* finish off todos
* missed to dos
* cleanup
Coke oven will get a new GUI when i get to it
* address review
* prevent npes from ControllerXXXLogic
* null checks
* remove accidentally added methods
* fix missed return
* fixes after rebase - fix conflict
* Laser Engraver Multi. (#2223) - fix conflict
* saving.............
* clean up
* savin
* Small fixes + Adding back stuff, Crashes you and spams logs.
* fix stack overflow
* Fixes
* Fixes
---------
Co-authored-by: BlueWeabo <76872108+BlueWeabo@users.noreply.github.com>
* Add TickableTask (#2216)
* Add autopush functionality to MuTE (#1976)
* Working auto push
* Revert wildcard import
* Addresssed reviews
* Fix reference issue
* MuTE Upgrade Casings (#1988)
* Added cleanroom upgrade casing
* Added inventory and tank upgrades
* Added tooltips to mute casings
* Added power upgrades
* Set player UUID when placing MuTE
* Add a Generic Processing Logic and extract methods (#1992)
* add a generic processing logic
* calculate tier in another method
* calculate power logic in another method
* MuTE inventory upgrade logic (#2082)
* Catch potential NPE
* Don't load name when it doesn't exist
* Potentially cause weird non-replicatable issue where registry ends up with different key
* Use proper block removal method
* Validate index before using it
* Don't open controller GUI from inventory upgrade
* semi-working concept
* sync the ID of the inventory upgrade to correctly remove it later
* remove unneeded boolean
---------
Co-authored-by: BlueWeabo <76872108+BlueWeabo@users.noreply.github.com>
* MuTE casing structure element (#2105)
* Added class containing MuTE relevant structure elements
* Migrate MuTE to new structure element
* Formatting fix
* Use int array instead of int hashmap, since its expected these arrays will never get long enough to be faster as hashmap
* Delete old code
* Refactor Item and Fluid to be in separate logic classes (#2178)
* basics of inventory logic
* mostly working item logic
* working nbt saving/loading
* fluid handler
* FluidSlotHandler WIP
* fluid handler mostly working
* remove fluid handler from gt5u
* prepare for conversion
* use correct imports
* spotless
* more controller logic
* spotless
* final refactor. migration next
* spotless
* add more methods to logic classes
* convert almost everything to use new Logic
* spotless
* make mute casing mode an int
* allow pump cover to work with FluidInventoryLogic
* pumps work
* spotless
* make item inventory logic work with every item input thing
* rework Fluid Inventory Logic to work with all fluid inputs
* spotless
* address annotation reviews
* finish off todos
* missed to dos
* cleanup
Coke oven will get a new GUI when i get to it
* address review
* prevent npes from ControllerXXXLogic
* null checks
* Base work
* PollutionTask
* move package
* Fix generics
* Internal -> OverrideOnly
* rebase fix
* Ducttape addPollution
---------
Co-authored-by: Maxim <maxim235@gmx.de>
Co-authored-by: BlueWeabo <ilia.iliev2005@gmail.com>
Co-authored-by: BlueWeabo <76872108+BlueWeabo@users.noreply.github.com>
* Rework a bit of ProcessingLogic to fit MuTEs (#2283) - fix conflicts
* Add a way to enable or disable the crafting buffer on GPL multiblocks (#2218)
* add a way to enable or disable the crafting buffer on GPL multiblocks
* don't register the hatch either
* fix Refractory Capsule (#2219)
* Fix PAs overclocking ulv recipes too much (#2220)
* fix PAs overclocking ulv recipes too much
* make sure we save the returned value
* Fix Digital Tank capacity for Fluid Storage Monitor (#2217)
* Fix Digital Tank capacity for Fluid Storage Monitor
* Annotations
* Blacklist AE2FC drop and packet, and Chisel stones from Recycler (#2222)
* Fix recycler blacklist being sensitive to NBT
* Blacklist AE2FC drop and packet, and Chisel stones
* fix class loader issue
* Add detailed logging for ME hatches (#2224)
* Fix overclock calculator calculating eu/t use for ulv recipe wrong on certain parallel (#2225)
* fix overclock calculator calculating eu/t use for ulv recipe wrong on certain parallel
* make formula into its own method
* Fix drilling rigs, plants and concrete backfiller to fail with multiple energy hatches (#2227)
* max-1-energy-hatch-in-drilling-rigs.-plants-and-concrete-backfiller
* spotlessApply (#2228)
Co-authored-by: GitHub GTNH Actions <>
* revert
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* clear stale crafting input bus list (#2233)
* add ability to remove item data and use it for clay (#2229)
* Update buildscript (#2232)
* Fix server crash with RecipeFilter (#2231)
* Fix server crash with RecipeFilter
* Make client send filtered machines to server
* Use mUniqueIdentifier
* Fix a NPE w/ injecting into super/quantum chests (#2234)
When simulating an injection, if the stackSize > chest's capacity, it
causes a NPE when the internal chest is empty.
Also fixes a potential bug when void overflow is set; the chest should
return null in such a scenario regardless of simulation/modulation.
* Fix lag caused by getRecipeMap for PA (#2236)
* Experimental fix to prevent infinite loop in Grid destruction (#2235)
Co-authored-by: Firenoo <49818773+firenoo@users.noreply.github.com>
* Fix ME Output Bus and Crafting Input Bus overflow when save/load (#2238)
* Remove fire display from singleblock generator (#2240)
* Fix some output slots allowing insertion (#2230)
* fix overlay zfighting by disable depth test (#2226)
* Crafting input - Optimize isEmpty check to reduce lag (#2239)
* Optimize isEmpty check
* rearrage
* remove broken hsla recipe (#2241)
* Correct PCB Factory Energy Hatch description (#2237)
* Correct PCB Factory Energy Hatch description
Changes the PCB factory description (the one seen when holding shift) which currently says "Energy Hatches: 1+"
I believe this is incorrect and that the correct description is 1-2 energy hatches or 1 TT energy hatch.
I believe the PCB factory uses this, which checks for 1-2 or 1 TT:
public boolean checkExoticAndNormalEnergyHatches() {
if (mExoticEnergyHatches.isEmpty() && mEnergyHatches.isEmpty()) {
return false;
}
if (!mExoticEnergyHatches.isEmpty()) {
if (!mEnergyHatches.isEmpty()) {
return false;
}
if (mExoticEnergyHatches.size() != 1) {
return false;
}
}
return mEnergyHatches.size() <= 2;
}
* gradlew spotlessApply
* Correct file name on resource pack guide (#2242)
* Fix GT_RecipeConstants.Fuel (#2243)
* Update text (#2246)
* Fix startup tier for fusion NEI (#2249)
* Update the conditionals buttons and tooltips on covers to reflect their actual effects (#2244)
* Update redstone buttons and tooltips to better reflect actual use
* Spotless Apply
* Update GT_Cover_FluidRegulator.java
* Update GT_Cover_FluidRegulator.java
* Typo fix, Icon Improved and interactive blocking ui
- Fixed a typo in the world machine
- Fixed double button situation for conveyor belts.
- There was never any issue, the testing methodology gave me invalid results.
- Conveyor behaviour is in line with all the other covers affected by this PR/Branch.
- Updated icon for the machine state to be a miniature machine controller cover.
- Made the block/allow input section more interactive in order to better reflect the actual effect of these buttons.
- In import mode, it actually blocks the machine from outputting from that side.
* typos
I can't write to save myself sometimes
* Better text alignment
- Better text alignment
* fix typos
I swear I can't write to save myself.
---------
Co-authored-by: Martin Robertz <dream-master@gmx.net>
* Fix Orichalcum and Shadowiron smelting (#2251)
* fix orichalcum and shadowiron smelting
* add Alduorite and Chrysotile
* Fix tier display for Fusion NEI header (#2250)
* fix ulv recipes being broken again when under 1 tick calculation is taken (#2254)
* change way to fix zfighting (#2253)
* Crafting input hatches QoLs (#2200)
* Fixes + Detect Inventory Slot Changes
* support rename + check for updates
* add back onChangeListener + fix npe
* ICustomNameObject TileEntity
* Fix NPEs
* Use IInterfaceTerminalSupport
* fix
* register
* dep
* spotless
* General Crafting Input Hatch QoL fixes (#2212)
* feat: refactor naming && include circuit and catalyst in default name
* feat: add 4 more slot to solve my ocd
* fix: formatting
* feat: migrate from 4x8 to 4x9
* spotlessApply (#2213)
Co-authored-by: GitHub GTNH Actions <>
* QoLs
* 9 manual items
* spotless
* feat: open master GUI when used, without holding a data-stick (#2221)
* fix destpos
* optimize empty check
* Fix error when fluidInventory.size() == 0
If the fluidInventory size is 0, there is no element to get. Add a check
for it.
* name in waila + fix int overflow
* unnecssary super
* update deps
---------
Co-authored-by: Fox_white <39846845+foxwhite25@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Firenoo <49818773+firenoo@users.noreply.github.com>
Co-authored-by: Martin Robertz <dream-master@gmx.net>
* Use real stack limit (#2256)
* Fix incorrect data stick behaviors for hatches (#2257)
* Fix pcb factory not applying its roughness multiplier when it doesn't OC (#2258)
* fix PCB Factory not applying its roughness multiplier when it doesn't do any overclocks
* spotless
* Remove duplicate obsidian long rod (#2259)
* disable gt obsidian long rod
* cleaner code
* Add hazmat to ThaumicBoots (#2260)
* Add hazmat to ThaumicBoots
does what it says
* fixed
* fix item names (#2263)
* Fix renaming recipe check might ignore NBT equality (#2261)
* Fix GPL ignoring if the recipe is allowed to be cached (#2262)
* Added bricked blast furnace recipe progress to waila. (#2265)
* Added bricked blast furnace recipe progress to waila.
* fixed formatting issues.
* Fix cutter recipes not being added (#2271)
* add processing task
* clean up item logic host
* temporary fix for GT_StructrureMuTE
* use j9+ feature on pollution task
* prepare complex parallel logic for transition
* feature to ProcessingLogicHost
* fix up multiblock bases
* add processing logic for each multi to prepare for transition
* spotless
* removed debug text from wailaBody of GT_MetaTileEntity_Hatch_CraftingInput_ME (#2272)
* Proper recipe selection for output overflow in LCR and other multiblocks (#2247)
* Implement Stream<FindRecipeResult> findRecipesWithResult for GT_RecipeMap
* Change ProcessingLogic.process to actually use new findRecipesWithResult
* Change ProcessingLogic.process to start finding something only for OUTPUT_FULL result
* Refactor ProcessingLogic.process to make logic more readable
* Replace while with for loop, remove NOT_FOUND return in end of findRecipesWithResult
* Apply spotless
* Make findRecipe use findRecipes, add annotation to GT_Recipe and FindRecipeResult for processRecipe and make method protected, replace wildcard imports
* Remake isRecipeWithOutputFullFound
* Add @Nonnull to methods
* Apply spotless
* Remove Stream version of findRecipeWithResult, replace with predicate one. Add GT_Predicated_Recipe_Map class for utilizing this method. Changes some existent recipe maps to inherit from base class.
* Remove GT_Predicated_Recipe_Map, add Predicate directly to GT_Recipe_Map#findRecipeWithResult. Add AdvancedRecipeValidatorPredicate and FindRecipeWithAdvancedValidatorResult to allow store validation calculations for further use and proper errors displaying.
* Fix InsufficientVoltage errors
* Changes according to review comments. Integrate FindRecipeWithAdvancedValidatorResult to FindRecipeResult, rename AdvancedRecipeValidatorPredicate, encapsulate AdvancedRecipeValidatorPredicate fields, fixes some typos, etc
* Moves InsufficientVoltage check to GT_ParallelHelper. Removes FindRecipeResult#State#INSUFFICIENT_VOLTAGE
* Return an old findRecipeWithResult
* Renames things, call old methods for singleblocks
* Renames things, makes FindRecipeResult ctor private
* Apply spotless
* Move RecipeValidator, fix comments typos
* update deps
* fix up complex processing logic
* add a getter for voiding mode
* fix getAccessibleSlotsFromSide being wrong sometimes
* allow for subtraction of a specific item
* use long for amount
* add a setter for machine host
* initial work on finding recipes and input consumption
* Deprecate PA by removing its controller recipe (#2273)
* Restore PA controller recipe (#2276)
* Restore PA controller recipe
* Remove duplicated recipe
* Add optional description to input hatch constructors (#2278)
* mini fix (#2204)
* [chore] Bump fallback version to 44 (#2274)
* find recipe in theory working
* add some helper methods to inventory logics
* update deps
* use collect not toList
* fix loading crash
* fix complex processing logic using wrong find recipe
* fix up everything and get recipe finding working
* annotate and clean up methods
* spotless
* save things to nbt
* input separation for mutes and fully working processing
* apply mute mode on processing logic
* clean up overrides
---------
Co-authored-by: chochem <40274384+chochem@users.noreply.github.com>
Co-authored-by: miozune <miozune@gmail.com>
Co-authored-by: Pxx500 <81298696+Pxx500@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Glease <4586901+Glease@users.noreply.github.com>
Co-authored-by: firenoo <49818773+firenoo@users.noreply.github.com>
Co-authored-by: Martin Robertz <dream-master@gmx.net>
Co-authored-by: Harry <harryyunull@gmail.com>
Co-authored-by: Eraldoe <Eraldoe@users.noreply.github.com>
Co-authored-by: Jakub <53441451+kuba6000@users.noreply.github.com>
Co-authored-by: Connor-Colenso <52056774+Connor-Colenso@users.noreply.github.com>
Co-authored-by: Guillaume Mercier <C0bra5@users.noreply.github.com>
Co-authored-by: Fox_white <39846845+foxwhite25@users.noreply.github.com>
Co-authored-by: Alastors <78517796+Alastors@users.noreply.github.com>
Co-authored-by: Kyium <43573052+Kyium@users.noreply.github.com>
Co-authored-by: SKProCH <29896317+SKProCH@users.noreply.github.com>
Co-authored-by: Sampsa <69092953+S4mpsa@users.noreply.github.com>
Co-authored-by: Jaiden Baker <jaidencolebaker@gmail.com>
* address minecraft's reviews from #2283
* Refactor MuTE processing logic (#2301) -fix conflicts
* Fix void protection for mutes (#2298) - fix conflicts
* initial variables
* implement working void protection on items and fluids
* Adds a Simple PowerOutput task and cleans up some of the code. (#2303)
* create a power output task which can be used for dynamos
* refactor the controllers and clean up
* add some documentation to power logic
* make a wireless network manager class instead of using an interface
* clean up and add documentation.
* setAmperage to setMaxAmperage
* fix comment
* remove IGlobalWirelessEnergy usage
* getAmperage -> getMaxAmperage
* add todo for future
* Cleanup MuTEMaster code (#2282)
* exit early
* spotless
* better side checking
* make if blocks mutually exclusive
* more exit early
* convert nested ternary operators into if blocks
* remove dead code
* collapse nested if blocks
* add todo to break verylong condition into much smaller ones
* spotless apply
* collapsing nested if blocks and more exit early
* spotless apply
* extract try/catch block to its own utility method
* break down this unreadable condition
* boolean magic (1/5)
* boolean magic (2/5)
Also corrected some logic on the player null check, we want it to be non null
* boolean magic (3/5)
* boolean magic (4/5)
* boolean magic (5/5)
* remove todo
* Fix logic
---------
Co-authored-by: Jason Mitchell <jason@puzzle.io>
Co-authored-by: BlueWeabo <76872108+BlueWeabo@users.noreply.github.com>
* Clean up a lil bit and fix some issues with MuTEs (#2316)
* clean up fixes
* actual fix and remove useless if
* Rework MuTEGUI structure (#2429) - fix conflicts`
Merged to rebase MuTEMaster and fix any non-compile errors and game not launching in there
* some docs on a few methods
* innitial GUI class
* try to implement guis
* almost working - fix comflict
* add UIBuildContext to getGUI method
* make it compile
* sketch gui - fix conflict
* compile and spotless
* add config option to enabling MuTEs
* Spotless apply for branch feature/MuTEMaster for #2431 (#2432)
spotlessApply
Co-authored-by: GitHub GTNH Actions <>
* address reviews on broken processing logic
* spotless
* fix doc and review
---------
Co-authored-by: Maxim <maxim235@gmx.de>
Co-authored-by: RIONDY 'POPlol333' Adam <76914762+POPlol333@users.noreply.github.com>
Co-authored-by: Jason Mitchell <mitchej@gmail.com>
Co-authored-by: Daniel Mendes <70096037+Steelux8@users.noreply.github.com>
Co-authored-by: kstvr32 <109012629+kstvr32@users.noreply.github.com>
Co-authored-by: TheEpicGamer274 <102255081+TheEpicGamer274@users.noreply.github.com>
Co-authored-by: miozune <miozune@gmail.com>
Co-authored-by: chochem <40274384+chochem@users.noreply.github.com>
Co-authored-by: Pxx500 <81298696+Pxx500@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Glease <4586901+Glease@users.noreply.github.com>
Co-authored-by: firenoo <49818773+firenoo@users.noreply.github.com>
Co-authored-by: Martin Robertz <dream-master@gmx.net>
Co-authored-by: Harry <harryyunull@gmail.com>
Co-authored-by: Eraldoe <Eraldoe@users.noreply.github.com>
Co-authored-by: Jakub <53441451+kuba6000@users.noreply.github.com>
Co-authored-by: Connor-Colenso <52056774+Connor-Colenso@users.noreply.github.com>
Co-authored-by: Guillaume Mercier <C0bra5@users.noreply.github.com>
Co-authored-by: Fox_white <39846845+foxwhite25@users.noreply.github.com>
Co-authored-by: Alastors <78517796+Alastors@users.noreply.github.com>
Co-authored-by: Kyium <43573052+Kyium@users.noreply.github.com>
Co-authored-by: SKProCH <29896317+SKProCH@users.noreply.github.com>
Co-authored-by: Sampsa <69092953+S4mpsa@users.noreply.github.com>
Co-authored-by: Jaiden Baker <jaidencolebaker@gmail.com>
Co-authored-by: boubou19 <miisterunknown@gmail.com>
Co-authored-by: Jason Mitchell <jason@puzzle.io>
Diffstat (limited to 'src/main/java/gregtech/api')
73 files changed, 5002 insertions, 3812 deletions
diff --git a/src/main/java/gregtech/api/GregTech_API.java b/src/main/java/gregtech/api/GregTech_API.java index c5e27aebca..1f936f3119 100644 --- a/src/main/java/gregtech/api/GregTech_API.java +++ b/src/main/java/gregtech/api/GregTech_API.java @@ -71,6 +71,7 @@ import gregtech.api.util.GT_Log; import gregtech.api.util.GT_ModHandler; import gregtech.api.util.GT_OreDictUnificator; import gregtech.api.util.GT_Utility; +import gregtech.api.util.item.ItemHolder; import gregtech.api.world.GT_Worldgen; import gregtech.common.GT_DummyWorld; import gregtech.common.items.GT_IntegratedCircuit_Item; @@ -107,8 +108,8 @@ public class GregTech_API { /** * Fixes the HashMap Mappings for ItemStacks once the Server started */ - public static final Collection<Map<? extends GT_ItemStack, ?>> sItemStackMappings = new ArrayList<>(); - public static final Collection<SetMultimap<? extends GT_ItemStack, ?>> itemStackMultiMaps = new ArrayList<>(); + public static final Collection<Map<? extends ItemHolder, ?>> sItemStackMappings = new ArrayList<>(); + public static final Collection<SetMultimap<? extends ItemHolder, ?>> itemStackMultiMaps = new ArrayList<>(); /** * The MetaTileEntity-ID-List-Length diff --git a/src/main/java/gregtech/api/enums/GT_Values.java b/src/main/java/gregtech/api/enums/GT_Values.java index 98d9e5a176..418bf2d14c 100644 --- a/src/main/java/gregtech/api/enums/GT_Values.java +++ b/src/main/java/gregtech/api/enums/GT_Values.java @@ -289,7 +289,7 @@ public class GT_Values { public static final String COLOR = "gt.color", // Integer COVERS = "gt.covers", // String CUSTOM_NAME = "name", // String - DISPAY = "gt.display", // String + DISPLAY = "gt.display", // String TIER = "gt.tier", // Number FACING = "gt.facing", // Byte LOCK_UPGRADE = "gt.locked", // Boolean @@ -322,6 +322,7 @@ public class GT_Values { BURN_TIME_LEFT = "gt.burn.time.left", // Number TOTAL_BURN_TIME = "gt.total.burn.time", // Number ALLOWED_WORK = "gt.allowed.work", // Boolean + TASKS = "gt.tasks", // Compound // MultiBlock STRUCTURE_OK = "gt.structure.ok", ROTATION = "gt.eRotation", FLIP = "gt.eFlip", TARGET = "gt.target", // Boolean @@ -337,13 +338,14 @@ public class GT_Values { UPGRADE_INVENTORIES_INPUT = "gt.invlist.upg.in", // NBT List UPGRADE_INVENTORIES_OUTPUT = "gt.invlist.upg.out", // NBT List UPGRADE_TANK_CAPACITY = "gt.tank.cap.upg", // Long + UPGRADE_TANK_COUNT = "gt.tank.ct.upg", // Int UPGRADE_TANK_CAPACITY_MULTIPLIER = "gt.tank.cap.mult.upg", // Long UPGRADE_TANK_UUID = "gt.tankuuid.upg", // String UPGRADE_TANK_NAME = "gt.tankname.upg", // String UPGRADE_TANKS_INPUT = "gt.tanklist.upg.in", // NBT List UPGRADE_TANKS_OUTPUT = "gt.tanklist.upg.out", // NBT List - UPGRADE_TANKS_COUNT = "gt.tankcount.upg", // Int UPGRADE_TANKS_PREFIX = "gt.tank.upg", // NBT Tag + UPGRADE_AMPERAGE = "gt.amp.upg", // Long SEPARATE_INPUTS = "gt.separate.inputs", // Boolean VOIDING_MODE = "gt.voiding.mode", // String BATCH_MODE = "gt.batch.mode", // Boolean @@ -490,6 +492,11 @@ public class GT_Values { */ public static boolean debugWorldData = false; /** + * Parameter if multi tile entities (MuTEs) should be enabled in the pack. Turned off by default until + * implementation is done. + */ + public static boolean enableMultiTileEntities = false; + /** * Number of ticks between sending sound packets to clients for electric machines. Default is 1.5 seconds. Trying to * mitigate lag and FPS drops. */ @@ -606,6 +613,7 @@ public class GT_Values { + "minecraft7771"; public static final String AuthorQuerns = "Author: " + EnumChatFormatting.RED + "Querns"; + public static final String AuthorTheEpicGamer274 = "Author: " + "TheEpicGamer274"; // 7.5F comes from GT_Tool_Turbine_Large#getBaseDamage() given huge turbines are the most efficient now. public static double getMaxPlasmaTurbineEfficiencyFromMaterial(Materials material) { diff --git a/src/main/java/gregtech/api/enums/InventoryType.java b/src/main/java/gregtech/api/enums/InventoryType.java new file mode 100644 index 0000000000..f8e3c47741 --- /dev/null +++ b/src/main/java/gregtech/api/enums/InventoryType.java @@ -0,0 +1,7 @@ +package gregtech.api.enums; + +public enum InventoryType { + Input, + Output, + Both; +} diff --git a/src/main/java/gregtech/api/gui/GUIHost.java b/src/main/java/gregtech/api/gui/GUIHost.java new file mode 100644 index 0000000000..bbb94317c4 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GUIHost.java @@ -0,0 +1,56 @@ +package gregtech.api.gui; + +import java.util.Objects; + +import javax.annotation.Nonnull; + +import net.minecraft.item.ItemStack; + +import com.gtnewhorizons.modularui.api.screen.ITileWithModularUI; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; + +public interface GUIHost extends ITileWithModularUI { + + @Nonnull + @Override + default ModularWindow createWindow(UIBuildContext uiContext) { + Objects.requireNonNull(uiContext); + GUIProvider<?> gui = getGUI(uiContext); + return gui.openGUI(uiContext); + } + + /** + * Width of the GUI when its being displayed + */ + default int getWidth() { + return 170; + } + + default int getHeight() { + return 192; + } + + @Nonnull + GUIProvider<?> getGUI(@Nonnull UIBuildContext uiContext); + + ItemStack getAsItem(); + + String getMachineName(); + + default boolean hasItemInput() { + return true; + } + + default boolean hasItemOutput() { + return true; + } + + default boolean hasFluidInput() { + return true; + } + + default boolean hasFluidOutput() { + return true; + } +} diff --git a/src/main/java/gregtech/api/gui/GUIProvider.java b/src/main/java/gregtech/api/gui/GUIProvider.java new file mode 100644 index 0000000000..6fec4aa52a --- /dev/null +++ b/src/main/java/gregtech/api/gui/GUIProvider.java @@ -0,0 +1,38 @@ +package gregtech.api.gui; + +import java.util.Objects; + +import javax.annotation.Nonnull; + +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.ModularWindow.Builder; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; + +public abstract class GUIProvider<T extends GUIHost> { + + @Nonnull + protected final T host; + + public GUIProvider(@Nonnull T host) { + this.host = host; + } + + @Nonnull + public ModularWindow openGUI(@Nonnull UIBuildContext uiContext) { + Builder builder = Objects.requireNonNull(ModularWindow.builder(host.getWidth(), host.getHeight())); + if (shouldBindPlayerInventory()) { + builder.bindPlayerInventory(uiContext.getPlayer()); + } + attachSynchHandlers(builder, uiContext); + addWidgets(builder, uiContext); + return Objects.requireNonNull(builder.build()); + } + + protected abstract void attachSynchHandlers(@Nonnull Builder builder, @Nonnull UIBuildContext uiContext); + + protected abstract void addWidgets(@Nonnull Builder builder, @Nonnull UIBuildContext uiContext); + + protected boolean shouldBindPlayerInventory() { + return true; + } +} diff --git a/src/main/java/gregtech/api/interfaces/IGlobalWirelessEnergy.java b/src/main/java/gregtech/api/interfaces/IGlobalWirelessEnergy.java index be4db5412a..47c03743a5 100644 --- a/src/main/java/gregtech/api/interfaces/IGlobalWirelessEnergy.java +++ b/src/main/java/gregtech/api/interfaces/IGlobalWirelessEnergy.java @@ -1,25 +1,25 @@ package gregtech.api.interfaces; -import static gregtech.common.misc.GlobalVariableStorage.GlobalEnergy; -import static gregtech.common.misc.GlobalVariableStorage.GlobalEnergyName; -import static gregtech.common.misc.GlobalVariableStorage.GlobalEnergyTeam; - import java.math.BigInteger; import java.util.UUID; import net.minecraft.entity.player.EntityPlayer; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; -import gregtech.common.misc.GlobalEnergyWorldSavedData; +import gregtech.common.misc.WirelessNetworkManager; // If you are adding very late-game content feel free to tap into this interface. // The eventual goal is to bypass laser/dynamo stuff and have energy deposited directly from ultra-endgame // multi-blocks directly into the users network. +/** + * Use WirelessNetworkManager instead + */ +@Deprecated public interface IGlobalWirelessEnergy { // User 0 will join user 1 by calling this function. They will share the same energy network. default void joinUserNetwork(String user_uuid_0, String user_uuid_1) { - GlobalEnergyTeam.put(user_uuid_0, user_uuid_1); + WirelessNetworkManager.joinUserNetwork(user_uuid_0, user_uuid_1); } // Adds a user to the energy map if they do not already exist. Otherwise, do nothing. Will also check if the user @@ -27,35 +27,18 @@ public interface IGlobalWirelessEnergy { // tick of a machine being placed only. default void strongCheckOrAddUser(EntityPlayer user) { - strongCheckOrAddUser( + WirelessNetworkManager.strongCheckOrAddUser( user.getUniqueID() .toString(), user.getDisplayName()); } default void strongCheckOrAddUser(UUID user_uuid, String user_name) { - strongCheckOrAddUser(user_uuid.toString(), user_name); + WirelessNetworkManager.strongCheckOrAddUser(user_uuid.toString(), user_name); } default void strongCheckOrAddUser(String user_uuid, String user_name) { - - // Check if the user has a team. Add them if not. - GlobalEnergyTeam.putIfAbsent(user_uuid, user_uuid); - - // Check if the user is in the global energy map. - GlobalEnergy.putIfAbsent(user_uuid, BigInteger.ZERO); - - // If the username linked to the users fixed uuid is not equal to their current name then remove it. - // This indicates that their username has changed. - if (!(GlobalEnergyName.getOrDefault(user_uuid, "") - .equals(user_name))) { - String old_name = GlobalEnergyName.get(user_uuid); - GlobalEnergyName.remove(old_name); - } - - // Add UUID -> Name, Name -> UUID. - GlobalEnergyName.put(user_name, user_uuid); - GlobalEnergyName.put(user_uuid, user_name); + WirelessNetworkManager.strongCheckOrAddUser(user_uuid, user_name); } // ------------------------------------------------------------------------------------ @@ -64,30 +47,7 @@ public interface IGlobalWirelessEnergy { // BigIntegers have much slower operations than longs/ints. You should call these methods // as infrequently as possible and bulk store values to add to the global map. default boolean addEUToGlobalEnergyMap(String userUUID, BigInteger EU) { - - // Mark the data as dirty and in need of saving. - try { - GlobalEnergyWorldSavedData.INSTANCE.markDirty(); - } catch (Exception exception) { - System.out.println("COULD NOT MARK GLOBAL ENERGY AS DIRTY IN ADD EU"); - exception.printStackTrace(); - } - - // Get the team UUID. Users are by default in a team with a UUID equal to their player UUID. - String teamUUID = GlobalEnergyTeam.getOrDefault(userUUID, userUUID); - - // Get the teams total energy stored. If they are not in the map, return 0 EU. - BigInteger totalEU = GlobalEnergy.getOrDefault(teamUUID, BigInteger.ZERO); - totalEU = totalEU.add(EU); - - // If there is sufficient EU then complete the operation and return true. - if (totalEU.signum() >= 0) { - GlobalEnergy.put(teamUUID, totalEU); - return true; - } - - // There is insufficient EU so cancel the operation and return false. - return false; + return WirelessNetworkManager.addEUToGlobalEnergyMap(userUUID, EU); } default boolean addEUToGlobalEnergyMap(UUID user_uuid, BigInteger EU) { @@ -113,28 +73,20 @@ public interface IGlobalWirelessEnergy { // ------------------------------------------------------------------------------------ default BigInteger getUserEU(String user_uuid) { - return GlobalEnergy.getOrDefault(GlobalEnergyTeam.getOrDefault(user_uuid, user_uuid), BigInteger.ZERO); + return WirelessNetworkManager.getUserEU(user_uuid); } // This overwrites the EU in the network. Only use this if you are absolutely sure you know what you are doing. default void setUserEU(String user_uuid, BigInteger EU) { - // Mark the data as dirty and in need of saving. - try { - GlobalEnergyWorldSavedData.INSTANCE.markDirty(); - } catch (Exception exception) { - System.out.println("COULD NOT MARK GLOBAL ENERGY AS DIRTY IN SET EU"); - exception.printStackTrace(); - } - - GlobalEnergy.put(GlobalEnergyTeam.get(user_uuid), EU); + WirelessNetworkManager.setUserEU(user_uuid, EU); } default String GetUsernameFromUUID(String uuid) { - return GlobalEnergyName.getOrDefault(GlobalEnergyTeam.getOrDefault(uuid, ""), ""); + return WirelessNetworkManager.getUsernameFromUUID(uuid); } default String getUUIDFromUsername(String username) { - return GlobalEnergyTeam.getOrDefault(GlobalEnergyName.getOrDefault(username, ""), ""); + return WirelessNetworkManager.getUUIDFromUsername(username); } /** @@ -143,24 +95,14 @@ public interface IGlobalWirelessEnergy { * @return */ default String getRawUUIDFromUsername(String username) { - return GlobalEnergyName.getOrDefault(username, ""); + return WirelessNetworkManager.getRawUUIDFromUsername(username); } static void clearGlobalEnergyInformationMaps() { - // Do not use this unless you are 100% certain you know what you are doing. - GlobalEnergy.clear(); - GlobalEnergyName.clear(); - GlobalEnergyTeam.clear(); + WirelessNetworkManager.clearGlobalEnergyInformationMaps(); } default String processInitialSettings(final IGregTechTileEntity machine) { - - // UUID and username of the owner. - final String UUID = machine.getOwnerUuid() - .toString(); - final String name = machine.getOwnerName(); - - strongCheckOrAddUser(UUID, name); - return UUID; + return WirelessNetworkManager.processInitialSettings(machine); } } diff --git a/src/main/java/gregtech/api/interfaces/tileentity/IEnergyConnected.java b/src/main/java/gregtech/api/interfaces/tileentity/IEnergyConnected.java index f866092d38..91a9759e47 100644 --- a/src/main/java/gregtech/api/interfaces/tileentity/IEnergyConnected.java +++ b/src/main/java/gregtech/api/interfaces/tileentity/IEnergyConnected.java @@ -1,5 +1,9 @@ package gregtech.api.interfaces.tileentity; +import java.util.Objects; + +import javax.annotation.Nonnull; + import net.minecraft.tileentity.TileEntity; import net.minecraftforge.common.util.ForgeDirection; @@ -53,24 +57,25 @@ public interface IEnergyConnected extends IColoredTileEntity { */ final class Util { + // TODO: Deduplicate code by rewokring the Enet system using the GTCEu one as inspiration - BlueWeabo /** * Emits Energy to the E-net. Also compatible with adjacent IC2 TileEntities. * * @return the used Amperage. */ - public static long emitEnergyToNetwork(long aVoltage, long aAmperage, IEnergyConnected aEmitter) { - long rUsedAmperes = 0; - if (!(aEmitter instanceof IHasWorldObjectAndCoords emitterTile)) { + public static long emitEnergyToNetwork(long voltage, long amperage, IEnergyConnected emitter) { + long usedAmperes = 0; + if (!(emitter instanceof IHasWorldObjectAndCoords emitterTile)) { return 0; } for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { - if (rUsedAmperes > aAmperage) break; - if (!aEmitter.outputsEnergyTo(side)) { + if (usedAmperes > amperage) break; + if (!emitter.outputsEnergyTo(side)) { continue; } - final ForgeDirection oppositeSide = side.getOpposite(); + final ForgeDirection oppositeSide = Objects.requireNonNull(side.getOpposite()); final TileEntity tTileEntity = emitterTile.getTileEntityAtSide(side); if (tTileEntity instanceof PowerLogicHost host) { @@ -79,28 +84,95 @@ public interface IEnergyConnected extends IColoredTileEntity { continue; } - rUsedAmperes += logic.injectEnergy(aVoltage, aAmperage - rUsedAmperes); + usedAmperes += logic.injectEnergy(voltage, amperage - usedAmperes); } else if (tTileEntity instanceof IEnergyConnected energyConnected) { - if (aEmitter.getColorization() >= 0) { + if (emitter.getColorization() >= 0) { final byte tColor = energyConnected.getColorization(); - if (tColor >= 0 && tColor != aEmitter.getColorization()) continue; + if (tColor >= 0 && tColor != emitter.getColorization()) continue; } - rUsedAmperes += energyConnected.injectEnergyUnits(oppositeSide, aVoltage, aAmperage - rUsedAmperes); + usedAmperes += energyConnected.injectEnergyUnits(oppositeSide, voltage, amperage - usedAmperes); } else if (tTileEntity instanceof IEnergySink sink) { - if (sink.acceptsEnergyFrom((TileEntity) aEmitter, oppositeSide)) { - while (aAmperage > rUsedAmperes && sink.getDemandedEnergy() > 0 - && sink.injectEnergy(oppositeSide, aVoltage, aVoltage) < aVoltage) rUsedAmperes++; + if (sink.acceptsEnergyFrom((TileEntity) emitter, oppositeSide)) { + while (amperage > usedAmperes && sink.getDemandedEnergy() > 0 + && sink.injectEnergy(oppositeSide, voltage, voltage) < voltage) usedAmperes++; } } else if (GregTech_API.mOutputRF && tTileEntity instanceof IEnergyReceiver receiver) { - final int rfOut = GT_Utility.safeInt(aVoltage * GregTech_API.mEUtoRF / 100); + final int rfOut = GT_Utility.safeInt(voltage * GregTech_API.mEUtoRF / 100); if (receiver.receiveEnergy(oppositeSide, rfOut, true) == rfOut) { receiver.receiveEnergy(oppositeSide, rfOut, false); - rUsedAmperes++; + usedAmperes++; + } + } + } + return usedAmperes; + } + + /** + * Same as {@link #emitEnergyToNetwork(long, long, IEnergyConnected)}, but instead we remove the energy directly from the logic itself. + * @param emitter The host, which is trying to emit energy in the network + * @param outputSide side from where energy is being outputted to. If its {@link ForgeDirection#UNKNOWN} then it doesn't emit energy to the network + */ + public static void emitEnergyToNetwork(@Nonnull final PowerLogicHost emitter, @Nonnull final ForgeDirection outputSide) { + if (outputSide == ForgeDirection.UNKNOWN) return; + final PowerLogic emitterLogic = emitter.getPowerLogic(); + long usedAmperes = 0; + long voltage = emitterLogic.getVoltage(); + long amperage = emitterLogic.getMaxAmperage(); + if (!(emitter instanceof final IHasWorldObjectAndCoords emitterTile)) { + return; + } + // We need to make sure we can actually output energy on this side. This is more of a safety check. + if (emitter.getPowerLogic(outputSide) == null) { + return; + } + + final ForgeDirection oppositeSide = Objects.requireNonNull(outputSide.getOpposite()); + final TileEntity tileEntity = emitterTile.getTileEntityAtSide(outputSide); + if (tileEntity instanceof PowerLogicHost host) { + + final PowerLogic logic = host.getPowerLogic(oppositeSide); + if (logic == null || logic.isEnergyReceiver()) { + return; + } + + usedAmperes += logic.injectEnergy(voltage, amperage); + emitterLogic.removeEnergyUnsafe(usedAmperes * voltage); + return; + } + + if (tileEntity instanceof IEnergyConnected energyConnected) { + if (emitter instanceof IColoredTileEntity coloredEmitter && coloredEmitter.getColorization() >= 0) { + final byte tColor = energyConnected.getColorization(); + if (tColor >= 0 && tColor != coloredEmitter.getColorization()) { + return; } } + usedAmperes += energyConnected.injectEnergyUnits(oppositeSide, voltage, amperage - usedAmperes); + emitterLogic.removeEnergyUnsafe(usedAmperes * voltage); + return; + } + + if (tileEntity instanceof IEnergySink sink) { + if (sink.acceptsEnergyFrom((TileEntity) emitter, oppositeSide)) { + while (amperage > usedAmperes && sink.getDemandedEnergy() > 0 + && sink.injectEnergy(oppositeSide, voltage, voltage) < voltage) { + usedAmperes++; + } + emitterLogic.removeEnergyUnsafe(usedAmperes * voltage); + return; + } + } + + if (GregTech_API.mOutputRF && tileEntity instanceof IEnergyReceiver receiver) { + final int rfOut = GT_Utility.safeInt(voltage * GregTech_API.mEUtoRF / 100); + if (receiver.receiveEnergy(oppositeSide, rfOut, true) == rfOut) { + receiver.receiveEnergy(oppositeSide, rfOut, false); + usedAmperes++; + emitterLogic.removeEnergyUnsafe(usedAmperes * voltage); + return; + } } - return rUsedAmperes; } } } diff --git a/src/main/java/gregtech/api/interfaces/tileentity/IMachineProgress.java b/src/main/java/gregtech/api/interfaces/tileentity/IMachineProgress.java index bcd213b4ff..517f4a0cd3 100644 --- a/src/main/java/gregtech/api/interfaces/tileentity/IMachineProgress.java +++ b/src/main/java/gregtech/api/interfaces/tileentity/IMachineProgress.java @@ -16,7 +16,7 @@ public interface IMachineProgress extends IHasWorldObjectAndCoords { int getMaxProgress(); /** - * increases the Progress of the Machine + * Manually increases the Progress of the Machine by vent cover. */ boolean increaseProgress(int aProgressAmountInTicks); @@ -46,6 +46,14 @@ public interface IMachineProgress extends IHasWorldObjectAndCoords { */ boolean isAllowedToWork(); + default void setAllowedToWork(Boolean allowedToWork) { + if (allowedToWork) { + enableWorking(); + } else { + disableWorking(); + } + } + /** * used to control Machines via Redstone Signal Strength by special Covers In case of 0 the Machine is very likely * doing nothing, or is just not being controlled at all. diff --git a/src/main/java/gregtech/api/logic/AbstractProcessingLogic.java b/src/main/java/gregtech/api/logic/AbstractProcessingLogic.java new file mode 100644 index 0000000000..ae78bbacc2 --- /dev/null +++ b/src/main/java/gregtech/api/logic/AbstractProcessingLogic.java @@ -0,0 +1,346 @@ +package gregtech.api.logic; + +import java.util.function.Supplier; + +import javax.annotation.Nonnull; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.interfaces.tileentity.IVoidable; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_ParallelHelper; +import gregtech.api.util.GT_Recipe; + +/** + * Logic class to calculate result of recipe check from inputs. + */ +@SuppressWarnings({ "unused", "UnusedReturnValue" }) +public abstract class AbstractProcessingLogic<P extends AbstractProcessingLogic<P>> { + + protected IVoidable machine; + protected Supplier<RecipeMap<?>> recipeMapSupplier; + protected GT_Recipe lastRecipe; + protected RecipeMap<?> lastRecipeMap; + protected ItemStack[] outputItems; + protected FluidStack[] outputFluids; + protected long calculatedEut; + protected int duration; + protected long availableVoltage; + protected long availableAmperage; + protected int overClockTimeReduction = 1; + protected int overClockPowerIncrease = 2; + protected boolean protectItems; + protected boolean protectFluids; + protected int maxParallel = 1; + protected Supplier<Integer> maxParallelSupplier; + protected int calculatedParallels = 0; + protected int batchSize = 1; + protected float euModifier = 1.0f; + protected float speedBoost = 1.0f; + protected boolean amperageOC = true; + protected boolean isCleanroom; + + // #region Setters + + /** + * Overwrites item output result of the calculation. + */ + public P setOutputItems(ItemStack... itemOutputs) { + this.outputItems = itemOutputs; + return getThis(); + } + + /** + * Overwrites fluid output result of the calculation. + */ + public P setOutputFluids(FluidStack... fluidOutputs) { + this.outputFluids = fluidOutputs; + return getThis(); + } + + public P setIsCleanroom(boolean isCleanroom) { + this.isCleanroom = isCleanroom; + return getThis(); + } + + /** + * Sets max amount of parallel. + */ + public P setMaxParallel(int maxParallel) { + this.maxParallel = maxParallel; + return getThis(); + } + + /** + * Sets method to get max amount of parallel. + */ + public P setMaxParallelSupplier(Supplier<Integer> supplier) { + this.maxParallelSupplier = supplier; + return getThis(); + } + + /** + * Sets batch size for batch mode. + */ + public P setBatchSize(int size) { + this.batchSize = size; + return getThis(); + } + + public P setRecipeMap(RecipeMap<?> recipeMap) { + return setRecipeMapSupplier(() -> recipeMap); + } + + public P setRecipeMapSupplier(Supplier<RecipeMap<?>> supplier) { + this.recipeMapSupplier = supplier; + return getThis(); + } + + public P setEuModifier(float modifier) { + this.euModifier = modifier; + return getThis(); + } + + public P setSpeedBonus(float speedModifier) { + this.speedBoost = speedModifier; + return getThis(); + } + + /** + * Sets machine used for void protection logic. + */ + public P setMachine(IVoidable machine) { + this.machine = machine; + return getThis(); + } + + /** + * Overwrites duration result of the calculation. + */ + public P setDuration(int duration) { + this.duration = duration; + return getThis(); + } + + /** + * Overwrites EU/t result of the calculation. + */ + public P setCalculatedEut(long calculatedEut) { + this.calculatedEut = calculatedEut; + return getThis(); + } + + /** + * Sets voltage of the machine. It doesn't need to be actual voltage (excluding amperage) of the machine; + * For example, most of the multiblock machines set maximum possible input power (including amperage) as voltage + * and 1 as amperage. That way recipemap search will be executed with overclocked voltage. + */ + public P setAvailableVoltage(long voltage) { + availableVoltage = voltage; + return getThis(); + } + + /** + * Sets amperage of the machine. This amperage doesn't involve in EU/t when searching recipemap. + * Useful for preventing tier skip but still considering amperage for parallel. + */ + public P setAvailableAmperage(long amperage) { + availableAmperage = amperage; + return getThis(); + } + + public P setVoidProtection(boolean protectItems, boolean protectFluids) { + this.protectItems = protectItems; + this.protectFluids = protectFluids; + return getThis(); + } + + /** + * Sets custom overclock ratio. 2/4 by default. + * Parameters represent number of bit shift, so 1 -> 2x, 2 -> 4x. + */ + public P setOverclock(int timeReduction, int powerIncrease) { + this.overClockTimeReduction = timeReduction; + this.overClockPowerIncrease = powerIncrease; + return getThis(); + } + + /** + * Sets overclock ratio to 4/4. + */ + public P enablePerfectOverclock() { + return this.setOverclock(2, 2); + } + + /** + * Sets whether the multi should use amperage to OC or not + */ + public P setAmperageOC(boolean amperageOC) { + this.amperageOC = amperageOC; + return getThis(); + } + + /** + * Clears calculated results (and provided machine inputs) to prepare for the next machine operation. + */ + public P clear() { + this.calculatedEut = 0; + this.duration = 0; + this.calculatedParallels = 0; + return getThis(); + } + + // #endregion + + // #region Logic + + /** + * Executes the recipe check: Find recipe from recipemap, Calculate parallel, overclock and outputs. + */ + @Nonnull + public abstract CheckRecipeResult process(); + + /** + * Refreshes recipemap to use. Remember to call this before {@link #process} to make sure correct recipemap is used. + * + * @return Recipemap to use now + */ + protected RecipeMap<?> preProcess() { + RecipeMap<?> recipeMap; + if (recipeMapSupplier == null) { + recipeMap = null; + } else { + recipeMap = recipeMapSupplier.get(); + } + if (lastRecipeMap != recipeMap) { + lastRecipe = null; + lastRecipeMap = recipeMap; + } + + if (maxParallelSupplier != null) { + maxParallel = maxParallelSupplier.get(); + } + + return recipeMap; + } + + /** + * Check has been succeeded, so it applies the recipe and calculated parameters. + * At this point, inputs have been already consumed. + */ + @Nonnull + protected CheckRecipeResult applyRecipe(@Nonnull GT_Recipe recipe, @Nonnull GT_ParallelHelper helper, + @Nonnull GT_OverclockCalculator calculator, @Nonnull CheckRecipeResult result) { + if (recipe.mCanBeBuffered) { + lastRecipe = recipe; + } else { + lastRecipe = null; + } + calculatedParallels = helper.getCurrentParallel(); + + if (calculator.getConsumption() == Long.MAX_VALUE) { + return CheckRecipeResultRegistry.POWER_OVERFLOW; + } + if (calculator.getDuration() == Integer.MAX_VALUE) { + return CheckRecipeResultRegistry.DURATION_OVERFLOW; + } + + calculatedEut = calculator.getConsumption(); + + double finalDuration = calculateDuration(recipe, helper, calculator); + if (finalDuration >= Integer.MAX_VALUE) { + return CheckRecipeResultRegistry.DURATION_OVERFLOW; + } + duration = (int) finalDuration; + + CheckRecipeResult hookResult = onRecipeStart(recipe); + if (!hookResult.wasSuccessful()) { + return hookResult; + } + + outputItems = helper.getItemOutputs(); + outputFluids = helper.getFluidOutputs(); + + return result; + } + + /** + * Override to tweak final duration that will be set as a result of this logic class. + */ + protected double calculateDuration(@Nonnull GT_Recipe recipe, @Nonnull GT_ParallelHelper helper, + @Nonnull GT_OverclockCalculator calculator) { + return calculator.getDuration() * helper.getDurationMultiplierDouble(); + } + + /** + * Override to do additional check for found recipe if needed. + */ + @Nonnull + protected CheckRecipeResult validateRecipe(@Nonnull GT_Recipe recipe) { + return CheckRecipeResultRegistry.SUCCESSFUL; + } + + /** + * Override to perform additional logic when recipe starts. + * + * This is called when the recipe processing logic has finished all + * checks, consumed all inputs, but has not yet set the outputs to + * be produced. Returning a result other than SUCCESSFUL will void + * all inputs! + */ + @Nonnull + protected CheckRecipeResult onRecipeStart(@Nonnull GT_Recipe recipe) { + return CheckRecipeResultRegistry.SUCCESSFUL; + } + + /** + * Override to tweak overclock logic if needed. + */ + @Nonnull + protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe) { + return new GT_OverclockCalculator().setRecipeEUt(recipe.mEUt) + .setAmperage(availableAmperage) + .setEUt(availableVoltage) + .setDuration(recipe.mDuration) + .setSpeedBoost(speedBoost) + .setEUtDiscount(euModifier) + .setAmperageOC(amperageOC) + .setDurationDecreasePerOC(overClockTimeReduction) + .setEUtIncreasePerOC(overClockPowerIncrease); + } + // #endregion + + // #region Getters + + public ItemStack[] getOutputItems() { + return outputItems; + } + + public FluidStack[] getOutputFluids() { + return outputFluids; + } + + public int getDuration() { + return duration; + } + + public long getCalculatedEut() { + return calculatedEut; + } + + public int getCurrentParallels() { + return calculatedParallels; + } + + @SuppressWarnings("unchecked") + @Nonnull + public P getThis() { + return (P) this; + } + + // #endregion +} diff --git a/src/main/java/gregtech/api/logic/ComplexParallelProcessingLogic.java b/src/main/java/gregtech/api/logic/ComplexParallelProcessingLogic.java index 3c7974db9e..72a74ebd04 100644 --- a/src/main/java/gregtech/api/logic/ComplexParallelProcessingLogic.java +++ b/src/main/java/gregtech/api/logic/ComplexParallelProcessingLogic.java @@ -5,180 +5,117 @@ import java.util.stream.LongStream; import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidStack; -import gregtech.api.multitileentity.multiblock.base.Controller; -import gregtech.api.recipe.RecipeMap; -import gregtech.api.util.GT_OverclockCalculator; -import gregtech.api.util.GT_ParallelHelper; -import gregtech.api.util.GT_Recipe; +public class ComplexParallelProcessingLogic<P extends ComplexParallelProcessingLogic<P>> + extends MuTEProcessingLogic<P> { -public class ComplexParallelProcessingLogic { + protected int maxComplexParallels; + protected ItemStack[][] outputItems; + protected FluidStack[][] outputFluids; + protected long[] calculatedEutValues; + protected int[] durations; + protected int[] progresses; - protected Controller<?> tileEntity; - protected RecipeMap<?> recipeMap; - protected boolean hasPerfectOverclock; - protected final int maxComplexParallels; - protected final ItemStack[][] outputItems; - protected final ItemStack[][] inputItems; - protected final FluidStack[][] inputFluids; - protected final FluidStack[][] outputFluids; - protected final long[] availableEut; - protected final long[] eut; - protected final long[] durations; - protected final boolean[] isItemVoidProtected; - protected final boolean[] isFluidVoidProtected; - - public ComplexParallelProcessingLogic(int maxComplexParallels) { - this(null, maxComplexParallels); - } - - public ComplexParallelProcessingLogic(RecipeMap<?> recipeMap, int maxComplexParallels) { + public P setMaxComplexParallel(int maxComplexParallels) { this.maxComplexParallels = maxComplexParallels; - this.recipeMap = recipeMap; - inputItems = new ItemStack[maxComplexParallels][]; - outputItems = new ItemStack[maxComplexParallels][]; - inputFluids = new FluidStack[maxComplexParallels][]; - outputFluids = new FluidStack[maxComplexParallels][]; - eut = new long[maxComplexParallels]; - availableEut = new long[maxComplexParallels]; - durations = new long[maxComplexParallels]; - isItemVoidProtected = new boolean[maxComplexParallels]; - isFluidVoidProtected = new boolean[maxComplexParallels]; - } - - public ComplexParallelProcessingLogic setRecipeMap(RecipeMap<?> recipeMap) { - this.recipeMap = recipeMap; - return this; + reinitializeProcessingArrays(); + return getThis(); } - public ComplexParallelProcessingLogic setInputItems(int index, ItemStack... itemInputs) { + public ItemStack[] getOutputItems(int index) { if (index >= 0 && index < maxComplexParallels) { - inputItems[index] = itemInputs; + return outputItems[index]; } - return this; + return null; } - public ComplexParallelProcessingLogic setInputFluids(int index, FluidStack... inputFluids) { + public FluidStack[] getOutputFluids(int index) { if (index >= 0 && index < maxComplexParallels) { - this.inputFluids[index] = inputFluids; + return outputFluids[index]; } - return this; + return null; } - public ComplexParallelProcessingLogic setTileEntity(Controller<?> tileEntity) { - this.tileEntity = tileEntity; - return this; + @Override + public boolean canWork() { + for (int i = 0; i < maxComplexParallels; i++) { + if (progresses[i] >= durations[i]) { + return machineHost.isAllowedToWork(); + } + } + return false; } - public ComplexParallelProcessingLogic setEut(int index, long eut) { - if (index >= 0 && index < maxComplexParallels) { - availableEut[index] = eut; - } - return this; + @Override + public long getCalculatedEut() { + return LongStream.of(this.calculatedEutValues) + .sum(); } - public ComplexParallelProcessingLogic setVoidProtection(int index, boolean protectItem, boolean protectFluid) { - if (index >= 0 && index < maxComplexParallels) { - isItemVoidProtected[index] = protectItem; - isFluidVoidProtected[index] = protectFluid; - } - return this; + public int getDuration(int index) { + return durations[index]; } - public ComplexParallelProcessingLogic setPerfectOverclock(boolean shouldOverclockPerfectly) { - this.hasPerfectOverclock = shouldOverclockPerfectly; - return this; + public int getProgress(int index) { + return progresses[index]; } - public ComplexParallelProcessingLogic clear() { + @Override + public void progress() { for (int i = 0; i < maxComplexParallels; i++) { - outputItems[i] = null; - outputFluids[i] = null; - durations[i] = 0; - eut[i] = 0; + if (progresses[i] == durations[i]) { + progresses[i] = 0; + durations[i] = 0; + output(i); + continue; + } + progresses[i] = progresses[i] + 1; } - return this; } - public ComplexParallelProcessingLogic clear(int index) { - if (index >= 0 && index < maxComplexParallels) { - inputItems[index] = null; - inputFluids[index] = null; - outputItems[index] = null; - outputFluids[index] = null; - durations[index] = 0; - availableEut[index] = 0; - eut[index] = 0; + @Override + public void startCheck() { + for (int i = 0; i < maxComplexParallels; i++) { + if (durations[i] > 0) continue; + recipeResult = process(); + calculatedEutValues[i] = calculatedEut; + durations[i] = duration; + progresses[i] = 0; + outputItems[i] = getOutputItems(); + outputFluids[i] = getOutputFluids(); } - return this; } - public boolean process(int index) { - if (recipeMap == null) { - return false; - } - GT_Recipe recipe = recipeMap - .findRecipe(tileEntity, false, false, availableEut[index], inputFluids[index], inputItems[index]); - if (recipe == null) { - return false; - } - - GT_ParallelHelper helper = new GT_ParallelHelper().setRecipe(recipe) - .setItemInputs(inputItems[index]) - .setFluidInputs(inputFluids[index]) - .setAvailableEUt(availableEut[index]) - .setMachine(tileEntity, isItemVoidProtected[index], isFluidVoidProtected[index]) - .setConsumption(true) - .setOutputCalculation(true); - - helper.build(); - - if (helper.getCurrentParallel() <= 0) { - return false; - } - - GT_OverclockCalculator calculator = new GT_OverclockCalculator().setRecipeEUt(recipe.mEUt) - .setDuration(recipe.mDuration) - .setEUt(availableEut[index]); + protected void output(int index) { + setOutputItems(getOutputItems(index)); + setOutputFluids(getOutputFluids(index)); + output(); + } - if (hasPerfectOverclock) { - calculator.enablePerfectOC(); + protected void reinitializeProcessingArrays() { + ItemStack[][] oldOutputItems = outputItems; + FluidStack[][] oldOutputFluids = outputFluids; + long[] oldCalculatedEutValues = calculatedEutValues; + int[] oldDurations = durations; + int[] oldProgresses = progresses; + outputItems = new ItemStack[maxComplexParallels][]; + outputFluids = new FluidStack[maxComplexParallels][]; + calculatedEutValues = new long[maxComplexParallels]; + durations = new int[maxComplexParallels]; + progresses = new int[maxComplexParallels]; + for (int i = 0; i < oldOutputItems.length; i++) { + outputItems[i] = oldOutputItems[i]; } - - if (calculator.getConsumption() == Long.MAX_VALUE - 1 || calculator.getDuration() == Integer.MAX_VALUE - 1) { - return false; + for (int i = 0; i < oldOutputFluids.length; i++) { + outputFluids[i] = oldOutputFluids[i]; } - - durations[index] = calculator.getDuration(); - eut[index] = calculator.getConsumption(); - outputItems[index] = helper.getItemOutputs(); - outputFluids[index] = helper.getFluidOutputs(); - - return true; - } - - public long getDuration(int index) { - if (index >= 0 && index < maxComplexParallels) { - return durations[index]; + for (int i = 0; i < oldCalculatedEutValues.length; i++) { + calculatedEutValues[i] = oldCalculatedEutValues[i]; } - return 0; - } - - public long getTotalEU() { - return LongStream.of(eut) - .sum(); - } - - public ItemStack[] getOutputItems(int index) { - if (index >= 0 && index < maxComplexParallels) { - return outputItems[index]; + for (int i = 0; i < oldDurations[i]; i++) { + durations[i] = oldDurations[i]; } - return null; - } - - public FluidStack[] getOutputFluids(int index) { - if (index >= 0 && index < maxComplexParallels) { - return outputFluids[index]; + for (int i = 0; i < oldProgresses.length; i++) { + progresses[i] = oldProgresses[i]; } - return null; } } diff --git a/src/main/java/gregtech/api/logic/ControllerFluidLogic.java b/src/main/java/gregtech/api/logic/ControllerFluidLogic.java new file mode 100644 index 0000000000..211c1c2982 --- /dev/null +++ b/src/main/java/gregtech/api/logic/ControllerFluidLogic.java @@ -0,0 +1,152 @@ +package gregtech.api.logic; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraftforge.common.util.Constants; + +import org.apache.commons.lang3.tuple.Pair; + +/** + * Controller logic for Fluid inventories + * + * @author BlueWeabo + */ +public class ControllerFluidLogic { + + private final Map<UUID, FluidInventoryLogic> inventories = new HashMap<>(); + private final Set<Pair<UUID, FluidInventoryLogic>> unallocatedInventories = new HashSet<>(); + + public void addInventory(@Nonnull UUID id, @Nonnull FluidInventoryLogic inventory) { + Pair<UUID, FluidInventoryLogic> found = checkIfInventoryExistsAsUnallocated(inventory); + if (inventory.isUpgradeInventory() && found != null) { + unallocatedInventories.remove(found); + inventories.put(id, found.getRight()); + return; + } + inventories.put(id, inventory); + } + + @Nonnull + public UUID addInventory(@Nonnull FluidInventoryLogic inventory) { + Pair<UUID, FluidInventoryLogic> found = checkIfInventoryExistsAsUnallocated(inventory); + if (inventory.isUpgradeInventory() && found != null) { + unallocatedInventories.remove(found); + inventories.put(found.getLeft(), found.getRight()); + return Objects.requireNonNull(found.getLeft()); + } + UUID generatedUUID = Objects.requireNonNull(UUID.randomUUID()); + inventories.put(generatedUUID, inventory); + return generatedUUID; + } + + @Nullable + private Pair<UUID, FluidInventoryLogic> checkIfInventoryExistsAsUnallocated( + @Nonnull FluidInventoryLogic inventory) { + if (unallocatedInventories.size() == 0) { + return null; + } + return unallocatedInventories.stream() + .filter( + unallocated -> unallocated.getRight() + .getTier() == inventory.getTier()) + .findFirst() + .get(); + } + + /** + * Removes the inventory with said id and gives it back to be processed if needed. + */ + @Nonnull + public FluidInventoryLogic removeInventory(@Nonnull UUID id) { + return Objects.requireNonNull(inventories.remove(id)); + } + + @Nonnull + public FluidInventoryLogic getAllInventoryLogics() { + return new FluidInventoryLogic( + inventories.values() + .stream() + .map(inv -> inv.getInventory()) + .collect(Collectors.toList())); + } + + @Nonnull + public FluidInventoryLogic getInventoryLogic(@Nullable UUID id) { + if (id == null) return getAllInventoryLogics(); + return Objects.requireNonNull(inventories.getOrDefault(id, getAllInventoryLogics())); + } + + @Nonnull + public Set<Entry<UUID, FluidInventoryLogic>> getAllInventoryLogicsAsEntrySet() { + return Objects.requireNonNull(inventories.entrySet()); + } + + @Nonnull + public String getInventoryDisplayName(@Nullable UUID id) { + if (id == null) return ""; + FluidInventoryLogic logic = inventories.get(id); + if (logic == null) return ""; + String displayName = logic.getDisplayName(); + if (displayName == null) return Objects.requireNonNull(id.toString()); + return displayName; + } + + public void setInventoryDisplayName(@Nullable UUID id, @Nullable String displayName) { + if (id == null) return; + FluidInventoryLogic logic = inventories.get(id); + if (logic == null) return; + logic.setDisplayName(displayName); + } + + @Nonnull + public NBTTagCompound saveToNBT() { + NBTTagCompound nbt = new NBTTagCompound(); + NBTTagList inventoriesNBT = new NBTTagList(); + inventories.forEach((uuid, inventory) -> { + NBTTagCompound inventoryNBT = new NBTTagCompound(); + inventoryNBT.setTag("inventory", inventory.saveToNBT()); + inventoryNBT.setString("uuid", uuid.toString()); + inventoryNBT.setInteger( + "invSize", + inventory.getInventory() + .getTanks()); + inventoryNBT.setLong( + "tankCapacity", + inventory.getInventory() + .getTankCapacity(0)); + inventoriesNBT.appendTag(inventoryNBT); + }); + nbt.setTag("inventories", inventoriesNBT); + return nbt; + } + + public void loadFromNBT(@Nonnull NBTTagCompound nbt) { + NBTTagList inventoriesNBT = nbt.getTagList("inventories", Constants.NBT.TAG_COMPOUND); + if (inventoriesNBT == null) return; + for (int i = 0; i < inventoriesNBT.tagCount(); i++) { + NBTTagCompound inventoryNBT = inventoriesNBT.getCompoundTagAt(i); + UUID uuid = UUID.fromString(inventoryNBT.getString("uuid")); + FluidInventoryLogic inventory = new FluidInventoryLogic( + inventoryNBT.getInteger("invSize"), + inventoryNBT.getLong("tankCapacity")); + inventory.loadFromNBT(inventoryNBT.getCompoundTag("inventory")); + if (inventory.isUpgradeInventory()) { + unallocatedInventories.add(Pair.of(uuid, inventory)); + } else { + inventories.put(uuid, inventory); + } + } + } +} diff --git a/src/main/java/gregtech/api/logic/ControllerItemLogic.java b/src/main/java/gregtech/api/logic/ControllerItemLogic.java new file mode 100644 index 0000000000..2863c2f49c --- /dev/null +++ b/src/main/java/gregtech/api/logic/ControllerItemLogic.java @@ -0,0 +1,148 @@ +package gregtech.api.logic; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraftforge.common.util.Constants; + +import org.apache.commons.lang3.tuple.Pair; + +/** + * Logic of the Item logic for the controller. This is controlling all of the inventories. + * + * @author BlueWeabo + */ +public class ControllerItemLogic { + + private final Map<UUID, ItemInventoryLogic> inventories = new HashMap<>(); + private final Set<Pair<UUID, ItemInventoryLogic>> unallocatedInventories = new HashSet<>(); + + public void addInventory(@Nonnull UUID id, @Nonnull ItemInventoryLogic inventory) { + Pair<UUID, ItemInventoryLogic> found = checkIfInventoryExistsAsUnallocated(inventory); + if (inventory.isUpgradeInventory() && found != null) { + unallocatedInventories.remove(found); + inventories.put(id, found.getRight()); + return; + } + inventories.put(id, inventory); + } + + @Nonnull + public UUID addInventory(@Nonnull ItemInventoryLogic inventory) { + Pair<UUID, ItemInventoryLogic> found = checkIfInventoryExistsAsUnallocated(inventory); + if (inventory.isUpgradeInventory() && found != null) { + unallocatedInventories.remove(found); + inventories.put(found.getLeft(), found.getRight()); + return Objects.requireNonNull(found.getLeft()); + } + UUID generatedUUID = Objects.requireNonNull(UUID.randomUUID()); + inventories.put(generatedUUID, inventory); + return generatedUUID; + } + + @Nullable + private Pair<UUID, ItemInventoryLogic> checkIfInventoryExistsAsUnallocated(@Nonnull ItemInventoryLogic inventory) { + if (unallocatedInventories.size() == 0) { + return null; + } + return unallocatedInventories.stream() + .filter( + unallocated -> unallocated.getRight() + .getTier() == inventory.getTier() + && unallocated.getRight() + .getSlots() == inventory.getSlots()) + .findFirst() + .get(); + } + + /** + * Removes the inventory with said id and gives it back to be processed if needed. + */ + @Nonnull + public ItemInventoryLogic removeInventory(@Nonnull UUID id) { + return Objects.requireNonNull(inventories.remove(id)); + } + + @Nonnull + public ItemInventoryLogic getAllInventoryLogics() { + return new ItemInventoryLogic( + inventories.values() + .stream() + .map(inv -> inv.getInventory()) + .collect(Collectors.toList())); + } + + @Nonnull + public ItemInventoryLogic getInventoryLogic(@Nullable UUID id) { + if (id == null) return getAllInventoryLogics(); + return Objects.requireNonNull(inventories.getOrDefault(id, getAllInventoryLogics())); + } + + @Nonnull + public Set<Entry<UUID, ItemInventoryLogic>> getAllInventoryLogicsAsEntrySet() { + return Objects.requireNonNull(inventories.entrySet()); + } + + @Nullable + public String getInventoryDisplayName(@Nullable UUID id) { + if (id == null) return ""; + ItemInventoryLogic logic = inventories.get(id); + if (logic == null) return ""; + String displayName = logic.getDisplayName(); + if (displayName == null) return Objects.requireNonNull(id.toString()); + return displayName; + } + + public void setInventoryDisplayName(@Nullable UUID id, @Nullable String displayName) { + if (id == null) return; + ItemInventoryLogic logic = inventories.get(id); + if (logic == null) return; + logic.setDisplayName(displayName); + } + + @Nonnull + public NBTTagCompound saveToNBT() { + NBTTagCompound nbt = new NBTTagCompound(); + NBTTagList inventoriesNBT = new NBTTagList(); + inventories.forEach((uuid, inventory) -> { + NBTTagCompound inventoryNBT = new NBTTagCompound(); + inventoryNBT.setTag("inventory", inventory.saveToNBT()); + inventoryNBT.setString("uuid", uuid.toString()); + inventoryNBT.setInteger( + "invSize", + inventory.getInventory() + .getSlots()); + inventoriesNBT.appendTag(inventoryNBT); + }); + nbt.setTag("inventories", inventoriesNBT); + return nbt; + } + + public void loadFromNBT(@Nonnull NBTTagCompound nbt) { + NBTTagList inventoriesNBT = nbt.getTagList("inventories", Constants.NBT.TAG_COMPOUND); + if (inventoriesNBT == null) return; + for (int i = 0; i < inventoriesNBT.tagCount(); i++) { + NBTTagCompound inventoryNBT = inventoriesNBT.getCompoundTagAt(i); + UUID uuid = UUID.fromString(inventoryNBT.getString("uuid")); + ItemInventoryLogic inventory = new ItemInventoryLogic(inventoryNBT.getInteger("invSize")); + NBTTagCompound internalInventoryNBT = inventoryNBT.getCompoundTag("inventory"); + if (internalInventoryNBT != null) inventory.loadFromNBT(internalInventoryNBT); + if (inventory.isUpgradeInventory()) { + unallocatedInventories.add(Pair.of(uuid, inventory)); + } else { + inventories.put(uuid, inventory); + } + } + } +} diff --git a/src/main/java/gregtech/api/logic/FluidInventoryLogic.java b/src/main/java/gregtech/api/logic/FluidInventoryLogic.java new file mode 100644 index 0000000000..88c0c954ec --- /dev/null +++ b/src/main/java/gregtech/api/logic/FluidInventoryLogic.java @@ -0,0 +1,269 @@ +package gregtech.api.logic; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; + +import com.gtnewhorizons.modularui.api.fluids.FluidTanksHandler; +import com.gtnewhorizons.modularui.api.fluids.IFluidTankLong; +import com.gtnewhorizons.modularui.api.fluids.IFluidTanksHandler; +import com.gtnewhorizons.modularui.api.fluids.ListFluidHandler; +import com.gtnewhorizons.modularui.api.math.Size; +import com.gtnewhorizons.modularui.api.widget.Widget; +import com.gtnewhorizons.modularui.common.widget.FluidSlotWidget; +import com.gtnewhorizons.modularui.common.widget.Scrollable; + +/** + * Generic Fluid logic for MuTEs. + * + * @author BlueWeabo + */ +public class FluidInventoryLogic { + + private static final int DEFAULT_COLUMNS_PER_ROW = 4; + private static final int POSITION_INTERVAL = 18; + private static final Size SIZE = new Size(18, 18); + + protected String displayName = ""; + @Nonnull + protected final IFluidTanksHandler inventory; + protected final Map<Fluid, IFluidTankLong> fluidToTankMap; + protected int tier = 0; + protected boolean isUpgradeInventory = false; + + public FluidInventoryLogic(int numberOfSlots, long capacityOfEachTank) { + this(new FluidTanksHandler(numberOfSlots, capacityOfEachTank), 0, false); + } + + public FluidInventoryLogic(int numberOfSlots, long capacityOfEachTank, int tier) { + this(new FluidTanksHandler(numberOfSlots, capacityOfEachTank), tier, false); + } + + public FluidInventoryLogic(int numberOfSlots, long capacityOfEachTank, int tier, boolean isUpgradeInventory) { + this(new FluidTanksHandler(numberOfSlots, capacityOfEachTank), tier, isUpgradeInventory); + } + + public FluidInventoryLogic(@Nonnull IFluidTanksHandler inventory, int tier, boolean isUpgradeInventory) { + this.inventory = inventory; + fluidToTankMap = new HashMap<>(inventory.getTanks()); + this.tier = tier; + this.isUpgradeInventory = isUpgradeInventory; + } + + public FluidInventoryLogic(Collection<IFluidTanksHandler> inventories) { + this(new ListFluidHandler(inventories), -1, false); + } + + @Nullable + public String getDisplayName() { + return displayName; + } + + public int getTier() { + return tier; + } + + public boolean isUpgradeInventory() { + return isUpgradeInventory; + } + + public void setDisplayName(@Nullable String displayName) { + this.displayName = displayName; + } + + /** + * + * @return The Fluid Inventory Logic as an NBTTagList to be saved in another nbt as how one wants. + */ + @Nonnull + public NBTTagCompound saveToNBT() { + final NBTTagCompound nbt = new NBTTagCompound(); + final NBTTagList tList = new NBTTagList(); + for (int tankNumber = 0; tankNumber < inventory.getTanks(); tankNumber++) { + final IFluidTankLong tank = inventory.getFluidTank(tankNumber); + if (tank == null) continue; + + final NBTTagCompound tag = new NBTTagCompound(); + tag.setByte("s", (byte) tankNumber); + tank.saveToNBT(tag); + tList.appendTag(tag); + } + nbt.setTag("inventory", tList); + nbt.setInteger("tier", tier); + if (displayName != null) { + nbt.setString("displayName", displayName); + } + nbt.setBoolean("isUpgradeInventory", isUpgradeInventory); + return nbt; + } + + /** + * Loads the Item Inventory Logic from an NBTTagList. + */ + public void loadFromNBT(@Nonnull NBTTagCompound nbt) { + NBTTagList nbtList = nbt.getTagList("inventory", Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < nbtList.tagCount(); i++) { + final NBTTagCompound tankNBT = nbtList.getCompoundTagAt(i); + final int tank = tankNBT.getShort("s"); + if (tank >= 0 && tank < inventory.getTanks()) inventory.getFluidTank(tank) + .loadFromNBT(tankNBT); + if (inventory.getFluidInTank(tank) != null) { + fluidToTankMap.put(inventory.getFluidInTank(tank), inventory.getFluidTank(tank)); + } + } + tier = nbt.getInteger("tier"); + if (nbt.hasKey("displayName")) { + displayName = nbt.getString("displayName"); + } + isUpgradeInventory = nbt.getBoolean("isUpgradeInventory"); + } + + @Nonnull + public IFluidTanksHandler getInventory() { + return inventory; + } + + @Nonnull + public FluidStack[] getStoredFluids() { + final FluidStack[] fluids = inventory.getFluids() + .stream() + .filter(fluid -> fluid != null) + .collect(Collectors.toList()) + .toArray(new FluidStack[0]); + if (fluids == null) { + return new FluidStack[0]; + } + return fluids; + } + + public boolean isFluidValid(@Nullable Fluid fluid) { + return fluid != null; + } + + /** + * @param fluid What we are trying to input + * @param amount amount of fluid we are trying to put + * @return amount of fluid filled into the tank + */ + public long fill(@Nullable Fluid fluid, long amount, boolean simulate) { + if (!isFluidValid(fluid)) return 0; + IFluidTankLong tank = fluidToTankMap.get(fluid); + if (tank != null) { + return tank.fill(fluid, amount, !simulate); + } + int tankNumber = 0; + tank = inventory.getFluidTank(tankNumber++); + while (tank.getStoredFluid() != fluid && tank.getStoredFluid() != null) { + tank = inventory.getFluidTank(tankNumber++); + } + fluidToTankMap.put(fluid, tank); + return tank.fill(fluid, amount, !simulate); + } + + @Nullable + public FluidStack fill(@Nullable FluidStack fluid) { + if (fluid == null) return null; + for (int i = 0; i < inventory.getTanks(); i++) { + fill(fluid.getFluid(), fluid.amount, false); + } + return fluid; + } + + /** + * Try and drain the first fluid found for that amount. Used by GT_Cover_Pump + * + * @param amount Fluid to drain from the tank + * @return A fluidstack with the possible amount drained + */ + @Nullable + public FluidStack drain(long amount, boolean simulate) { + for (int i = 0; i < inventory.getTanks(); i++) { + Fluid fluid = inventory.getFluidInTank(i); + FluidStack drained = drain(fluid, amount, simulate); + if (drained != null) return drained; + } + + return null; + } + + @Nullable + public FluidStack drain(Fluid fluid, long amount, boolean simulate) { + if (!isFluidValid(fluid)) return null; + IFluidTankLong tank = fluidToTankMap.get(fluid); + if (tank != null) { + return tank.drain(amount, !simulate); + } + int tankNumber = 0; + tank = inventory.getFluidTank(tankNumber++); + while (tank.getStoredFluid() != fluid) { + tank = inventory.getFluidTank(tankNumber++); + } + fluidToTankMap.put(fluid, tank); + return tank.drain(amount, !simulate); + } + + public void update() { + for (int i = 0; i < inventory.getTanks(); i++) { + IFluidTankLong tank = inventory.getFluidTank(i); + if (tank.getFluidAmountLong() > 0) continue; + tank.setFluid(null, 0); + } + } + + public long calculateAmountOfTimesFluidCanBeTaken(Fluid fluid, long amountToTake) { + if (!isFluidValid(fluid)) return 0; + IFluidTankLong tank = fluidToTankMap.get(fluid); + if (tank == null) return 0; + return tank.getFluidAmountLong() / amountToTake; + } + + @Nonnull + public Map<Fluid, Long> getMapOfStoredFluids() { + Map<Fluid, Long> map = new HashMap<>(); + for (int i = 0; i < inventory.getTanks(); i++) { + IFluidTankLong tank = inventory.getFluidTank(i); + if (tank == null) continue; + Fluid fluid = tank.getStoredFluid(); + if (fluid == null) continue; + map.put(fluid, map.getOrDefault(fluid, 0L) + tank.getFluidAmountLong()); + } + return map; + } + + /** + * Return a scrollable widget with only the inventory. + */ + @Nonnull + public Widget getGuiPart() { + return getGUIPart(DEFAULT_COLUMNS_PER_ROW); + } + + /** + * Return a scrollable widget with only the inventory. + */ + @Nonnull + public Widget getGUIPart(int columnsPerRow) { + final Scrollable scrollable = new Scrollable(); + scrollable.setVerticalScroll(); + for (int rows = 0; rows * 4 < inventory.getTanks(); rows++) { + final int columnsToMake = Math.min(inventory.getTanks() - rows * 4, 4); + for (int column = 0; column < columnsToMake; column++) { + final FluidSlotWidget fluidSlot = new FluidSlotWidget(inventory, rows * 4 + column); + scrollable.widget( + fluidSlot.setPos(column * POSITION_INTERVAL, rows * POSITION_INTERVAL) + .setSize(SIZE)); + } + } + return scrollable; + } +} diff --git a/src/main/java/gregtech/api/logic/ItemInventoryLogic.java b/src/main/java/gregtech/api/logic/ItemInventoryLogic.java new file mode 100644 index 0000000000..69005216b8 --- /dev/null +++ b/src/main/java/gregtech/api/logic/ItemInventoryLogic.java @@ -0,0 +1,314 @@ +package gregtech.api.logic; + +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraftforge.common.util.Constants; + +import com.gtnewhorizons.modularui.api.forge.IItemHandlerModifiable; +import com.gtnewhorizons.modularui.api.forge.ItemStackHandler; +import com.gtnewhorizons.modularui.api.forge.ListItemHandler; +import com.gtnewhorizons.modularui.api.math.Size; +import com.gtnewhorizons.modularui.api.widget.Widget; +import com.gtnewhorizons.modularui.common.widget.Scrollable; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; + +import gregtech.api.util.GT_Utility; +import gregtech.api.util.item.ItemHolder; + +/** + * Generic Item logic for MuTEs. + * + * @author BlueWeabo + */ +public class ItemInventoryLogic { + + private static final int DEFAULT_COLUMNS_PER_ROW = 4; + private static final int POSITION_INTERVAL = 18; + private static final Size SIZE = new Size(18, 18); + + protected String displayName; + @Nonnull + protected final IItemHandlerModifiable inventory; + protected UUID connectedFluidInventory; + protected int tier; + protected boolean isUpgradeInventory; + protected Map<ItemHolder, Long> cachedItemMap; + protected boolean inRecipeCheck; + + public ItemInventoryLogic(int numberOfSlots) { + this(numberOfSlots, 0); + } + + public ItemInventoryLogic(int numberOfSlots, int tier) { + this(new ItemStackHandler(numberOfSlots), tier, false); + } + + public ItemInventoryLogic(int numberOfSlots, int tier, boolean isUpgradeInventory) { + this(new ItemStackHandler(numberOfSlots), tier, isUpgradeInventory); + } + + public ItemInventoryLogic(@Nonnull IItemHandlerModifiable inventory, int tier, boolean isUpgradeInventory) { + this.inventory = inventory; + this.tier = tier; + this.isUpgradeInventory = isUpgradeInventory; + } + + public ItemInventoryLogic(Collection<IItemHandlerModifiable> inventories) { + this(new ListItemHandler(inventories), -1, false); + } + + @Nullable + public String getDisplayName() { + return displayName; + } + + public int getTier() { + return tier; + } + + public boolean isUpgradeInventory() { + return isUpgradeInventory; + } + + public int getSlots() { + return getInventory().getSlots(); + } + + public void setDisplayName(@Nullable String displayName) { + this.displayName = displayName; + } + + @Nullable + public UUID getConnectedFluidInventoryID() { + return connectedFluidInventory; + } + + public void setConnectedFluidInventoryID(@Nullable UUID connectedFluidTank) { + this.connectedFluidInventory = connectedFluidTank; + } + + /** + * + * @return The Item Inventory Logic as an NBTTagCompound to be saved in another nbt as how one wants. + */ + @Nonnull + public NBTTagCompound saveToNBT() { + final NBTTagCompound nbt = new NBTTagCompound(); + final NBTTagList tList = new NBTTagList(); + for (int slot = 0; slot < inventory.getSlots(); slot++) { + final ItemStack tStack = inventory.getStackInSlot(slot); + if (tStack == null) continue; + + final NBTTagCompound tag = new NBTTagCompound(); + tag.setByte("s", (byte) slot); + tStack.writeToNBT(tag); + tList.appendTag(tag); + } + nbt.setTag("inventory", tList); + nbt.setInteger("tier", tier); + if (displayName != null) { + nbt.setString("displayName", displayName); + } + nbt.setBoolean("isUpgradeInventory", isUpgradeInventory); + if (connectedFluidInventory != null) { + nbt.setString("connectedFluidInventory", connectedFluidInventory.toString()); + } + return nbt; + } + + /** + * Loads the Item Inventory Logic from an NBTTagCompound. + */ + public void loadFromNBT(@Nonnull NBTTagCompound nbt) { + tier = nbt.getInteger("tier"); + if (nbt.hasKey("displayName")) { + displayName = nbt.getString("displayName"); + } + + isUpgradeInventory = nbt.getBoolean("isUpgradeInventory"); + if (nbt.hasKey("connectedFluidInventory")) { + connectedFluidInventory = UUID.fromString(nbt.getString("connectedFluidInventory")); + } + + NBTTagList nbtList = nbt.getTagList("inventory", Constants.NBT.TAG_COMPOUND); + if (nbtList == null) return; + + for (int i = 0; i < nbtList.tagCount(); i++) { + final NBTTagCompound tNBT = nbtList.getCompoundTagAt(i); + final int tSlot = tNBT.getShort("s"); + if (tSlot >= 0 && tSlot < inventory.getSlots()) { + inventory.setStackInSlot(tSlot, GT_Utility.loadItem(tNBT)); + } + } + } + + @Nonnull + public IItemHandlerModifiable getInventory() { + return inventory; + } + + @Nonnull + public ItemStack[] getStoredItems() { + final ItemStack[] items = inventory.getStacks() + .stream() + .filter(item -> item != null) + .collect(Collectors.toList()) + .toArray(new ItemStack[0]); + if (items == null) { + return new ItemStack[0]; + } + return items; + } + + public boolean isStackValid(ItemStack item) { + return true; + } + + @Nullable + public ItemStack insertItem(ItemStack item) { + if (!isStackValid(item)) return item; + for (int i = 0; i < inventory.getSlots() && item != null && item.stackSize > 0; i++) { + item = inventory.insertItem(i, item, false); + } + return item; + } + + @Nullable + public ItemStack extractItem(int slot, int amount) { + return inventory.extractItem(slot, amount, false); + } + + public boolean subtractItemAmount(@Nonnull ItemHolder item, long amount, boolean simulate) { + Map<ItemHolder, Long> itemMap = getMapOfStoredItems(); + if (!itemMap.containsKey(item)) { + return false; + } + + if (itemMap.get(item) < amount) { + return false; + } + + if (simulate) { + return true; + } + + itemMap.put(item, itemMap.get(item) - amount); + return true; + } + + @Nullable + public ItemStack getItemInSlot(int slot) { + return inventory.getStackInSlot(slot); + } + + public void sort() { + Map<ItemHolder, Long> itemMap = getMapOfStoredItems(); + List<ItemHolder> sortedItems = itemMap.keySet() + .stream() + .sorted( + Comparator.comparing( + a -> a.getItem() + .getUnlocalizedName() + a.getMeta())) + .collect(Collectors.toList()); + putInItemsFromMap(itemMap, sortedItems); + } + + public void update(boolean shouldSort) { + if (shouldSort) { + sort(); + } + + for (int i = 0; i < inventory.getSlots(); i++) { + ItemStack item = inventory.getStackInSlot(i); + if (item == null) continue; + if (item.stackSize > 0) continue; + inventory.setStackInSlot(i, null); + } + } + + /** + * Return a scrollable widget with only the inventory. + */ + @Nonnull + public Widget getGuiPart() { + return getGUIPart(DEFAULT_COLUMNS_PER_ROW); + } + + /** + * Return a scrollable widget with only the inventory. + */ + @Nonnull + public Widget getGUIPart(int columnsPerRow) { + final Scrollable scrollable = new Scrollable(); + scrollable.setVerticalScroll(); + for (int rows = 0; rows * columnsPerRow < Math.min(inventory.getSlots(), 128); rows++) { + final int columnsToMake = Math + .min(Math.min(inventory.getSlots(), 128) - rows * columnsPerRow, columnsPerRow); + for (int column = 0; column < columnsToMake; column++) { + scrollable.widget( + new SlotWidget(inventory, rows * columnsPerRow + column) + .setPos(column * POSITION_INTERVAL, rows * POSITION_INTERVAL) + .setSize(SIZE)); + } + } + return scrollable; + } + + public void startRecipeCheck() { + cachedItemMap = getMapOfStoredItems(); + inRecipeCheck = true; + } + + public void stopRecipeCheck() { + inRecipeCheck = false; + putInItemsFromMap(cachedItemMap, null); + cachedItemMap = null; + } + + @Nonnull + public Map<ItemHolder, Long> getMapOfStoredItems() { + if (inRecipeCheck) return cachedItemMap; + Map<ItemHolder, Long> items = new HashMap<>(); + for (int i = 0; i < inventory.getSlots(); i++) { + ItemStack item = extractItem(i, Integer.MAX_VALUE); + if (item == null) continue; + ItemHolder itemHolder = new ItemHolder(item); + items.put(itemHolder, items.getOrDefault(itemHolder, 0L) + item.stackSize); + } + return items; + } + + protected void putInItemsFromMap(@Nonnull Map<ItemHolder, Long> itemMap, @Nullable List<ItemHolder> sortedList) { + for (ItemHolder itemHolder : (sortedList == null ? itemMap.keySet() : sortedList)) { + long itemAmount = itemMap.get(itemHolder); + ItemStack item = new ItemStack(itemHolder.getItem(), 0, itemHolder.getMeta()); + item.setTagCompound(itemHolder.getNBT()); + while (itemAmount > 0) { + item.stackSize = (int) Math.min(item.getMaxStackSize(), itemAmount); + itemAmount -= item.stackSize; + insertItem(item); + } + } + } + + public long calculateAmountOfTimesItemCanBeTaken(ItemHolder item, long amount) { + return getMapOfStoredItems().getOrDefault(item, 0L) / amount; + } + + public Set<ItemHolder> getSetOfStoredItems() { + return getMapOfStoredItems().keySet(); + } +} diff --git a/src/main/java/gregtech/api/logic/MuTEProcessingLogic.java b/src/main/java/gregtech/api/logic/MuTEProcessingLogic.java new file mode 100644 index 0000000000..da53c8875d --- /dev/null +++ b/src/main/java/gregtech/api/logic/MuTEProcessingLogic.java @@ -0,0 +1,256 @@ +package gregtech.api.logic; + +import static net.minecraftforge.common.util.Constants.NBT.TAG_COMPOUND; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraftforge.fluids.FluidStack; + +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.widget.Widget; +import com.gtnewhorizons.modularui.common.widget.Scrollable; + +import gregtech.api.enums.InventoryType; +import gregtech.api.logic.interfaces.ProcessingLogicHost; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_ParallelHelper; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; + +/** + * Processing logic class, dedicated for MultiTileEntities. + */ +public class MuTEProcessingLogic<P extends MuTEProcessingLogic<P>> extends AbstractProcessingLogic<P> { + + protected boolean hasWork; + protected int progress; + protected ProcessingLogicHost<P> machineHost; + @Nonnull + protected CheckRecipeResult recipeResult = CheckRecipeResultRegistry.NONE; + @Nullable + protected UUID itemOutputID; + @Nullable + protected UUID fluidOutputID; + + public P setMachineHost(@Nonnull ProcessingLogicHost<P> machineHost) { + this.machineHost = machineHost; + return getThis(); + } + + // #region Logic + + @Nonnull + @Override + public CheckRecipeResult process() { + RecipeMap<?> recipeMap = preProcess(); + + ItemInventoryLogic itemInput = null; + FluidInventoryLogic fluidInput = null; + if (machineHost.isInputSeparated()) { + for (Map.Entry<UUID, ItemInventoryLogic> itemEntry : machineHost + .getAllItemInventoryLogics(InventoryType.Input)) { + itemOutputID = Objects.requireNonNull(itemEntry.getKey()); + itemInput = Objects.requireNonNull(itemEntry.getValue()); + fluidInput = Objects.requireNonNull( + machineHost.getFluidLogic(InventoryType.Input, itemInput.getConnectedFluidInventoryID())); + fluidOutputID = itemInput.getConnectedFluidInventoryID(); + } + } else { + itemInput = Objects.requireNonNull(machineHost.getItemLogic(InventoryType.Input, null)); + fluidInput = Objects.requireNonNull(machineHost.getFluidLogic(InventoryType.Input, null)); + } + + CheckRecipeResult recipeValidatorResult = null; + if (recipeValidatorResult != null) { + return recipeValidatorResult; + } + + return processRecipe(null, Objects.requireNonNull(itemInput), Objects.requireNonNull(fluidInput)); + } + + @Nonnull + protected CheckRecipeResult processRecipe(@Nonnull List<GT_Recipe> recipes, @Nonnull ItemInventoryLogic itemInput, + @Nonnull FluidInventoryLogic fluidInput) { + CheckRecipeResult result = CheckRecipeResultRegistry.INTERNAL_ERROR; + for (GT_Recipe recipe : recipes) { + Objects.requireNonNull(recipe); + GT_ParallelHelper helper = createParallelHelper(recipe, itemInput, fluidInput); + GT_OverclockCalculator calculator = createOverclockCalculator(recipe); + helper.setCalculator(calculator); + helper.build(); + result = helper.getResult(); + if (result.wasSuccessful()) { + return applyRecipe(recipe, helper, calculator, result); + } + } + return result; + } + + /** + * Override if you don't work with regular gt recipe maps + */ + @Nonnull + protected Object findRecipe(@Nullable RecipeMap<?> map, @Nonnull ItemInventoryLogic itemInput, + @Nonnull FluidInventoryLogic fluidInput) { + if (map == null) { + return false; + } + + return true; + } + + @Nonnull + protected GT_ParallelHelper createParallelHelper(@Nonnull GT_Recipe recipe, @Nonnull ItemInventoryLogic itemInput, + @Nonnull FluidInventoryLogic fluidInput) { + return new GT_ParallelHelper().setRecipe(recipe) + .setItemInputInventory(itemInput) + .setFluidInputInventory(fluidInput) + .setAvailableEUt(availableVoltage * availableAmperage) + .setMaxParallel(maxParallel) + .setEUtModifier(euModifier) + .enableBatchMode(batchSize) + .setConsumption(true) + .setOutputCalculation(true) + .setMuTEMode(true); + } + + // #endregion + + // #region Getters + + @Nonnull + public CheckRecipeResult getResult() { + return recipeResult; + } + + public int getProgress() { + return progress; + } + + // #endregion + + // #region Other + + public void startCheck() { + recipeResult = process(); + } + + public void progress() { + if (!hasWork) return; + if (progress == duration) { + progress = 0; + duration = 0; + calculatedEut = 0; + output(); + return; + } + progress++; + } + + protected void output() { + ItemInventoryLogic itemOutput = machineHost.getItemLogic(InventoryType.Output, itemOutputID); + FluidInventoryLogic fluidOutput = machineHost.getFluidLogic(InventoryType.Output, fluidOutputID); + if (itemOutput == null || fluidOutput == null) return; + for (ItemStack item : outputItems) { + if (item == null) continue; + itemOutput.insertItem(item); + } + for (FluidStack fluid : outputFluids) { + if (fluid == null) continue; + fluidOutput.fill(fluid.getFluid(), fluid.amount, false); + } + outputItems = new ItemStack[0]; + outputFluids = new FluidStack[0]; + } + + public boolean canWork() { + return !hasWork && machineHost.isAllowedToWork(); + } + + /** + * By how much to increase the progress? + * + * @param progressAmount in ticks + */ + public void increaseProgress(int progressAmount) { + progress += progressAmount; + } + + public NBTTagCompound saveToNBT() { + NBTTagCompound logicNBT = new NBTTagCompound(); + logicNBT.setLong("eutConsumption", calculatedEut); + logicNBT.setInteger("duration", duration); + logicNBT.setInteger("progress", progress); + logicNBT.setBoolean("hasWork", hasWork); + if (outputItems != null) { + NBTTagList itemOutputsNBT = new NBTTagList(); + for (ItemStack item : outputItems) { + itemOutputsNBT.appendTag(GT_Utility.saveItem(item)); + } + logicNBT.setTag("itemOutputs", itemOutputsNBT); + } + if (outputFluids != null) { + NBTTagList fluidOutputsNBT = new NBTTagList(); + for (FluidStack fluid : outputFluids) { + fluidOutputsNBT.appendTag(fluid.writeToNBT(new NBTTagCompound())); + } + logicNBT.setTag("fluidOutputs", fluidOutputsNBT); + } + if (itemOutputID != null) { + logicNBT.setString("itemOutputID", itemOutputID.toString()); + } + if (fluidOutputID != null) { + logicNBT.setString("fluidOutputID", fluidOutputID.toString()); + } + return logicNBT; + } + + public void loadFromNBT(@Nonnull NBTTagCompound logicNBT) { + calculatedEut = logicNBT.getLong("eutConsumption"); + duration = logicNBT.getInteger("duration"); + progress = logicNBT.getInteger("progress"); + hasWork = logicNBT.getBoolean("hasWork"); + if (logicNBT.hasKey("itemOutputs")) { + NBTTagList itemOutputsNBT = logicNBT.getTagList("itemOutputs", TAG_COMPOUND); + outputItems = new ItemStack[itemOutputsNBT.tagCount()]; + for (int i = 0; i < itemOutputsNBT.tagCount(); i++) { + outputItems[i] = GT_Utility.loadItem(itemOutputsNBT.getCompoundTagAt(i)); + } + } + if (logicNBT.hasKey("fluidOutputs")) { + NBTTagList fluidOutputsNBT = logicNBT.getTagList("fluidOutputs", TAG_COMPOUND); + outputFluids = new FluidStack[fluidOutputsNBT.tagCount()]; + for (int i = 0; i < fluidOutputsNBT.tagCount(); i++) { + outputFluids[i] = FluidStack.loadFluidStackFromNBT(fluidOutputsNBT.getCompoundTagAt(i)); + } + } + if (logicNBT.hasKey("itemOutputID")) { + itemOutputID = UUID.fromString(logicNBT.getString("itemOutputID")); + } + if (logicNBT.hasKey("fluidOutputID")) { + fluidOutputID = UUID.fromString(logicNBT.getString("fluidOutputID")); + } + } + + /** + * Returns a gui part, which will be displayed in a separate tab on the machine's gui. + */ + @Nonnull + public Widget getGUIPart(ModularWindow.Builder builder) { + return new Scrollable(); + } + + // #endregion +} diff --git a/src/main/java/gregtech/api/logic/NullPowerLogic.java b/src/main/java/gregtech/api/logic/NullPowerLogic.java new file mode 100644 index 0000000000..0017f0e647 --- /dev/null +++ b/src/main/java/gregtech/api/logic/NullPowerLogic.java @@ -0,0 +1,5 @@ +package gregtech.api.logic; + +public class NullPowerLogic extends PowerLogic { + +} diff --git a/src/main/java/gregtech/api/logic/PollutionLogic.java b/src/main/java/gregtech/api/logic/PollutionLogic.java deleted file mode 100644 index 8e1172e105..0000000000 --- a/src/main/java/gregtech/api/logic/PollutionLogic.java +++ /dev/null @@ -1,17 +0,0 @@ -package gregtech.api.logic; - -public class PollutionLogic { - - private int pollutionAmount; - - public PollutionLogic() {} - - public PollutionLogic setPollutionAmount(int pollutionAmount) { - this.pollutionAmount = pollutionAmount; - return this; - } - - public int getPollutionAmount() { - return pollutionAmount; - } -} diff --git a/src/main/java/gregtech/api/logic/PowerLogic.java b/src/main/java/gregtech/api/logic/PowerLogic.java index ac12ef8917..ad19987a76 100644 --- a/src/main/java/gregtech/api/logic/PowerLogic.java +++ b/src/main/java/gregtech/api/logic/PowerLogic.java @@ -1,54 +1,97 @@ package gregtech.api.logic; +import static gregtech.common.misc.WirelessNetworkManager.addEUToGlobalEnergyMap; + +import java.util.UUID; + +import javax.annotation.Nonnull; + import net.minecraft.nbt.NBTTagCompound; import gregtech.api.enums.GT_Values.NBT; +/** + * Power logic for machines. This is used to store all the important variables for a machine to have energy and use it + * in any way. + * + * @author BlueWeabo, Maxim + */ public class PowerLogic { - public static int NONE = 0; - public static int RECEIVER = 1; - public static int EMITTER = 2; - public static int BOTH = RECEIVER | EMITTER; + public static final int NONE = 0; + public static final int RECEIVER = 1; + public static final int EMITTER = 2; + public static final int BOTH = RECEIVER | EMITTER; + private static float wirelessChargeFactor = 0.5F; private long storedEnergy = 0; private long energyCapacity = 0; private long voltage = 0; private long amperage = 0; private int type = 0; private boolean canUseLaser = false; + private boolean canUseWireless = false; + private UUID owner; public PowerLogic() {} + /** + * Sets the max voltage the logic can accept + */ + @Nonnull public PowerLogic setMaxVoltage(long voltage) { this.voltage = voltage; return this; } + /** + * Sets the maximum amount of energy the machine can store inside of it + */ + @Nonnull public PowerLogic setEnergyCapacity(long energyCapacity) { this.energyCapacity = energyCapacity; return this; } - public PowerLogic setAmperage(long amperage) { + /** + * Sets the maximum amount of amps a machine can receive from an emitter + */ + @Nonnull + public PowerLogic setMaxAmperage(long amperage) { this.amperage = amperage; return this; } + /** + * Sets the type of power logic this is. Whether it will receive EU or emit it to others, or do both + */ + @Nonnull public PowerLogic setType(int type) { this.type = type; return this; } - public PowerLogic disableLaser() { - canUseLaser = false; + /** + * If this power logic can use lasers to be used for it + */ + @Nonnull + public PowerLogic setCanUseLaser(boolean canUse) { + canUseLaser = canUse; return this; } - public PowerLogic enableLaser() { - canUseLaser = true; + /** + * If the power logic should use wireless EU first before using its internal buffer + */ + @Nonnull + public PowerLogic setCanUseWireless(boolean canUse, UUID owner) { + canUseWireless = canUse; + this.owner = owner; return this; } + /** + * Adding energy directly to the buffer, but only if it has the capacity. + */ public boolean addEnergyUnsafe(long totalEUAdded) { if (storedEnergy + totalEUAdded >= energyCapacity) { return false; @@ -58,6 +101,9 @@ public class PowerLogic { return true; } + /** + * Adding energy to the buffer if the voltage given isn't higher than the voltage of the logic + */ public boolean addEnergy(long voltage, long amperage) { if (voltage > this.voltage) { return false; @@ -66,11 +112,23 @@ public class PowerLogic { return addEnergyUnsafe(voltage * amperage); } + /** + * Same as {@link #addEnergy(long, long)}, but only 1 amp of it + */ public boolean addEnergy(long voltage) { return addEnergy(voltage, 1); } + /** + * Injecting energy in the multiblock ampere per ampere until full or until we have added the maximum possible + * amperes for this tick + * + * @param voltage At what voltage are the amps? + * @param availableAmperage How much amperage do we have available + * @return Amount of amperes used + */ public long injectEnergy(long voltage, long availableAmperage) { + if (canUseWireless) return 0; long usedAmperes = 0; while (addEnergy(voltage, 1) && usedAmperes < amperage) { usedAmperes++; @@ -79,7 +137,17 @@ public class PowerLogic { return usedAmperes; } + /** + * Remove energy from the logic only if it has enough to be removed. + */ public boolean removeEnergyUnsafe(long totalEURemoved) { + if (canUseWireless) { + if (storedEnergy < energyCapacity * wirelessChargeFactor) { + if (addEUToGlobalEnergyMap(owner, -(energyCapacity - storedEnergy))) { + storedEnergy = energyCapacity; + } + } + } if (storedEnergy - totalEURemoved < 0) { return false; } @@ -88,6 +156,9 @@ public class PowerLogic { return true; } + /** + * Remove the given voltage for the amount of amperage if the removed isn't higher than the logic's voltage + */ public boolean removeEnergy(long voltage, long amperage) { if (voltage > this.voltage) { return false; @@ -96,31 +167,61 @@ public class PowerLogic { return removeEnergyUnsafe(voltage * amperage); } + /** + * Same as {@link #removeEnergy(long, long)}, but with only 1 amperage + */ public boolean removeEnergy(long voltage) { return removeEnergy(voltage, 1); } + /** + * @return The maximum energy that can be stored. + */ public long getCapacity() { return energyCapacity; } + /** + * @return The maximum voltage that is available + */ public long getVoltage() { return voltage; } + /** + * @return The current energy stored + */ public long getStoredEnergy() { return storedEnergy; } + /** + * @return The current maximum Amperage + */ + public long getMaxAmperage() { + return amperage; + } + + /** + * Is the logic a receiver to receive energy + */ public boolean isEnergyReceiver() { return (type & RECEIVER) > 0; } + /** + * Is the logic a emitter to emit energy + */ public boolean isEnergyEmitter() { return (type & EMITTER) > 0; } - public void writeToNBT(NBTTagCompound nbt) { + /** + * Saves the power logic to its own nbt tag before saving it to the given one. + * + * @param nbt Tag where you want to save the power logic tag to. + */ + public void saveToNBT(NBTTagCompound nbt) { NBTTagCompound powerLogic = new NBTTagCompound(); powerLogic.setLong(NBT.POWER_LOGIC_ENERGY_CAPACITY, energyCapacity); powerLogic.setLong(NBT.POWER_LOGIC_STORED_ENERGY, storedEnergy); @@ -130,6 +231,11 @@ public class PowerLogic { nbt.setTag(NBT.POWER_LOGIC, powerLogic); } + /** + * Loads the power logic from its own nbt after getting it from the given one + * + * @param nbt Tag where the power logic tag was saved to + */ public void loadFromNBT(NBTTagCompound nbt) { NBTTagCompound powerLogic = nbt.getCompoundTag(NBT.POWER_LOGIC); energyCapacity = powerLogic.getLong(NBT.POWER_LOGIC_ENERGY_CAPACITY); @@ -139,6 +245,9 @@ public class PowerLogic { type = powerLogic.getInteger(NBT.POWER_LOGIC_TYPE); } + /** + * Can we use lasers for inputting EU + */ public boolean canUseLaser() { return canUseLaser; } diff --git a/src/main/java/gregtech/api/logic/ProcessingLogic.java b/src/main/java/gregtech/api/logic/ProcessingLogic.java index 6b9f2d454f..4d203ed80f 100644 --- a/src/main/java/gregtech/api/logic/ProcessingLogic.java +++ b/src/main/java/gregtech/api/logic/ProcessingLogic.java @@ -1,7 +1,6 @@ package gregtech.api.logic; import java.util.List; -import java.util.function.Supplier; import java.util.stream.Stream; import javax.annotation.Nonnull; @@ -10,10 +9,7 @@ import javax.annotation.Nullable; import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidStack; -import org.jetbrains.annotations.NotNull; - import gregtech.api.interfaces.tileentity.IRecipeLockable; -import gregtech.api.interfaces.tileentity.IVoidable; import gregtech.api.recipe.RecipeMap; import gregtech.api.recipe.check.CheckRecipeResult; import gregtech.api.recipe.check.CheckRecipeResultRegistry; @@ -26,90 +22,45 @@ import gregtech.api.util.GT_Recipe; * Logic class to calculate result of recipe check from inputs, based on recipemap. */ @SuppressWarnings({ "unused", "UnusedReturnValue" }) -public class ProcessingLogic { +public class ProcessingLogic extends AbstractProcessingLogic<ProcessingLogic> { - protected IVoidable machine; protected IRecipeLockable recipeLockableMachine; - protected Supplier<RecipeMap<?>> recipeMapSupplier; - protected GT_Recipe lastRecipe; - protected RecipeMap<?> lastRecipeMap; protected ItemStack specialSlotItem; protected ItemStack[] inputItems; - protected ItemStack[] outputItems; - protected ItemStack[] currentOutputItems; protected FluidStack[] inputFluids; - protected FluidStack[] outputFluids; - protected FluidStack[] currentOutputFluids; - protected long calculatedEut; - protected int duration; - protected long availableVoltage; - protected long availableAmperage; - protected int overClockTimeReduction = 1; - protected int overClockPowerIncrease = 2; - protected boolean protectItems; - protected boolean protectFluids; protected boolean isRecipeLocked; - protected int maxParallel = 1; - protected int calculatedParallels = 0; - protected Supplier<Integer> maxParallelSupplier; - protected int batchSize = 1; - protected float euModifier = 1.0f; - protected float speedBoost = 1.0f; - protected boolean amperageOC = true; public ProcessingLogic() {} - // region Setters + // #region Setters + @Nonnull public ProcessingLogic setInputItems(ItemStack... itemInputs) { this.inputItems = itemInputs; - return this; + return getThis(); } + @Nonnull public ProcessingLogic setInputItems(List<ItemStack> itemOutputs) { this.inputItems = itemOutputs.toArray(new ItemStack[0]); - return this; + return getThis(); } + @Nonnull public ProcessingLogic setInputFluids(FluidStack... fluidInputs) { this.inputFluids = fluidInputs; - return this; + return getThis(); } + @Nonnull public ProcessingLogic setInputFluids(List<FluidStack> fluidInputs) { this.inputFluids = fluidInputs.toArray(new FluidStack[0]); - return this; + return getThis(); } public ProcessingLogic setSpecialSlotItem(ItemStack specialSlotItem) { this.specialSlotItem = specialSlotItem; - return this; - } - - /** - * Overwrites item output result of the calculation. - */ - public ProcessingLogic setOutputItems(ItemStack... itemOutputs) { - this.outputItems = itemOutputs; - return this; - } - - /** - * Overwrites fluid output result of the calculation. - */ - public ProcessingLogic setOutputFluids(FluidStack... fluidOutputs) { - this.outputFluids = fluidOutputs; - return this; - } - - public ProcessingLogic setCurrentOutputItems(ItemStack... currentOutputItems) { - this.currentOutputItems = currentOutputItems; - return this; - } - - public ProcessingLogic setCurrentOutputFluids(FluidStack... currentOutputFluids) { - this.currentOutputFluids = currentOutputFluids; - return this; + return getThis(); } /** @@ -118,129 +69,13 @@ public class ProcessingLogic { public ProcessingLogic setRecipeLocking(IRecipeLockable recipeLockableMachine, boolean isRecipeLocked) { this.recipeLockableMachine = recipeLockableMachine; this.isRecipeLocked = isRecipeLocked; - return this; - } - - /** - * Sets max amount of parallel. - */ - public ProcessingLogic setMaxParallel(int maxParallel) { - this.maxParallel = maxParallel; - return this; - } - - /** - * Sets method to get max amount of parallel. - */ - public ProcessingLogic setMaxParallelSupplier(Supplier<Integer> supplier) { - this.maxParallelSupplier = supplier; - return this; - } - - /** - * Sets batch size for batch mode. - */ - public ProcessingLogic setBatchSize(int size) { - this.batchSize = size; - return this; - } - - public ProcessingLogic setRecipeMap(RecipeMap<?> recipeMap) { - return setRecipeMapSupplier(() -> recipeMap); - } - - public ProcessingLogic setRecipeMapSupplier(Supplier<RecipeMap<?>> supplier) { - this.recipeMapSupplier = supplier; - return this; - } - - public ProcessingLogic setEuModifier(float modifier) { - this.euModifier = modifier; - return this; - } - - public ProcessingLogic setSpeedBonus(float speedModifier) { - this.speedBoost = speedModifier; - return this; - } - - /** - * Sets machine used for void protection logic. - */ - public ProcessingLogic setMachine(IVoidable machine) { - this.machine = machine; - return this; - } - - /** - * Overwrites duration result of the calculation. - */ - public ProcessingLogic setDuration(int duration) { - this.duration = duration; - return this; - } - - /** - * Overwrites EU/t result of the calculation. - */ - public ProcessingLogic setCalculatedEut(long calculatedEut) { - this.calculatedEut = calculatedEut; - return this; - } - - /** - * Sets voltage of the machine. It doesn't need to be actual voltage (excluding amperage) of the machine; - * For example, most of the multiblock machines set maximum possible input power (including amperage) as voltage - * and 1 as amperage. That way recipemap search will be executed with overclocked voltage. - */ - public ProcessingLogic setAvailableVoltage(long voltage) { - availableVoltage = voltage; - return this; - } - - /** - * Sets amperage of the machine. This amperage doesn't involve in EU/t when searching recipemap. - * Useful for preventing tier skip but still considering amperage for parallel. - */ - public ProcessingLogic setAvailableAmperage(long amperage) { - availableAmperage = amperage; - return this; - } - - public ProcessingLogic setVoidProtection(boolean protectItems, boolean protectFluids) { - this.protectItems = protectItems; - this.protectFluids = protectFluids; - return this; - } - - /** - * Sets custom overclock ratio. 2/4 by default. - * Parameters represent number of bit shift, so 1 -> 2x, 2 -> 4x. - */ - public ProcessingLogic setOverclock(int timeReduction, int powerIncrease) { - this.overClockTimeReduction = timeReduction; - this.overClockPowerIncrease = powerIncrease; - return this; - } - - /** - * Sets overclock ratio to 4/4. - */ - public ProcessingLogic enablePerfectOverclock() { - return this.setOverclock(2, 2); - } - - /** - * Sets wether the multi should use amperage to OC or not - */ - public ProcessingLogic setAmperageOC(boolean amperageOC) { - this.amperageOC = amperageOC; - return this; + return getThis(); } /** * Clears calculated results and provided machine inputs to prepare for the next machine operation. */ + public ProcessingLogic clear() { this.inputItems = null; this.inputFluids = null; @@ -250,32 +85,19 @@ public class ProcessingLogic { this.calculatedEut = 0; this.duration = 0; this.calculatedParallels = 0; - return this; + return getThis(); } - // endregion + // #endregion - // region Logic + // #region Logic /** * Executes the recipe check: Find recipe from recipemap, Calculate parallel, overclock and outputs. */ @Nonnull public CheckRecipeResult process() { - RecipeMap<?> recipeMap; - if (recipeMapSupplier == null) { - recipeMap = null; - } else { - recipeMap = recipeMapSupplier.get(); - } - if (lastRecipeMap != recipeMap) { - lastRecipe = null; - lastRecipeMap = recipeMap; - } - - if (maxParallelSupplier != null) { - maxParallel = maxParallelSupplier.get(); - } + RecipeMap<?> recipeMap = preProcess(); if (inputItems == null) { inputItems = new ItemStack[0]; @@ -297,7 +119,6 @@ public class ProcessingLogic { recipeLockableMachine.getSingleRecipeCheck() .getRecipe()).checkRecipeResult; } - Stream<GT_Recipe> matchedRecipes = findRecipeMatches(recipeMap); Iterable<GT_Recipe> recipeIterable = matchedRecipes::iterator; CheckRecipeResult checkRecipeResult = CheckRecipeResultRegistry.NO_RECIPE; @@ -342,53 +163,6 @@ public class ProcessingLogic { } /** - * Check has been succeeded, so it applies the recipe and calculated parameters. - * At this point, inputs have been already consumed. - */ - private CheckRecipeResult applyRecipe(@NotNull GT_Recipe recipe, GT_ParallelHelper helper, - GT_OverclockCalculator calculator, CheckRecipeResult result) { - if (recipe.mCanBeBuffered) { - lastRecipe = recipe; - } else { - lastRecipe = null; - } - calculatedParallels = helper.getCurrentParallel(); - - if (calculator.getConsumption() == Long.MAX_VALUE) { - return CheckRecipeResultRegistry.POWER_OVERFLOW; - } - if (calculator.getDuration() == Integer.MAX_VALUE) { - return CheckRecipeResultRegistry.DURATION_OVERFLOW; - } - - calculatedEut = calculator.getConsumption(); - - double finalDuration = calculateDuration(recipe, helper, calculator); - if (finalDuration >= Integer.MAX_VALUE) { - return CheckRecipeResultRegistry.DURATION_OVERFLOW; - } - duration = (int) finalDuration; - - CheckRecipeResult hookResult = onRecipeStart(recipe); - if (!hookResult.wasSuccessful()) { - return hookResult; - } - - outputItems = helper.getItemOutputs(); - outputFluids = helper.getFluidOutputs(); - - return result; - } - - /** - * Override to tweak final duration that will be set as a result of this logic class. - */ - protected double calculateDuration(@Nonnull GT_Recipe recipe, @Nonnull GT_ParallelHelper helper, - @Nonnull GT_OverclockCalculator calculator) { - return calculator.getDuration() * helper.getDurationMultiplierDouble(); - } - - /** * Finds a list of matched recipes. At this point no additional check to the matched recipe has been done. * <p> * Override {@link #validateRecipe} to have custom check. @@ -409,14 +183,6 @@ public class ProcessingLogic { } /** - * Override to do additional check for found recipe if needed. - */ - @Nonnull - protected CheckRecipeResult validateRecipe(@Nonnull GT_Recipe recipe) { - return CheckRecipeResultRegistry.SUCCESSFUL; - } - - /** * Override to tweak parallel logic if needed. */ @Nonnull @@ -434,60 +200,7 @@ public class ProcessingLogic { .setOutputCalculation(true); } - /** - * Override to tweak overclock logic if needed. - */ - @Nonnull - protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe) { - return new GT_OverclockCalculator().setRecipeEUt(recipe.mEUt) - .setAmperage(availableAmperage) - .setEUt(availableVoltage) - .setDuration(recipe.mDuration) - .setSpeedBoost(speedBoost) - .setEUtDiscount(euModifier) - .setAmperageOC(amperageOC) - .setDurationDecreasePerOC(overClockTimeReduction) - .setEUtIncreasePerOC(overClockPowerIncrease); - } - - /** - * Override to perform additional logic when recipe starts. - * - * This is called when the recipe processing logic has finished all - * checks, consumed all inputs, but has not yet set the outputs to - * be produced. Returning a result other than SUCCESSFUL will void - * all inputs! - */ - @Nonnull - protected CheckRecipeResult onRecipeStart(@Nonnull GT_Recipe recipe) { - return CheckRecipeResultRegistry.SUCCESSFUL; - } - - // endregion - - // region Getters - - public ItemStack[] getOutputItems() { - return outputItems; - } - - public FluidStack[] getOutputFluids() { - return outputFluids; - } - - public int getDuration() { - return duration; - } - - public long getCalculatedEut() { - return calculatedEut; - } - - public int getCurrentParallels() { - return calculatedParallels; - } - - // endregion + // #endregion /** * Represents the status of check recipe calculation. {@link #successfullyConsumedInputs} does not necessarily mean diff --git a/src/main/java/gregtech/api/logic/interfaces/FluidInventoryLogicHost.java b/src/main/java/gregtech/api/logic/interfaces/FluidInventoryLogicHost.java new file mode 100644 index 0000000000..c12333a4c6 --- /dev/null +++ b/src/main/java/gregtech/api/logic/interfaces/FluidInventoryLogicHost.java @@ -0,0 +1,95 @@ +package gregtech.api.logic.interfaces; + +import static com.google.common.primitives.Ints.saturatedCast; + +import java.util.HashSet; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTankInfo; +import net.minecraftforge.fluids.IFluidHandler; + +import gregtech.api.enums.InventoryType; +import gregtech.api.logic.FluidInventoryLogic; + +public interface FluidInventoryLogicHost extends IFluidHandler { + + /** + * To be used for single blocks or when directly interacting with the controller + * + * @param side The side from where fluids are being inputted or extracted from + * @param type The type of inventory being accessed. For inputting its Input, For outputting its Output. + * @return The Fluid Logic responsible for said type. Can return null if the side is invalid + */ + @Nullable + FluidInventoryLogic getFluidLogic(@Nonnull ForgeDirection side, @Nonnull InventoryType type); + + /** + * Only to be used by MultiBlockPart for accessing the Controller Inventory + * + * @param type Type of inventory, is it Input or Output + * @param id ID of the locked inventory. A null id is all inventories of said controller of said type + * @return The Fluid Logic responsible for everything that should be done with said inventory + */ + @Nonnull + default FluidInventoryLogic getFluidLogic(@Nonnull InventoryType type, @Nullable UUID id) { + return Objects.requireNonNull(getFluidLogic(ForgeDirection.UNKNOWN, type)); + } + + /** + * Returns an empty set if the type is {@link InventoryType#Both} or when the machine isn't a controller. + */ + @Nonnull + default Set<Entry<UUID, FluidInventoryLogic>> getAllFluidInventoryLogics(@Nonnull InventoryType type) { + return new HashSet<>(); + } + + @Override + default boolean canDrain(@Nonnull ForgeDirection from, Fluid fluid) { + FluidInventoryLogic logic = getFluidLogic(from, InventoryType.Output); + return logic != null; + } + + @Override + default boolean canFill(@Nonnull ForgeDirection from, Fluid fluid) { + FluidInventoryLogic logic = getFluidLogic(from, InventoryType.Input); + return logic != null; + } + + @Override + @Nullable + default FluidStack drain(@Nonnull ForgeDirection from, @Nonnull FluidStack resource, boolean doDrain) { + FluidInventoryLogic logic = getFluidLogic(from, InventoryType.Output); + if (logic == null) return null; + return logic.drain(resource.getFluid(), resource.amount, !doDrain); + } + + @Override + @Nullable + default FluidStack drain(@Nonnull ForgeDirection from, int maxDrain, boolean doDrain) { + FluidInventoryLogic logic = getFluidLogic(from, InventoryType.Output); + if (logic == null) return null; + return logic.drain(maxDrain, !doDrain); + } + + @Override + default int fill(@Nonnull ForgeDirection from, @Nonnull FluidStack resource, boolean doFill) { + FluidInventoryLogic logic = getFluidLogic(from, InventoryType.Input); + if (logic == null) return 0; + return saturatedCast(logic.fill(resource.getFluid(), resource.amount, !doFill)); + } + + @Override + @Nullable + default FluidTankInfo[] getTankInfo(@Nonnull ForgeDirection from) { + return null; + } +} diff --git a/src/main/java/gregtech/api/logic/interfaces/ItemInventoryLogicHost.java b/src/main/java/gregtech/api/logic/interfaces/ItemInventoryLogicHost.java new file mode 100644 index 0000000000..a65f3c50f1 --- /dev/null +++ b/src/main/java/gregtech/api/logic/interfaces/ItemInventoryLogicHost.java @@ -0,0 +1,172 @@ +package gregtech.api.logic.interfaces; + +import java.util.HashSet; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.api.enums.InventoryType; +import gregtech.api.logic.ItemInventoryLogic; + +public interface ItemInventoryLogicHost extends ISidedInventory { + + /** + * To be used for single blocks or when directly interacting with the controller + * + * @param side The side from where items are being inputted or extracted from + * @param type The type of inventory being accessed. For inputting its Input, For outputting its Output. + * @return The Item Logic responsible for said type. Will return null if the side is not valid + */ + @Nullable + ItemInventoryLogic getItemLogic(@Nonnull ForgeDirection side, @Nonnull InventoryType type); + + /** + * Only to be used by MultiBlockPart for accessing the Controller Inventory + * + * @param type Type of inventory, is it Input or Output + * @param id ID of the locked inventory. A null id is all inventories of said controller of said type + * @return The Item Logic responsible for everything that should be done with said inventory + */ + @Nonnull + default ItemInventoryLogic getItemLogic(@Nonnull InventoryType type, @Nullable UUID id) { + return Objects.requireNonNull(getItemLogic(ForgeDirection.UNKNOWN, type)); + } + + /** + * Only to be used for MultiBlockPart + * + * @return + */ + @Nullable + default InventoryType getItemInventoryType() { + return null; + } + + /** + * Returns an empty set if the type is {@link InventoryType#Both} or this is used when the machine isn't a + * controller + */ + @Nonnull + default Set<Entry<UUID, ItemInventoryLogic>> getAllItemInventoryLogics(@Nonnull InventoryType type) { + return new HashSet<>(); + } + + @Override + @Nullable + default ItemStack decrStackSize(int slot, int count) { + InventoryType type = getItemInventoryType(); + if (type == InventoryType.Both) return null; + ItemInventoryLogic logic = getItemLogic(ForgeDirection.UNKNOWN, type == null ? InventoryType.Output : type); + if (logic == null) return null; + return logic.extractItem(slot, count); + } + + @Override + default int getSizeInventory() { + InventoryType type = getItemInventoryType(); + if (type == InventoryType.Both) return 0; + ItemInventoryLogic logic = getItemLogic(ForgeDirection.UNKNOWN, type == null ? InventoryType.Output : type); + if (logic == null) return 0; + return logic.getSlots(); + } + + @Override + @Nullable + default ItemStack getStackInSlot(int slot) { + InventoryType type = getItemInventoryType(); + if (type == InventoryType.Both) return null; + ItemInventoryLogic logic = getItemLogic(ForgeDirection.UNKNOWN, type == null ? InventoryType.Output : type); + if (logic == null) return null; + return logic.getInventory() + .getStackInSlot(slot); + } + + @Override + default boolean isItemValidForSlot(int slot, @Nullable ItemStack stack) { + InventoryType type = getItemInventoryType(); + if (type == InventoryType.Both) return false; + ItemInventoryLogic logic = getItemLogic(ForgeDirection.UNKNOWN, type == null ? InventoryType.Output : type); + if (logic == null) return false; + return logic.getInventory() + .isItemValid(slot, stack); + } + + @Override + default void setInventorySlotContents(int slot, @Nullable ItemStack stack) { + InventoryType type = getItemInventoryType(); + if (type == InventoryType.Both) return; + ItemInventoryLogic logic = getItemLogic(ForgeDirection.UNKNOWN, type == null ? InventoryType.Output : type); + if (logic == null) return; + logic.getInventory() + .setStackInSlot(slot, stack); + } + + @Override + default boolean canExtractItem(int ignoredSlot, ItemStack ignoredItem, int side) { + InventoryType type = getItemInventoryType(); + if (type == null) return false; + return getItemLogic(ForgeDirection.getOrientation(side), type) != null; + } + + @Override + default boolean canInsertItem(int ignoredSlot, ItemStack ignoredItem, int side) { + InventoryType type = getItemInventoryType(); + if (type == null) return false; + return getItemInventoryType() != InventoryType.Output + && getItemLogic(ForgeDirection.getOrientation(side), type) != null; + } + + @Override + default int[] getAccessibleSlotsFromSide(int side) { + InventoryType type = getItemInventoryType(); + if (type == null) return new int[0]; + ItemInventoryLogic logic = getItemLogic(ForgeDirection.UNKNOWN, type == null ? InventoryType.Output : type); + if (logic == null) return new int[0]; + int[] indexes = new int[logic.getSlots()]; + for (int i = 0; i < logic.getSlots(); i++) { + indexes[i] = i; + } + return indexes; + } + + @Override + default void closeInventory() {} + + @Override + default String getInventoryName() { + return ""; + } + + @Override + default int getInventoryStackLimit() { + return 64; + } + + @Override + default ItemStack getStackInSlotOnClosing(int index) { + return null; + } + + @Override + default boolean hasCustomInventoryName() { + return false; + } + + @Override + default boolean isUseableByPlayer(@Nonnull EntityPlayer player) { + return false; + } + + @Override + default void openInventory() {} + +} diff --git a/src/main/java/gregtech/api/logic/interfaces/PollutionLogicHost.java b/src/main/java/gregtech/api/logic/interfaces/PollutionLogicHost.java deleted file mode 100644 index 657efbb74d..0000000000 --- a/src/main/java/gregtech/api/logic/interfaces/PollutionLogicHost.java +++ /dev/null @@ -1,8 +0,0 @@ -package gregtech.api.logic.interfaces; - -import gregtech.api.logic.PollutionLogic; - -public interface PollutionLogicHost { - - PollutionLogic getPollutionLogic(); -} diff --git a/src/main/java/gregtech/api/logic/interfaces/PowerLogicHost.java b/src/main/java/gregtech/api/logic/interfaces/PowerLogicHost.java index 8604c160fb..4903d7fa23 100644 --- a/src/main/java/gregtech/api/logic/interfaces/PowerLogicHost.java +++ b/src/main/java/gregtech/api/logic/interfaces/PowerLogicHost.java @@ -1,18 +1,60 @@ package gregtech.api.logic.interfaces; +import java.util.Objects; + +import javax.annotation.Nonnull; + import net.minecraftforge.common.util.ForgeDirection; +import gregtech.api.interfaces.tileentity.IEnergyConnected; import gregtech.api.logic.PowerLogic; +/** + * Power logic class for one to use to enable a machine to use energy + */ public interface PowerLogicHost { - PowerLogic getPowerLogic(ForgeDirection side); + /** + * + * @param side Side being access to try and get the power logic from + * @return Can return NullPowerLogic if the side doesn't allow the return of the logic. That power logic is unusable + */ + @Nonnull + PowerLogic getPowerLogic(@Nonnull ForgeDirection side); + + /** + * Gives the power logic ignoring the side. + */ + @Nonnull + default PowerLogic getPowerLogic() { + return Objects.requireNonNull(getPowerLogic(ForgeDirection.UNKNOWN)); + } + /** + * Shortcut to the method of {@link PowerLogic#isEnergyReceiver()} + */ default boolean isEnergyReceiver() { - return false; + return getPowerLogic().isEnergyReceiver(); } + /** + * Shortcut to the method of {@link PowerLogic#isEnergyEmitter()} + */ default boolean isEnergyEmitter() { - return false; + return getPowerLogic().isEnergyEmitter(); } + + /** + * Method for emitting energy to other blocks and machines. Override when it needs to be changed. + */ + default void emitEnergyFromLogic() { + IEnergyConnected.Util.emitEnergyToNetwork(this, getPowerOutputSide()); + } + + /** + * From where does the machine output energy from? + * When the output side is {@link ForgeDirection#UNKNOWN} then it won't output energy + */ + @Nonnull + ForgeDirection getPowerOutputSide(); } diff --git a/src/main/java/gregtech/api/logic/interfaces/ProcessingLogicHost.java b/src/main/java/gregtech/api/logic/interfaces/ProcessingLogicHost.java index 55418208b0..b8291c9843 100644 --- a/src/main/java/gregtech/api/logic/interfaces/ProcessingLogicHost.java +++ b/src/main/java/gregtech/api/logic/interfaces/ProcessingLogicHost.java @@ -1,8 +1,82 @@ package gregtech.api.logic.interfaces; -import gregtech.api.logic.ProcessingLogic; +import javax.annotation.Nonnull; -public interface ProcessingLogicHost { +import gregtech.api.enums.VoidingMode; +import gregtech.api.interfaces.tileentity.IMachineProgress; +import gregtech.api.interfaces.tileentity.IVoidable; +import gregtech.api.logic.MuTEProcessingLogic; - ProcessingLogic getProcessingLogic(); +public interface ProcessingLogicHost<P extends MuTEProcessingLogic<P>> + extends IVoidable, ItemInventoryLogicHost, FluidInventoryLogicHost, IMachineProgress { + + /** + * Get the processing logic for the current machine + */ + @Nonnull + P getProcessingLogic(); + + boolean isInputSeparated(); + + void setInputSeparation(Boolean inputSeparation); + + default boolean supportsInputSeparation() { + return true; + } + + default boolean getDefaultInputSeparationMode() { + return false; + } + + boolean isRecipeLockingEnabled(); + + void setRecipeLocking(Boolean recipeLocked); + + default boolean supportsSingleRecipeLocking() { + return true; + } + + default boolean getDefaultRecipeLockingMode() { + return false; + } + + default boolean supportsBatchMode() { + return true; + } + + void setBatchMode(Boolean batchMode); + + boolean isBatchModeEnabled(); + + default boolean getDefaultBatchMode() { + return false; + } + + /** + * Get what the machine can void or not + */ + @Nonnull + VoidingMode getVoidMode(); + + /** + * Called when the processing logic should be updated by {@link #needsUpdate()} + */ + default void updateProcessingLogic(@Nonnull P processingLogic) {} + + /** + * Called before the recipe check, but after any other updates + */ + default void setProcessingLogicPower(@Nonnull P processingLogic) {} + + /** + * DO NOT CALL YOURSELF!!! + * + * If you want to make the processing logic be updated call {@link #setProcessingUpdate(boolean)} + */ + boolean needsUpdate(); + + /** + * To be called when one needs to updated the processing logic. That can be when parallel changes, ect. + */ + void setProcessingUpdate(boolean update); } diff --git a/src/main/java/gregtech/api/metatileentity/BaseTileEntity.java b/src/main/java/gregtech/api/metatileentity/BaseTileEntity.java index 774c13e91b..d8b0086f0f 100644 --- a/src/main/java/gregtech/api/metatileentity/BaseTileEntity.java +++ b/src/main/java/gregtech/api/metatileentity/BaseTileEntity.java @@ -51,6 +51,8 @@ import com.gtnewhorizons.modularui.common.widget.SlotGroup; import com.gtnewhorizons.modularui.common.widget.SlotWidget; import com.gtnewhorizons.modularui.common.widget.TextWidget; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.relauncher.Side; import gregtech.GT_Mod; import gregtech.api.enums.Dyes; import gregtech.api.enums.GT_Values; @@ -175,13 +177,18 @@ public abstract class BaseTileEntity extends TileEntity implements IHasWorldObje @Override public final boolean isServerSide() { if (worldObj == null) { - return false; + return FMLCommonHandler.instance() + .getEffectiveSide() == Side.SERVER; } return !worldObj.isRemote; } @Override public final boolean isClientSide() { + if (worldObj == null) { + return FMLCommonHandler.instance() + .getEffectiveSide() == Side.CLIENT; + } return worldObj.isRemote; } @@ -609,29 +616,6 @@ public abstract class BaseTileEntity extends TileEntity implements IHasWorldObje return false; } - @Override - public ModularWindow createWindow(UIBuildContext buildContext) { - if (!useModularUI()) return null; - - buildContext.setValidator(getValidator()); - final ModularWindow.Builder builder = ModularWindow.builder(getGUIWidth(), getGUIHeight()); - builder.setBackground(getGUITextureSet().getMainBackground()); - builder.setGuiTint(getGUIColorization()); - if (doesBindPlayerInventory()) { - bindPlayerInventoryUI(builder, buildContext); - } - addUIWidgets(builder, buildContext); - addTitleToUI(builder); - addCoverTabs(builder, buildContext); - final IConfigurationCircuitSupport csc = getConfigurationCircuitSupport(); - if (csc != null && csc.allowSelectCircuit()) { - addConfigurationCircuitSlot(builder); - } else { - addGregTechLogo(builder); - } - return builder.build(); - } - /* * IC2 Energy Compat */ diff --git a/src/main/java/gregtech/api/metatileentity/CommonMetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/CommonMetaTileEntity.java index acb3e75235..5a2e88b242 100644 --- a/src/main/java/gregtech/api/metatileentity/CommonMetaTileEntity.java +++ b/src/main/java/gregtech/api/metatileentity/CommonMetaTileEntity.java @@ -314,4 +314,27 @@ public abstract class CommonMetaTileEntity extends CoverableTileEntity public ItemStack getMachineCraftingIcon() { return getMetaTileEntity() != null ? getMetaTileEntity().getMachineCraftingIcon() : null; } + + @Override + public ModularWindow createWindow(UIBuildContext buildContext) { + if (!useModularUI()) return null; + + buildContext.setValidator(getValidator()); + final ModularWindow.Builder builder = ModularWindow.builder(getGUIWidth(), getGUIHeight()); + builder.setBackground(getGUITextureSet().getMainBackground()); + builder.setGuiTint(getGUIColorization()); + if (doesBindPlayerInventory()) { + bindPlayerInventoryUI(builder, buildContext); + } + addUIWidgets(builder, buildContext); + addTitleToUI(builder); + addCoverTabs(builder, buildContext); + final IConfigurationCircuitSupport csc = getConfigurationCircuitSupport(); + if (csc != null && csc.allowSelectCircuit()) { + addConfigurationCircuitSlot(builder); + } else { + addGregTechLogo(builder); + } + return builder.build(); + } } diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Cable.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Cable.java index db4ead0932..d2e37bf2f3 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Cable.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaPipeEntity_Cable.java @@ -360,7 +360,7 @@ public class GT_MetaPipeEntity_Cable extends MetaPipeEntity implements IMetaTile final ForgeDirection oppositeSide = side.getOpposite(); // GT Machine handling - if ((tileEntity instanceof PowerLogicHost powerLogic && powerLogic.getPowerLogic(side) != null) + if ((tileEntity instanceof PowerLogicHost powerLogic && powerLogic.getPowerLogic(oppositeSide) != null) || ((tileEntity instanceof IEnergyConnected energyConnected) && (energyConnected.inputEnergyFrom(oppositeSide, false) || energyConnected.outputsEnergyTo(oppositeSide, false)))) diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Wireless_Dynamo.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Wireless_Dynamo.java index 821c02d10f..4b73210afd 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Wireless_Dynamo.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Wireless_Dynamo.java @@ -2,6 +2,8 @@ package gregtech.api.metatileentity.implementations; import static gregtech.api.enums.GT_Values.AuthorColen; import static gregtech.api.enums.GT_Values.V; +import static gregtech.common.misc.WirelessNetworkManager.addEUToGlobalEnergyMap; +import static gregtech.common.misc.WirelessNetworkManager.strongCheckOrAddUser; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; @@ -9,14 +11,13 @@ import net.minecraft.util.EnumChatFormatting; import net.minecraftforge.common.util.ForgeDirection; import gregtech.api.enums.Textures; -import gregtech.api.interfaces.IGlobalWirelessEnergy; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.interfaces.tileentity.IWirelessEnergyHatchInformation; import gregtech.api.metatileentity.MetaTileEntity; public class GT_MetaTileEntity_Wireless_Dynamo extends GT_MetaTileEntity_Hatch_Dynamo - implements IGlobalWirelessEnergy, IWirelessEnergyHatchInformation { + implements IWirelessEnergyHatchInformation { private String owner_uuid; private String owner_name; diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Wireless_Hatch.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Wireless_Hatch.java index 66a84dfa99..251a9dfcec 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Wireless_Hatch.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_Wireless_Hatch.java @@ -2,6 +2,8 @@ package gregtech.api.metatileentity.implementations; import static gregtech.api.enums.GT_Values.AuthorColen; import static gregtech.api.enums.GT_Values.V; +import static gregtech.common.misc.WirelessNetworkManager.addEUToGlobalEnergyMap; +import static gregtech.common.misc.WirelessNetworkManager.strongCheckOrAddUser; import static java.lang.Long.min; import java.math.BigInteger; @@ -12,14 +14,13 @@ import net.minecraft.util.EnumChatFormatting; import net.minecraftforge.common.util.ForgeDirection; import gregtech.api.enums.Textures; -import gregtech.api.interfaces.IGlobalWirelessEnergy; import gregtech.api.interfaces.ITexture; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.interfaces.tileentity.IWirelessEnergyHatchInformation; import gregtech.api.metatileentity.MetaTileEntity; public class GT_MetaTileEntity_Wireless_Hatch extends GT_MetaTileEntity_Hatch_Energy - implements IGlobalWirelessEnergy, IWirelessEnergyHatchInformation { + implements IWirelessEnergyHatchInformation { private final BigInteger eu_transferred_per_operation = BigInteger .valueOf(2 * V[mTier] * ticks_between_energy_addition); diff --git a/src/main/java/gregtech/api/multitileentity/MultiTileEntityBlock.java b/src/main/java/gregtech/api/multitileentity/MultiTileEntityBlock.java index a30d523b55..5ea1069193 100644 --- a/src/main/java/gregtech/api/multitileentity/MultiTileEntityBlock.java +++ b/src/main/java/gregtech/api/multitileentity/MultiTileEntityBlock.java @@ -189,8 +189,8 @@ public class MultiTileEntityBlock extends Block implements IDebugableBlock, ITil @Override public ArrayList<String> getDebugInfo(EntityPlayer aPlayer, int aX, int aY, int aZ, int aLogLevel) { final TileEntity aTileEntity = aPlayer.worldObj.getTileEntity(aX, aY, aZ); - if (aTileEntity instanceof IDebugableTileEntity) { - return ((IDebugableTileEntity) aTileEntity).getDebugInfo(aPlayer, aLogLevel); + if (aTileEntity instanceof IDebugableTileEntity mte) { + return mte.getDebugInfo(aPlayer, aLogLevel); } return new ArrayList<>(); } @@ -291,7 +291,7 @@ public class MultiTileEntityBlock extends Block implements IDebugableBlock, ITil final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ); if (!LOCK) { LOCK = true; - if (aTileEntity instanceof BaseTileEntity) ((BaseTileEntity) aTileEntity).onAdjacentBlockChange(aX, aY, aZ); + if (aTileEntity instanceof BaseTileEntity bte) bte.onAdjacentBlockChange(aX, aY, aZ); LOCK = false; } if (aTileEntity instanceof IMTE_OnNeighborBlockChange change) change.onNeighborBlockChange(aWorld, aBlock); @@ -368,21 +368,25 @@ public class MultiTileEntityBlock extends Block implements IDebugableBlock, ITil final int aFortune = EnchantmentHelper.getFortuneModifier(aPlayer); float aChance = 1.0F; final TileEntity aTileEntity = getTileEntity(aWorld, aX, aY, aZ, true); - if (aTileEntity instanceof IMultiTileEntity) { - final ArrayList<ItemStack> tList = ((IMultiTileEntity) aTileEntity).getDrops(aFortune, aSilkTouch); - aChance = ForgeEventFactory - .fireBlockHarvesting(tList, aWorld, this, aX, aY, aZ, aMeta, aFortune, aChance, aSilkTouch, aPlayer); - for (final ItemStack tStack : tList) - if (XSTR.XSTR_INSTANCE.nextFloat() <= aChance) dropBlockAsItem(aWorld, aX, aY, aZ, tStack); + + if (!(aTileEntity instanceof IMultiTileEntity mte)) { + return; } + + final ArrayList<ItemStack> tList = mte.getDrops(aFortune, aSilkTouch); + aChance = ForgeEventFactory + .fireBlockHarvesting(tList, aWorld, this, aX, aY, aZ, aMeta, aFortune, aChance, aSilkTouch, aPlayer); + for (final ItemStack tStack : tList) + if (XSTR.XSTR_INSTANCE.nextFloat() <= aChance) dropBlockAsItem(aWorld, aX, aY, aZ, tStack); + } @Override public final boolean shouldSideBeRendered(IBlockAccess aWorld, int aX, int aY, int aZ, int ordinalSide) { final TileEntity aTileEntity = aWorld .getTileEntity(aX - OFFX[ordinalSide], aY - OFFY[ordinalSide], aZ - OFFZ[ordinalSide]); - return aTileEntity instanceof IMultiTileEntity - ? ((IMultiTileEntity) aTileEntity).shouldSideBeRendered(ForgeDirection.getOrientation(ordinalSide)) + return aTileEntity instanceof IMultiTileEntity mte + ? mte.shouldSideBeRendered(ForgeDirection.getOrientation(ordinalSide)) : super.shouldSideBeRendered(aWorld, aX, aY, aZ, ordinalSide); } @@ -473,12 +477,17 @@ public class MultiTileEntityBlock extends Block implements IDebugableBlock, ITil @Override public final int getComparatorInputOverride(World aWorld, int aX, int aY, int aZ, int ordinalSide) { final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ); - return aTileEntity instanceof IMTE_GetComparatorInputOverride override - ? override.getComparatorInputOverride(ForgeDirection.getOrientation(ordinalSide)) - : aTileEntity instanceof IMTE_IsProvidingWeakPower power ? power.isProvidingWeakPower( + if (aTileEntity instanceof IMTE_GetComparatorInputOverride override) { + return override.getComparatorInputOverride(ForgeDirection.getOrientation(ordinalSide)); + } + + if (aTileEntity instanceof IMTE_IsProvidingWeakPower power) { + return power.isProvidingWeakPower( ForgeDirection.getOrientation(ordinalSide) - .getOpposite()) - : super.getComparatorInputOverride(aWorld, aX, aY, aZ, ordinalSide); + .getOpposite()); + } + + return super.getComparatorInputOverride(aWorld, aX, aY, aZ, ordinalSide); } @Override @@ -523,7 +532,7 @@ public class MultiTileEntityBlock extends Block implements IDebugableBlock, ITil public final ArrayList<ItemStack> getDrops(World aWorld, int aX, int aY, int aZ, int aUnusableMetaData, int aFortune) { final TileEntity aTileEntity = getTileEntity(aWorld, aX, aY, aZ, true); - if (aTileEntity instanceof IMultiTileEntity) return ((IMultiTileEntity) aTileEntity).getDrops(aFortune, false); + if (aTileEntity instanceof IMultiTileEntity mte) return mte.getDrops(aFortune, false); return new ArrayList<>(); } @@ -536,8 +545,8 @@ public class MultiTileEntityBlock extends Block implements IDebugableBlock, ITil public final float getExplosionResistance(Entity aExploder, World aWorld, int aX, int aY, int aZ, double aExplosionX, double aExplosionY, double aExplosionZ) { final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ); - return aTileEntity instanceof IMultiTileEntity - ? ((IMultiTileEntity) aTileEntity).getExplosionResistance(aExploder, aExplosionX, aExplosionY, aExplosionZ) + return aTileEntity instanceof IMultiTileEntity mte + ? mte.getExplosionResistance(aExploder, aExplosionX, aExplosionY, aExplosionZ) : 1.0F; } @@ -546,14 +555,14 @@ public class MultiTileEntityBlock extends Block implements IDebugableBlock, ITil if (aWorld.isRemote) return; final TileEntity aTileEntity = getTileEntity(aWorld, aX, aY, aZ, true); if (aTileEntity != null) LAST_BROKEN_TILEENTITY.set(aTileEntity); - if (aTileEntity instanceof IMultiTileEntity) { + if (aTileEntity instanceof IMultiTileEntity mte) { GT_Log.exp.printf( "Explosion at : %d | %d | %d DIMID: %s due to near explosion!%n", aX, aY, aZ, aWorld.provider.dimensionId); - ((IMultiTileEntity) aTileEntity).onExploded(aExplosion); + mte.onExploded(aExplosion); } else aWorld.setBlockToAir(aX, aY, aZ); } @@ -587,13 +596,13 @@ public class MultiTileEntityBlock extends Block implements IDebugableBlock, ITil public final ItemStack getPickBlock(MovingObjectPosition aTarget, World aWorld, int aX, int aY, int aZ, EntityPlayer aPlayer) { final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ); - return aTileEntity instanceof IMultiTileEntity ? ((IMultiTileEntity) aTileEntity).getPickBlock(aTarget) : null; + return aTileEntity instanceof IMultiTileEntity mte ? mte.getPickBlock(aTarget) : null; } @Override public final ItemStack getPickBlock(MovingObjectPosition aTarget, World aWorld, int aX, int aY, int aZ) { final TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ); - return aTileEntity instanceof IMultiTileEntity ? ((IMultiTileEntity) aTileEntity).getPickBlock(aTarget) : null; + return aTileEntity instanceof IMultiTileEntity mte ? mte.getPickBlock(aTarget) : null; } public final IMultiTileEntity receiveMultiTileEntityData(IBlockAccess aWorld, int aX, short aY, int aZ, short aRID, @@ -601,9 +610,8 @@ public class MultiTileEntityBlock extends Block implements IDebugableBlock, ITil if (!(aWorld instanceof World)) return null; TileEntity aTileEntity = aWorld.getTileEntity(aX, aY, aZ); - if (!(aTileEntity instanceof IMultiTileEntity) - || ((IMultiTileEntity) aTileEntity).getMultiTileEntityRegistryID() != aRID - || ((IMultiTileEntity) aTileEntity).getMultiTileEntityID() != aID) { + if (!(aTileEntity instanceof IMultiTileEntity mte) || mte.getMultiTileEntityRegistryID() != aRID + || mte.getMultiTileEntityID() != aID) { final MultiTileEntityRegistry tRegistry = MultiTileEntityRegistry.getRegistry(aRID); if (tRegistry == null) return null; @@ -612,7 +620,7 @@ public class MultiTileEntityBlock extends Block implements IDebugableBlock, ITil setTileEntity((World) aWorld, aX, aY, aZ, aTileEntity, false); } - return ((IMultiTileEntity) aTileEntity); + return (IMultiTileEntity) aTileEntity; } public void receiveCoverData(IMultiTileEntity mte, int aCover0, int aCover1, int aCover2, int aCover3, int aCover4, @@ -629,14 +637,6 @@ public class MultiTileEntityBlock extends Block implements IDebugableBlock, ITil mte.issueBlockUpdate(); } } - // - // te.receiveClientEvent(GregTechTileClientEvents.CHANGE_COMMON_DATA, aTextureData); - // - // te.receiveClientEvent(GregTechTileClientEvents.CHANGE_CUSTOM_DATA, aUpdateData & 0x7F); - // te.receiveClientEvent(GregTechTileClientEvents.CHANGE_CUSTOM_DATA, aTexturePage | 0x80); - // - // te.receiveClientEvent(GregTechTileClientEvents.CHANGE_COLOR, aColorData); - // te.receiveClientEvent(GregTechTileClientEvents.CHANGE_REDSTONE_OUTPUT, aRedstoneData); @Override public final TileEntity createTileEntity(World aWorld, int aMeta) { diff --git a/src/main/java/gregtech/api/multitileentity/MultiTileEntityClassContainer.java b/src/main/java/gregtech/api/multitileentity/MultiTileEntityClassContainer.java index 3eae75f934..4ce4c3c886 100644 --- a/src/main/java/gregtech/api/multitileentity/MultiTileEntityClassContainer.java +++ b/src/main/java/gregtech/api/multitileentity/MultiTileEntityClassContainer.java @@ -13,6 +13,7 @@ import gregtech.api.multitileentity.multiblock.casing.FunctionalCasing; import gregtech.api.multitileentity.multiblock.casing.UpgradeCasing; import gregtech.api.util.GT_Util; import gregtech.common.tileentities.casings.upgrade.Inventory; +import gregtech.common.tileentities.casings.upgrade.Tank; public class MultiTileEntityClassContainer { @@ -144,6 +145,23 @@ public class MultiTileEntityClassContainer { return this; } + public MultiTileEntityClassContainer upgradeTankCount(int count) { + verifyDescendentOf(Tank.class); + + mParameters.setInteger(NBT.UPGRADE_TANK_COUNT, count); + return this; + } + + public MultiTileEntityClassContainer upgradeTankCapacity(Long aCapacity) { + mParameters.setLong(NBT.UPGRADE_TANK_CAPACITY, aCapacity); + return this; + } + + public MultiTileEntityClassContainer upgradeAmperage(long amperage) { + mParameters.setLong(NBT.UPGRADE_AMPERAGE, amperage); + return this; + } + @SuppressWarnings("unused") public MultiTileEntityClassContainer setNBT(String key, Object val) { return setNBT(new Tuple(key, val)); diff --git a/src/main/java/gregtech/api/multitileentity/MultiTileEntityItemInternal.java b/src/main/java/gregtech/api/multitileentity/MultiTileEntityItemInternal.java index 07a9124df4..cc10485f84 100644 --- a/src/main/java/gregtech/api/multitileentity/MultiTileEntityItemInternal.java +++ b/src/main/java/gregtech/api/multitileentity/MultiTileEntityItemInternal.java @@ -51,14 +51,14 @@ public class MultiTileEntityItemInternal extends ItemBlock implements IFluidCont @SuppressWarnings("unchecked") public void addInformation(ItemStack aStack, EntityPlayer aPlayer, List<String> aList, boolean aF3_H) { final MultiTileEntityContainer tTileEntityContainer = mBlock.mMultiTileEntityRegistry - .getNewTileEntityContainer(aStack); + .getCachedTileEntityContainer(aStack); if (tTileEntityContainer == null) { aList.add("INVALID ITEM!"); return; } - if (tTileEntityContainer.mTileEntity instanceof IMTE_AddToolTips) { + if (tTileEntityContainer.mTileEntity instanceof IMTE_AddToolTips mte) { try { - ((IMTE_AddToolTips) tTileEntityContainer.mTileEntity).addToolTips(aList, aStack, aF3_H); + mte.addToolTips(aList, aStack, aF3_H); } catch (Throwable e) { GT_FML_LOGGER.error("addInformation", e); } @@ -73,11 +73,9 @@ public class MultiTileEntityItemInternal extends ItemBlock implements IFluidCont @SuppressWarnings("unchecked") public void getSubItems(Item aItem, CreativeTabs aTab, List<ItemStack> aList) { for (MultiTileEntityClassContainer tClass : mBlock.mMultiTileEntityRegistry.mRegistrations) { - if (!tClass.mHidden) { - if (((IMultiTileEntity) tClass.mCanonicalTileEntity) - .getSubItems(mBlock, aItem, aTab, aList, tClass.mID)) { - aList.add(mBlock.mMultiTileEntityRegistry.getItem(tClass.mID)); - } + if (!tClass.mHidden && ((IMultiTileEntity) tClass.mCanonicalTileEntity) + .getSubItems(mBlock, aItem, aTab, aList, tClass.mID)) { + aList.add(mBlock.mMultiTileEntityRegistry.getItem(tClass.mID)); } } } @@ -85,10 +83,15 @@ public class MultiTileEntityItemInternal extends ItemBlock implements IFluidCont @Override public boolean onItemUse(ItemStack aStack, EntityPlayer aPlayer, World aWorld, int aX, int aY, int aZ, int ordinalSide, float aHitX, float aHitY, float aHitZ) { + if (aY < 0 || aY > aWorld.getHeight()) return false; + + if (aPlayer == null) return false; + try { ForgeDirection side = ForgeDirection.getOrientation(ordinalSide); final Block tClickedBlock = aWorld.getBlock(aX, aY, aZ); + if (tClickedBlock instanceof BlockSnow && (aWorld.getBlockMetadata(aX, aY, aZ) & 7) < 1) { ordinalSide = SIDE_TOP; side = ForgeDirection.UP; @@ -102,79 +105,86 @@ public class MultiTileEntityItemInternal extends ItemBlock implements IFluidCont final Block tReplacedBlock = aWorld.getBlock(aX, aY, aZ); if (!tReplacedBlock.isReplaceable(aWorld, aX, aY, aZ) - || !mBlock.canReplace(aWorld, aX, aY, aZ, ordinalSide, aStack)) return false; - if (aStack.stackSize == 0 || (aPlayer != null && !aPlayer.canPlayerEdit(aX, aY, aZ, ordinalSide, aStack))) + || !mBlock.canReplace(aWorld, aX, aY, aZ, ordinalSide, aStack)) { return false; + } + + if (aStack.stackSize == 0 || (!aPlayer.canPlayerEdit(aX, aY, aZ, ordinalSide, aStack))) { + return false; + } final MultiTileEntityContainer aMTEContainer = mBlock.mMultiTileEntityRegistry .getNewTileEntityContainer(aWorld, aX, aY, aZ, aStack); - if (aMTEContainer != null - && (aPlayer == null || aPlayer.isSneaking() - || !(aMTEContainer.mTileEntity instanceof IMTE_OnlyPlaceableWhenSneaking mteSNeaking) - || !mteSNeaking.onlyPlaceableWhenSneaking()) - && (aWorld.checkNoEntityCollision(AxisAlignedBB.getBoundingBox(aX, aY, aZ, aX + 1, aY + 1, aZ + 1)) - || (aMTEContainer.mTileEntity instanceof IMTE_IgnoreEntityCollisionWhenPlacing mteIgnoreCollision - && mteIgnoreCollision.ignoreEntityCollisionWhenPlacing( - aStack, - aPlayer, - aWorld, - aX, - aY, - aZ, - side, - aHitX, - aHitY, - aHitZ))) - && (!(aMTEContainer.mTileEntity instanceof IMTE_CanPlace mteCanPlace) - || mteCanPlace.canPlace(aStack, aPlayer, aWorld, aX, aY, aZ, side, aHitX, aHitY, aHitZ)) - && aWorld.setBlock(aX, aY, aZ, aMTEContainer.mBlock, 15 - aMTEContainer.mBlockMetaData, 2)) { - aMTEContainer.setMultiTile(aWorld, aX, aY, aZ); - - try { - if (((IMultiTileEntity) aMTEContainer.mTileEntity) - .onPlaced(aStack, aPlayer, aWorld, aX, aY, aZ, side, aHitX, aHitY, aHitZ)) { - aWorld.playSoundEffect( - aX + 0.5, - aY + 0.5, - aZ + 0.5, - aMTEContainer.mBlock.stepSound.func_150496_b(), - (aMTEContainer.mBlock.stepSound.getVolume() + 1) / 2, - aMTEContainer.mBlock.stepSound.getPitch() * 0.8F); - } - } catch (Throwable e) { - GT_FML_LOGGER.error("onPlaced", e); - } - try { - if (aMTEContainer.mTileEntity instanceof IMTE_HasMultiBlockMachineRelevantData mteData - && (mteData.hasMultiBlockMachineRelevantData())) { - GregTech_API.causeMachineUpdate(aWorld, aX, aY, aZ); - } - } catch (Throwable e) { - GT_FML_LOGGER.error("causeMachineUpdate", e); - } - try { - if (!aWorld.isRemote) { - aWorld.notifyBlockChange(aX, aY, aZ, tReplacedBlock); - aWorld.func_147453_f /* updateNeighborsAboutBlockChange */(aX, aY, aZ, aMTEContainer.mBlock); - } - } catch (Throwable e) { - GT_FML_LOGGER.error("notifyBlockChange", e); + if (aMTEContainer == null) return false; + + if (!aPlayer.isSneaking() && aMTEContainer.mTileEntity instanceof IMTE_OnlyPlaceableWhenSneaking mteSNeaking + && mteSNeaking.onlyPlaceableWhenSneaking()) { + return false; + } + + if ((!(aMTEContainer.mTileEntity instanceof IMTE_IgnoreEntityCollisionWhenPlacing mteIgnoreCollision) + || !mteIgnoreCollision + .ignoreEntityCollisionWhenPlacing(aStack, aPlayer, aWorld, aX, aY, aZ, side, aHitX, aHitY, aHitZ)) + && !aWorld.checkNoEntityCollision(AxisAlignedBB.getBoundingBox(aX, aY, aZ, aX + 1, aY + 1, aZ + 1))) { + return false; + } + + if (aMTEContainer.mTileEntity instanceof IMTE_CanPlace mteCanPlace + && !mteCanPlace.canPlace(aStack, aPlayer, aWorld, aX, aY, aZ, side, aHitX, aHitY, aHitZ)) { + return false; + } + + if (!aWorld.setBlock(aX, aY, aZ, aMTEContainer.mBlock, 15 - aMTEContainer.mBlockMetaData, 2)) { + return false; + } + + aMTEContainer.setMultiTile(aWorld, aX, aY, aZ); + + try { + if (((IMultiTileEntity) aMTEContainer.mTileEntity) + .onPlaced(aStack, aPlayer, aWorld, aX, aY, aZ, side, aHitX, aHitY, aHitZ)) { + aWorld.playSoundEffect( + aX + 0.5, + aY + 0.5, + aZ + 0.5, + aMTEContainer.mBlock.stepSound.func_150496_b(), + (aMTEContainer.mBlock.stepSound.getVolume() + 1) / 2, + aMTEContainer.mBlock.stepSound.getPitch() * 0.8F); } - try { - ((IMultiTileEntity) aMTEContainer.mTileEntity).onTileEntityPlaced(); - } catch (Throwable e) { - GT_FML_LOGGER.error("onTileEntityPlaced", e); + } catch (Throwable e) { + GT_FML_LOGGER.error("onPlaced", e); + } + try { + if (aMTEContainer.mTileEntity instanceof IMTE_HasMultiBlockMachineRelevantData mteData + && (mteData.hasMultiBlockMachineRelevantData())) { + GregTech_API.causeMachineUpdate(aWorld, aX, aY, aZ); } - try { - aWorld.func_147451_t /* updateAllLightTypes */(aX, aY, aZ); - } catch (Throwable e) { - GT_FML_LOGGER.error("updateAllLightTypes", e); + } catch (Throwable e) { + GT_FML_LOGGER.error("causeMachineUpdate", e); + } + try { + if (!aWorld.isRemote) { + aWorld.notifyBlockChange(aX, aY, aZ, tReplacedBlock); + aWorld.func_147453_f /* updateNeighborsAboutBlockChange */(aX, aY, aZ, aMTEContainer.mBlock); } - - aStack.stackSize--; - return true; + } catch (Throwable e) { + GT_FML_LOGGER.error("notifyBlockChange", e); + } + try { + ((IMultiTileEntity) aMTEContainer.mTileEntity).onTileEntityPlaced(); + } catch (Throwable e) { + GT_FML_LOGGER.error("onTileEntityPlaced", e); } + try { + aWorld.func_147451_t /* updateAllLightTypes */(aX, aY, aZ); + } catch (Throwable e) { + GT_FML_LOGGER.error("updateAllLightTypes", e); + } + + aStack.stackSize--; + return true; + } catch (Throwable e) { GT_FML_LOGGER.error("onItemUse", e); } @@ -186,7 +196,7 @@ public class MultiTileEntityItemInternal extends ItemBlock implements IFluidCont final MultiTileEntityClassContainer tContainer = mBlock.mMultiTileEntityRegistry.getClassContainer(aStack); if (tContainer == null) return; final MultiTileEntityContainer tTileEntityContainer = mBlock.mMultiTileEntityRegistry - .getNewTileEntityContainer(aStack); + .getCachedTileEntityContainer(aStack); if (tTileEntityContainer != null && tTileEntityContainer.mTileEntity instanceof IItemUpdatable itemUpdatable) { itemUpdatable.updateItemStack(aStack); } @@ -197,7 +207,7 @@ public class MultiTileEntityItemInternal extends ItemBlock implements IFluidCont final MultiTileEntityClassContainer tContainer = mBlock.mMultiTileEntityRegistry.getClassContainer(aStack); if (tContainer == null) return; final MultiTileEntityContainer tTileEntityContainer = mBlock.mMultiTileEntityRegistry - .getNewTileEntityContainer(aStack); + .getCachedTileEntityContainer(aStack); if (tTileEntityContainer != null && tTileEntityContainer.mTileEntity instanceof IItemUpdatable itemUpdatable) { itemUpdatable.updateItemStack(aStack, aWorld, aX, aY, aZ); } @@ -208,7 +218,7 @@ public class MultiTileEntityItemInternal extends ItemBlock implements IFluidCont final MultiTileEntityClassContainer tContainer = mBlock.mMultiTileEntityRegistry.getClassContainer(aStack); if (tContainer == null) return 1; final MultiTileEntityContainer tTileEntityContainer = mBlock.mMultiTileEntityRegistry - .getNewTileEntityContainer(aStack); + .getCachedTileEntityContainer(aStack); if (tTileEntityContainer != null && tTileEntityContainer.mTileEntity instanceof IMTE_GetMaxStackSize maxStackSize) { return maxStackSize.getMaxStackSize(aStack, tContainer.mStackSize); @@ -224,7 +234,7 @@ public class MultiTileEntityItemInternal extends ItemBlock implements IFluidCont @Override public FluidStack getFluid(ItemStack aStack) { final MultiTileEntityContainer tTileEntityContainer = mBlock.mMultiTileEntityRegistry - .getNewTileEntityContainer(aStack); + .getCachedTileEntityContainer(aStack); if (tTileEntityContainer != null && tTileEntityContainer.mTileEntity instanceof IFluidContainerItem fluidContainerItem) { final FluidStack rFluid = fluidContainerItem.getFluid(aStack); @@ -237,7 +247,7 @@ public class MultiTileEntityItemInternal extends ItemBlock implements IFluidCont @Override public int getCapacity(ItemStack aStack) { final MultiTileEntityContainer tTileEntityContainer = mBlock.mMultiTileEntityRegistry - .getNewTileEntityContainer(aStack); + .getCachedTileEntityContainer(aStack); if (tTileEntityContainer != null && tTileEntityContainer.mTileEntity instanceof IFluidContainerItem fluidContainerItem) { final int rCapacity = fluidContainerItem.getCapacity(aStack); @@ -250,7 +260,7 @@ public class MultiTileEntityItemInternal extends ItemBlock implements IFluidCont @Override public int fill(ItemStack aStack, FluidStack aFluid, boolean aDoFill) { final MultiTileEntityContainer tTileEntityContainer = mBlock.mMultiTileEntityRegistry - .getNewTileEntityContainer(aStack); + .getCachedTileEntityContainer(aStack); if (tTileEntityContainer != null && tTileEntityContainer.mTileEntity instanceof IFluidContainerItem fluidContainerItem) { final int tFilled = fluidContainerItem.fill(aStack, aFluid, aDoFill); @@ -263,7 +273,7 @@ public class MultiTileEntityItemInternal extends ItemBlock implements IFluidCont @Override public FluidStack drain(ItemStack aStack, int aMaxDrain, boolean aDoDrain) { final MultiTileEntityContainer tTileEntityContainer = mBlock.mMultiTileEntityRegistry - .getNewTileEntityContainer(aStack); + .getCachedTileEntityContainer(aStack); if (tTileEntityContainer != null && tTileEntityContainer.mTileEntity instanceof IFluidContainerItem fluidContainerItem) { final FluidStack rFluid = fluidContainerItem.drain(aStack, aMaxDrain, aDoDrain); diff --git a/src/main/java/gregtech/api/multitileentity/MultiTileEntityRegistry.java b/src/main/java/gregtech/api/multitileentity/MultiTileEntityRegistry.java index 45117773fe..a5e30fb76c 100644 --- a/src/main/java/gregtech/api/multitileentity/MultiTileEntityRegistry.java +++ b/src/main/java/gregtech/api/multitileentity/MultiTileEntityRegistry.java @@ -38,6 +38,7 @@ public class MultiTileEntityRegistry { // TODO: NBT sensitive or not? Starting with not for now private static final ItemStackMap<MultiTileEntityRegistry> REGISTRIES = new ItemStackMap<>(false); private static final HashSet<Class<?>> sRegisteredTileEntities = new HashSet<>(); + private final HashMap<Integer, MultiTileEntityContainer> cachedTileEntityContainers = new HashMap<>(); public HashMap<Short, CreativeTab> mCreativeTabs = new HashMap<>(); public Map<Short, MultiTileEntityClassContainer> mRegistry = new HashMap<>(); @@ -80,7 +81,7 @@ public class MultiTileEntityRegistry { mBlock = aBlock; GT_FML_LOGGER.info(aNameInternal + " " + Block.getIdFromBlock(aBlock) + "This is the answer"); mBlock.mMultiTileEntityRegistry = this; - REGISTRIES.put(new ItemStack(Item.getItemFromBlock(aBlock), 1, GT_Values.W), this); + REGISTRIES.put(new ItemStack(Item.getItemById(Block.getIdFromBlock(aBlock)), 1, GT_Values.W), this); NAMED_REGISTRIES.put(mNameInternal, this); } @@ -267,6 +268,15 @@ public class MultiTileEntityRegistry { return tContainer == null ? null : tContainer.mTileEntity; } + public MultiTileEntityContainer getCachedTileEntityContainer(ItemStack stack) { + MultiTileEntityContainer container = cachedTileEntityContainers.get(Items.feather.getDamage(stack)); + if (container == null) { + container = getNewTileEntityContainer(stack); + cachedTileEntityContainers.put(Items.feather.getDamage(stack), container); + } + return container; + } + public MultiTileEntityContainer getNewTileEntityContainer(ItemStack aStack) { return getNewTileEntityContainer(null, 0, 0, 0, Items.feather.getDamage(aStack), aStack.getTagCompound()); } diff --git a/src/main/java/gregtech/api/multitileentity/base/MultiTileEntity.java b/src/main/java/gregtech/api/multitileentity/base/MultiTileEntity.java index 4b2a5aca67..3d98663e6d 100644 --- a/src/main/java/gregtech/api/multitileentity/base/MultiTileEntity.java +++ b/src/main/java/gregtech/api/multitileentity/base/MultiTileEntity.java @@ -8,6 +8,8 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; +import javax.annotation.Nonnull; + import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.creativetab.CreativeTabs; @@ -16,6 +18,7 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Items; import net.minecraft.item.Item; +import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.Packet; @@ -28,9 +31,6 @@ import net.minecraft.world.Explosion; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.Fluid; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.FluidTankInfo; -import net.minecraftforge.fluids.IFluidTank; import com.gtnewhorizons.modularui.common.internal.network.NetworkUtils; @@ -90,6 +90,7 @@ public abstract class MultiTileEntity extends CoverableTileEntity protected boolean needsUpdate = false; protected boolean hasInventoryChanged = false; protected boolean isPainted = false; + @Nonnull protected ForgeDirection facing = ForgeDirection.WEST; // Default to WEST, so it renders facing Left in the // inventory protected byte color; @@ -203,12 +204,6 @@ public abstract class MultiTileEntity extends CoverableTileEntity } @Override - public ITexture[] getTexture(Block ignoredBlock, ForgeDirection ignoredSide) { - // We are not going to be using this - return null; - } - - @Override public void readFromNBT(NBTTagCompound nbt) { // Check if it is a World/Chunk-Loading Process calling readFromNBT if (mteID == GT_Values.W || mteRegistry == GT_Values.W) { @@ -231,7 +226,7 @@ public abstract class MultiTileEntity extends CoverableTileEntity if (nbt.hasKey("y")) yCoord = nbt.getInteger("y"); if (nbt.hasKey("z")) zCoord = nbt.getInteger("z"); // read the custom Name. - if (nbt.hasKey(NBT.DISPAY)) customName = nbt.getCompoundTag(NBT.DISPAY) + if (nbt.hasKey(NBT.DISPLAY)) customName = nbt.getCompoundTag(NBT.DISPLAY) .getString(NBT.CUSTOM_NAME); // And now everything else. @@ -249,6 +244,7 @@ public abstract class MultiTileEntity extends CoverableTileEntity if (nbt.hasKey(NBT.FACING)) facing = ForgeDirection.getOrientation(nbt.getInteger(NBT.FACING)); readCoverNBT(nbt); + readTasksNBT(nbt); readMultiTileNBT(nbt); if (NetworkUtils.isDedicatedClient()) { @@ -272,6 +268,8 @@ public abstract class MultiTileEntity extends CoverableTileEntity /* Do Nothing */ } + protected void readTasksNBT(NBTTagCompound nbt) {} + @Override public final void writeToNBT(NBTTagCompound aNBT) { super.writeToNBT(aNBT); @@ -281,11 +279,11 @@ public abstract class MultiTileEntity extends CoverableTileEntity // write the Custom Name if (GT_Utility.isStringValid(customName)) { final NBTTagCompound displayNBT; - if (aNBT.hasKey(NBT.DISPAY)) { - displayNBT = aNBT.getCompoundTag(NBT.DISPAY); + if (aNBT.hasKey(NBT.DISPLAY)) { + displayNBT = aNBT.getCompoundTag(NBT.DISPLAY); } else { displayNBT = new NBTTagCompound(); - aNBT.setTag(NBT.DISPAY, displayNBT); + aNBT.setTag(NBT.DISPLAY, displayNBT); } displayNBT.setString(NBT.CUSTOM_NAME, customName); } @@ -298,6 +296,7 @@ public abstract class MultiTileEntity extends CoverableTileEntity aNBT.setInteger(NBT.FACING, facing.ordinal()); writeCoverNBT(aNBT, false); + writeTasksNBT(aNBT); writeMultiTileNBT(aNBT); } catch (Throwable e) { GT_FML_LOGGER.error("writeToNBT", e); @@ -308,10 +307,13 @@ public abstract class MultiTileEntity extends CoverableTileEntity /* Do Nothing */ } + protected void writeTasksNBT(NBTTagCompound aNBT) {} + @Override public NBTTagCompound writeItemNBT(NBTTagCompound aNBT) { writeCoverNBT(aNBT, true); if (shouldSaveNBTToItemStack()) { + writeTasksNBT(aNBT); writeMultiTileNBT(aNBT); } return aNBT; @@ -711,6 +713,8 @@ public abstract class MultiTileEntity extends CoverableTileEntity public boolean onPlaced(ItemStack aStack, EntityPlayer aPlayer, World aWorld, int aX, int aY, int aZ, ForgeDirection side, float aHitX, float aHitY, float aHitZ) { facing = getSideForPlayerPlacing(aPlayer, facing, getValidFacings()); + setOwnerUuid(aPlayer.getUniqueID()); + setOwnerName(aPlayer.getDisplayName()); onFacingChange(); return true; } @@ -749,8 +753,7 @@ public abstract class MultiTileEntity extends CoverableTileEntity } if (!getCoverInfoAtSide(side).isGUIClickable()) return false; - } - if (isServerSide()) { + } else { // server side if (!privateAccess() || aPlayer.getDisplayName() .equalsIgnoreCase(getOwnerName())) { final ItemStack tCurrentItem = aPlayer.inventory.getCurrentItem(); @@ -836,6 +839,11 @@ public abstract class MultiTileEntity extends CoverableTileEntity if (!getCoverInfoAtSide(side).isGUIClickable()) return false; + if (aPlayer.getHeldItem() != null && aPlayer.getHeldItem() + .getItem() instanceof ItemBlock) { + return false; + } + return openModularUi(aPlayer, side); } } @@ -1060,7 +1068,7 @@ public abstract class MultiTileEntity extends CoverableTileEntity } @Override - public boolean receiveClientEvent(int aEventID, int aValue) { + public boolean receiveClientData(int aEventID, int aValue) { super.receiveClientEvent(aEventID, aValue); if (isClientSide()) { issueTextureUpdate(); @@ -1127,11 +1135,6 @@ public abstract class MultiTileEntity extends CoverableTileEntity } @Override - public boolean hasCustomInventoryName() { - return false; - } - - @Override public ArrayList<String> getDebugInfo(EntityPlayer aPlayer, int aLogLevel) { final ArrayList<String> tList = new ArrayList<>(); if (aLogLevel > 2) { @@ -1155,82 +1158,6 @@ public abstract class MultiTileEntity extends CoverableTileEntity } /** - * Fluid - A Default implementation of the Fluid Tank behaviour, so that every TileEntity can use this to simplify - * its Code. - */ - protected IFluidTank getFluidTankFillable(ForgeDirection side, FluidStack aFluidToFill) { - return null; - } - - protected IFluidTank getFluidTankDrainable(ForgeDirection side, FluidStack aFluidToDrain) { - return null; - } - - protected IFluidTank[] getFluidTanks(ForgeDirection side) { - return GT_Values.emptyFluidTank; - } - - public boolean isLiquidInput(ForgeDirection side) { - return true; - } - - public boolean isLiquidOutput(ForgeDirection side) { - return true; - } - - @Override - public int fill(ForgeDirection aDirection, FluidStack aFluid, boolean aDoFill) { - if (aFluid == null || aFluid.amount <= 0) return 0; - final IFluidTank tTank = getFluidTankFillable(aDirection, aFluid); - return (tTank == null) ? 0 : tTank.fill(aFluid, aDoFill); - } - - @Override - public FluidStack drain(ForgeDirection aDirection, FluidStack aFluid, boolean aDoDrain) { - if (aFluid == null || aFluid.amount <= 0) return null; - final IFluidTank tTank = getFluidTankDrainable(aDirection, aFluid); - if (tTank == null || tTank.getFluid() == null - || tTank.getFluidAmount() == 0 - || !tTank.getFluid() - .isFluidEqual(aFluid)) - return null; - return tTank.drain(aFluid.amount, aDoDrain); - } - - @Override - public FluidStack drain(ForgeDirection aDirection, int aAmountToDrain, boolean aDoDrain) { - if (aAmountToDrain <= 0) return null; - final IFluidTank tTank = getFluidTankDrainable(aDirection, null); - if (tTank == null || tTank.getFluid() == null || tTank.getFluidAmount() == 0) return null; - return tTank.drain(aAmountToDrain, aDoDrain); - } - - @Override - public boolean canFill(ForgeDirection aDirection, Fluid aFluid) { - if (aFluid == null) return false; - final IFluidTank tTank = getFluidTankFillable(aDirection, new FluidStack(aFluid, 0)); - return tTank != null && (tTank.getFluid() == null || tTank.getFluid() - .getFluid() == aFluid); - } - - @Override - public boolean canDrain(ForgeDirection aDirection, Fluid aFluid) { - if (aFluid == null) return false; - final IFluidTank tTank = getFluidTankDrainable(aDirection, new FluidStack(aFluid, 0)); - return tTank != null && (tTank.getFluid() != null && tTank.getFluid() - .getFluid() == aFluid); - } - - @Override - public FluidTankInfo[] getTankInfo(ForgeDirection aDirection) { - final IFluidTank[] tTanks = getFluidTanks(aDirection); - if (tTanks == null || tTanks.length <= 0) return GT_Values.emptyFluidTankInfo; - final FluidTankInfo[] rInfo = new FluidTankInfo[tTanks.length]; - for (int i = 0; i < tTanks.length; i++) rInfo[i] = new FluidTankInfo(tTanks[i]); - return rInfo; - } - - /** * Energy - Do nothing by Default */ @Override @@ -1321,17 +1248,6 @@ public abstract class MultiTileEntity extends CoverableTileEntity /** * Inventory - Do nothing by default */ - @Override - public void openInventory() { - System.out.println("Open Inventory"); - /* Do nothing */ - } - - @Override - public void closeInventory() { - System.out.println("Close Inventory"); - /* Do nothing */ - } @Override public boolean hasInventoryBeenModified() { @@ -1354,56 +1270,6 @@ public abstract class MultiTileEntity extends CoverableTileEntity } @Override - public int[] getAccessibleSlotsFromSide(int ordinalSide) { - return GT_Values.emptyIntArray; - } - - @Override - public boolean canInsertItem(int aSlot, ItemStack aStack, int ordinalSide) { - return false; - } - - @Override - public boolean canExtractItem(int aSlot, ItemStack aStack, int ordinalSide) { - return false; - } - - @Override - public int getSizeInventory() { - return 0; - } - - @Override - public ItemStack getStackInSlot(int aSlot) { - return null; - } - - @Override - public ItemStack decrStackSize(int aSlot, int aDecrement) { - return null; - } - - @Override - public ItemStack getStackInSlotOnClosing(int aSlot) { - return null; - } - - @Override - public void setInventorySlotContents(int aSlot, ItemStack aStack) { - /* Do nothing */ - } - - @Override - public int getInventoryStackLimit() { - return 0; - } - - @Override - public boolean isItemValidForSlot(int aSlot, ItemStack aStack) { - return false; - } - - @Override public void markInventoryBeenModified() { hasInventoryChanged = true; } diff --git a/src/main/java/gregtech/api/multitileentity/base/TickableMultiTileEntity.java b/src/main/java/gregtech/api/multitileentity/base/TickableMultiTileEntity.java index d61f32813f..9dcfce6d43 100644 --- a/src/main/java/gregtech/api/multitileentity/base/TickableMultiTileEntity.java +++ b/src/main/java/gregtech/api/multitileentity/base/TickableMultiTileEntity.java @@ -2,16 +2,26 @@ package gregtech.api.multitileentity.base; import static gregtech.GT_Mod.GT_FML_LOGGER; +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import net.minecraft.block.Block; import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; +import gregtech.api.enums.GT_Values; import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_OnNeighborBlockChange; +import gregtech.api.task.TaskHost; +import gregtech.api.task.TickableTask; import gregtech.api.util.GT_Log; import gregtech.api.util.GT_Util; -public abstract class TickableMultiTileEntity extends MultiTileEntity implements IMTE_OnNeighborBlockChange { +public abstract class TickableMultiTileEntity extends MultiTileEntity implements TaskHost, IMTE_OnNeighborBlockChange { /** Variable for seeing if the Tick Function is called right now. */ public boolean isRunningTick = false; @@ -22,11 +32,26 @@ public abstract class TickableMultiTileEntity extends MultiTileEntity implements /** Variable for updating Data to the Client */ private boolean sendClientData = false; + private final Map<String, TickableTask<?>> tasks = new HashMap<>(); + public TickableMultiTileEntity() { super(true); } @Override + public final void registerTask(@Nonnull TickableTask<?> task) { + if (tasks.containsKey(task.getName())) { + throw new IllegalStateException(String.format("Task with name %s is already registered", task.getName())); + } + tasks.put(task.getName(), task); + } + + @Nullable + public TickableTask<?> getTask(@Nonnull String name) { + return tasks.get(name); + } + + @Override public final void updateEntity() { isRunningTick = true; final boolean isServerSide = isServerSide(); @@ -46,6 +71,9 @@ public abstract class TickableMultiTileEntity extends MultiTileEntity implements needsUpdate = false; } onTick(timer, isServerSide); + for (TickableTask<?> task : tasks.values()) { + task.update(timer, isServerSide); + } if (isServerSide && timer > 2 && sendClientData) { sendClientData(null); } @@ -73,7 +101,9 @@ public abstract class TickableMultiTileEntity extends MultiTileEntity implements } } - /** The very first Tick happening to this TileEntity */ + /** + * The very first Tick happening to this TileEntity. + */ public void onFirstTick(boolean isServerSide) { if (isServerSide) { checkDropCover(); @@ -82,19 +112,48 @@ public abstract class TickableMultiTileEntity extends MultiTileEntity implements } } - /** The first part of the Tick. */ - public void onPreTick(long aTick, boolean isServerSide) {} + /** + * The first part of the Tick, before block update. + */ + public void onPreTick(long tick, boolean isServerSide) {} - /** The regular Tick. */ - public void onTick(long tick, boolean isServerSide) { + /** + * The regular Tick. After block update, before sending data to client. + */ + public void onTick(long tick, boolean isServerSide) {} - } + /** + * The absolute last part of the Tick, after sending data to client. + */ + public void onPostTick(long tick, boolean isServerSide) {} - /** The absolute last part of the Tick. */ - public void onPostTick(long aTick, boolean isServerSide) {} + /** + * Gets called when there is an Exception/Error happening during one of the Tick methods. + */ + public void onTickFailed(long tick, boolean isServerSide) {} - /** Gets called when there is an Exception happening during one of the Tick Functions. */ - public void onTickFailed(long aTimer, boolean isServerSide) {} + @Override + protected final void readTasksNBT(NBTTagCompound nbt) { + if (nbt.hasKey(GT_Values.NBT.TASKS)) { + NBTTagCompound tasksTag = nbt.getCompoundTag(GT_Values.NBT.TASKS); + for (TickableTask<?> task : tasks.values()) { + if (tasksTag.hasKey(task.getName())) { + task.readFromNBT(tasksTag.getCompoundTag(task.getName())); + } + } + } + } + + @Override + protected final void writeTasksNBT(NBTTagCompound aNBT) { + NBTTagCompound tasksTag = new NBTTagCompound(); + for (TickableTask<?> task : tasks.values()) { + NBTTagCompound tag = new NBTTagCompound(); + task.writeToNBT(tag); + tasksTag.setTag(task.getName(), tag); + } + aNBT.setTag(GT_Values.NBT.TASKS, tasksTag); + } @Override public void onNeighborBlockChange(World aWorld, Block aBlock) { diff --git a/src/main/java/gregtech/api/multitileentity/enums/GT_MultiTileCasing.java b/src/main/java/gregtech/api/multitileentity/enums/GT_MultiTileCasing.java index baa235ccf1..73bd55738a 100644 --- a/src/main/java/gregtech/api/multitileentity/enums/GT_MultiTileCasing.java +++ b/src/main/java/gregtech/api/multitileentity/enums/GT_MultiTileCasing.java @@ -1,20 +1,43 @@ package gregtech.api.multitileentity.enums; +import static gregtech.api.util.GT_StructureUtilityMuTE.createMuTEStructureCasing; +import static gregtech.loaders.preload.GT_Loader_MultiTileEntities.CASING_REGISTRY_NAME; + import gregtech.api.enums.GT_Values; +import gregtech.api.util.GT_StructureUtilityMuTE; public enum GT_MultiTileCasing { CokeOven(0), Chemical(1), + Distillation(2), + Macerator(18000), + LaserEngraver(4), + Mirror(5), + BlackLaserEngraverCasing(6), + LaserEngraverUpgrade1(7), + LaserEngraverUpgrade2(8), + LaserEngraverUpgrade3(9), + LaserEngraverUpgrade4(10), NONE(GT_Values.W); private final int meta; + private final GT_StructureUtilityMuTE.MuTEStructureCasing casing; GT_MultiTileCasing(int meta) { this.meta = meta; + casing = createMuTEStructureCasing(CASING_REGISTRY_NAME, meta); } public int getId() { return meta; } + + public short getRegistryId() { + return (short) casing.getRegistryId(); + } + + public GT_StructureUtilityMuTE.MuTEStructureCasing getCasing() { + return casing; + } } diff --git a/src/main/java/gregtech/api/multitileentity/enums/GT_MultiTileUpgradeCasing.java b/src/main/java/gregtech/api/multitileentity/enums/GT_MultiTileUpgradeCasing.java new file mode 100644 index 0000000000..296bae546d --- /dev/null +++ b/src/main/java/gregtech/api/multitileentity/enums/GT_MultiTileUpgradeCasing.java @@ -0,0 +1,71 @@ +package gregtech.api.multitileentity.enums; + +import gregtech.api.enums.GT_Values; + +public enum GT_MultiTileUpgradeCasing { + + ULV_Inventory(0), + LV_Inventory(1), + MV_Inventory(2), + HV_Inventory(3), + EV_Inventory(4), + IV_Inventory(5), + LuV_Inventory(6), + ZPM_Inventory(7), + UV_Inventory(8), + UHV_Inventory(9), + UEV_Inventory(10), + UIV_Inventory(11), + UXV_Inventory(12), + UMV_Inventory(13), + MAX_Inventory(14), + ULV_Tank(15), + LV_Tank(16), + MV_Tank(17), + HV_Tank(18), + EV_Tank(19), + IV_Tank(20), + LuV_Tank(21), + ZPM_Tank(22), + UV_Tank(23), + UHV_Tank(24), + UEV_Tank(25), + UIV_Tank(26), + UXV_Tank(27), + UMV_Tank(28), + MAX_Tank(29), + Amp_4(30), + Amp_16(31), + Amp_64(32), + Amp_256(33), + Amp_1_024(34), + Amp_4_096(35), + Amp_16_384(36), + Amp_65_536(37), + Amp_262_144(38), + Amp_1_048_576(39), + Laser(40), + Wireless(41), + Cleanroom(42), + Heater_Prototype(100), + Heater_IndustrialGrade(101), + Heater_NextGen(102), + Heater_Omnipotent(103), + Heater_OmegaType(104), + Insulator_Prototype(105), + Insulator_IndustrialGrade(106), + Insulator_NextGen(107), + Insulator_Omnipotent(108), + Insulator_OmegaType(109), + NONE(GT_Values.W); + + private final int meta; + + GT_MultiTileUpgradeCasing(int meta) { + this.meta = meta; + } + + public int getId() { + return meta; + } +} diff --git a/src/main/java/gregtech/api/multitileentity/enums/MultiTileCasingPurpose.java b/src/main/java/gregtech/api/multitileentity/enums/MultiTileCasingPurpose.java new file mode 100644 index 0000000000..2733da33cf --- /dev/null +++ b/src/main/java/gregtech/api/multitileentity/enums/MultiTileCasingPurpose.java @@ -0,0 +1,13 @@ +package gregtech.api.multitileentity.enums; + +/** + * Purposes with which a casing can registered itself in the MuTE controller to be ticked. + * Can be used for example to auto output recipe outputs from output casings. + * + * @author minecraft7771 + */ +public enum MultiTileCasingPurpose { + ItemOutput, + FluidOutput, + EnergyOutput, +} diff --git a/src/main/java/gregtech/api/multitileentity/interfaces/IMultiBlockController.java b/src/main/java/gregtech/api/multitileentity/interfaces/IMultiBlockController.java index 8535c50790..58af918c50 100644 --- a/src/main/java/gregtech/api/multitileentity/interfaces/IMultiBlockController.java +++ b/src/main/java/gregtech/api/multitileentity/interfaces/IMultiBlockController.java @@ -1,16 +1,24 @@ package gregtech.api.multitileentity.interfaces; +import java.util.UUID; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import net.minecraft.util.ChunkCoordinates; import net.minecraftforge.common.util.ForgeDirection; -import net.minecraftforge.fluids.Fluid; -import net.minecraftforge.fluids.FluidStack; -import com.gtnewhorizons.modularui.api.screen.ModularWindow; -import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import gregtech.api.enums.InventoryType; +import gregtech.api.gui.GUIHost; +import gregtech.api.logic.FluidInventoryLogic; +import gregtech.api.logic.ItemInventoryLogic; +import gregtech.api.logic.interfaces.FluidInventoryLogicHost; +import gregtech.api.logic.interfaces.ItemInventoryLogicHost; +import gregtech.api.logic.interfaces.PowerLogicHost; +import gregtech.api.multitileentity.enums.MultiTileCasingPurpose; -import gregtech.api.logic.PowerLogic; - -public interface IMultiBlockController extends IMultiTileEntity, IMultiBlockFluidHandler, IMultiBlockInventory { +public interface IMultiBlockController + extends IMultiTileEntity, FluidInventoryLogicHost, ItemInventoryLogicHost, UpgradableMuTE, PowerLogicHost, GUIHost { boolean checkStructure(boolean aForceReset); @@ -20,25 +28,24 @@ public interface IMultiBlockController extends IMultiTileEntity, IMultiBlockFlui @Override ChunkCoordinates getCoords(); - FluidStack getDrainableFluid(ForgeDirection side); - - FluidStack getDrainableFluid(ForgeDirection side, Fluid fluid); + void registerCoveredPartOnSide(final ForgeDirection side, IMultiBlockPart part); - boolean isLiquidInput(ForgeDirection side); + void unregisterCoveredPartOnSide(final ForgeDirection side, IMultiBlockPart part); - boolean isLiquidOutput(ForgeDirection side); + void registerCaseWithPurpose(MultiTileCasingPurpose purpose, IMultiBlockPart part); - void registerCoveredPartOnSide(final ForgeDirection side, IMultiBlockPart part); + void unregisterCaseWithPurpose(MultiTileCasingPurpose purpose, IMultiBlockPart part); - void unregisterCoveredPartOnSide(final ForgeDirection side, IMultiBlockPart part); + UUID registerItemInventory(int slots, int tier, @Nonnull InventoryType type, boolean isUpgradeInventory); - void registerInventory(String aName, String aID, int aInventorySize, int aType); + ItemInventoryLogic unregisterItemInventory(@Nonnull UUID id, @Nonnull InventoryType type); - void unregisterInventory(String aName, String aID, int aType); + void changeItemInventoryDisplayName(@Nonnull UUID id, @Nullable String displayName, @Nonnull InventoryType type); - void changeInventoryName(String aName, String aID, int aType); + UUID registerFluidInventory(int tanks, long capacity, int tier, @Nonnull InventoryType type, + boolean isUpgradeInventory); - PowerLogic getPowerLogic(IMultiBlockPart part, ForgeDirection side); + FluidInventoryLogic unregisterFluidInventory(@Nonnull UUID id, @Nonnull InventoryType type); - ModularWindow createWindowGUI(UIBuildContext buildContext); + void changeFluidInventoryDisplayName(@Nonnull UUID id, @Nullable String displayName, @Nonnull InventoryType type); } diff --git a/src/main/java/gregtech/api/multitileentity/interfaces/IMultiBlockPart.java b/src/main/java/gregtech/api/multitileentity/interfaces/IMultiBlockPart.java index 017954f554..59d838fdeb 100644 --- a/src/main/java/gregtech/api/multitileentity/interfaces/IMultiBlockPart.java +++ b/src/main/java/gregtech/api/multitileentity/interfaces/IMultiBlockPart.java @@ -1,9 +1,14 @@ package gregtech.api.multitileentity.interfaces; +import java.util.UUID; + import net.minecraft.util.ChunkCoordinates; import net.minecraftforge.common.util.ForgeDirection; -public interface IMultiBlockPart extends IMultiTileEntity { +import gregtech.api.logic.interfaces.FluidInventoryLogicHost; +import gregtech.api.logic.interfaces.ItemInventoryLogicHost; + +public interface IMultiBlockPart extends IMultiTileEntity, ItemInventoryLogicHost, FluidInventoryLogicHost { ChunkCoordinates getTargetPos(); @@ -13,5 +18,9 @@ public interface IMultiBlockPart extends IMultiTileEntity { int getLockedInventoryIndex(); + UUID getLockedInventory(); + boolean tickCoverAtSide(ForgeDirection side, long aTickTimer); + + boolean shouldTick(long tickTimer); } diff --git a/src/main/java/gregtech/api/multitileentity/interfaces/IMultiTileEntity.java b/src/main/java/gregtech/api/multitileentity/interfaces/IMultiTileEntity.java index 7925ebd5b9..91803690fc 100644 --- a/src/main/java/gregtech/api/multitileentity/interfaces/IMultiTileEntity.java +++ b/src/main/java/gregtech/api/multitileentity/interfaces/IMultiTileEntity.java @@ -17,18 +17,11 @@ import net.minecraft.util.MovingObjectPosition; import net.minecraft.world.Explosion; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; -import net.minecraftforge.fluids.IFluidHandler; import cpw.mods.fml.common.Optional; import gregtech.api.enums.Mods; -import gregtech.api.interfaces.tileentity.IBasicEnergyContainer; -import gregtech.api.interfaces.tileentity.IColoredTileEntity; import gregtech.api.interfaces.tileentity.ICoverable; import gregtech.api.interfaces.tileentity.IDebugableTileEntity; -import gregtech.api.interfaces.tileentity.IEnergyConnected; -import gregtech.api.interfaces.tileentity.IHasInventory; -import gregtech.api.interfaces.tileentity.IHasWorldObjectAndCoords; -import gregtech.api.interfaces.tileentity.ITexturedTileEntity; import gregtech.api.interfaces.tileentity.ITurnable; import gregtech.api.multitileentity.MultiTileEntityBlockInternal; import gregtech.api.multitileentity.MultiTileEntityItemInternal; @@ -37,9 +30,7 @@ import gregtech.api.multitileentity.MultiTileEntityRegistry; /* * Heavily inspired by GT6 */ -public interface IMultiTileEntity - extends IHasWorldObjectAndCoords, ICoverable, ITurnable, IHasInventory, IEnergyConnected, IBasicEnergyContainer, - IFluidHandler, ITexturedTileEntity, IDebugableTileEntity, IColoredTileEntity { +public interface IMultiTileEntity extends ICoverable, ITurnable, IDebugableTileEntity { /** * Those two IDs HAVE to be saved inside the NBT of the TileEntity itself. They get set by the Registry itself, when @@ -88,7 +79,7 @@ public interface IMultiTileEntity void sendClientData(EntityPlayerMP aPlayer); - boolean receiveClientEvent(int aEventID, int aValue); + boolean receiveClientData(int aEventID, int aValue); void setShouldRefresh(boolean aShouldRefresh); @@ -291,12 +282,12 @@ public interface IMultiTileEntity interface IMTE_HasModes extends IMultiTileEntity { - byte getMode(); + int getMode(); - void setMode(byte aMode); + void setMode(int mode); int getAllowedModes(); - void setAllowedModes(int aAllowedModes); + void setAllowedModes(int allowedModes); } } diff --git a/src/main/java/gregtech/api/multitileentity/interfaces/UpgradableModularMuTE.java b/src/main/java/gregtech/api/multitileentity/interfaces/UpgradableModularMuTE.java new file mode 100644 index 0000000000..3b4c3cb6f3 --- /dev/null +++ b/src/main/java/gregtech/api/multitileentity/interfaces/UpgradableModularMuTE.java @@ -0,0 +1,10 @@ +package gregtech.api.multitileentity.interfaces; + +import gregtech.api.util.GT_StructureUtilityMuTE.UpgradeCasings; + +public interface UpgradableModularMuTE extends UpgradableMuTE { + + void increaseMucCount(UpgradeCasings casingType, int tier); + + void resetMucCount(); +} diff --git a/src/main/java/gregtech/api/multitileentity/interfaces/UpgradableMuTE.java b/src/main/java/gregtech/api/multitileentity/interfaces/UpgradableMuTE.java new file mode 100644 index 0000000000..c18852c95e --- /dev/null +++ b/src/main/java/gregtech/api/multitileentity/interfaces/UpgradableMuTE.java @@ -0,0 +1,12 @@ +package gregtech.api.multitileentity.interfaces; + +public interface UpgradableMuTE { + + void setCleanroom(boolean isCleanroom); + + void setWirelessSupport(boolean canUse); + + void setLaserSupport(boolean canUse); + + void setMaxAmperage(long amperage); +} diff --git a/src/main/java/gregtech/api/multitileentity/machine/MultiTileBasicMachine.java b/src/main/java/gregtech/api/multitileentity/machine/MultiTileBasicMachine.java index 0b6d4f587d..19c052b96a 100644 --- a/src/main/java/gregtech/api/multitileentity/machine/MultiTileBasicMachine.java +++ b/src/main/java/gregtech/api/multitileentity/machine/MultiTileBasicMachine.java @@ -1,18 +1,19 @@ package gregtech.api.multitileentity.machine; -import static com.google.common.primitives.Ints.saturatedCast; -import static gregtech.api.enums.GT_Values.B; -import static gregtech.api.enums.GT_Values.VN; +import static gregtech.api.enums.GT_Values.*; +import static gregtech.api.enums.TickTime.MINUTE; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Objects; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityFurnace; import net.minecraft.util.EnumChatFormatting; @@ -20,26 +21,32 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.StatCollector; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.IFluidTank; + +import org.jetbrains.annotations.ApiStatus.OverrideOnly; import com.gtnewhorizons.modularui.api.forge.IItemHandlerModifiable; import com.gtnewhorizons.modularui.api.forge.ItemStackHandler; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import gregtech.api.enums.GT_Values; import gregtech.api.enums.GT_Values.NBT; +import gregtech.api.enums.InventoryType; import gregtech.api.enums.Mods; import gregtech.api.enums.SoundResource; import gregtech.api.enums.Textures; import gregtech.api.enums.Textures.BlockIcons.CustomIcon; import gregtech.api.enums.TickTime; -import gregtech.api.fluid.FluidTankGT; +import gregtech.api.enums.VoidingMode; +import gregtech.api.gui.GUIHost; +import gregtech.api.gui.GUIProvider; import gregtech.api.interfaces.ITexture; -import gregtech.api.logic.PollutionLogic; +import gregtech.api.logic.FluidInventoryLogic; +import gregtech.api.logic.ItemInventoryLogic; +import gregtech.api.logic.MuTEProcessingLogic; +import gregtech.api.logic.NullPowerLogic; import gregtech.api.logic.PowerLogic; -import gregtech.api.logic.ProcessingLogic; -import gregtech.api.logic.interfaces.PollutionLogicHost; import gregtech.api.logic.interfaces.PowerLogicHost; import gregtech.api.logic.interfaces.ProcessingLogicHost; import gregtech.api.metatileentity.GregTechTileClientEvents; @@ -47,13 +54,14 @@ import gregtech.api.multitileentity.MultiTileEntityRegistry; import gregtech.api.multitileentity.base.TickableMultiTileEntity; import gregtech.api.multitileentity.interfaces.IMultiTileMachine; import gregtech.api.net.GT_Packet_MultiTileEntity; -import gregtech.api.recipe.check.CheckRecipeResult; import gregtech.api.render.TextureFactory; +import gregtech.api.task.tasks.ProcessingTask; import gregtech.api.util.GT_Utility; import gregtech.client.GT_SoundLoop; -import gregtech.common.GT_Pollution; +import gregtech.common.gui.MachineGUIProvider; -public abstract class MultiTileBasicMachine extends TickableMultiTileEntity implements IMultiTileMachine { +public abstract class MultiTileBasicMachine<P extends MuTEProcessingLogic<P>> extends TickableMultiTileEntity + implements IMultiTileMachine, ProcessingLogicHost<P>, PowerLogicHost, GUIHost { protected static final int ACTIVE = B[0]; protected static final int TICKS_BETWEEN_RECIPE_CHECKS = 5 * TickTime.SECOND; @@ -70,22 +78,10 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl protected int maxParallel = 1; protected boolean active = false; - protected long storedEnergy = 0; - protected long voltage = 0; - protected long amperage = 2; - protected long eut = 0; protected int tier = 0; - protected long maxProgressTime = 0; - protected long progressTime = 0; protected long burnTime = 0; protected long totalBurnTime = 0; - protected FluidTankGT[] inputTanks = GT_Values.emptyFluidTankGT; - protected FluidTankGT[] outputTanks = GT_Values.emptyFluidTankGT; - protected FluidStack[] fluidsToOutput = GT_Values.emptyFluidStack; - protected ItemStack[] itemsToOutput = GT_Values.emptyItemStackArray; - protected IItemHandlerModifiable inputInventory = EMPTY_INVENTORY; - protected IItemHandlerModifiable outputInventory = EMPTY_INVENTORY; protected boolean outputInventoryChanged = false; protected boolean powerShutDown = false; protected boolean wasEnabled = false; @@ -93,13 +89,30 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl protected boolean isElectric = true; protected boolean isSteam = false; protected boolean acceptsFuel = false; - protected boolean isWireless = false; + protected byte soundEvent = 0; protected int soundEventValue = 0; + protected ItemInventoryLogic itemInput; + protected ItemInventoryLogic itemOutput; + protected FluidInventoryLogic fluidInput; + protected FluidInventoryLogic fluidOutput; + + protected P processingLogic; + @Nonnull + protected VoidingMode voidingMode = VoidingMode.VOID_NONE; + protected boolean processingUpdate = false; + @Nonnull + protected PowerLogic power = createPowerLogic(); + @Nonnull + protected GUIProvider<?> guiProvider = createGUIProvider(); @SideOnly(Side.CLIENT) protected GT_SoundLoop activitySoundLoop; + public MultiTileBasicMachine() { + new ProcessingTask<>(this); + } + @Override public String getTileEntityName() { return "gt.multitileentity.machine.basic"; @@ -116,80 +129,34 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl nbt.setBoolean(NBT.ACTIVE, active); } - if (inputInventory != null && inputInventory.getSlots() > 0) { - writeInventory(nbt, inputInventory, NBT.INV_INPUT_LIST); - } - - if (outputInventory != null && outputInventory.getSlots() > 0) { - writeInventory(nbt, outputInventory, NBT.INV_OUTPUT_LIST); - } + saveItemLogic(nbt); + saveFluidLogic(nbt); - for (int i = 0; i < inputTanks.length; i++) { - inputTanks[i].writeToNBT(nbt, NBT.TANK_IN + i); - } - - for (int i = 0; i < outputTanks.length; i++) { - outputTanks[i].writeToNBT(nbt, NBT.TANK_OUT + i); - } - - if (fluidsToOutput != null && fluidsToOutput.length > 0) { - writeFluids(nbt, fluidsToOutput, NBT.FLUID_OUT); - } - - if (itemsToOutput != null) { - saveItemsToOutput(nbt); + if (processingLogic != null) { + NBTTagCompound processingLogicNBT = processingLogic.saveToNBT(); + nbt.setTag("processingLogic", processingLogicNBT); } nbt.setInteger(NBT.TIER, tier); - nbt.setLong(NBT.EUT_CONSUMPTION, eut); nbt.setLong(NBT.BURN_TIME_LEFT, burnTime); nbt.setLong(NBT.TOTAL_BURN_TIME, totalBurnTime); nbt.setBoolean(NBT.ALLOWED_WORK, canWork); nbt.setBoolean(NBT.ACTIVE, active); + power.saveToNBT(nbt); } - protected void writeFluids(NBTTagCompound nbt, FluidStack[] fluids, String fluidListTag) { - if (fluids != null && fluids.length > 0) { - final NBTTagList tList = new NBTTagList(); - for (final FluidStack tFluid : fluids) { - if (tFluid != null) { - final NBTTagCompound tag = new NBTTagCompound(); - tFluid.writeToNBT(tag); - tList.appendTag(tag); - } - } - nbt.setTag(fluidListTag, tList); - } - } - - protected void writeInventory(NBTTagCompound nbt, IItemHandlerModifiable inv, String invListTag) { - if (inv != null && inv.getSlots() > 0) { - final NBTTagList tList = new NBTTagList(); - for (int slot = 0; slot < inv.getSlots(); slot++) { - final ItemStack tStack = inv.getStackInSlot(slot); - if (tStack != null) { - final NBTTagCompound tag = new NBTTagCompound(); - tag.setByte("s", (byte) slot); - tStack.writeToNBT(tag); - tList.appendTag(tag); - } - } - nbt.setTag(invListTag, tList); - } + protected void saveItemLogic(NBTTagCompound nbt) { + NBTTagCompound nbtListInput = itemInput.saveToNBT(); + nbt.setTag(NBT.INV_INPUT_LIST, nbtListInput); + NBTTagCompound nbtListOutput = itemOutput.saveToNBT(); + nbt.setTag(NBT.INV_OUTPUT_LIST, nbtListOutput); } - protected void saveItemsToOutput(NBTTagCompound aNBT) { - final NBTTagList nbtList = new NBTTagList(); - for (int slot = 0; slot < itemsToOutput.length; slot++) { - final ItemStack itemStack = itemsToOutput[slot]; - if (itemStack != null) { - final NBTTagCompound tag = new NBTTagCompound(); - tag.setByte("s", (byte) slot); - itemStack.writeToNBT(tag); - nbtList.appendTag(tag); - } - } - aNBT.setTag(NBT.ITEM_OUT, nbtList); + protected void saveFluidLogic(NBTTagCompound nbt) { + NBTTagCompound fluidInputNBT = fluidInput.saveToNBT(); + nbt.setTag(NBT.TANK_IN, fluidInputNBT); + NBTTagCompound fluidOutputNBT = fluidOutput.saveToNBT(); + nbt.setTag(NBT.TANK_OUT, fluidOutputNBT); } @Override @@ -203,63 +170,48 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl active = nbt.getBoolean(NBT.ACTIVE); } - /* Inventories */ - inputInventory = new ItemStackHandler(Math.max(nbt.getInteger(NBT.INV_INPUT_SIZE), 0)); - outputInventory = new ItemStackHandler(Math.max(nbt.getInteger(NBT.INV_OUTPUT_SIZE), 0)); - loadInventory(nbt, inputInventory, NBT.INV_INPUT_LIST); - loadInventory(nbt, outputInventory, NBT.INV_OUTPUT_LIST); - - /* Tanks */ - long capacity = 1000; - if (nbt.hasKey(NBT.TANK_CAPACITY)) { - capacity = saturatedCast(nbt.getLong(NBT.TANK_CAPACITY)); - } - - inputTanks = new FluidTankGT[getFluidInputCount()]; - outputTanks = new FluidTankGT[getFluidOutputCount()]; - fluidsToOutput = new FluidStack[getFluidOutputCount()]; - - // TODO: See if we need the adjustable map here `.setCapacity(mRecipes, mParallel * 2L)` in place of the - // `setCapacityMultiplier` - for (int i = 0; i < inputTanks.length; i++) { - inputTanks[i] = new FluidTankGT(capacity).setCapacityMultiplier(maxParallel * 2L) - .readFromNBT(nbt, NBT.TANK_IN + i); - } - for (int i = 0; i < outputTanks.length; i++) { - outputTanks[i] = new FluidTankGT(capacity).setCapacityMultiplier(maxParallel * 2L) - .readFromNBT(nbt, NBT.TANK_OUT + i); - } + loadItemLogic(nbt); + loadFluidLogic(nbt); - for (int i = 0; i < fluidsToOutput.length; i++) { - fluidsToOutput[i] = FluidStack.loadFluidStackFromNBT(nbt.getCompoundTag(NBT.FLUID_OUT + "." + i)); + if (nbt.hasKey("processingLogic")) { + P processingLogic = getProcessingLogic(); + processingLogic.loadFromNBT(Objects.requireNonNull(nbt.getCompoundTag("processingLogic"))); } - loadItemsToOutput(nbt); - tier = nbt.getInteger(NBT.TIER); - eut = nbt.getLong(NBT.EUT_CONSUMPTION); burnTime = nbt.getLong(NBT.BURN_TIME_LEFT); totalBurnTime = nbt.getLong(NBT.TOTAL_BURN_TIME); canWork = nbt.getBoolean(NBT.ALLOWED_WORK); active = nbt.getBoolean(NBT.ACTIVE); + power.loadFromNBT(nbt); } - protected void loadInventory(NBTTagCompound aNBT, IItemHandlerModifiable inv, String invListTag) { - final NBTTagList tList = aNBT.getTagList(invListTag, 10); - for (int i = 0; i < tList.tagCount(); i++) { - final NBTTagCompound tNBT = tList.getCompoundTagAt(i); - final int tSlot = tNBT.getShort("s"); - if (tSlot >= 0 && tSlot < inv.getSlots()) inv.setStackInSlot(tSlot, GT_Utility.loadItem(tNBT)); + protected void loadItemLogic(NBTTagCompound nbt) { + itemInput = new ItemInventoryLogic(nbt.getInteger(NBT.INV_OUTPUT_SIZE), tier); + itemOutput = new ItemInventoryLogic(nbt.getInteger(NBT.INV_OUTPUT_SIZE), tier); + if (nbt.hasKey(NBT.INV_INPUT_LIST)) { + itemInput.loadFromNBT(nbt.getCompoundTag(NBT.INV_INPUT_LIST)); + } + if (nbt.hasKey(NBT.INV_OUTPUT_LIST)) { + itemOutput.loadFromNBT(nbt.getCompoundTag(NBT.INV_OUTPUT_LIST)); } } - protected void loadItemsToOutput(NBTTagCompound aNBT) { - final NBTTagList tList = aNBT.getTagList(NBT.ITEM_OUT, 10); - itemsToOutput = new ItemStack[tList.tagCount()]; - for (int i = 0; i < tList.tagCount(); i++) { - final NBTTagCompound tNBT = tList.getCompoundTagAt(i); - final int tSlot = tNBT.getByte("s"); - if (tSlot >= 0 && tSlot < itemsToOutput.length) itemsToOutput[tSlot] = GT_Utility.loadItem(tNBT); + protected void loadFluidLogic(NBTTagCompound nbt) { + fluidInput = new FluidInventoryLogic(16, 10000, tier); + fluidOutput = new FluidInventoryLogic(16, 10000, tier); + fluidInput.loadFromNBT(nbt.getCompoundTag(NBT.TANK_IN)); + fluidOutput.loadFromNBT(nbt.getCompoundTag(NBT.TANK_OUT)); + } + + public boolean checkTexture(String modID, String resourcePath) { + try { + Minecraft.getMinecraft() + .getResourceManager() + .getResource(new ResourceLocation(modID, resourcePath)); + return true; + } catch (IOException ignored) { + return false; } } @@ -268,17 +220,10 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl super.loadTextures(folder); for (StatusTextures textureName : StatusTextures.TEXTURES) { ITexture texture = null; - try { - Minecraft.getMinecraft() - .getResourceManager() - .getResource( - new ResourceLocation( - Mods.GregTech.ID, - "textures/blocks/multitileentity/" + folder + "/" + textureName.getName() + ".png")); - } catch (IOException ignored) { + String texturePath = "textures/blocks/multitileentity/" + folder + "/" + textureName.getName() + ".png"; + if (!checkTexture(Mods.GregTech.ID, texturePath)) { texture = TextureFactory.of(Textures.BlockIcons.VOID); - } - if (texture == null) { + } else { if (textureName.hasGlow()) { texture = TextureFactory.builder() .addIcon(new CustomIcon("multitileentity/" + folder + "/" + textureName.getName())) @@ -357,79 +302,6 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl @Override public void setLightValue(byte aLightValue) {} - @Override - public String getInventoryName() { - final String name = getCustomName(); - if (name != null) return name; - final MultiTileEntityRegistry tRegistry = MultiTileEntityRegistry.getRegistry(getMultiTileEntityRegistryID()); - return tRegistry == null ? getClass().getName() : tRegistry.getLocal(getMultiTileEntityID()); - } - - @Override - public boolean isUseableByPlayer(EntityPlayer aPlayer) { - return playerOwnsThis(aPlayer, false) && mTickTimer > 40 - && getTileEntityOffset(0, 0, 0) == this - && aPlayer.getDistanceSq(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5) < 64 - && allowInteraction(aPlayer); - } - - @Override - public boolean isLiquidInput(ForgeDirection side) { - return side != facing; - } - - @Override - public boolean isLiquidOutput(ForgeDirection side) { - return side != facing; - } - - @Override - protected IFluidTank[] getFluidTanks(ForgeDirection side) { - final boolean fluidInput = isLiquidInput(side); - final boolean fluidOutput = isLiquidOutput(side); - - if (fluidInput && fluidOutput) { - final IFluidTank[] rTanks = new IFluidTank[inputTanks.length + outputTanks.length]; - System.arraycopy(inputTanks, 0, rTanks, 0, inputTanks.length); - System.arraycopy(outputTanks, 0, rTanks, inputTanks.length, outputTanks.length); - return rTanks; - } else if (fluidInput) { - return inputTanks; - } else if (fluidOutput) { - return outputTanks; - } - return GT_Values.emptyFluidTank; - } - - @Override - public IFluidTank getFluidTankFillable(ForgeDirection side, FluidStack aFluidToFill) { - return getFluidTankFillable(facing, side, aFluidToFill); - } - - public IFluidTank getFluidTankFillable(ForgeDirection sideSource, ForgeDirection sideDestination, - FluidStack fluidToFill) { - if (sideSource.compareTo(sideDestination) != 0) return null; - for (FluidTankGT tankGT : inputTanks) if (tankGT.contains(fluidToFill)) return tankGT; - // if (!mRecipes.containsInput(aFluidToFill, this, slot(mRecipes.mInputItemsCount + - // mRecipes.mOutputItemsCount))) return null; - for (FluidTankGT fluidTankGT : inputTanks) if (fluidTankGT.isEmpty()) return fluidTankGT; - return null; - } - - @Override - protected IFluidTank getFluidTankDrainable(ForgeDirection side, FluidStack aFluidToDrain) { - return getFluidTankDrainable(facing, side, aFluidToDrain); - } - - protected IFluidTank getFluidTankDrainable(ForgeDirection sideSource, ForgeDirection sideDestination, - FluidStack fluidToDrain) { - if (sideSource.compareTo(sideDestination) != 0) return null; - for (FluidTankGT fluidTankGT : outputTanks) - if (fluidToDrain == null ? fluidTankGT.has() : fluidTankGT.contains(fluidToDrain)) return fluidTankGT; - - return null; - } - /* * Inventory */ @@ -453,16 +325,6 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl hasInventoryChanged = true; } - @Override - public boolean isItemValidForSlot(int aSlot, ItemStack aStack) { - return true; - } - - @Override - public int getInventoryStackLimit() { - return 64; - } - // #region Machine @Override @@ -480,28 +342,26 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl * @param tick The current tick of the machine */ protected void runMachine(long tick) { - if (acceptsFuel() && isActive()) { - if (!consumeFuel()) { - stopMachine(true); - return; - } + if (acceptsFuel() && isActive() && !consumeFuel()) { + stopMachine(true); + return; } if (hasThingsToDo()) { markDirty(); runningTick(tick); - } else { - if (tick % TICKS_BETWEEN_RECIPE_CHECKS == 0 || hasWorkJustBeenEnabled() || hasInventoryBeenModified()) { - if (isAllowedToWork()) { - wasEnabled = false; - if (checkRecipe()) { - setActive(true); - setSound(GregTechTileClientEvents.START_SOUND_LOOP, PROCESS_START_SOUND_INDEX); - updateSlots(); - markDirty(); - issueClientUpdate(); - } - } + return; + } + + if (tick % TICKS_BETWEEN_RECIPE_CHECKS == 0 || hasWorkJustBeenEnabled() + || hasInventoryBeenModified() && isAllowedToWork()) { + wasEnabled = false; + if (checkRecipe()) { + setActive(true); + setSound(GregTechTileClientEvents.START_SOUND_LOOP, PROCESS_START_SOUND_INDEX); + updateSlots(); + markDirty(); + issueClientUpdate(); } } } @@ -512,81 +372,25 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl * @param tick The current tick of the machine */ protected void runningTick(long tick) { - if (this instanceof PowerLogicHost) { - consumeEnergy(); - } - - if (maxProgressTime > 0 && ++progressTime >= maxProgressTime) { - progressTime = 0; - maxProgressTime = 0; - outputItems(); - outputFluids(); - if (isAllowedToWork()) { - if (!checkRecipe()) { - setActive(false); - issueClientUpdate(); - } - } - updateSlots(); - } - - if (this instanceof PollutionLogicHost && tick % POLLUTION_TICK == 0) { - doPollution(); - } - emitEnergy(); + consumeEnergy(); } /** * Runs only on server side */ protected boolean checkRecipe() { - if (!(this instanceof ProcessingLogicHost)) { - return false; - } - ProcessingLogic logic = ((ProcessingLogicHost) this).getProcessingLogic(); - logic.clear(); - CheckRecipeResult result = logic.setInputItems(getInputItems()) - .setInputFluids(getInputFluids()) - .setCurrentOutputItems( - outputInventory.getStacks() - .toArray(new ItemStack[0])) - .process(); - setDuration(logic.getDuration()); - setEut(logic.getCalculatedEut()); - setItemOutputs(logic.getOutputItems()); - setFluidOutputs(logic.getOutputFluids()); - return result.wasSuccessful(); - } - - /** - * Runs only on server side - */ - protected void doPollution() { - PollutionLogic logic = ((PollutionLogicHost) this).getPollutionLogic(); - - if (logic == null) { - return; - } - - GT_Pollution.addPollution(getWorld(), getXCoord() >> 4, getZCoord() >> 4, logic.getPollutionAmount()); + return false; } /** * Runs only on server side */ - protected void emitEnergy() {} - - /** - * Runs only on server side - */ protected void consumeEnergy() { - PowerLogic logic = ((PowerLogicHost) this).getPowerLogic(ForgeDirection.UNKNOWN); + PowerLogic logic = getPowerLogic(); - if (logic == null) { - return; - } + P processing = getProcessingLogic(); - if (!logic.removeEnergyUnsafe(eut)) { + if (!logic.removeEnergyUnsafe(processing.getCalculatedEut())) { stopMachine(true); } } @@ -603,9 +407,8 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl } public void startSoundLoop(byte aIndex, double aX, double aY, double aZ) { - if (aIndex == PROCESS_START_SOUND_INDEX) { - if (getProcessStartSound() != null) - GT_Utility.doSoundAtClient(getProcessStartSound(), getTimeBetweenProcessSounds(), 1.0F, aX, aY, aZ); + if (aIndex == PROCESS_START_SOUND_INDEX && getProcessStartSound() != null) { + GT_Utility.doSoundAtClient(getProcessStartSound(), getTimeBetweenProcessSounds(), 1.0F, aX, aY, aZ); } } @@ -619,18 +422,18 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl @SideOnly(Side.CLIENT) protected void doActivitySound(ResourceLocation activitySound) { - if (isActive() && activitySound != null) { - if (activitySoundLoop == null) { - activitySoundLoop = new GT_SoundLoop(activitySound, this, false, true); - Minecraft.getMinecraft() - .getSoundHandler() - .playSound(activitySoundLoop); - } - } else { - if (activitySoundLoop != null) { - activitySoundLoop = null; - } + if (isActive() && activitySound != null && activitySoundLoop == null) { + activitySoundLoop = new GT_SoundLoop(activitySound, this, false, true); + Minecraft.getMinecraft() + .getSoundHandler() + .playSound(activitySoundLoop); + return; } + + if (activitySoundLoop != null) { + activitySoundLoop = null; + } + } @SideOnly(Side.CLIENT) @@ -639,105 +442,69 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl } protected ItemStack[] getInputItems() { - return inputInventory.getStacks() - .toArray(new ItemStack[0]); + return itemInput.getStoredItems(); } protected FluidStack[] getInputFluids() { - return Arrays.stream(inputTanks) - .map(FluidTankGT::get) - .toArray(FluidStack[]::new); - } - - protected void outputItems() { - outputItems(itemsToOutput); - itemsToOutput = null; - } - - protected void outputItems(ItemStack... itemsToOutput) { - outputItems(outputInventory, itemsToOutput); + return fluidInput.getStoredFluids(); } - protected void outputItems(IItemHandlerModifiable inventory, ItemStack... itemsToOutput) { - if (itemsToOutput == null || inventory == null) { - return; - } - for (ItemStack item : itemsToOutput) { - int index = 0; - while (item != null && item.stackSize > 0 && index < inventory.getSlots()) { - item = inventory.insertItem(index++, item.copy(), false); - } - } - } - - protected void outputFluids() { - outputFluids(fluidsToOutput); - fluidsToOutput = null; - } - - protected void outputFluids(FluidStack... fluidsToOutput) { - outputFluids(outputTanks, fluidsToOutput); - } - - protected void outputFluids(FluidTankGT[] tankArray, FluidStack... fluidsToOutput) { - if (fluidsToOutput == null) { - return; - } - for (FluidStack fluid : fluidsToOutput) { - tryToFillTanks(fluid, tankArray); - } - } - - protected void tryToFillTanks(FluidStack fluid, FluidTankGT... tanks) { - for (FluidTankGT tank : tanks) { - if (tank.canFillAll(fluid)) { - fluid.amount -= tank.add(fluid.amount, fluid); - } - } - } - - public long getProgress() { - return progressTime; + @Override + public int getProgress() { + P processing = getProcessingLogic(); + return processing.getProgress(); } - public long getMaxProgress() { - return maxProgressTime; + @Override + public int getMaxProgress() { + P processing = getProcessingLogic(); + return processing.getDuration(); } - public boolean increaseProgress(int aProgressAmountInTicks) { - progressTime += aProgressAmountInTicks; + @Override + public boolean increaseProgress(int progressAmount) { + P processing = getProcessingLogic(); + processing.increaseProgress(progressAmount); return true; } + @Override public boolean hasThingsToDo() { return getMaxProgress() > 0; } + @Override public boolean hasWorkJustBeenEnabled() { return wasEnabled; } + @Override public void enableWorking() { wasEnabled = true; canWork = true; } + @Override public void disableWorking() { canWork = false; } + @Override public boolean wasShutdown() { return powerShutDown; } + @Override public boolean isAllowedToWork() { return canWork; } + @Override public boolean isActive() { return active; } + @Override public void setActive(boolean active) { this.active = active; } @@ -766,37 +533,18 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl this.acceptsFuel = acceptsFuel; } - protected boolean isWireless() { - return isWireless; - } - - protected void setWireless(boolean isWireless) { - this.isWireless = isWireless; - } - - protected boolean drainEut(long eut) { - return decreaseStoredEnergyUnits(eut, false); - } - - protected boolean generateEut(long eut) { - return increaseStoredEnergyUnits(eut, true); - } - - protected boolean isGenerator() { - return false; - } - protected boolean consumeFuel() { + if (isElectric() || isSteam()) return false; if (isActive() && burnTime <= 0) { - for (int i = 0; i < inputInventory.getSlots(); i++) { - if (inputInventory.getStackInSlot(i) != null) { - int checkBurnTime = TileEntityFurnace.getItemBurnTime(inputInventory.getStackInSlot(i)) / 10; - if (checkBurnTime <= 0) continue; - inputInventory.getStackInSlot(i).stackSize--; - burnTime = checkBurnTime; - totalBurnTime = checkBurnTime; - break; - } + for (int i = 0; i < itemInput.getSlots(); i++) { + ItemStack item = itemInput.getItemInSlot(i); + if (item == null) continue; + int checkBurnTime = TileEntityFurnace.getItemBurnTime(item) / 10; + if (checkBurnTime <= 0) continue; + item.stackSize--; + burnTime = checkBurnTime; + totalBurnTime = checkBurnTime; + break; } updateSlots(); } @@ -806,8 +554,7 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl totalBurnTime = 0; return false; } - - return true; + return false; } @Override @@ -826,38 +573,36 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl list.add("Fuel: " + EnumChatFormatting.GOLD + burnTime + "/" + totalBurnTime); } - if (this instanceof PowerLogicHost powerLogicHost) { - PowerLogic logic = powerLogicHost.getPowerLogic(facing); - if (isElectric) { - list.add( - StatCollector.translateToLocal("GT5U.multiblock.energy") + ": " - + EnumChatFormatting.GREEN - + GT_Utility.formatNumbers(logic.getStoredEnergy()) - + EnumChatFormatting.RESET - + " EU / " - + EnumChatFormatting.YELLOW - + GT_Utility.formatNumbers(logic.getCapacity()) - + EnumChatFormatting.RESET - + " EU"); - list.add( - StatCollector.translateToLocal("GT5U.multiblock.usage") + ": " - + EnumChatFormatting.RED - + GT_Utility.formatNumbers(eut) - + EnumChatFormatting.RESET - + " EU/t"); - list.add( - StatCollector.translateToLocal("GT5U.multiblock.mei") + ": " - + EnumChatFormatting.YELLOW - + GT_Utility.formatNumbers(logic.getVoltage()) - + EnumChatFormatting.RESET - // TODO: Put ampere getter here, once that's variable - + " EU/t(*2A) " - + StatCollector.translateToLocal("GT5U.machines.tier") - + ": " - + EnumChatFormatting.YELLOW - + VN[GT_Utility.getTier(logic.getVoltage())] - + EnumChatFormatting.RESET); - } + PowerLogic logic = getPowerLogic(); + if (isElectric) { + list.add( + StatCollector.translateToLocal("GT5U.multiblock.energy") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(logic.getStoredEnergy()) + + EnumChatFormatting.RESET + + " EU / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(logic.getCapacity()) + + EnumChatFormatting.RESET + + " EU"); + list.add( + StatCollector.translateToLocal("GT5U.multiblock.usage") + ": " + + EnumChatFormatting.RED + + GT_Utility.formatNumbers(getProcessingLogic().getCalculatedEut()) + + EnumChatFormatting.RESET + + " EU/t"); + list.add( + StatCollector.translateToLocal("GT5U.multiblock.mei") + ": " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(logic.getVoltage()) + + EnumChatFormatting.RESET + // TODO: Put ampere getter here, once that's variable + + " EU/t(*2A) " + + StatCollector.translateToLocal("GT5U.machines.tier") + + ": " + + EnumChatFormatting.YELLOW + + VN[GT_Utility.getTier(logic.getVoltage())] + + EnumChatFormatting.RESET); } addProgressStringToScanner(player, logLevel, list); @@ -873,6 +618,9 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl } protected void addProgressStringToScanner(EntityPlayer player, int logLevel, ArrayList<String> list) { + P processing = getProcessingLogic(); + int progressTime = processing.getProgress(); + int maxProgressTime = processing.getDuration(); list.add( StatCollector.translateToLocal("GT5U.multiblock.Progress") + ": " + EnumChatFormatting.GREEN @@ -886,7 +634,6 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl } protected void stopMachine(boolean powerShutDown) { - progressTime = 0; setActive(false); disableWorking(); if (powerShutDown) { @@ -896,50 +643,10 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl } protected void updateSlots() { - for (int i = 0; i < inputInventory.getSlots(); i++) { - ItemStack item = inputInventory.getStackInSlot(i); - if (item != null && item.stackSize <= 0) { - inputInventory.setStackInSlot(i, null); - } - } - - for (FluidTankGT inputTank : inputTanks) { - if (inputTank == null) { - continue; - } - - if (inputTank.get() != null && inputTank.get().amount <= 0) { - inputTank.setEmpty(); - continue; - } - - FluidStack afterRecipe = inputTank.get(); - FluidStack beforeRecipe = inputTank.get(Integer.MAX_VALUE); - if (afterRecipe == null || beforeRecipe == null) { - continue; - } - int difference = beforeRecipe.amount - afterRecipe.amount; - inputTank.remove(difference); - } - } - - /** - * Must always be a positive. If the multi generates Eu/t isGenerator() should be overridden to true - */ - protected void setEut(long eut) { - if (eut < 0) { - eut = -eut; - } - - this.eut = eut; - } - - protected void setDuration(long duration) { - if (duration < 0) { - duration = -duration; - } - - maxProgressTime = duration; + itemInput.update(false); + itemOutput.update(false); + fluidInput.update(); + fluidOutput.update(); } @Override @@ -956,53 +663,149 @@ public abstract class MultiTileBasicMachine extends TickableMultiTileEntity impl setActive((booleans & ACTIVE) == ACTIVE); } - protected boolean hasItemInput() { + public boolean hasItemInput() { return true; } - protected boolean hasItemOutput() { + public boolean hasItemOutput() { return true; } - protected boolean hasFluidInput() { + public boolean hasFluidInput() { return true; } - protected boolean hasFluidOutput() { + public boolean hasFluidOutput() { return true; } - protected void setItemOutputs(ItemStack... outputs) { - itemsToOutput = outputs; - } - - protected void setFluidOutputs(FluidStack... outputs) { - fluidsToOutput = outputs; - } - @Override public void setSound(byte soundEvent, int soundEventValue) { this.soundEvent = soundEvent; this.soundEventValue = soundEventValue; - if (isClientSide()) { - switch (soundEventValue) { - case PROCESS_START_SOUND_INDEX -> { - if (getProcessStartSound() != null) GT_Utility.doSoundAtClient( - getProcessStartSound(), - getTimeBetweenProcessSounds(), - 1.0F, - getXCoord(), - getYCoord(), - getZCoord()); - } - case INTERRUPT_SOUND_INDEX -> GT_Utility.doSoundAtClient( - SoundResource.IC2_MACHINES_INTERRUPT_ONE, - 100, + if (isServerSide()) { + return; + } + + switch (soundEventValue) { + case PROCESS_START_SOUND_INDEX -> { + if (getProcessStartSound() != null) GT_Utility.doSoundAtClient( + getProcessStartSound(), + getTimeBetweenProcessSounds(), 1.0F, getXCoord(), getYCoord(), getZCoord()); } + case INTERRUPT_SOUND_INDEX -> GT_Utility.doSoundAtClient( + SoundResource.IC2_MACHINES_INTERRUPT_ONE, + 100, + 1.0F, + getXCoord(), + getYCoord(), + getZCoord()); } + + } + + @Nullable + public ItemInventoryLogic getItemLogic(@Nonnull ForgeDirection side, @Nonnull InventoryType type) { + if (side == facing) return null; + return switch (type) { + case Input -> itemInput; + case Output -> itemOutput; + default -> null; + }; + } + + @Nullable + public FluidInventoryLogic getFluidLogic(@Nonnull ForgeDirection side, @Nonnull InventoryType type) { + if (side == facing) return null; + return switch (type) { + case Input -> fluidInput; + case Output -> fluidOutput; + default -> null; + }; } + + @Override + @Nonnull + public P getProcessingLogic() { + if (processingLogic == null) { + processingLogic = createProcessingLogic().setMachineHost(this); + } + return Objects.requireNonNull(processingLogic); + } + + @OverrideOnly + @Nonnull + protected abstract P createProcessingLogic(); + + @Override + public boolean isInputSeparated() { + return false; + } + + @Nonnull + @Override + public VoidingMode getVoidMode() { + return voidingMode; + } + + @Override + public boolean needsUpdate() { + return processingUpdate; + } + + @Override + public void setProcessingUpdate(boolean update) { + processingUpdate = update; + } + + @Override + @Nonnull + public PowerLogic getPowerLogic(@Nonnull ForgeDirection side) { + if (side == facing) return new NullPowerLogic(); + return power; + } + + @Override + @Nonnull + public ForgeDirection getPowerOutputSide() { + return Objects.requireNonNull(facing.getOpposite()); + } + + protected void updatePowerLogic() { + power.setEnergyCapacity(GT_Values.V[tier] * power.getMaxAmperage() * 2 * MINUTE); + power.setMaxVoltage(GT_Values.V[tier]); + power.setMaxAmperage(1); + } + + @Nonnull + protected PowerLogic createPowerLogic() { + return new PowerLogic().setMaxAmperage(1) + .setType(PowerLogic.RECEIVER); + } + + @Nonnull + protected GUIProvider<?> createGUIProvider() { + return new MachineGUIProvider<>(this); + } + + @Nonnull + public GUIProvider<?> getGUI(@Nonnull UIBuildContext uiContext) { + return guiProvider; + } + + @Override + public ItemStack getAsItem() { + return MultiTileEntityRegistry.getRegistry(getMultiTileEntityRegistryID()) + .getItem(getMultiTileEntityID()); + } + + @Override + public String getMachineName() { + return StatCollector.translateToLocal(getAsItem().getUnlocalizedName()); + } + } diff --git a/src/main/java/gregtech/api/multitileentity/multiblock/base/ComplexParallelController.java b/src/main/java/gregtech/api/multitileentity/multiblock/base/ComplexParallelController.java index 808c16a200..cdcb77d6e5 100644 --- a/src/main/java/gregtech/api/multitileentity/multiblock/base/ComplexParallelController.java +++ b/src/main/java/gregtech/api/multitileentity/multiblock/base/ComplexParallelController.java @@ -2,7 +2,8 @@ package gregtech.api.multitileentity.multiblock.base; import java.util.ArrayList; import java.util.List; -import java.util.stream.LongStream; + +import javax.annotation.Nonnull; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; @@ -12,206 +13,58 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.StatCollector; import net.minecraft.world.World; -import net.minecraftforge.fluids.FluidStack; -import gregtech.api.enums.GT_Values; import gregtech.api.logic.ComplexParallelProcessingLogic; -import gregtech.api.logic.interfaces.PollutionLogicHost; import gregtech.api.util.GT_Utility; import gregtech.api.util.GT_Waila; import mcp.mobius.waila.api.IWailaConfigHandler; import mcp.mobius.waila.api.IWailaDataAccessor; -public abstract class ComplexParallelController<T extends ComplexParallelController<T>> extends PowerController<T> { +public abstract class ComplexParallelController<C extends ComplexParallelController<C, P>, P extends ComplexParallelProcessingLogic<P>> + extends Controller<C, P> { - protected ComplexParallelProcessingLogic processingLogic; protected int maxComplexParallels = 0; protected int currentComplexParallels = 0; - protected long[] maxProgressTimes = new long[0]; - protected long[] progressTimes = new long[0]; public ComplexParallelController() { isSimpleMachine = false; } - protected void setMaxComplexParallels(int parallel) { - if (parallel != maxComplexParallels) { - if (maxComplexParallels != 0) { - stopMachine(false); - } - maxProgressTimes = new long[parallel]; - progressTimes = new long[parallel]; + protected void setMaxComplexParallels(int parallel, boolean stopMachine) { + if (parallel != maxComplexParallels && maxComplexParallels != 0 && stopMachine) { + stopMachine(false); } maxComplexParallels = parallel; - } - - @Override - protected void runMachine(long tick) { - if (acceptsFuel() && isActive()) { - if (!consumeFuel()) { - stopMachine(true); - return; - } - } - - if (hasThingsToDo()) { - markDirty(); - runningTick(tick); - } - if ((tick % TICKS_BETWEEN_RECIPE_CHECKS == 0 || hasWorkJustBeenEnabled() || hasInventoryBeenModified()) - && maxComplexParallels != currentComplexParallels) { - if (isAllowedToWork() && maxComplexParallels > currentComplexParallels) { - wasEnabled = false; - boolean started = false; - for (int i = 0; i < maxComplexParallels; i++) { - if (maxProgressTimes[i] <= 0 && checkRecipe(i)) { - currentComplexParallels++; - started = true; - } - } - if (started) { - setActive(true); - updateSlots(); - markDirty(); - issueClientUpdate(); - } - } - } - } - - @Override - protected void runningTick(long tick) { - consumeEnergy(); - boolean allStopped = true; - for (int i = 0; i < maxComplexParallels; i++) { - if (maxProgressTimes[i] > 0 && ++progressTimes[i] >= maxProgressTimes[i]) { - progressTimes[i] = 0; - maxProgressTimes[i] = 0; - outputItems(i); - outputFluids(i); - if (isAllowedToWork()) { - if (checkRecipe(i)) { - allStopped = false; - } else { - currentComplexParallels--; - } - } - updateSlots(); - } else if (maxProgressTimes[i] > 0) { - allStopped = false; - } - } - if (allStopped) { - setActive(false); - issueClientUpdate(); - } - - if (this instanceof PollutionLogicHost && tick % POLLUTION_TICK == 0) { - doPollution(); - } - emitEnergy(); - } - - protected boolean checkRecipe(int index) { - ComplexParallelProcessingLogic processingLogic = getComplexProcessingLogic(); - if (processingLogic == null || index < 0 || index >= maxComplexParallels) { - return false; - } - processingLogic.clear(index); - boolean result = processingLogic.setInputItems(index, getInputItems(index)) - .setInputFluids(index, getInputFluids(index)) - .setTileEntity(this) - .setVoidProtection(index, isVoidProtectionEnabledForItem(index), isVoidProtectionEnabledForFluid(index)) - .setEut(index, getEutForComplexParallel(index)) - .setPerfectOverclock(hasPerfectOverclock()) - .process(index); - setDuration(index, processingLogic.getDuration(index)); - setEut(processingLogic.getTotalEU()); - return result; - } - - protected void outputItems(int index) { - ComplexParallelProcessingLogic processingLogic = getComplexProcessingLogic(); - if (processingLogic != null && index >= 0 && index < maxComplexParallels) { - outputItems(processingLogic.getOutputItems(index)); - } - } - - protected void outputFluids(int index) { - ComplexParallelProcessingLogic processingLogic = getComplexProcessingLogic(); - if (processingLogic != null && index >= 0 && index < maxComplexParallels) { - outputFluids(processingLogic.getOutputFluids(index)); - } - } - - protected ComplexParallelProcessingLogic getComplexProcessingLogic() { - return processingLogic; - } - - @Override - public boolean hasThingsToDo() { - return LongStream.of(maxProgressTimes) - .sum() > 0; + setProcessingUpdate(true); } @Override protected void stopMachine(boolean powerShutDown) { super.stopMachine(powerShutDown); - for (int i = 0; i < maxComplexParallels; i++) { - maxProgressTimes[i] = 0; - } - } - - protected void setDuration(int index, long duration) { - if (duration < 0) { - duration = -duration; - } - if (index >= 0 && index < maxComplexParallels) { - maxProgressTimes[index] = duration; - } - } - - protected ItemStack[] getInputItems(int index) { - return getInputItems(); - } - - protected FluidStack[] getInputFluids(int index) { - return getInputFluids(); - } - - protected boolean isVoidProtectionEnabledForItem(int index) { - return protectsExcessItem(); - } - - protected boolean isVoidProtectionEnabledForFluid(int index) { - return protectsExcessFluid(); } protected boolean hasPerfectOverclock() { return false; } - protected long getEutForComplexParallel(int index) { - // As default behavior we'll give the parallel all remaining EU we have - return GT_Values.V[tier] - eut; - } - @Override protected void addProgressStringToScanner(EntityPlayer player, int logLevel, ArrayList<String> list) { + P processing = getProcessingLogic(); for (int i = 0; i < maxComplexParallels; i++) { list.add( StatCollector.translateToLocal("GT5U.multiblock.Progress") + " " + (i + 1) + ": " + EnumChatFormatting.GREEN - + GT_Utility.formatNumbers(progressTimes[i] > 20 ? progressTimes[i] / 20 : progressTimes[i]) + + GT_Utility.formatNumbers( + processing.getProgress(i) > 20 ? processing.getProgress(i) / 20 : processing.getProgress(i)) + EnumChatFormatting.RESET - + (progressTimes[i] > 20 ? " s / " : " ticks / ") + + (processing.getProgress(i) > 20 ? " s / " : " ticks / ") + EnumChatFormatting.YELLOW - + GT_Utility - .formatNumbers(maxProgressTimes[i] > 20 ? maxProgressTimes[i] / 20 : maxProgressTimes[i]) + + GT_Utility.formatNumbers( + processing.getDuration(i) > 20 ? processing.getDuration(i) / 20 : processing.getDuration(i)) + EnumChatFormatting.RESET - + (maxProgressTimes[i] > 20 ? " s" : " ticks")); + + (processing.getDuration(i) > 20 ? " s" : " ticks")); } } @@ -219,10 +72,11 @@ public abstract class ComplexParallelController<T extends ComplexParallelControl public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, int z) { super.getWailaNBTData(player, tile, tag, world, x, y, z); + P processing = getProcessingLogic(); tag.setInteger("maxComplexParallels", maxComplexParallels); for (int i = 0; i < maxComplexParallels; i++) { - tag.setLong("maxProgress" + i, maxProgressTimes[i]); - tag.setLong("progress" + i, progressTimes[i]); + tag.setInteger("maxProgress" + i, processing.getDuration(i)); + tag.setInteger("progress" + i, processing.getProgress(i)); } } @@ -233,8 +87,8 @@ public abstract class ComplexParallelController<T extends ComplexParallelControl final NBTTagCompound tag = accessor.getNBTData(); maxComplexParallels = tag.getInteger("maxComplexParallels"); for (int i = 0; i < maxComplexParallels; i++) { - long maxProgress = tag.getLong("maxProgress" + i); - long progress = tag.getLong("progress" + i); + long maxProgress = tag.getInteger("maxProgress" + i); + long progress = tag.getInteger("progress" + i); currentTip.add( "Process " + (i + 1) + ": " @@ -242,4 +96,16 @@ public abstract class ComplexParallelController<T extends ComplexParallelControl .getMachineProgressString(maxProgress > 0 && maxProgress >= progress, maxProgress, progress)); } } + + @Override + public void setProcessingLogicPower(@Nonnull P processingLogic) { + processingLogic.setAmperageOC(true); + processingLogic.setAvailableAmperage(getPowerLogic().getMaxAmperage() / maxComplexParallels); + processingLogic.setAvailableVoltage(getPowerLogic().getVoltage() / maxComplexParallels); + } + + @Override + public void updateProcessingLogic(@Nonnull P processingLogic) { + processingLogic.setMaxComplexParallel(maxComplexParallels); + } } diff --git a/src/main/java/gregtech/api/multitileentity/multiblock/base/Controller.java b/src/main/java/gregtech/api/multitileentity/multiblock/base/Controller.java index 606d957fd6..8ac908be12 100644 --- a/src/main/java/gregtech/api/multitileentity/multiblock/base/Controller.java +++ b/src/main/java/gregtech/api/multitileentity/multiblock/base/Controller.java @@ -1,261 +1,109 @@ package gregtech.api.multitileentity.multiblock.base; -import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain; -import static gregtech.GT_Mod.GT_FML_LOGGER; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.EV_Conveyor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.EV_Emitter; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.EV_FieldGenerator; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.EV_Motor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.EV_Piston; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.EV_Pump; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.EV_RobotArm; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.EV_Sensor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.HV_Conveyor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.HV_Emitter; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.HV_FieldGenerator; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.HV_Motor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.HV_Piston; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.HV_Pump; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.HV_RobotArm; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.HV_Sensor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.IV_Conveyor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.IV_Emitter; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.IV_FieldGenerator; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.IV_Motor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.IV_Piston; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.IV_Pump; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.IV_RobotArm; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.IV_Sensor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.LV_Conveyor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.LV_Emitter; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.LV_FieldGenerator; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.LV_Motor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.LV_Piston; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.LV_Pump; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.LV_RobotArm; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.LV_Sensor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.LuV_Conveyor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.LuV_Emitter; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.LuV_FieldGenerator; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.LuV_Motor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.LuV_Piston; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.LuV_Pump; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.LuV_RobotArm; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.LuV_Sensor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.MAX_Conveyor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.MAX_Emitter; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.MAX_FieldGenerator; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.MAX_Motor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.MAX_Piston; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.MAX_Pump; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.MAX_RobotArm; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.MAX_Sensor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.MV_Conveyor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.MV_Emitter; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.MV_FieldGenerator; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.MV_Motor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.MV_Piston; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.MV_Pump; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.MV_RobotArm; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.MV_Sensor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UEV_Conveyor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UEV_Emitter; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UEV_FieldGenerator; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UEV_Motor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UEV_Piston; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UEV_Pump; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UEV_RobotArm; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UEV_Sensor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UHV_Conveyor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UHV_Emitter; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UHV_FieldGenerator; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UHV_Motor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UHV_Piston; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UHV_Pump; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UHV_RobotArm; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UHV_Sensor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UIV_Conveyor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UIV_Emitter; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UIV_FieldGenerator; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UIV_Motor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UIV_Piston; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UIV_Pump; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UIV_RobotArm; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UIV_Sensor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UMV_Conveyor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UMV_Emitter; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UMV_FieldGenerator; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UMV_Motor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UMV_Piston; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UMV_Pump; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UMV_RobotArm; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UMV_Sensor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UV_Conveyor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UV_Emitter; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UV_FieldGenerator; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UV_Motor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UV_Piston; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UV_Pump; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UV_RobotArm; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UV_Sensor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UXV_Conveyor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UXV_Emitter; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UXV_FieldGenerator; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UXV_Motor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UXV_Piston; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UXV_Pump; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UXV_RobotArm; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.UXV_Sensor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.ZPM_Conveyor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.ZPM_Emitter; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.ZPM_FieldGenerator; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.ZPM_Motor; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.ZPM_Piston; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.ZPM_Pump; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.ZPM_RobotArm; -import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.ZPM_Sensor; -import static gregtech.loaders.preload.GT_Loader_MultiTileEntities.COMPONENT_CASING_REGISTRY_NAME; -import static mcp.mobius.waila.api.SpecialChars.GREEN; -import static mcp.mobius.waila.api.SpecialChars.RED; -import static mcp.mobius.waila.api.SpecialChars.RESET; +import static gregtech.api.util.GT_Utility.moveMultipleItemStacks; +import static gregtech.common.misc.WirelessNetworkManager.strongCheckOrAddUser; +import static mcp.mobius.waila.api.SpecialChars.*; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; -import net.minecraft.block.Block; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.IIcon; +import net.minecraft.util.StatCollector; import net.minecraft.world.World; -import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.ForgeDirection; -import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.FluidTankInfo; -import net.minecraftforge.fluids.IFluidTank; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; import org.lwjgl.input.Keyboard; import com.gtnewhorizon.structurelib.StructureLibAPI; import com.gtnewhorizon.structurelib.alignment.IAlignment; import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits; -import com.gtnewhorizon.structurelib.alignment.constructable.IConstructable; import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing; import com.gtnewhorizon.structurelib.alignment.enumerable.Flip; import com.gtnewhorizon.structurelib.alignment.enumerable.Rotation; import com.gtnewhorizon.structurelib.structure.IStructureDefinition; -import com.gtnewhorizon.structurelib.structure.IStructureElement; -import com.gtnewhorizon.structurelib.structure.IStructureElementChain; import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; import com.gtnewhorizon.structurelib.util.Vec3Impl; -import com.gtnewhorizons.modularui.api.ModularUITextures; -import com.gtnewhorizons.modularui.api.drawable.ItemDrawable; -import com.gtnewhorizons.modularui.api.forge.IItemHandler; -import com.gtnewhorizons.modularui.api.forge.IItemHandlerModifiable; -import com.gtnewhorizons.modularui.api.forge.ItemStackHandler; -import com.gtnewhorizons.modularui.api.forge.ListItemHandler; -import com.gtnewhorizons.modularui.api.math.Pos2d; import com.gtnewhorizons.modularui.api.screen.ModularWindow; -import com.gtnewhorizons.modularui.api.screen.UIBuildContext; -import com.gtnewhorizons.modularui.api.widget.IWidgetBuilder; -import com.gtnewhorizons.modularui.api.widget.Widget; -import com.gtnewhorizons.modularui.common.widget.DrawableWidget; -import com.gtnewhorizons.modularui.common.widget.FluidSlotWidget; -import com.gtnewhorizons.modularui.common.widget.MultiChildWidget; -import com.gtnewhorizons.modularui.common.widget.Scrollable; -import com.gtnewhorizons.modularui.common.widget.SlotWidget; -import com.gtnewhorizons.modularui.common.widget.TabButton; -import com.gtnewhorizons.modularui.common.widget.TabContainer; import cpw.mods.fml.common.network.NetworkRegistry; -import gnu.trove.list.TIntList; -import gnu.trove.list.array.TIntArrayList; -import gregtech.api.enums.GT_Values; import gregtech.api.enums.GT_Values.NBT; -import gregtech.api.enums.OrePrefixes; -import gregtech.api.enums.TextureSet; +import gregtech.api.enums.InventoryType; import gregtech.api.enums.VoidingMode; -import gregtech.api.fluid.FluidTankGT; -import gregtech.api.gui.modularui.GT_UITextures; import gregtech.api.interfaces.IDescribable; import gregtech.api.interfaces.fluid.IFluidStore; -import gregtech.api.interfaces.modularui.ControllerWithOptionalFeatures; +import gregtech.api.logic.ControllerFluidLogic; +import gregtech.api.logic.ControllerItemLogic; +import gregtech.api.logic.FluidInventoryLogic; +import gregtech.api.logic.ItemInventoryLogic; +import gregtech.api.logic.MuTEProcessingLogic; import gregtech.api.logic.PowerLogic; -import gregtech.api.logic.ProcessingLogic; -import gregtech.api.logic.interfaces.PowerLogicHost; -import gregtech.api.logic.interfaces.ProcessingLogicHost; -import gregtech.api.multitileentity.MultiTileEntityContainer; -import gregtech.api.multitileentity.MultiTileEntityRegistry; +import gregtech.api.multitileentity.enums.MultiTileCasingPurpose; import gregtech.api.multitileentity.interfaces.IMultiBlockController; import gregtech.api.multitileentity.interfaces.IMultiBlockPart; -import gregtech.api.multitileentity.interfaces.IMultiTileEntity; import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_AddToolTips; import gregtech.api.multitileentity.machine.MultiTileBasicMachine; import gregtech.api.multitileentity.multiblock.casing.FunctionalCasing; import gregtech.api.multitileentity.multiblock.casing.UpgradeCasing; +import gregtech.api.net.GT_Packet_MultiTileEntity; import gregtech.api.objects.GT_ItemStack; -import gregtech.api.recipe.RecipeMap; -import gregtech.api.recipe.check.CheckRecipeResult; -import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; import gregtech.api.util.GT_Utility; import gregtech.api.util.GT_Waila; -import gregtech.common.tileentities.casings.upgrade.Inventory; import mcp.mobius.waila.api.IWailaConfigHandler; import mcp.mobius.waila.api.IWailaDataAccessor; /** * Multi Tile Entities - or MuTEs - don't have dedicated hatches, but their casings can become hatches. */ -public abstract class Controller<T extends Controller<T>> extends MultiTileBasicMachine - implements IAlignment, IConstructable, IMultiBlockController, IDescribable, IMTE_AddToolTips, - ISurvivalConstructable, ControllerWithOptionalFeatures { +public abstract class Controller<C extends Controller<C, P>, P extends MuTEProcessingLogic<P>> + extends MultiTileBasicMachine<P> + implements IAlignment, IMultiBlockController, IDescribable, IMTE_AddToolTips, ISurvivalConstructable { public static final String ALL_INVENTORIES_NAME = "all"; + protected static final int AUTO_OUTPUT_FREQUENCY_TICK = 20; private static final Map<Integer, GT_Multiblock_Tooltip_Builder> tooltip = new ConcurrentHashMap<>(); private final List<UpgradeCasing> upgradeCasings = new ArrayList<>(); private final List<FunctionalCasing> functionalCasings = new ArrayList<>(); protected BuildState buildState = new BuildState(); - protected Map<String, String> multiBlockInputInventoryNames = new LinkedHashMap<>(); - protected Map<String, String> multiBlockOutputInventoryNames = new LinkedHashMap<>(); - protected Map<String, String> multiBlockInputInventoryToTankLink = new LinkedHashMap<>(); - protected Map<String, IItemHandlerModifiable> multiBlockInputInventory = new LinkedHashMap<>(); - protected Map<String, IItemHandlerModifiable> multiBlockOutputInventory = new LinkedHashMap<>(); - - protected Map<String, String> multiBlockInputTankNames = new LinkedHashMap<>(); - protected Map<String, String> multiBlockOutputTankNames = new LinkedHashMap<>(); - protected Map<String, FluidTankGT[]> multiBlockInputTank = new LinkedHashMap<>(); - protected Map<String, FluidTankGT[]> multiBlockOutputTank = new LinkedHashMap<>(); - private boolean structureOkay = false, structureChanged = false; private ExtendedFacing extendedFacing = ExtendedFacing.DEFAULT; private IAlignmentLimits limits = getInitialAlignmentLimits(); - private String inventoryName; - private String tankName; protected boolean separateInputs = getDefaultInputSeparationMode(); protected VoidingMode voidingMode = getDefaultVoidingMode(); protected boolean batchMode = getDefaultBatchMode(); protected boolean recipeLock = getDefaultRecipeLockingMode(); + protected boolean shouldSort = false; /** If this is set to true, the machine will get default WAILA behavior */ protected boolean isSimpleMachine = true; + protected boolean isCleanroom = false; + protected ControllerItemLogic controllerItemInput = new ControllerItemLogic(); + protected ControllerItemLogic controllerItemOutput = new ControllerItemLogic(); + protected ControllerFluidLogic controllerFluidInput = new ControllerFluidLogic(); + protected ControllerFluidLogic controllerFluidOutput = new ControllerFluidLogic(); + // A list of sides // Each side has a list of parts that have a cover that need to be ticked protected List<LinkedList<WeakReference<IMultiBlockPart>>> registeredCoveredParts = Arrays.asList( @@ -266,6 +114,15 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic new LinkedList<>(), new LinkedList<>()); + // A list for each purpose that a casing can register to, to be ticked + protected List<LinkedList<WeakReference<IMultiBlockPart>>> registeredTickableParts = new ArrayList<>(); + + public Controller() { + for (int i = 0; i < MultiTileCasingPurpose.values().length; i++) { + registeredTickableParts.add(new LinkedList<>()); + } + } + /** Registry ID of the required casing */ public abstract short getCasingRegistryID(); @@ -288,7 +145,7 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic * other instances, even for those of the same class. */ @Override - public abstract IStructureDefinition<T> getStructureDefinition(); + public abstract IStructureDefinition<C> getStructureDefinition(); /** * Checks the Machine. @@ -296,16 +153,20 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic * NOTE: If using `buildState` be sure to `startBuilding()` and either `endBuilding()` or `failBuilding()` */ public boolean checkMachine() { + calculateTier(); + updatePowerLogic(); + return tier > 0; + } + + protected void calculateTier() { double sum = 0; if (functionalCasings == null || functionalCasings.size() == 0) { - return false; + return; } for (FunctionalCasing casing : functionalCasings) { sum += casing.getPartTier() * casing.getPartModifier(); } - tier = (int) Math.floor(sum / functionalCasings.size()); - // Maximum Energy stores will have a cap of 2 minute work time of current voltage - return tier > 0; + tier = (int) Math.min(Math.floor(sum / functionalCasings.size()), 14); } @Override @@ -322,77 +183,26 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic (byte) extendedFacing.getFlip() .getIndex()); - saveUpgradeInventoriesToNBT(nbt); - saveUpgradeTanksToNBT(nbt); - nbt.setString(NBT.VOIDING_MODE, voidingMode.name); nbt.setBoolean(NBT.SEPARATE_INPUTS, separateInputs); nbt.setBoolean(NBT.RECIPE_LOCK, recipeLock); nbt.setBoolean(NBT.BATCH_MODE, batchMode); } - private void saveUpgradeInventoriesToNBT(NBTTagCompound nbt) { - final NBTTagList inputInvList = new NBTTagList(); - multiBlockInputInventory.forEach((id, inv) -> { - if (!id.equals("controller")) { - final NBTTagCompound tTag = new NBTTagCompound(); - tTag.setString(NBT.UPGRADE_INVENTORY_UUID, id); - tTag.setString(NBT.UPGRADE_INVENTORY_NAME, multiBlockInputInventoryNames.get(id)); - tTag.setInteger(NBT.UPGRADE_INVENTORY_SIZE, inv.getSlots()); - writeInventory(tTag, inv, NBT.INV_INPUT_LIST); - inputInvList.appendTag(tTag); - } - }); - final NBTTagList outputInvList = new NBTTagList(); - multiBlockOutputInventory.forEach((id, inv) -> { - if (!id.equals("controller")) { - final NBTTagCompound tTag = new NBTTagCompound(); - tTag.setString(NBT.UPGRADE_INVENTORY_UUID, id); - tTag.setString(NBT.UPGRADE_INVENTORY_NAME, multiBlockOutputInventoryNames.get(id)); - tTag.setInteger(NBT.UPGRADE_INVENTORY_SIZE, inv.getSlots()); - writeInventory(tTag, inv, NBT.INV_OUTPUT_LIST); - outputInvList.appendTag(tTag); - } - }); - nbt.setTag(NBT.UPGRADE_INVENTORIES_INPUT, inputInvList); - nbt.setTag(NBT.UPGRADE_INVENTORIES_OUTPUT, outputInvList); - } - - private void saveUpgradeTanksToNBT(NBTTagCompound nbt) { - final NBTTagList inputTankList = new NBTTagList(); - multiBlockInputTank.forEach((id, tanks) -> { - if (!id.equals("controller") && tanks != null && tanks.length > 0) { - final NBTTagCompound tTag = new NBTTagCompound(); - tTag.setString(NBT.UPGRADE_TANK_UUID, id); - tTag.setString(NBT.UPGRADE_TANK_NAME, multiBlockInputTankNames.get(id)); - // We assume all tanks in the tank-array are equally sized - tTag.setLong(NBT.UPGRADE_TANK_CAPACITY, tanks[0].capacity()); - tTag.setLong(NBT.UPGRADE_TANK_CAPACITY_MULTIPLIER, tanks[0].getCapacityMultiplier()); - tTag.setInteger(NBT.UPGRADE_TANKS_COUNT, tanks.length); - for (int i = 0; i < tanks.length; i++) { - tanks[i].writeToNBT(tTag, NBT.UPGRADE_TANKS_PREFIX + i); - } - inputTankList.appendTag(tTag); - } - }); - final NBTTagList outputTankList = new NBTTagList(); - multiBlockOutputTank.forEach((id, tanks) -> { - if (!id.equals("controller") && tanks != null && tanks.length > 0) { - final NBTTagCompound tTag = new NBTTagCompound(); - tTag.setString(NBT.UPGRADE_TANK_UUID, id); - tTag.setString(NBT.UPGRADE_TANK_NAME, multiBlockInputTankNames.get(id)); - // We assume all tanks in the tank-array are equally sized - tTag.setLong(NBT.UPGRADE_TANK_CAPACITY, tanks[0].capacity()); - tTag.setLong(NBT.UPGRADE_TANK_CAPACITY_MULTIPLIER, tanks[0].getCapacityMultiplier()); - tTag.setInteger(NBT.UPGRADE_TANKS_COUNT, tanks.length); - for (int i = 0; i < tanks.length; i++) { - tanks[i].writeToNBT(tTag, NBT.UPGRADE_TANKS_PREFIX + i); - } - outputTankList.appendTag(tTag); - } - }); - nbt.setTag(NBT.UPGRADE_TANKS_INPUT, inputTankList); - nbt.setTag(NBT.UPGRADE_TANKS_OUTPUT, outputTankList); + @Override + protected void saveItemLogic(NBTTagCompound nbt) { + NBTTagCompound itemInputNBT = controllerItemInput.saveToNBT(); + nbt.setTag(NBT.INV_INPUT_LIST, itemInputNBT); + NBTTagCompound itemOutputNBT = controllerItemOutput.saveToNBT(); + nbt.setTag(NBT.INV_OUTPUT_LIST, itemOutputNBT); + } + + @Override + protected void saveFluidLogic(NBTTagCompound nbt) { + NBTTagCompound fluidInputNBT = controllerFluidInput.saveToNBT(); + nbt.setTag(NBT.TANK_IN, fluidInputNBT); + NBTTagCompound fluidOutputNBT = controllerFluidOutput.saveToNBT(); + nbt.setTag(NBT.TANK_OUT, fluidOutputNBT); } @Override @@ -401,83 +211,37 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic // Multiblock inventories are a collection of inventories. The first inventory is the default internal // inventory, and the others are added by inventory extending blocks. - if (inputInventory != null) registerInventory("controller", "controller", inputInventory, Inventory.INPUT); - if (outputInventory != null) registerInventory("controller", "controller", outputInventory, Inventory.OUTPUT); - - if (inputTanks != null) registerFluidInventory("controller", "controller", inputTanks, Inventory.INPUT); - if (outputTanks != null) registerFluidInventory("controller", "controller", outputTanks, Inventory.OUTPUT); structureOkay = nbt.getBoolean(NBT.STRUCTURE_OK); extendedFacing = ExtendedFacing .of(getFrontFacing(), Rotation.byIndex(nbt.getByte(NBT.ROTATION)), Flip.byIndex(nbt.getByte(NBT.FLIP))); - loadUpgradeInventoriesFromNBT(nbt); - loadUpgradeTanksFromNBT(nbt); - voidingMode = VoidingMode.fromName(nbt.getString(NBT.VOIDING_MODE)); separateInputs = nbt.getBoolean(NBT.SEPARATE_INPUTS); recipeLock = nbt.getBoolean(NBT.RECIPE_LOCK); batchMode = nbt.getBoolean(NBT.BATCH_MODE); } - private void loadUpgradeInventoriesFromNBT(NBTTagCompound nbt) { - final NBTTagList listInputInventories = nbt - .getTagList(NBT.UPGRADE_INVENTORIES_INPUT, Constants.NBT.TAG_COMPOUND); - for (int i = 0; i < listInputInventories.tagCount(); i++) { - final NBTTagCompound nbtInv = listInputInventories.getCompoundTagAt(i); - final String invUUID = nbtInv.getString(NBT.UPGRADE_INVENTORY_UUID); - final String invName = nbtInv.getString(NBT.UPGRADE_INVENTORY_NAME); - final int invSize = nbtInv.getInteger(NBT.UPGRADE_INVENTORY_SIZE); - final IItemHandlerModifiable inv = new ItemStackHandler(invSize); - loadInventory(nbtInv, inv, NBT.INV_INPUT_LIST); - registerInventory(invName, invUUID, invSize, Inventory.INPUT); - } - - final NBTTagList listOutputInventories = nbt - .getTagList(NBT.UPGRADE_INVENTORIES_OUTPUT, Constants.NBT.TAG_COMPOUND); - for (int i = 0; i < listOutputInventories.tagCount(); i++) { - final NBTTagCompound nbtInv = listOutputInventories.getCompoundTagAt(i); - final String invUUID = nbtInv.getString(NBT.UPGRADE_INVENTORY_UUID); - final String invName = nbtInv.getString(NBT.UPGRADE_INVENTORY_NAME); - final int invSize = nbtInv.getInteger(NBT.UPGRADE_INVENTORY_SIZE); - IItemHandlerModifiable inv = new ItemStackHandler(invSize); - loadInventory(nbtInv, inv, NBT.INV_OUTPUT_LIST); - registerInventory(invName, invUUID, invSize, Inventory.OUTPUT); + @Override + protected void loadItemLogic(NBTTagCompound nbt) { + if (!nbt.hasKey(NBT.INV_INPUT_LIST) && !nbt.hasKey(NBT.INV_OUTPUT_LIST)) { + controllerItemInput.addInventory(new ItemInventoryLogic(16)); + controllerItemOutput.addInventory(new ItemInventoryLogic(16)); + return; } + controllerItemInput.loadFromNBT(nbt.getCompoundTag(NBT.INV_INPUT_LIST)); + controllerItemOutput.loadFromNBT(nbt.getCompoundTag(NBT.INV_OUTPUT_LIST)); } - private void loadUpgradeTanksFromNBT(NBTTagCompound nbt) { - final NBTTagList listInputTanks = nbt.getTagList(NBT.UPGRADE_TANKS_INPUT, Constants.NBT.TAG_COMPOUND); - for (int i = 0; i < listInputTanks.tagCount(); i++) { - final NBTTagCompound nbtTank = listInputTanks.getCompoundTagAt(i); - String tankUUID = nbtTank.getString(NBT.UPGRADE_TANK_UUID); - String tankName = nbtTank.getString(NBT.UPGRADE_TANK_NAME); - long capacity = nbtTank.getLong(NBT.UPGRADE_TANK_CAPACITY); - long capacityMultiplier = nbtTank.getLong(NBT.UPGRADE_TANK_CAPACITY_MULTIPLIER); - int count = nbtTank.getInteger(NBT.UPGRADE_TANKS_COUNT); - FluidTankGT[] tanks = new FluidTankGT[count]; - for (int j = 0; j < count; j++) { - tanks[j] = new FluidTankGT(capacity).setCapacityMultiplier(capacityMultiplier) - .readFromNBT(nbtTank, NBT.UPGRADE_TANKS_PREFIX + j); - } - registerFluidInventory(tankName, tankUUID, count, capacity, capacityMultiplier, Inventory.INPUT); - } - - final NBTTagList listOutputTanks = nbt.getTagList(NBT.UPGRADE_TANKS_OUTPUT, Constants.NBT.TAG_COMPOUND); - for (int i = 0; i < listOutputTanks.tagCount(); i++) { - final NBTTagCompound nbtTank = listOutputTanks.getCompoundTagAt(i); - String tankUUID = nbtTank.getString(NBT.UPGRADE_TANK_UUID); - String tankName = nbtTank.getString(NBT.UPGRADE_TANK_NAME); - long capacity = nbtTank.getLong(NBT.UPGRADE_TANK_CAPACITY); - long capacityMultiplier = nbtTank.getLong(NBT.UPGRADE_TANK_CAPACITY_MULTIPLIER); - int count = nbtTank.getInteger(NBT.UPGRADE_TANKS_COUNT); - FluidTankGT[] tanks = new FluidTankGT[count]; - for (int j = 0; j < count; j++) { - tanks[j] = new FluidTankGT(capacity).setCapacityMultiplier(capacityMultiplier) - .readFromNBT(nbtTank, NBT.UPGRADE_TANKS_PREFIX + j); - } - registerFluidInventory(tankName, tankUUID, count, capacity, capacityMultiplier, Inventory.OUTPUT); + @Override + protected void loadFluidLogic(NBTTagCompound nbt) { + if (!nbt.hasKey(NBT.TANK_IN) && !nbt.hasKey(NBT.TANK_OUT)) { + controllerFluidInput.addInventory(new FluidInventoryLogic(16, 32000)); + controllerFluidOutput.addInventory(new FluidInventoryLogic(16, 32000)); + return; } + controllerFluidInput.loadFromNBT(nbt.getCompoundTag(NBT.TANK_IN)); + controllerFluidOutput.loadFromNBT(nbt.getCompoundTag(NBT.TANK_OUT)); } @Override @@ -489,9 +253,9 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic public String[] getDescription() { if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) { return getTooltip().getStructureInformation(); - } else { - return getTooltip().getInformation(); } + + return getTooltip().getInformation(); } @Override @@ -519,6 +283,7 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic // Only trigger an update if forced (from onPostTick, generally), or if the structure has changed if ((structureChanged || aForceReset)) { + clearSpecialLists(); structureOkay = checkMachine(); } structureChanged = false; @@ -531,8 +296,6 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic } public final boolean checkPiece(String piece, Vec3Impl offset) { - functionalCasings.clear(); - upgradeCasings.clear(); return checkPiece(piece, offset.get0(), offset.get1(), offset.get2()); } @@ -617,8 +380,8 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic } @SuppressWarnings("unchecked") - private IStructureDefinition<Controller<T>> getCastedStructureDefinition() { - return (IStructureDefinition<Controller<T>>) getStructureDefinition(); + private IStructureDefinition<Controller<C, P>> getCastedStructureDefinition() { + return (IStructureDefinition<Controller<C, P>>) getStructureDefinition(); } @Override @@ -628,24 +391,27 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic @Override public void setExtendedFacing(ExtendedFacing newExtendedFacing) { - if (extendedFacing != newExtendedFacing) { - onStructureChange(); - if (structureOkay) stopMachine(false); - extendedFacing = newExtendedFacing; - structureOkay = false; - if (isServerSide()) { - StructureLibAPI.sendAlignment( - this, - new NetworkRegistry.TargetPoint( - getWorld().provider.dimensionId, - getXCoord(), - getYCoord(), - getZCoord(), - 512)); - } else { - issueTextureUpdate(); - } + if (extendedFacing == newExtendedFacing) { + return; + } + + onStructureChange(); + if (structureOkay) stopMachine(false); + extendedFacing = newExtendedFacing; + structureOkay = false; + if (isServerSide()) { + StructureLibAPI.sendAlignment( + this, + new NetworkRegistry.TargetPoint( + getWorld().provider.dimensionId, + getXCoord(), + getYCoord(), + getZCoord(), + 512)); + } else { + issueTextureUpdate(); } + } @Override @@ -686,6 +452,31 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic } @Override + public void registerCaseWithPurpose(MultiTileCasingPurpose purpose, IMultiBlockPart part) { + final LinkedList<WeakReference<IMultiBlockPart>> tickableParts = registeredTickableParts.get(purpose.ordinal()); + final Iterator<WeakReference<IMultiBlockPart>> it = tickableParts.iterator(); + while (it.hasNext()) { + final IMultiBlockPart next = (it.next()).get(); + if (next == null) { + it.remove(); + } else if (next == part) { + return; + } + } + tickableParts.add(new WeakReference<>(part)); + } + + @Override + public void unregisterCaseWithPurpose(MultiTileCasingPurpose purpose, IMultiBlockPart part) { + final LinkedList<WeakReference<IMultiBlockPart>> tickableParts = registeredTickableParts.get(purpose.ordinal()); + final Iterator<WeakReference<IMultiBlockPart>> it = tickableParts.iterator(); + while (it.hasNext()) { + final IMultiBlockPart next = (it.next()).get(); + if (next == null || next == part) it.remove(); + } + } + + @Override public void onFirstTick(boolean isServerSide) { super.onFirstTick(isServerSide); if (isServerSide) { @@ -715,7 +506,7 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic } @Override - public void onTick(long timer, boolean isServerSide) { + public void onTick(long tick, boolean isServerSide) { if (!tickCovers()) { return; } @@ -723,24 +514,94 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic @Override public void onPostTick(long tick, boolean isServerSide) { - if (isServerSide) { - if (tick % 600 == 5) { - clearSpecialLists(); - // Recheck the structure every 30 seconds or so - if (!checkStructure(false)) checkStructure(true); + if (!isServerSide) { // client side + doActivitySound(getActivitySoundLoop()); + return; + } + + // server side + if (tick % 600 == 5) { + // Recheck the structure every 30 seconds or so + if (!checkStructure(false)) checkStructure(true); + } + if (checkStructure(false)) { + runMachine(tick); + pushItemOutputs(tick); + pushFluidOutputs(tick); + + } else { + stopMachine(false); + } + + } + + protected void pushItemOutputs(long tick) { + if (tick % AUTO_OUTPUT_FREQUENCY_TICK != 0) return; + final LinkedList<WeakReference<IMultiBlockPart>> registeredItemOutputs = registeredTickableParts + .get(MultiTileCasingPurpose.ItemOutput.ordinal()); + final Iterator<WeakReference<IMultiBlockPart>> itemOutputIterator = registeredItemOutputs.iterator(); + while (itemOutputIterator.hasNext()) { + final IMultiBlockPart part = (itemOutputIterator.next()).get(); + if (part == null) { + itemOutputIterator.remove(); + continue; } - if (checkStructure(false)) { - runMachine(tick); - } else { - stopMachine(false); + if (!part.shouldTick(mTickTimer)) { + itemOutputIterator.remove(); + continue; + } + + final IInventory facingInventory = part.getIInventoryAtSide(part.getFrontFacing()); + if (facingInventory == null) { + continue; + } + + moveMultipleItemStacks( + part, + facingInventory, + part.getFrontFacing(), + part.getBackFacing(), + null, + false, + (byte) 64, + (byte) 1, + (byte) 64, + (byte) 1, + part.getSizeInventory()); + for (int i = 0; i < part.getSizeInventory(); i++) { + if (part.getStackInSlot(i) != null && part.getStackInSlot(i).stackSize <= 0) { + part.setInventorySlotContents(i, null); + } + } + + } + } + + protected void pushFluidOutputs(long tick) { + if (tick % AUTO_OUTPUT_FREQUENCY_TICK != 0) return; + final LinkedList<WeakReference<IMultiBlockPart>> registeredFluidOutputs = registeredTickableParts + .get(MultiTileCasingPurpose.FluidOutput.ordinal()); + final Iterator<WeakReference<IMultiBlockPart>> fluidOutputIterator = registeredFluidOutputs.iterator(); + while (fluidOutputIterator.hasNext()) { + final IMultiBlockPart part = (fluidOutputIterator.next()).get(); + if (part == null) { + fluidOutputIterator.remove(); + continue; + } + if (!part.shouldTick(mTickTimer)) { + fluidOutputIterator.remove(); } - } else { - doActivitySound(getActivitySoundLoop()); } } + @Override + public void setCleanroom(boolean cleanroom) { + isCleanroom = cleanroom; + } + protected void clearSpecialLists() { upgradeCasings.clear(); + functionalCasings.clear(); } @Override @@ -773,47 +634,6 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic this.limits = mLimits; } - // IMachineProgress - @Override - public long getProgress() { - return progressTime; - } - - @Override - public long getMaxProgress() { - return maxProgressTime; - } - - @Override - public boolean increaseProgress(int aProgressAmountInTicks) { - return increaseProgressGetOverflow(aProgressAmountInTicks) != aProgressAmountInTicks; - } - - @Override - public FluidStack getDrainableFluid(ForgeDirection side) { - return getDrainableFluid(side, null); - } - - @Override - public FluidStack getDrainableFluid(ForgeDirection side, Fluid fluidToDrain) { - final IFluidTank tank = getFluidTankDrainable( - side, - fluidToDrain == null ? null : new FluidStack(fluidToDrain, 0)); - return tank == null ? null : tank.getFluid(); - } - - /** - * Increases the Progress, returns the overflown Progress. - */ - public int increaseProgressGetOverflow(int aProgress) { - return 0; - } - - @Override - public boolean hasThingsToDo() { - return getMaxProgress() > 0; - } - public boolean isSeparateInputs() { return separateInputs; } @@ -822,8 +642,6 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic separateInputs = aSeparateInputs; } - // End IMachineProgress - protected IAlignmentLimits getInitialAlignmentLimits() { return (d, r, f) -> !f.isVerticallyFliped(); } @@ -877,226 +695,7 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic } } - public <S> IStructureElement<S> addMultiTileCasing(String registryName, int meta, int modes) { - MultiTileEntityRegistry registry = MultiTileEntityRegistry.getRegistry(registryName); - int registryID = Block.getIdFromBlock(registry.mBlock); - return addMultiTileCasing(registryID, meta, modes); - } - - public <S> IStructureElement<S> addMultiTileCasing(int registryID, int meta, int modes) { - return new IStructureElement<S>() { - - private final short[] DEFAULT = new short[] { 255, 255, 255, 0 }; - private IIcon[] mIcons = null; - - @Override - public boolean check(S t, World world, int x, int y, int z) { - final TileEntity tileEntity = world.getTileEntity(x, y, z); - if (!(tileEntity instanceof MultiBlockPart part)) return false; - - if (registryID != part.getMultiTileEntityRegistryID() || meta != part.getMultiTileEntityID()) - return false; - - final IMultiBlockController tTarget = part.getTarget(false); - if (tTarget != null && tTarget != t) return false; - - part.setTarget((IMultiBlockController) t, modes); - - ((Controller<?>) t).registerSpecialCasings(part); - return true; - } - - @Override - public boolean spawnHint(S t, World world, int x, int y, int z, ItemStack trigger) { - if (mIcons == null) { - mIcons = new IIcon[6]; - Arrays.fill(mIcons, TextureSet.SET_NONE.mTextures[OrePrefixes.block.mTextureIndex].getIcon()); - // Arrays.fill(mIcons, getTexture(aCasing); - // for (byte i : ALL_VALID_SIDES) { - // mIcons[i] = aCasing.getIcon(i, aMeta); - // } - } - final short[] RGBA = DEFAULT; - StructureLibAPI.hintParticleTinted(world, x, y, z, mIcons, RGBA); - // StructureLibAPI.hintParticle(world, x, y, z, aCasing, aMeta); - return true; - } - - @Override - public boolean placeBlock(S t, World world, int x, int y, int z, ItemStack trigger) { - final MultiTileEntityRegistry tRegistry = MultiTileEntityRegistry.getRegistry(registryID); - final MultiTileEntityContainer tContainer = tRegistry - .getNewTileEntityContainer(world, x, y, z, meta, null); - if (tContainer == null) { - GT_FML_LOGGER.error("NULL CONTAINER"); - return false; - } - final IMultiTileEntity te = ((IMultiTileEntity) tContainer.mTileEntity); - if (!(te instanceof MultiBlockPart)) { - GT_FML_LOGGER.error("Not a multiblock part"); - return false; - } - if (world.setBlock(x, y, z, tContainer.mBlock, 15 - tContainer.mBlockMetaData, 2)) { - tContainer.setMultiTile(world, x, y, z); - ((MultiBlockPart) te).setTarget(Controller.this, modes); - - ((Controller<?>) t).registerSpecialCasings((MultiBlockPart) te); - } - - return false; - } - - public IIcon getTexture(OrePrefixes aBlock) { - return TextureSet.SET_NONE.mTextures[OrePrefixes.block.mTextureIndex].getIcon(); - } - }; - } - - protected <S> IStructureElementChain<S> addMotorCasings(int modes) { - return ofChain( - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, LV_Motor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, MV_Motor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, HV_Motor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, EV_Motor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, IV_Motor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, LuV_Motor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, ZPM_Motor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UV_Motor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UHV_Motor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UEV_Motor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UIV_Motor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UMV_Motor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UXV_Motor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, MAX_Motor.getId(), modes)); - } - - protected <S> IStructureElementChain<S> addPumpCasings(int modes) { - return ofChain( - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, LV_Pump.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, MV_Pump.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, HV_Pump.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, EV_Pump.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, IV_Pump.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, LuV_Pump.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, ZPM_Pump.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UV_Pump.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UHV_Pump.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UEV_Pump.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UIV_Pump.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UMV_Pump.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UXV_Pump.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, MAX_Pump.getId(), modes)); - } - - protected <S> IStructureElementChain<S> addPistonCasings(int modes) { - return ofChain( - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, LV_Piston.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, MV_Piston.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, HV_Piston.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, EV_Piston.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, IV_Piston.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, LuV_Piston.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, ZPM_Piston.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UV_Piston.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UHV_Piston.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UEV_Piston.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UIV_Piston.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UMV_Piston.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UXV_Piston.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, MAX_Piston.getId(), modes)); - } - - protected <S> IStructureElementChain<S> addConveyorCasings(int modes) { - return ofChain( - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, LV_Conveyor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, MV_Conveyor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, HV_Conveyor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, EV_Conveyor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, IV_Conveyor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, LuV_Conveyor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, ZPM_Conveyor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UV_Conveyor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UHV_Conveyor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UEV_Conveyor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UIV_Conveyor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UMV_Conveyor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UXV_Conveyor.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, MAX_Conveyor.getId(), modes)); - } - - protected <S> IStructureElementChain<S> addRobotArmCasings(int modes) { - return ofChain( - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, LV_RobotArm.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, MV_RobotArm.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, HV_RobotArm.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, EV_RobotArm.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, IV_RobotArm.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, LuV_RobotArm.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, ZPM_RobotArm.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UV_RobotArm.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UHV_RobotArm.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UEV_RobotArm.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UIV_RobotArm.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UMV_RobotArm.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UXV_RobotArm.getId(), modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, MAX_RobotArm.getId(), modes)); - } - - protected <S> IStructureElementChain<S> addSensorCasings(int Modes) { - return ofChain( - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, LV_Sensor.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, MV_Sensor.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, HV_Sensor.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, EV_Sensor.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, IV_Sensor.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, LuV_Sensor.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, ZPM_Sensor.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UV_Sensor.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UHV_Sensor.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UEV_Sensor.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UIV_Sensor.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UMV_Sensor.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UXV_Sensor.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, MAX_Sensor.getId(), Modes)); - } - - protected <S> IStructureElementChain<S> addEmitterCasings(int Modes) { - return ofChain( - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, LV_Emitter.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, MV_Emitter.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, HV_Emitter.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, EV_Emitter.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, IV_Emitter.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, LuV_Emitter.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, ZPM_Emitter.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UV_Emitter.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UHV_Emitter.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UEV_Emitter.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UIV_Emitter.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UMV_Emitter.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UXV_Emitter.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, MAX_Emitter.getId(), Modes)); - } - - protected <S> IStructureElementChain<S> addFieldGeneratorCasings(int Modes) { - return ofChain( - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, LV_FieldGenerator.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, MV_FieldGenerator.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, HV_FieldGenerator.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, EV_FieldGenerator.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, IV_FieldGenerator.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, LuV_FieldGenerator.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, ZPM_FieldGenerator.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UV_FieldGenerator.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UHV_FieldGenerator.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UEV_FieldGenerator.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UIV_FieldGenerator.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UMV_FieldGenerator.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, UXV_FieldGenerator.getId(), Modes), - addMultiTileCasing(COMPONENT_CASING_REGISTRY_NAME, MAX_FieldGenerator.getId(), Modes)); - } - - protected void registerSpecialCasings(MultiBlockPart part) { + public void registerSpecialCasings(MultiBlockPart part) { if (part instanceof UpgradeCasing) { upgradeCasings.add((UpgradeCasing) part); } @@ -1105,728 +704,177 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic } } - /** - * Fluid - MultiBlock related Fluid Tank behaviour. - */ - public void registerFluidInventory(String name, String id, int numberOfSlots, long capacity, - long capacityMultiplier, int type) { - if (name == null || name.equals("") - || id == null - || id.equals("") - || numberOfSlots < 0 - || capacity < 0 - || capacityMultiplier < 0) { - return; - } - FluidTankGT[] tanks = new FluidTankGT[numberOfSlots]; - for (int i = 0; i < numberOfSlots; i++) { - tanks[i] = new FluidTankGT(capacity).setCapacityMultiplier(capacityMultiplier); - } - registerFluidInventory(name, id, tanks, type); - } - - public void registerFluidInventory(String name, String id, FluidTankGT[] fluidInventory, int type) { - if (name == null || name.equals("") - || id == null - || id.equals("") - || fluidInventory == null - || fluidInventory.length == 0) { - return; - } - if (type == Inventory.INPUT || type == Inventory.BOTH) { - if (multiBlockInputTank.containsKey(id)) return; - multiBlockInputTank.put(id, fluidInventory); - multiBlockInputTankNames.put(id, name); - } - if (type == Inventory.OUTPUT || type == Inventory.BOTH) { - if (multiBlockOutputTank.containsKey(id)) return; - multiBlockOutputTank.put(id, fluidInventory); - multiBlockOutputTankNames.put(id, name); - } - } - - public void unregisterFluidInventory(String aName, String aID, int aType) { - if ((aType == Inventory.INPUT || aType == Inventory.BOTH) && multiBlockInputTank.containsKey(aID)) { - multiBlockInputTank.remove(aID, multiBlockInputTank.get(aID)); - multiBlockInputTankNames.remove(aID, aName); - } - if ((aType == Inventory.OUTPUT || aType == Inventory.BOTH) && multiBlockOutputTank.containsKey(aID)) { - multiBlockOutputTank.remove(aID, multiBlockOutputTank.get(aID)); - multiBlockOutputTankNames.remove(aID, aName); - } - } - - protected FluidTankGT[] getTanksForInput() { - List<FluidTankGT> tanks = new ArrayList<>(); - for (FluidTankGT[] inputTanks : multiBlockInputTank.values()) { - tanks.addAll(Arrays.asList(inputTanks)); - } - return tanks.toArray(new FluidTankGT[0]); - } - - protected FluidTankGT[] getTanksForOutput() { - List<FluidTankGT> tanks = new ArrayList<>(); - for (FluidTankGT[] outputTanks : multiBlockOutputTank.values()) { - tanks.addAll(Arrays.asList(outputTanks)); - } - return tanks.toArray(new FluidTankGT[0]); - } - - protected IFluidTank getFluidTankFillable(MultiBlockPart aPart, ForgeDirection side, FluidStack aFluidToFill) { - return getFluidTankFillable(side, aFluidToFill); - } - - protected IFluidTank getFluidTankDrainable(MultiBlockPart aPart, ForgeDirection side, FluidStack aFluidToDrain) { - return getFluidTankDrainable(side, aFluidToDrain); - } - - protected IFluidTank[] getFluidTanks(MultiBlockPart aPart, ForgeDirection side) { - return getFluidTanks(side); - } - - @Override - public int fill(MultiBlockPart aPart, ForgeDirection aDirection, FluidStack aFluid, boolean aDoFill) { - if (aFluid == null || aFluid.amount <= 0) return 0; - final IFluidTank tTank = getFluidTankFillable(aPart, aDirection, aFluid); - if (tTank == null) return 0; - final int rFilledAmount = tTank.fill(aFluid, aDoFill); - if (rFilledAmount > 0 && aDoFill) hasInventoryChanged = true; - return rFilledAmount; - } - - @Override - public FluidStack drain(MultiBlockPart aPart, ForgeDirection aDirection, FluidStack aFluid, boolean aDoDrain) { - if (aFluid == null || aFluid.amount <= 0) return null; - final IFluidTank tTank = getFluidTankDrainable(aPart, aDirection, aFluid); - if (tTank == null || tTank.getFluid() == null - || tTank.getFluidAmount() == 0 - || !tTank.getFluid() - .isFluidEqual(aFluid)) - return null; - final FluidStack rDrained = tTank.drain(aFluid.amount, aDoDrain); - if (rDrained != null && aDoDrain) markInventoryBeenModified(); - return rDrained; - } - - @Override - public FluidStack drain(MultiBlockPart aPart, ForgeDirection aDirection, int aAmountToDrain, boolean aDoDrain) { - if (aAmountToDrain <= 0) return null; - final IFluidTank tTank = getFluidTankDrainable(aPart, aDirection, null); - if (tTank == null || tTank.getFluid() == null || tTank.getFluidAmount() == 0) return null; - final FluidStack rDrained = tTank.drain(aAmountToDrain, aDoDrain); - if (rDrained != null && aDoDrain) markInventoryBeenModified(); - return rDrained; - } - - @Override - public boolean canFill(MultiBlockPart aPart, ForgeDirection aDirection, Fluid aFluid) { - if (aFluid == null) return false; - final IFluidTank tTank = getFluidTankFillable(aPart, aDirection, new FluidStack(aFluid, 0)); - return tTank != null && (tTank.getFluid() == null || tTank.getFluid() - .getFluid() == aFluid); - } - - @Override - public boolean canDrain(MultiBlockPart aPart, ForgeDirection aDirection, Fluid aFluid) { - if (aFluid == null) return false; - final IFluidTank tTank = getFluidTankDrainable(aPart, aDirection, new FluidStack(aFluid, 0)); - return tTank != null && (tTank.getFluid() != null && tTank.getFluid() - .getFluid() == aFluid); - } - - @Override - public FluidTankInfo[] getTankInfo(MultiBlockPart aPart, ForgeDirection aDirection) { - final IFluidTank[] tTanks = getFluidTanks(aPart, aDirection); - if (tTanks == null || tTanks.length <= 0) return GT_Values.emptyFluidTankInfo; - final FluidTankInfo[] rInfo = new FluidTankInfo[tTanks.length]; - for (int i = 0; i < tTanks.length; i++) rInfo[i] = new FluidTankInfo(tTanks[i]); - return rInfo; - } - - @Override - public IFluidTank[] getFluidTanksForGUI(MultiBlockPart aPart) { - final String lockedInventory = aPart.getLockedInventory(); - if (lockedInventory == null) { - if (aPart.modeSelected(MultiBlockPart.FLUID_IN)) return getTanksForInput(); - else if (aPart.modeSelected(MultiBlockPart.FLUID_OUT)) return getTanksForOutput(); - } else { - final Map<String, FluidTankGT[]> tankMap = getMultiBlockTankArray(aPart); - if (tankMap == null) return GT_Values.emptyFluidTank; - final FluidTankGT[] tanks = tankMap.get(lockedInventory); - return tanks != null ? tanks : GT_Values.emptyFluidTank; - } - return GT_Values.emptyFluidTank; - } - - // #region Energy - @Override - public PowerLogic getPowerLogic(IMultiBlockPart part, ForgeDirection side) { - if (!(this instanceof PowerLogicHost powerLogicHost)) { - return null; - } - - if (part.getFrontFacing() != side) { - return null; - } - - return powerLogicHost.getPowerLogic(side); - } - // #endregion Energy - - /** - * Item - MultiBlock related Item behaviour. - */ - @Override - public void registerInventory(String aName, String aID, int aInventorySize, int aType) { - registerInventory(aName, aID, new ItemStackHandler(aInventorySize), aType); - } - - public void registerInventory(String name, String id, IItemHandlerModifiable inventory, int type) { - if (name == null || name.equals("") || id == null || id.equals("") || inventory == null) { - return; - } - if (type == Inventory.INPUT || type == Inventory.BOTH) { - if (multiBlockInputInventory.containsKey(id)) return; - multiBlockInputInventory.put(id, inventory); - multiBlockInputInventoryNames.put(id, name); - } - if (type == Inventory.OUTPUT || type == Inventory.BOTH) { - if (multiBlockOutputInventory.containsKey(id)) return; - multiBlockOutputInventory.put(id, inventory); - multiBlockOutputInventoryNames.put(id, name); - } - } - - @Override - public void unregisterInventory(String aName, String aID, int aType) { - if ((aType == Inventory.INPUT || aType == Inventory.BOTH) && multiBlockInputInventory.containsKey(aID)) { - multiBlockInputInventory.remove(aID, multiBlockInputInventory.get(aID)); - multiBlockInputInventoryNames.remove(aID, aName); - } - if ((aType == Inventory.OUTPUT || aType == Inventory.BOTH) && multiBlockOutputInventory.containsKey(aID)) { - multiBlockOutputInventory.remove(aID, multiBlockOutputInventory.get(aID)); - multiBlockOutputInventoryNames.remove(aID, aName); - } - } - - @Override - public void changeInventoryName(String aName, String aID, int aType) { - if ((aType == Inventory.INPUT || aType == Inventory.BOTH) && multiBlockInputInventoryNames.containsKey(aID)) { - multiBlockInputInventoryNames.put(aID, aName); - } - if ((aType == Inventory.OUTPUT || aType == Inventory.BOTH) && multiBlockOutputInventoryNames.containsKey(aID)) { - multiBlockOutputInventoryNames.put(aID, aName); - } - } - - @Override - public boolean hasInventoryBeenModified(MultiBlockPart aPart) { - if (aPart.modeSelected(MultiBlockPart.ITEM_IN)) return hasInventoryBeenModified(); - else if (aPart.modeSelected(MultiBlockPart.ITEM_OUT)) return hasOutputInventoryBeenModified(); - - return false; - } + // #region Fluid - MultiBlock related Fluid Tank behaviour. @Override - public boolean isValidSlot(MultiBlockPart aPart, int aIndex) { - return false; + @Nullable + public FluidInventoryLogic getFluidLogic(@Nonnull ForgeDirection side, @Nonnull InventoryType type) { + if (side == facing) return null; + return switch (type) { + case Input -> controllerFluidInput.getAllInventoryLogics(); + case Output -> controllerFluidOutput.getAllInventoryLogics(); + default -> null; + }; } - @Override - public void enableWorking() { - super.enableWorking(); - if (!structureOkay) { - checkStructure(true); - } + @Nullable + public FluidInventoryLogic getFluidLogic(@Nonnull InventoryType type, @Nullable UUID id) { + return switch (type) { + case Input -> controllerFluidInput.getInventoryLogic(id); + case Output -> controllerFluidOutput.getInventoryLogic(id); + default -> null; + }; } @Override - public IItemHandlerModifiable getInventoryForGUI(MultiBlockPart aPart) { - if (isServerSide()) { - for (UpgradeCasing tPart : upgradeCasings) { - if (!(tPart instanceof Inventory)) continue; - tPart.issueClientUpdate(); + @Nonnull + public UUID registerFluidInventory(int tanks, long capacity, int tier, @Nonnull InventoryType type, + boolean isUpgradeInventory) { + return switch (type) { + case Input -> controllerFluidInput + .addInventory(new FluidInventoryLogic(tanks, capacity, tier, isUpgradeInventory)); + case Output -> controllerFluidOutput + .addInventory(new FluidInventoryLogic(tanks, capacity, tier, isUpgradeInventory)); + case Both -> { + UUID id = controllerFluidInput + .addInventory(new FluidInventoryLogic(tanks, capacity, tier, isUpgradeInventory)); + controllerFluidOutput + .addInventory(id, new FluidInventoryLogic(tanks, capacity, tier, isUpgradeInventory)); + yield id; } - } - final Map<String, IItemHandlerModifiable> multiBlockInventory = getMultiBlockInventory(aPart); - if (multiBlockInventory == null) return null; - - final String lockedInventory = aPart.getLockedInventory(); - if (lockedInventory == null) { - return new ListItemHandler(multiBlockInventory.values()); - } else { - final IItemHandlerModifiable inv = multiBlockInventory.get(lockedInventory); - return inv; - } - } - - @Override - public boolean addStackToSlot(MultiBlockPart aPart, int aIndex, ItemStack aStack) { - return false; + }; } @Override - public boolean addStackToSlot(MultiBlockPart aPart, int aIndex, ItemStack aStack, int aAmount) { - return false; - } - - protected Map<String, FluidTankGT[]> getMultiBlockTankArray(MultiBlockPart aPart) { - if (aPart.modeSelected(MultiBlockPart.FLUID_IN)) return multiBlockInputTank; - else if (aPart.modeSelected(MultiBlockPart.FLUID_OUT)) return multiBlockOutputTank; - return null; - } - - protected Map<String, String> getMultiBlockTankArrayNames(MultiBlockPart aPart) { - if (aPart.modeSelected(MultiBlockPart.FLUID_IN)) return multiBlockInputTankNames; - else if (aPart.modeSelected(MultiBlockPart.FLUID_OUT)) return multiBlockOutputTankNames; - return null; - } - - protected Map<String, IItemHandlerModifiable> getMultiBlockInventory(MultiBlockPart aPart) { - if (aPart.modeSelected(MultiBlockPart.ITEM_IN)) return multiBlockInputInventory; - else if (aPart.modeSelected(MultiBlockPart.ITEM_OUT)) return multiBlockOutputInventory; - return null; - } - - protected Map<String, String> getMultiBlockInventoryNames(MultiBlockPart aPart) { - if (aPart.modeSelected(MultiBlockPart.ITEM_IN)) return multiBlockInputInventoryNames; - else if (aPart.modeSelected(MultiBlockPart.ITEM_OUT)) return multiBlockOutputInventoryNames; - return null; - } - - protected Pair<IItemHandlerModifiable, Integer> getInventory(MultiBlockPart aPart, int aSlot) { - final Map<String, IItemHandlerModifiable> multiBlockInventory = getMultiBlockInventory(aPart); - if (multiBlockInventory == null) return null; - - final String invName = aPart.getLockedInventory(); - if (invName != null && !invName.isEmpty()) return new ImmutablePair<>(multiBlockInventory.get(invName), aSlot); - - int start = 0; - for (IItemHandlerModifiable inv : multiBlockInventory.values()) { - if (aSlot >= start && aSlot < start + inv.getSlots()) { - return new ImmutablePair<>(inv, aSlot - start); + @Nonnull + public FluidInventoryLogic unregisterFluidInventory(@Nonnull UUID id, @Nonnull InventoryType type) { + return switch (type) { + case Input -> controllerFluidInput.removeInventory(id); + case Output -> controllerFluidOutput.removeInventory(id); + case Both -> { + FluidInventoryLogic input = controllerFluidInput.removeInventory(id); + FluidInventoryLogic output = controllerFluidOutput.removeInventory(id); + yield new FluidInventoryLogic( + Arrays.asList(input, output) + .stream() + .map(inv -> inv.getInventory()) + .collect(Collectors.toList())); } - start += inv.getSlots(); - } - return null; + }; } @Override - public int[] getAccessibleSlotsFromSide(MultiBlockPart aPart, ForgeDirection side) { - final TIntList tList = new TIntArrayList(); - final Map<String, IItemHandlerModifiable> multiBlockInventory = getMultiBlockInventory(aPart); - if (multiBlockInventory == null) return tList.toArray(); - - final String lockedInventory = aPart.getLockedInventory(); - // Item in --> input inv - // Item out --> output inv - - int start = 0; - if (lockedInventory == null) { - for (IItemHandlerModifiable inv : multiBlockInventory.values()) { - for (int i = start; i < inv.getSlots() + start; i++) tList.add(i); - start += inv.getSlots(); - } - } else { - final IItemHandlerModifiable inv = multiBlockInventory.get(lockedInventory); - final int len = inv != null ? inv.getSlots() : 0; - for (int i = 0; i < len; i++) tList.add(i); + public void changeFluidInventoryDisplayName(@Nullable UUID id, @Nullable String displayName, + @Nonnull InventoryType type) { + switch (type) { + case Input: + controllerFluidInput.setInventoryDisplayName(id, displayName); + break; + case Output: + controllerFluidOutput.setInventoryDisplayName(id, displayName); + break; + case Both: + controllerFluidInput.setInventoryDisplayName(id, displayName); + controllerFluidOutput.setInventoryDisplayName(id, displayName); + break; } - return tList.toArray(); } - @Override - public boolean canInsertItem(MultiBlockPart aPart, int aSlot, ItemStack aStack, ForgeDirection side) { - final Pair<IItemHandlerModifiable, Integer> tInv = getInventory(aPart, aSlot); - if (tInv == null) return false; - - final int tSlot = tInv.getRight(); - final IItemHandlerModifiable inv = tInv.getLeft(); - - return inv.getStackInSlot(tSlot) == null || GT_Utility.areStacksEqual(aStack, inv.getStackInSlot(tSlot)); // && - // allowPutStack(getBaseMetaTileEntity(), - // aIndex, - // (byte) - // aSide, - // aStack) - } + // #endregion Fluid - @Override - public boolean canExtractItem(MultiBlockPart aPart, int aSlot, ItemStack aStack, ForgeDirection side) { - final Pair<IItemHandlerModifiable, Integer> tInv = getInventory(aPart, aSlot); - if (tInv == null) return false; - - final int tSlot = tInv.getRight(); - final IItemHandlerModifiable inv = tInv.getLeft(); - - return inv.getStackInSlot(tSlot) != null; // && allowPullStack(getBaseMetaTileEntity(), aIndex, (byte) aSide, - // aStack); - } + // #region Item - MultiBlock related Item behaviour. @Override - public int getSizeInventory(MultiBlockPart aPart) { - final Map<String, IItemHandlerModifiable> multiBlockInventory = getMultiBlockInventory(aPart); - if (multiBlockInventory == null) return 0; - - final String lockedInventory = aPart.getLockedInventory(); - if (lockedInventory == null) { - int len = 0; - for (IItemHandlerModifiable inv : multiBlockInventory.values()) len += inv.getSlots(); - return len; - } else { - final IItemHandlerModifiable inv = multiBlockInventory.get(lockedInventory); - return inv != null ? inv.getSlots() : 0; - } + @Nullable + public ItemInventoryLogic getItemLogic(@Nonnull ForgeDirection side, @Nonnull InventoryType type) { + if (side == facing) return null; + return switch (type) { + case Input -> controllerItemInput.getAllInventoryLogics(); + case Output -> controllerItemOutput.getAllInventoryLogics(); + default -> null; + }; } @Override - public ItemStack getStackInSlot(MultiBlockPart aPart, int aSlot) { - final Pair<IItemHandlerModifiable, Integer> tInv = getInventory(aPart, aSlot); - if (tInv == null) return null; - - final int tSlot = tInv.getRight(); - final IItemHandlerModifiable inv = tInv.getLeft(); - if (inv == null) return null; - - return inv.getStackInSlot(tSlot); + @Nullable + public ItemInventoryLogic getItemLogic(@Nonnull InventoryType type, @Nullable UUID id) { + return switch (type) { + case Input -> controllerItemInput.getInventoryLogic(id); + case Output -> controllerItemOutput.getInventoryLogic(id); + default -> null; + }; } @Override - public ItemStack decrStackSize(MultiBlockPart aPart, int aSlot, int aDecrement) { - final ItemStack tStack = getStackInSlot(aPart, aSlot); - ItemStack rStack = GT_Utility.copyOrNull(tStack); - if (tStack != null) { - if (tStack.stackSize <= aDecrement) { - setInventorySlotContents(aPart, aSlot, null); - } else { - rStack = tStack.splitStack(aDecrement); - if (tStack.stackSize == 0) setInventorySlotContents(aPart, aSlot, null); + @Nonnull + public UUID registerItemInventory(int slots, int tier, @Nonnull InventoryType type, boolean isUpgradeInventory) { + return switch (type) { + case Input -> controllerItemInput.addInventory(new ItemInventoryLogic(slots, tier, isUpgradeInventory)); + case Output -> controllerItemOutput.addInventory(new ItemInventoryLogic(slots, tier, isUpgradeInventory)); + case Both -> { + UUID id = controllerItemInput.addInventory(new ItemInventoryLogic(slots, tier, isUpgradeInventory)); + controllerItemOutput.addInventory(id, new ItemInventoryLogic(slots, tier, isUpgradeInventory)); + yield id; } - } - return rStack; - } - - @Override - public ItemStack getStackInSlotOnClosing(MultiBlockPart aPart, int aSlot) { - final Pair<IItemHandlerModifiable, Integer> tInv = getInventory(aPart, aSlot); - if (tInv == null) return null; - - final IItemHandlerModifiable inv = tInv.getLeft(); - final int tSlot = tInv.getRight(); - - final ItemStack rStack = inv.getStackInSlot(tSlot); - inv.setStackInSlot(tSlot, null); - return rStack; - } - - @Override - public void setInventorySlotContents(MultiBlockPart aPart, int aSlot, ItemStack aStack) { - final Pair<IItemHandlerModifiable, Integer> tInv = getInventory(aPart, aSlot); - if (tInv == null) return; - - final IItemHandlerModifiable inv = tInv.getLeft(); - final int tSlot = tInv.getRight(); - inv.setStackInSlot(tSlot, aStack); - } - - @Override - public List<String> getInventoryNames(MultiBlockPart aPart) { - final List<String> inventoryNames = new ArrayList<>(); - inventoryNames.add(ALL_INVENTORIES_NAME); - inventoryNames.addAll(getMultiBlockInventoryNames(aPart).values()); - return inventoryNames; - } - - @Override - public List<String> getInventoryIDs(MultiBlockPart aPart) { - final List<String> tInventoryIDs = new ArrayList<>(); - tInventoryIDs.add(ALL_INVENTORIES_NAME); - tInventoryIDs.addAll(getMultiBlockInventory(aPart).keySet()); - return tInventoryIDs; - } - - @Override - public String getInventoryName(MultiBlockPart aPart) { - final StringBuilder str = new StringBuilder(); - str.append(getInventoryName()); - if (aPart.modeSelected(MultiBlockPart.ITEM_IN)) { - str.append(" Input"); - } else if (aPart.modeSelected(MultiBlockPart.ITEM_OUT)) { - str.append(" Output"); - String a; - } else { - str.append(" Unknown"); - } - final String lockedInventory = aPart.getLockedInventory(); - if (lockedInventory != null && !lockedInventory.equals("")) { - str.append(" [Locked: ") - .append(lockedInventory) - .append("]"); - } - - return str.toString(); - } - - @Override - public List<String> getTankArrayNames(MultiBlockPart aPart) { - final List<String> inventoryNames = new ArrayList<>(); - inventoryNames.add(ALL_INVENTORIES_NAME); - inventoryNames.addAll(getMultiBlockTankArrayNames(aPart).values()); - return inventoryNames; - } - - @Override - public List<String> getTankArrayIDs(MultiBlockPart aPart) { - final List<String> inventoryIDs = new ArrayList<>(); - inventoryIDs.add(ALL_INVENTORIES_NAME); - inventoryIDs.addAll(getMultiBlockTankArray(aPart).keySet()); - return inventoryIDs; - } - - @Override - public boolean hasCustomInventoryName(MultiBlockPart aPart) { - return hasCustomInventoryName(); - } - - @Override - public int getInventoryStackLimit(MultiBlockPart aPart) { - return getInventoryStackLimit(); - } - - @Override - public void markDirty(MultiBlockPart aPart) { - markDirty(); - if (aPart.modeSelected(MultiBlockPart.ITEM_OUT)) markOutputInventoryBeenModified(); - else markInventoryBeenModified(); - } - - @Override - public boolean isUseableByPlayer(MultiBlockPart aPart, EntityPlayer aPlayer) { - return isUseableByPlayer(aPlayer); - } - - @Override - public void openInventory(MultiBlockPart aPart) { - // TODO: MultiInventory - consider the part's inventory - openInventory(); - } - - @Override - public void closeInventory(MultiBlockPart aPart) { - // TODO: MultiInventory - consider the part's inventory - closeInventory(); - } - - @Override - public boolean isItemValidForSlot(MultiBlockPart aPart, int aSlot, ItemStack aStack) { - return isItemValidForSlot(aSlot, aStack); - } - - /* - * Helper Methods For Recipe checking - */ - - @Override - protected ItemStack[] getInputItems() { - return getInventoriesForInput().getStacks() - .toArray(new ItemStack[0]); - } - - protected ItemStack[] getOutputItems() { - return getInventoriesForOutput().getStacks() - .toArray(new ItemStack[0]); - } - - protected Iterable<Pair<ItemStack[], String>> getItemInputsForEachInventory() { - return multiBlockInputInventory.entrySet() - .stream() - .map( - (entry) -> Pair.of( - entry.getValue() - .getStacks() - .toArray(new ItemStack[0]), - entry.getKey())) - .collect(Collectors.toList()); - } - - protected ItemStack[] getItemInputsForInventory(String id) { - IItemHandlerModifiable inventory = multiBlockInputInventory.get(id); - if (inventory != null) { - return inventory.getStacks() - .toArray(new ItemStack[0]); - } - return null; + }; } @Override - protected FluidStack[] getInputFluids() { - List<FluidStack> fluidStacks = new ArrayList<>(); - for (FluidTankGT[] inputTanks : multiBlockInputTank.values()) { - for (FluidTankGT inputTank : inputTanks) { - FluidStack fluidStack = inputTank.get(); - if (fluidStack != null) { - fluidStacks.add(fluidStack); - } + public ItemInventoryLogic unregisterItemInventory(@Nonnull UUID id, @Nonnull InventoryType type) { + return switch (type) { + case Input -> controllerItemInput.removeInventory(id); + case Output -> controllerItemOutput.removeInventory(id); + case Both -> { + ItemInventoryLogic input = controllerItemInput.removeInventory(id); + ItemInventoryLogic output = controllerItemOutput.removeInventory(id); + yield new ItemInventoryLogic( + Arrays.asList(input, output) + .stream() + .map(inv -> inv.getInventory()) + .collect(Collectors.toList())); } - } - return fluidStacks.toArray(new FluidStack[0]); - } - - protected FluidStack[] getOutputFluids() { - List<FluidStack> fluidStacks = new ArrayList<>(); - for (FluidTankGT[] inputTanks : multiBlockInputTank.values()) { - for (FluidTankGT inputTank : inputTanks) { - FluidStack fluidStack = inputTank.getFluid(); - if (fluidStack != null) { - fluidStacks.add(fluidStack); - } - } - } - return fluidStacks.toArray(new FluidStack[0]); - } - - protected Iterable<Pair<FluidStack[], String>> getFluidInputsForEachTankArray() { - return multiBlockInputTank.entrySet() - .stream() - .map((entry) -> Pair.of(FluidTankGT.getFluidsFromTanks(entry.getValue()), entry.getKey())) - .collect(Collectors.toList()); - } - - protected FluidStack[] getFluidInputsForTankArray(String id) { - return FluidTankGT.getFluidsFromTanks(multiBlockInputTank.get(id)); - } - - protected void setItemOutputs(String inventory, ItemStack... itemOutputs) { - itemsToOutput = itemOutputs; - inventoryName = inventory; - } - - @Override - protected void setItemOutputs(ItemStack... outputs) { - super.setItemOutputs(outputs); - inventoryName = null; + }; } @Override - protected void outputItems() { - if (itemsToOutput == null) { - return; - } - - IItemHandlerModifiable inv; - if (inventoryName != null) { - inv = multiBlockOutputInventory.getOrDefault(inventoryName, getInventoriesForOutput()); - } else { - inv = getInventoriesForOutput(); + public void changeItemInventoryDisplayName(@Nullable UUID id, @Nullable String displayName, + @Nonnull InventoryType type) { + switch (type) { + case Input: + controllerItemInput.setInventoryDisplayName(id, displayName); + break; + case Output: + controllerItemOutput.setInventoryDisplayName(id, displayName); + break; + case Both: + controllerItemInput.setInventoryDisplayName(id, displayName); + controllerItemOutput.setInventoryDisplayName(id, displayName); + break; } - for (ItemStack item : itemsToOutput) { - int index = 0; - while (item != null && item.stackSize > 0 && index < inv.getSlots()) { - item = inv.insertItem(index++, item.copy(), false); - } - } - itemsToOutput = null; } - protected void setFluidOutputs(String tank, FluidStack... fluidOuputs) { - fluidsToOutput = fluidOuputs; - tankName = tank; - } + // #endregion Item - @Override - protected void setFluidOutputs(FluidStack... outputs) { - super.setFluidOutputs(outputs); - tankName = null; - } + // #region Energy + @Nonnull @Override - protected void outputFluids() { - if (fluidsToOutput == null) { - return; - } - - List<FluidTankGT> tanks = Arrays.asList(outputTanks); - for (FluidStack fluid : fluidsToOutput) { - int index = 0; - while (fluid != null && fluid.amount > 0 && index < tanks.size()) { - int filled = tanks.get(index++) - .fill(fluid, true); - fluid.amount -= filled; - } - } + public PowerLogic getPowerLogic() { + return getPowerLogic(ForgeDirection.UNKNOWN); } - @Override - protected void updateSlots() { - IItemHandlerModifiable inv = getInventoriesForInput(); - for (int i = 0; i < inv.getSlots(); i++) { - if (inv.getStackInSlot(i) != null && inv.getStackInSlot(i).stackSize <= 0) { - inv.setStackInSlot(i, null); - } - } - - for (FluidTankGT inputTank : getTanksForInput()) { - if (inputTank == null) { - continue; - } - - if (inputTank.get() != null && inputTank.get().amount <= 0) { - inputTank.setEmpty(); - continue; - } - - FluidStack afterRecipe = inputTank.get(); - FluidStack beforeRecipe = inputTank.get(Integer.MAX_VALUE); - if (afterRecipe == null || beforeRecipe == null) { - continue; - } - int difference = beforeRecipe.amount - afterRecipe.amount; - inputTank.remove(difference); - } - } + // #endregion Energy @Override - protected boolean checkRecipe() { - if (!(this instanceof ProcessingLogicHost)) { - return false; - } - ProcessingLogic logic = ((ProcessingLogicHost) this).getProcessingLogic(); - logic.clear(); - CheckRecipeResult result = CheckRecipeResultRegistry.NO_RECIPE; - if (isSeparateInputs()) { - // TODO: Add separation with fluids - for (Pair<ItemStack[], String> inventory : getItemInputsForEachInventory()) { - IItemHandlerModifiable outputInventory = multiBlockOutputInventory - .getOrDefault(inventory.getLeft(), null); - result = logic.setInputItems(inventory.getLeft()) - .setCurrentOutputItems(getOutputItems()) - .process(); - if (result.wasSuccessful()) { - inventoryName = inventory.getRight(); - break; - } - logic.clear(); - } - } else { - result = logic.setInputItems(getInputItems()) - .setCurrentOutputItems(getOutputItems()) - .setInputFluids(getInputFluids()) - .setCurrentOutputFluids(getOutputFluids()) - .process(); - } - setDuration(logic.getDuration()); - setEut(logic.getCalculatedEut()); - setItemOutputs(logic.getOutputItems()); - setFluidOutputs(logic.getOutputFluids()); - return result.wasSuccessful(); - } - - public IItemHandlerModifiable getOutputInventory() { - return outputInventory; - } - - public FluidTankGT[] getOutputTanks() { - return outputTanks; + protected void updateSlots() { + controllerItemInput.getAllInventoryLogics() + .update(shouldSort); + controllerItemOutput.getAllInventoryLogics() + .update(shouldSort); + controllerFluidInput.getAllInventoryLogics() + .update(); + controllerFluidOutput.getAllInventoryLogics() + .update(); } /* @@ -1838,24 +886,6 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic } @Override - public ModularWindow createWindow(UIBuildContext buildContext) { - System.out.println("MultiBlockController::createWindow"); - if (!useModularUI()) return null; - - buildContext.setValidator(getValidator()); - final ModularWindow.Builder builder = ModularWindow.builder(getGUIWidth(), getGUIHeight()); - builder.setBackground(getGUITextureSet().getMainBackground()); - builder.setGuiTint(getGUIColorization()); - if (doesBindPlayerInventory()) { - bindPlayerInventoryUI(builder, buildContext); - } - addUIWidgets(builder, buildContext); - addTitleToUI(builder); - addCoverTabs(builder, buildContext); - return builder.build(); - } - - @Override public boolean hasGui(ForgeDirection side) { return true; } @@ -1866,222 +896,6 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic } @Override - public int getGUIHeight() { - return 192; - } - - protected Widget getGregTechLogo() { - return new DrawableWidget().setDrawable(getGUITextureSet().getGregTechLogo()) - .setSize(17, 17); - } - - @Override - public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { - if (isServerSide()) { - for (UpgradeCasing tPart : upgradeCasings) { - if (!(tPart instanceof Inventory)) continue; - tPart.issueClientUpdate(); - } - } - int page = 0; - TabContainer tabs = new TabContainer().setButtonSize(20, 24); - tabs.addTabButton( - new TabButton(page++) - .setBackground( - false, - ModularUITextures.VANILLA_TAB_TOP_START.getSubArea(0, 0, 1f, 0.5f), - new ItemDrawable(getStackForm(1)).withFixedSize(16, 16) - .withOffset(2, 4)) - .setBackground( - true, - ModularUITextures.VANILLA_TAB_TOP_START.getSubArea(0, 0.5f, 1f, 1f), - new ItemDrawable(getStackForm(1)).withFixedSize(16, 16) - .withOffset(2, 4)) - .addTooltip(getLocalName()) - .setPos(20 * (page - 1), -20)) - .addPage(createMainPage(builder).setSize(getGUIWidth(), getGUIHeight())); - if (hasItemInput()) { - tabs.addTabButton( - new TabButton(page++) - .setBackground( - false, - ModularUITextures.VANILLA_TAB_TOP_MIDDLE.getSubArea(0, 0, 1f, 0.5f), - GT_UITextures.PICTURE_ITEM_IN.withFixedSize(16, 16) - .withOffset(2, 4)) - .setBackground( - true, - ModularUITextures.VANILLA_TAB_TOP_MIDDLE.getSubArea(0, 0.5f, 1f, 1f), - GT_UITextures.PICTURE_ITEM_IN.withFixedSize(16, 16) - .withOffset(2, 4)) - .setPos(20 * (page - 1), -20)) - .addPage( - new MultiChildWidget().addChild(getItemInventoryInputGUI()) - .addChild(getGregTechLogo().setPos(147, 86)) - .setSize(getGUIWidth(), getGUIHeight())); - } - - if (hasItemOutput()) { - tabs.addTabButton( - new TabButton(page++) - .setBackground( - false, - ModularUITextures.VANILLA_TAB_TOP_MIDDLE.getSubArea(0, 0, 1f, 0.5f), - GT_UITextures.PICTURE_ITEM_OUT.withFixedSize(16, 16) - .withOffset(2, 4)) - .setBackground( - true, - ModularUITextures.VANILLA_TAB_TOP_MIDDLE.getSubArea(0, 0.5f, 1f, 1f), - GT_UITextures.PICTURE_ITEM_OUT.withFixedSize(16, 16) - .withOffset(2, 4)) - .setPos(20 * (page - 1), -20)) - .addPage( - new MultiChildWidget().addChild(getItemInventoryOutputGUI()) - .addChild(getGregTechLogo().setPos(147, 86)) - .setSize(getGUIWidth(), getGUIHeight())); - } - - if (hasFluidInput()) { - tabs.addTabButton( - new TabButton(page++) - .setBackground( - false, - ModularUITextures.VANILLA_TAB_TOP_MIDDLE.getSubArea(0, 0, 1f, 0.5f), - GT_UITextures.PICTURE_FLUID_IN.withFixedSize(16, 16) - .withOffset(2, 4)) - .setBackground( - true, - ModularUITextures.VANILLA_TAB_TOP_MIDDLE.getSubArea(0, 0.5f, 1f, 1f), - GT_UITextures.PICTURE_FLUID_IN.withFixedSize(16, 16) - .withOffset(2, 4)) - .setPos(20 * (page - 1), -20)) - .addPage( - new MultiChildWidget().addChild(getFluidInventoryInputGUI()) - .addChild(getGregTechLogo().setPos(147, 86)) - .setSize(getGUIWidth(), getGUIHeight())); - } - - if (hasFluidOutput()) { - tabs.addTabButton( - new TabButton(page++) - .setBackground( - false, - ModularUITextures.VANILLA_TAB_TOP_MIDDLE.getSubArea(0, 0, 1f, 0.5f), - GT_UITextures.PICTURE_FLUID_OUT.withFixedSize(16, 16) - .withOffset(2, 4)) - .setBackground( - true, - ModularUITextures.VANILLA_TAB_TOP_MIDDLE.getSubArea(0, 0.5f, 1f, 1f), - GT_UITextures.PICTURE_FLUID_OUT.withFixedSize(16, 16) - .withOffset(2, 4)) - .setPos(20 * (page - 1), -20)) - .addPage( - new MultiChildWidget().addChild(getFluidInventoryOutputGUI()) - .addChild(getGregTechLogo().setPos(147, 86)) - .setSize(getGUIWidth(), getGUIHeight())); - } - builder.widget(tabs); - } - - protected MultiChildWidget createMainPage(IWidgetBuilder<?> builder) { - MultiChildWidget page = new MultiChildWidget(); - page.addChild( - new DrawableWidget().setDrawable(GT_UITextures.PICTURE_SCREEN_BLACK) - .setPos(7, 4) - .setSize(160, 75)) - .addChild(createButtons(builder)); - return page; - } - - protected MultiChildWidget createButtons(IWidgetBuilder<?> builder) { - MultiChildWidget buttons = new MultiChildWidget(); - buttons.setSize(16, 167) - .setPos(7, 86); - buttons.addChild(createPowerSwitchButton(builder)) - .addChild(createVoidExcessButton(builder)) - .addChild(createInputSeparationButton(builder)) - .addChild(createBatchModeButton(builder)) - .addChild(createLockToSingleRecipeButton(builder)); - - return buttons; - } - - protected Widget getItemInventoryInputGUI() { - final IItemHandlerModifiable inv = getInventoriesForInput(); - final Scrollable scrollable = new Scrollable().setVerticalScroll(); - for (int rows = 0; rows * 4 < Math.min(inv.getSlots(), 128); rows++) { - final int columnsToMake = Math.min(Math.min(inv.getSlots(), 128) - rows * 4, 4); - for (int column = 0; column < columnsToMake; column++) { - scrollable.widget( - new SlotWidget(inv, rows * 4 + column).setPos(column * 18, rows * 18) - .setSize(18, 18)); - } - } - return scrollable.setSize(18 * 4 + 4, 18 * 5) - .setPos(52, 7); - } - - protected Widget getItemInventoryOutputGUI() { - final IItemHandlerModifiable inv = getInventoriesForOutput(); - final Scrollable scrollable = new Scrollable().setVerticalScroll(); - for (int rows = 0; rows * 4 < Math.min(inv.getSlots(), 128); rows++) { - final int columnsToMake = Math.min(Math.min(inv.getSlots(), 128) - rows * 4, 4); - for (int column = 0; column < columnsToMake; column++) { - scrollable.widget( - new SlotWidget(inv, rows * 4 + column).setPos(column * 18, rows * 18) - .setSize(18, 18)); - } - } - return scrollable.setSize(18 * 4 + 4, 18 * 5) - .setPos(52, 7); - } - - protected IItemHandlerModifiable getInventoriesForInput() { - return new ListItemHandler(multiBlockInputInventory.values()); - } - - protected IItemHandlerModifiable getInventoriesForOutput() { - return new ListItemHandler(multiBlockOutputInventory.values()); - } - - protected Widget getFluidInventoryInputGUI() { - final IFluidTank[] tanks = getTanksForInput(); - final Scrollable scrollable = new Scrollable().setVerticalScroll(); - for (int rows = 0; rows * 4 < tanks.length; rows++) { - final int columnsToMake = Math.min(tanks.length - rows * 4, 4); - for (int column = 0; column < columnsToMake; column++) { - final FluidSlotWidget fluidSlot = new FluidSlotWidget(tanks[rows * 4 + column]); - scrollable.widget( - fluidSlot.setPos(column * 18, rows * 18) - .setSize(18, 18)); - } - } - return scrollable.setSize(18 * 4 + 4, 18 * 5) - .setPos(52, 7); - } - - protected Widget getFluidInventoryOutputGUI() { - final IFluidTank[] tanks = getTanksForOutput(); - final Scrollable scrollable = new Scrollable().setVerticalScroll(); - for (int rows = 0; rows * 4 < tanks.length; rows++) { - final int columnsToMake = Math.min(tanks.length - rows * 4, 4); - for (int column = 0; column < columnsToMake; column++) { - final FluidSlotWidget fluidSlot = new FluidSlotWidget(tanks[rows * 4 + column]); - fluidSlot.setInteraction(true, false); - scrollable.widget( - fluidSlot.setPos(column * 18, rows * 18) - .setSize(18, 18)); - } - } - return scrollable.setSize(18 * 4 + 4, 18 * 5) - .setPos(52, 7); - } - - @Override - public Pos2d getPowerSwitchButtonPos() { - return new Pos2d(144, 0); - } - - @Override public boolean supportsVoidProtection() { return true; } @@ -2097,23 +911,6 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic } @Override - public List<ItemStack> getItemOutputSlots(ItemStack[] toOutput) { - List<ItemStack> ret = new ArrayList<>(); - IItemHandler inv = getOutputInventory(); - if (inv != null && inv.getSlots() > 0) { - for (int i = 0; i < inv.getSlots(); i++) { - ret.add(inv.getStackInSlot(i)); - } - } - return ret; - } - - @Override - public List<? extends IFluidStore> getFluidOutputSlots(FluidStack[] toOutput) { - return Arrays.asList(getOutputTanks()); - } - - @Override public boolean canDumpItemToME() { return false; } @@ -2124,31 +921,21 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic } @Override - public Pos2d getVoidingModeButtonPos() { - return new Pos2d(54, 0); - } - - @Override public boolean supportsInputSeparation() { return true; } @Override - public boolean isInputSeparationEnabled() { + public boolean isInputSeparated() { return separateInputs; } @Override - public void setInputSeparation(boolean enabled) { + public void setInputSeparation(Boolean enabled) { this.separateInputs = enabled; } @Override - public Pos2d getInputSeparationButtonPos() { - return new Pos2d(36, 0); - } - - @Override public boolean supportsBatchMode() { return true; } @@ -2159,16 +946,11 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic } @Override - public void setBatchMode(boolean mode) { + public void setBatchMode(Boolean mode) { this.batchMode = mode; } @Override - public Pos2d getBatchModeButtonPos() { - return new Pos2d(18, 0); - } - - @Override public boolean supportsSingleRecipeLocking() { return false; } @@ -2179,32 +961,23 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic } @Override - public void setRecipeLocking(boolean enabled) { + public void setRecipeLocking(Boolean enabled) { this.recipeLock = enabled; } @Override - public RecipeMap<?> getRecipeMap() { - return null; - } - - @Override - public Pos2d getRecipeLockingButtonPos() { - return new Pos2d(0, 0); - } - - @Override - public ModularWindow createWindowGUI(UIBuildContext buildContext) { - return createWindow(buildContext); - } - - @Override public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, int z) { super.getWailaNBTData(player, tile, tag, world, x, y, z); - tag.setLong("progress", progressTime); - tag.setLong("maxProgress", maxProgressTime); + P processing = getProcessingLogic(); + tag.setInteger("progress", processing.getProgress()); + tag.setInteger("maxProgress", processing.getDuration()); tag.setBoolean("structureOkay", structureOkay); + tag.setBoolean("isActive", isActive()); + if (isActive()) { + tag.setLong("energyUsage", getProcessingLogic().getCalculatedEut()); + tag.setLong("energyTier", tier); + } } @Override @@ -2219,8 +992,92 @@ public abstract class Controller<T extends Controller<T>> extends MultiTileBasic } if (isSimpleMachine) { boolean isActive = tag.getBoolean("isActive"); - currentTip - .add(GT_Waila.getMachineProgressString(isActive, tag.getLong("maxProgress"), tag.getLong("progress"))); + currentTip.add( + GT_Waila.getMachineProgressString(isActive, tag.getInteger("maxProgress"), tag.getInteger("progress"))); + } + boolean isActive = tag.getBoolean("isActive"); + if (isActive) { + long energyTier = tag.getLong("energyTier"); + long actualEnergyUsage = tag.getLong("energyUsage"); + if (actualEnergyUsage > 0) { + currentTip.add( + StatCollector.translateToLocalFormatted( + "GT5U.waila.energy.use_with_amperage", + GT_Utility.formatNumbers(actualEnergyUsage), + GT_Utility.getAmperageForTier(actualEnergyUsage, (byte) energyTier), + GT_Utility.getColoredTierNameFromTier((byte) energyTier))); + } else if (actualEnergyUsage < 0) { + currentTip.add( + StatCollector.translateToLocalFormatted( + "GT5U.waila.energy.produce_with_amperage", + GT_Utility.formatNumbers(-actualEnergyUsage), + GT_Utility.getAmperageForTier(-actualEnergyUsage, (byte) energyTier), + GT_Utility.getColoredTierNameFromTier((byte) energyTier))); + } } } + + @Override + public GT_Packet_MultiTileEntity getClientDataPacket() { + final GT_Packet_MultiTileEntity packet = super.getClientDataPacket(); + + return packet; + + } + + @Override + public void enableWorking() { + super.enableWorking(); + if (!structureOkay) { + checkStructure(true); + } + } + + @Override + public List<ItemStack> getItemOutputSlots(ItemStack[] toOutput) { + return new ArrayList<>(0); + } + + @Override + public List<? extends IFluidStore> getFluidOutputSlots(FluidStack[] toOutput) { + return new ArrayList<>(0); + } + + @Override + @Nonnull + public Set<Entry<UUID, FluidInventoryLogic>> getAllFluidInventoryLogics(@Nonnull InventoryType type) { + return switch (type) { + case Input -> controllerFluidInput.getAllInventoryLogicsAsEntrySet(); + case Output -> controllerFluidOutput.getAllInventoryLogicsAsEntrySet(); + default -> super.getAllFluidInventoryLogics(type); + }; + } + + @Override + @Nonnull + public Set<Entry<UUID, ItemInventoryLogic>> getAllItemInventoryLogics(@Nonnull InventoryType type) { + return switch (type) { + case Input -> controllerItemInput.getAllInventoryLogicsAsEntrySet(); + case Output -> controllerItemOutput.getAllInventoryLogicsAsEntrySet(); + default -> super.getAllItemInventoryLogics(type); + }; + } + + @Override + public void setWirelessSupport(boolean canUse) { + if (canUse) { + strongCheckOrAddUser(getOwnerUuid(), getOwnerName()); + } + power.setCanUseWireless(canUse, getOwnerUuid()); + } + + @Override + public void setLaserSupport(boolean canUse) { + power.setCanUseLaser(canUse); + } + + @Override + public void setMaxAmperage(long amperage) { + power.setMaxAmperage(amperage); + } } diff --git a/src/main/java/gregtech/api/multitileentity/multiblock/base/MultiBlockPart.java b/src/main/java/gregtech/api/multitileentity/multiblock/base/MultiBlockPart.java index db9053b0d7..223edc0761 100644 --- a/src/main/java/gregtech/api/multitileentity/multiblock/base/MultiBlockPart.java +++ b/src/main/java/gregtech/api/multitileentity/multiblock/base/MultiBlockPart.java @@ -2,7 +2,6 @@ package gregtech.api.multitileentity.multiblock.base; import static com.google.common.math.LongMath.log2; import static gregtech.api.enums.GT_Values.B; -import static gregtech.api.enums.GT_Values.NBT; import static gregtech.api.enums.Textures.BlockIcons.FLUID_IN_SIGN; import static gregtech.api.enums.Textures.BlockIcons.FLUID_OUT_SIGN; import static gregtech.api.enums.Textures.BlockIcons.ITEM_IN_SIGN; @@ -11,13 +10,17 @@ import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_ENERGY_IN_MULTI; import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_ENERGY_OUT_MULTI; import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPE_IN; import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPE_OUT; -import static org.apache.commons.lang3.ObjectUtils.firstNonNull; import java.math.RoundingMode; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.UUID; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; @@ -25,44 +28,42 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.StatCollector; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.Fluid; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.FluidTankInfo; -import net.minecraftforge.fluids.IFluidTank; -import com.gtnewhorizons.modularui.api.forge.IItemHandlerModifiable; -import com.gtnewhorizons.modularui.api.screen.ModularWindow; import com.gtnewhorizons.modularui.api.screen.ModularWindow.Builder; import com.gtnewhorizons.modularui.api.screen.UIBuildContext; import com.gtnewhorizons.modularui.common.widget.DrawableWidget; -import com.gtnewhorizons.modularui.common.widget.DropDownWidget; -import com.gtnewhorizons.modularui.common.widget.FluidSlotWidget; -import com.gtnewhorizons.modularui.common.widget.Scrollable; -import com.gtnewhorizons.modularui.common.widget.SlotGroup; -import com.gtnewhorizons.modularui.common.widget.SlotWidget; -import com.gtnewhorizons.modularui.common.widget.TextWidget; - -import gregtech.api.enums.GT_Values; + +import gregtech.api.enums.GT_Values.NBT; +import gregtech.api.enums.InventoryType; import gregtech.api.fluid.FluidTankGT; -import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.gui.GUIHost; +import gregtech.api.gui.GUIProvider; import gregtech.api.interfaces.ITexture; +import gregtech.api.logic.FluidInventoryLogic; +import gregtech.api.logic.ItemInventoryLogic; +import gregtech.api.logic.NullPowerLogic; import gregtech.api.logic.PowerLogic; import gregtech.api.logic.interfaces.PowerLogicHost; +import gregtech.api.multitileentity.MultiTileEntityRegistry; import gregtech.api.multitileentity.base.NonTickableMultiTileEntity; +import gregtech.api.multitileentity.enums.MultiTileCasingPurpose; import gregtech.api.multitileentity.interfaces.IMultiBlockController; import gregtech.api.multitileentity.interfaces.IMultiBlockPart; -import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_BreakBlock; +import gregtech.api.multitileentity.interfaces.IMultiTileEntity; import gregtech.api.multitileentity.interfaces.IMultiTileEntity.IMTE_HasModes; import gregtech.api.net.GT_Packet_MultiTileEntity; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Utility; import gregtech.common.covers.CoverInfo; +import gregtech.common.gui.PartGUIProvider; import mcp.mobius.waila.api.IWailaConfigHandler; import mcp.mobius.waila.api.IWailaDataAccessor; public abstract class MultiBlockPart extends NonTickableMultiTileEntity - implements IMultiBlockPart, IMTE_BreakBlock, IMTE_HasModes, PowerLogicHost { + implements IMultiBlockPart, IMTE_HasModes, PowerLogicHost, IMultiTileEntity.IMTE_AddToolTips, GUIHost { public static final int NOTHING = 0, ENERGY_IN = B[0], ENERGY_OUT = B[1], FLUID_IN = B[2], FLUID_OUT = B[3], ITEM_IN = B[4], ITEM_OUT = B[5]; @@ -70,16 +71,20 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity protected final List<Integer> BASIC_MODES = new ArrayList<>( Arrays.asList(NOTHING, ENERGY_IN, ENERGY_OUT, FLUID_IN, FLUID_OUT, ITEM_IN, ITEM_OUT)); - protected ChunkCoordinates mTargetPos = null; - protected IMultiBlockController target = null; + protected Set<MultiTileCasingPurpose> registeredPurposes = new HashSet<>(); - protected int mAllowedModes = NOTHING; // BITMASK - Modes allowed for this part - protected byte mMode = 0; // Mode selected for this part + protected ChunkCoordinates targetPosition = null; - protected String mLockedInventory = GT_Values.E; + protected int allowedModes = NOTHING; // BITMASK - Modes allowed for this part + protected int mode = 0; // Mode selected for this part + + protected UUID lockedInventory; protected int mLockedInventoryIndex = 0; protected FluidTankGT configurationTank = new FluidTankGT(); + @Nonnull + protected final GUIProvider<?> guiProvider = createGUIProvider(); + /** * What Part Tier is this part? All Basic Casings are Tier 1, and will allow: Energy, Item, Fluid input/output. Some * of the more advanced modes can be set to require a higher tier part. @@ -88,33 +93,40 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity return 1; } - public String getLockedInventory() { - // TODO: Can this cause side-effects? Removed for now because it causes huge network traffic when using covers - // issueClientUpdate(); - IMultiBlockController controller = getTarget(false); - if (modeSelected(ITEM_IN) || modeSelected(ITEM_OUT)) { - if (!getNameOfInventoryFromIndex(controller, mLockedInventoryIndex).equals(mLockedInventory)) { - mLockedInventory = getNameOfInventoryFromIndex(controller, mLockedInventoryIndex); - if (mLockedInventory.equals(Controller.ALL_INVENTORIES_NAME)) { - mLockedInventory = ""; - } - } - } else { - if (!getNameOfTankArrayFromIndex(controller, mLockedInventoryIndex).equals(mLockedInventory)) { - mLockedInventory = getNameOfTankArrayFromIndex(controller, mLockedInventoryIndex); - if (mLockedInventory.equals(Controller.ALL_INVENTORIES_NAME)) { - mLockedInventory = ""; - } + @Override + public UUID getLockedInventory() { + return lockedInventory; + } + + public void setTarget(IMultiBlockController newTarget, int aAllowedModes) { + IMultiBlockController currentTarget = getTarget(false); + if (currentTarget != null && currentTarget != newTarget) { + for (MultiTileCasingPurpose purpose : registeredPurposes) { + unregisterPurpose(purpose); } } - return mLockedInventory.equals("") ? null : mLockedInventory; + targetPosition = (newTarget == null ? null : newTarget.getCoords()); + allowedModes = aAllowedModes; + if (newTarget != null) { + registerCovers(newTarget); + registerPurposes(); + } } - public void setTarget(IMultiBlockController aTarget, int aAllowedModes) { - target = aTarget; - mTargetPos = (target == null ? null : target.getCoords()); - mAllowedModes = aAllowedModes; - if (target != null) registerCovers(target); + protected void registerPurpose(MultiTileCasingPurpose purpose) { + IMultiBlockController target = getTarget(false); + if (target != null) { + target.registerCaseWithPurpose(purpose, this); + registeredPurposes.add(purpose); + } + } + + protected void unregisterPurpose(MultiTileCasingPurpose purpose) { + IMultiBlockController target = getTarget(false); + if (target != null) { + target.unregisterCaseWithPurpose(purpose, this); + } + registeredPurposes.remove(purpose); } @Override @@ -125,14 +137,14 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity } else { tList.add("No Controller"); } - tList.add("Casing Mode: " + getModeName(mMode)); + tList.add("Casing Mode: " + getModeName(mode)); } @Override public void getWailaBody(ItemStack itemStack, List<String> currentTip, IWailaDataAccessor accessor, IWailaConfigHandler config) { super.getWailaBody(itemStack, currentTip, accessor, config); - currentTip.add(String.format("Mode: %s", getModeName(mMode))); + currentTip.add(String.format("Mode: %s", getModeName(mode))); if (modeSelected(FLUID_OUT)) { if (configurationTank != null && configurationTank.get() != null) { currentTip.add( @@ -147,19 +159,22 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity } public IMultiBlockController getTarget(boolean aCheckValidity) { - if (mTargetPos == null) return null; - if (target == null || target.isDead()) { - if (worldObj.blockExists(mTargetPos.posX, mTargetPos.posY, mTargetPos.posZ)) { - final TileEntity te = worldObj.getTileEntity(mTargetPos.posX, mTargetPos.posY, mTargetPos.posZ); - if (te instanceof IMultiBlockController) { - target = (IMultiBlockController) te; - // Register our covers with the controller - registerCovers(target); - } else { - mTargetPos = null; - } - } + if (targetPosition == null) { + return null; + } + + if (!worldObj.blockExists(targetPosition.posX, targetPosition.posY, targetPosition.posZ)) { + return null; + } + final TileEntity te = worldObj.getTileEntity(targetPosition.posX, targetPosition.posY, targetPosition.posZ); + IMultiBlockController target = null; + if (te instanceof IMultiBlockController targetFound) { + target = targetFound; + } else { + targetPosition = null; + return null; } + if (aCheckValidity) { return target != null && target.checkStructure(false) ? target : null; } @@ -175,17 +190,26 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity } } + protected void registerPurposes() { + for (MultiTileCasingPurpose purpose : registeredPurposes) { + registerPurpose(purpose); + } + } + @Override public void setCoverItemAtSide(ForgeDirection side, ItemStack aCover) { super.setCoverItemAtSide(side, aCover); // TODO: Filter on tickable covers final IMultiBlockController tTarget = getTarget(true); - if (tTarget != null) { - final CoverInfo coverInfo = getCoverInfoAtSide(side); - if (coverInfo.isValid() && coverInfo.getTickRate() > 0) { - tTarget.registerCoveredPartOnSide(side, this); - } + if (tTarget == null) { + return; } + + final CoverInfo coverInfo = getCoverInfoAtSide(side); + if (coverInfo.isValid() && coverInfo.getTickRate() > 0) { + tTarget.registerCoveredPartOnSide(side, this); + } + } public void unregisterCovers(IMultiBlockController controller) { @@ -208,16 +232,16 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity @Override public void readMultiTileNBT(NBTTagCompound aNBT) { - if (aNBT.hasKey(NBT.ALLOWED_MODES)) mAllowedModes = aNBT.getInteger(NBT.ALLOWED_MODES); - if (aNBT.hasKey(NBT.MODE)) mMode = aNBT.getByte(NBT.MODE); + if (aNBT.hasKey(NBT.ALLOWED_MODES)) allowedModes = aNBT.getInteger(NBT.ALLOWED_MODES); + if (aNBT.hasKey(NBT.MODE)) setMode(aNBT.getByte(NBT.MODE)); if (aNBT.hasKey(NBT.TARGET)) { - mTargetPos = new ChunkCoordinates( + targetPosition = new ChunkCoordinates( aNBT.getInteger(NBT.TARGET_X), aNBT.getShort(NBT.TARGET_Y), aNBT.getInteger(NBT.TARGET_Z)); } if (aNBT.hasKey(NBT.LOCKED_INVENTORY)) { - mLockedInventory = aNBT.getString(NBT.LOCKED_INVENTORY); + lockedInventory = UUID.fromString(aNBT.getString(NBT.LOCKED_INVENTORY)); } if (aNBT.hasKey(NBT.LOCKED_INVENTORY_INDEX)) { mLockedInventoryIndex = aNBT.getInteger(NBT.LOCKED_INVENTORY_INDEX); @@ -225,20 +249,26 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity if (aNBT.hasKey(NBT.LOCKED_FLUID)) { configurationTank.readFromNBT(aNBT, NBT.LOCKED_FLUID); } + if (modeSelected(ITEM_OUT)) { + registeredPurposes.add(MultiTileCasingPurpose.ItemOutput); + } + if (modeSelected(FLUID_OUT)) { + registeredPurposes.add(MultiTileCasingPurpose.FluidOutput); + } } @Override public void writeMultiTileNBT(NBTTagCompound aNBT) { - if (mAllowedModes != NOTHING) aNBT.setInteger(NBT.ALLOWED_MODES, mAllowedModes); - if (mMode != 0) aNBT.setInteger(NBT.MODE, mMode); - if (mTargetPos != null) { + if (allowedModes != NOTHING) aNBT.setInteger(NBT.ALLOWED_MODES, allowedModes); + if (mode != 0) aNBT.setInteger(NBT.MODE, mode); + if (targetPosition != null) { aNBT.setBoolean(NBT.TARGET, true); - aNBT.setInteger(NBT.TARGET_X, mTargetPos.posX); - aNBT.setShort(NBT.TARGET_Y, (short) mTargetPos.posY); - aNBT.setInteger(NBT.TARGET_Z, mTargetPos.posZ); + aNBT.setInteger(NBT.TARGET_X, targetPosition.posX); + aNBT.setShort(NBT.TARGET_Y, (short) targetPosition.posY); + aNBT.setInteger(NBT.TARGET_Z, targetPosition.posZ); } - if (mLockedInventory != null) { - aNBT.setString(NBT.LOCKED_INVENTORY, mLockedInventory); + if (lockedInventory != null) { + aNBT.setString(NBT.LOCKED_INVENTORY, lockedInventory.toString()); } if (mLockedInventoryIndex != 0) { aNBT.setInteger(NBT.LOCKED_INVENTORY_INDEX, mLockedInventoryIndex); @@ -270,34 +300,47 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity @Override public void setTargetPos(ChunkCoordinates aTargetPos) { - mTargetPos = aTargetPos; - IMultiBlockController mTarget = getTarget(false); - setTarget(mTarget, mAllowedModes); + targetPosition = aTargetPos; + IMultiBlockController target = getTarget(false); + setTarget(target, allowedModes); } @Override public ChunkCoordinates getTargetPos() { - return mTargetPos; + return targetPosition; } @Override - public void setMode(byte aMode) { - mMode = aMode; + public void setMode(int mode) { + if (this.mode == mode) return; + if (modeSelected(FLUID_OUT)) { + unregisterPurpose(MultiTileCasingPurpose.FluidOutput); + } + if (modeSelected(ITEM_OUT)) { + unregisterPurpose(MultiTileCasingPurpose.ItemOutput); + } + this.mode = mode; + if (modeSelected(FLUID_OUT)) { + registerPurpose(MultiTileCasingPurpose.FluidOutput); + } + if (modeSelected(ITEM_OUT)) { + registerPurpose(MultiTileCasingPurpose.ItemOutput); + } } @Override - public byte getMode() { - return mMode; + public int getMode() { + return mode; } @Override public int getAllowedModes() { - return mAllowedModes; + return allowedModes; } @Override public void setAllowedModes(int aAllowedModes) { - mAllowedModes = aAllowedModes; + allowedModes = aAllowedModes; } /** @@ -305,7 +348,7 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity */ public boolean hasMode(int aMode) { // This is not sent to the client - return (mAllowedModes & aMode) != 0; + return (allowedModes & aMode) != 0; } /** @@ -313,7 +356,7 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity */ public boolean modeSelected(int... aModes) { for (int aMode : aModes) { - if (hasMode(aMode) && mMode == getModeOrdinal(aMode)) return true; + if (hasMode(aMode) && mode == getModeOrdinal(aMode)) return true; } return false; } @@ -344,39 +387,39 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity @Override public ITexture getTexture(ForgeDirection side) { ITexture texture = super.getTexture(side); - if (mMode != 0 && side == facing) { - if (mMode == getModeOrdinal(ITEM_IN)) { + if (mode != 0 && side == facing) { + if (mode == getModeOrdinal(ITEM_IN)) { return TextureFactory.of( texture, TextureFactory.of(OVERLAY_PIPE_IN), TextureFactory.of(ITEM_IN_SIGN), getCoverTexture(side)); } - if (mMode == getModeOrdinal(ITEM_OUT)) { + if (mode == getModeOrdinal(ITEM_OUT)) { return TextureFactory.of( texture, TextureFactory.of(OVERLAY_PIPE_OUT), TextureFactory.of(ITEM_OUT_SIGN), getCoverTexture(side)); } - if (mMode == getModeOrdinal(FLUID_IN)) { + if (mode == getModeOrdinal(FLUID_IN)) { return TextureFactory.of( texture, TextureFactory.of(OVERLAY_PIPE_IN), TextureFactory.of(FLUID_IN_SIGN), getCoverTexture(side)); } - if (mMode == getModeOrdinal(FLUID_OUT)) { + if (mode == getModeOrdinal(FLUID_OUT)) { return TextureFactory.of( texture, TextureFactory.of(OVERLAY_PIPE_OUT), TextureFactory.of(FLUID_OUT_SIGN), getCoverTexture(side)); } - if (mMode == getModeOrdinal(ENERGY_IN)) { + if (mode == getModeOrdinal(ENERGY_IN)) { return TextureFactory.of(texture, TextureFactory.of(OVERLAY_ENERGY_IN_MULTI), getCoverTexture(side)); } - if (mMode == getModeOrdinal(ENERGY_OUT)) { + if (mode == getModeOrdinal(ENERGY_OUT)) { return TextureFactory.of(texture, TextureFactory.of(OVERLAY_ENERGY_OUT_MULTI), getCoverTexture(side)); } } @@ -384,11 +427,6 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity return TextureFactory.of(texture, getCoverTexture(side)); } - @Override - public boolean isUseableByPlayer(EntityPlayer entityPlayer) { - return false; - } - protected String getModeName(int aMode) { if (aMode == NOTHING) return "Nothing"; if (aMode == getModeOrdinal(ITEM_IN)) return "Item Input"; @@ -407,11 +445,11 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity } protected byte getNextAllowedMode(List<Integer> allowedModes) { - if (mAllowedModes == NOTHING) return NOTHING; + if (this.allowedModes == NOTHING) return NOTHING; final int numModes = allowedModes.size(); for (byte i = 1; i <= numModes; i++) { - final byte curMode = (byte) ((mMode + i) % numModes); + final byte curMode = (byte) ((mode + i) % numModes); if (curMode == NOTHING || hasMode(1 << (curMode - 1))) return curMode; } // Nothing valid found @@ -420,16 +458,16 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity @Override public boolean onMalletRightClick(EntityPlayer aPlayer, ItemStack tCurrentItem, ForgeDirection wrenchSide, float aX, - float aY, float aZ, ItemStack aTool) { - if (mAllowedModes == NOTHING) return true; - if (mMode == NOTHING) { + float aY, float aZ) { + if (allowedModes == NOTHING) return true; + if (mode == NOTHING) { facing = wrenchSide; } - mMode = getNextAllowedMode(BASIC_MODES); + setMode(getNextAllowedMode(BASIC_MODES)); if (aPlayer.isSneaking()) { facing = wrenchSide; } - GT_Utility.sendChatToPlayer(aPlayer, "Mode set to `" + getModeName(mMode) + "' (" + mMode + ")"); + GT_Utility.sendChatToPlayer(aPlayer, "Mode set to `" + getModeName(mode) + "' (" + mode + ")"); sendClientData((EntityPlayerMP) aPlayer); return true; } @@ -447,109 +485,50 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity return "gt.multitileentity.multiblock.part"; } + @Override + public boolean shouldTick(long tickTimer) { + return modeSelected(ITEM_OUT, FLUID_OUT); + } + /** * TODO: Make sure the energy/item/fluid hatch is facing that way! or has that mode enabled on that side Check * SIDE_UNKNOWN for or coverbehavior */ - /** - * Fluid - Depending on the part type - proxy it to the multiblock controller, if we have one - */ + // #region Fluid - Depending on the part type - proxy it to the multiblock controller, if we have one @Override - public int fill(ForgeDirection aDirection, FluidStack aFluidStack, boolean aDoFill) { - if (!modeSelected(FLUID_IN)) return 0; + @Nullable + public FluidInventoryLogic getFluidLogic(@Nonnull ForgeDirection side, @Nonnull InventoryType type) { + if (side != facing && side != ForgeDirection.UNKNOWN) return null; - if (aFluidStack == null || isWrongFluid(aFluidStack.getFluid())) return 0; - if (aDirection != ForgeDirection.UNKNOWN - && (facing.compareTo(aDirection) != 0 || !coverLetsFluidIn(aDirection, aFluidStack.getFluid()))) return 0; - final IMultiBlockController controller = getTarget(true); - return controller == null ? 0 : controller.fill(this, aDirection, aFluidStack, aDoFill); - } + if (!modeSelected(FLUID_IN, FLUID_OUT)) return null; - @Override - public FluidStack drain(ForgeDirection aDirection, FluidStack aFluidStack, boolean aDoDrain) { - if (!modeSelected(FLUID_OUT)) return null; - if (aFluidStack == null || isWrongFluid(aFluidStack.getFluid())) return null; - if (aDirection != ForgeDirection.UNKNOWN - && (facing.compareTo(aDirection) != 0 || !coverLetsFluidOut(aDirection, aFluidStack.getFluid()))) - return null; - final IMultiBlockController controller = getTarget(true); - return controller == null ? null : controller.drain(this, aDirection, aFluidStack, aDoDrain); - } - - @Override - public FluidStack drain(ForgeDirection aDirection, int aAmountToDrain, boolean aDoDrain) { - if (!modeSelected(FLUID_OUT)) return null; - final IMultiBlockController controller = getTarget(true); + IMultiBlockController controller = getTarget(false); if (controller == null) return null; - FluidStack aFluidStack = null; - if (getLockedFluid() != null) { - aFluidStack = controller.getDrainableFluid(aDirection, getLockedFluid()); - } else { - aFluidStack = controller.getDrainableFluid(aDirection); - } - if (aFluidStack == null || isWrongFluid(aFluidStack.getFluid())) return null; - if (aDirection != ForgeDirection.UNKNOWN - && (facing.compareTo(aDirection) != 0 || !coverLetsFluidOut(aDirection, aFluidStack.getFluid()))) - return null; - return controller.drain(this, aDirection, aFluidStack, aDoDrain); - } - - @Override - public boolean canFill(ForgeDirection aDirection, Fluid aFluid) { - if (!modeSelected(FLUID_IN)) return false; - - if (aDirection != ForgeDirection.UNKNOWN - && (facing.compareTo(aDirection) != 0 || !coverLetsFluidIn(aDirection, aFluid))) return false; - if (isWrongFluid(aFluid)) return false; - final IMultiBlockController controller = getTarget(true); - return controller != null && controller.canFill(this, aDirection, aFluid); + return controller + .getFluidLogic(modeSelected(FLUID_IN) ? InventoryType.Input : InventoryType.Output, lockedInventory); } - @Override - public boolean canDrain(ForgeDirection aDirection, Fluid aFluid) { - if (!modeSelected(FLUID_OUT)) return false; - if (aDirection != ForgeDirection.UNKNOWN - && (facing.compareTo(aDirection) != 0 || !coverLetsFluidOut(aDirection, aFluid))) return false; - if (isWrongFluid(aFluid)) return false; - final IMultiBlockController controller = getTarget(true); - return controller != null && controller.canDrain(this, aDirection, aFluid); - } - - @Override - public FluidTankInfo[] getTankInfo(ForgeDirection aDirection) { - if (!modeSelected(FLUID_IN, FLUID_OUT) - || (aDirection != ForgeDirection.UNKNOWN && facing.compareTo(aDirection) != 0)) - return GT_Values.emptyFluidTankInfo; - final IMultiBlockController controller = getTarget(true); - if (controller == null) return GT_Values.emptyFluidTankInfo; - - final CoverInfo coverInfo = getCoverInfoAtSide(aDirection); - - if ((controller.isLiquidInput(aDirection) && coverInfo.letsFluidIn(null, controller)) - || (controller.isLiquidOutput(aDirection) && coverInfo.letsFluidOut(null, controller))) - return controller.getTankInfo(this, aDirection); - - return GT_Values.emptyFluidTankInfo; - } + // #endregion Fluid // #region Energy - Depending on the part type - proxy to the multiblock controller, if we have one @Override - public PowerLogic getPowerLogic(ForgeDirection side) { - if (facing == side) { - return null; + @Nonnull + public PowerLogic getPowerLogic(@Nonnull ForgeDirection side) { + if (side != facing && side != ForgeDirection.UNKNOWN) { + return new NullPowerLogic(); } if (!modeSelected(ENERGY_IN, ENERGY_OUT)) { - return null; + return new NullPowerLogic(); } final IMultiBlockController controller = getTarget(true); if (controller == null) { - return null; + return new NullPowerLogic(); } - return controller.getPowerLogic(this, side); + return controller.getPowerLogic(); } @Override @@ -562,119 +541,32 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity return modeSelected(ENERGY_OUT); } - // #endregion - - /** - * Inventory - Depending on the part type - proxy to the multiblock controller, if we have one - */ - @Override - public boolean hasInventoryBeenModified() { - final IMultiBlockController controller = getTarget(true); - return (controller != null && controller.hasInventoryBeenModified(this)); - } - - @Override - public boolean isValidSlot(int aIndex) { - final IMultiBlockController controller = getTarget(true); - return (controller != null && controller.isValidSlot(this, aIndex)); - } - - @Override - public boolean addStackToSlot(int aIndex, ItemStack aStack) { - if (!modeSelected(ITEM_IN, ITEM_OUT)) return false; - final IMultiBlockController controller = getTarget(true); - return (controller != null && controller.addStackToSlot(this, aIndex, aStack)); - } - - @Override - public boolean addStackToSlot(int aIndex, ItemStack aStack, int aAmount) { - if (!modeSelected(ITEM_IN, ITEM_OUT)) return false; - final IMultiBlockController controller = getTarget(true); - return (controller != null && controller.addStackToSlot(this, aIndex, aStack, aAmount)); - } + // #endregion Energy - @Override - public int[] getAccessibleSlotsFromSide(int ordinalSide) { - final ForgeDirection side = ForgeDirection.getOrientation(ordinalSide); - if (!modeSelected(ITEM_IN, ITEM_OUT) || (facing != ForgeDirection.UNKNOWN && facing.compareTo(side) != 0)) - return GT_Values.emptyIntArray; - final IMultiBlockController controller = getTarget(true); - return controller != null ? controller.getAccessibleSlotsFromSide(this, side) : GT_Values.emptyIntArray; - } + // #region Item - Depending on the part type - proxy to the multiblock controller, if we have one @Override - public boolean canInsertItem(int aSlot, ItemStack aStack, int ordinalSide) { - final ForgeDirection side = ForgeDirection.getOrientation(ordinalSide); - if (!modeSelected(ITEM_IN, ITEM_OUT) - || (facing != ForgeDirection.UNKNOWN && (facing.compareTo(side) != 0 || !coverLetsItemsIn(side, aSlot)))) - return false; - final IMultiBlockController controller = getTarget(true); - return (controller != null && controller.canInsertItem(this, aSlot, aStack, side)); - } + @Nullable + public ItemInventoryLogic getItemLogic(@Nonnull ForgeDirection side, @Nonnull InventoryType unused) { + if (side != facing && side != ForgeDirection.UNKNOWN) return null; - @Override - public boolean canExtractItem(int aSlot, ItemStack aStack, int ordinalSide) { - final ForgeDirection side = ForgeDirection.getOrientation(ordinalSide); - if (!modeSelected(ITEM_IN, ITEM_OUT) - || (facing != ForgeDirection.UNKNOWN && (facing.compareTo(side) != 0 || !coverLetsItemsOut(side, aSlot)))) - return false; - final IMultiBlockController controller = getTarget(true); - return (controller != null && controller.canExtractItem(this, aSlot, aStack, side)); - } - - @Override - public int getSizeInventory() { - if (!modeSelected(ITEM_IN, ITEM_OUT)) return 0; - final IMultiBlockController controller = getTarget(true); - return controller != null ? controller.getSizeInventory(this) : 0; - } - - @Override - public ItemStack getStackInSlot(int aSlot) { if (!modeSelected(ITEM_IN, ITEM_OUT)) return null; - final IMultiBlockController controller = getTarget(true); - return controller != null ? controller.getStackInSlot(this, aSlot) : null; - } - - @Override - public ItemStack decrStackSize(int aSlot, int aDecrement) { - if (!modeSelected(ITEM_IN, ITEM_OUT)) return null; - final IMultiBlockController controller = getTarget(true); - return controller != null ? controller.decrStackSize(this, aSlot, aDecrement) : null; - } - @Override - public ItemStack getStackInSlotOnClosing(int aSlot) { - final IMultiBlockController controller = getTarget(true); - return controller != null ? controller.getStackInSlotOnClosing(this, aSlot) : null; - } - - @Override - public void setInventorySlotContents(int aSlot, ItemStack aStack) { - final IMultiBlockController controller = getTarget(true); - if (controller != null) controller.setInventorySlotContents(this, aSlot, aStack); - } - - @Override - public String getInventoryName() { - final IMultiBlockController controller = getTarget(true); - if (controller != null) return controller.getInventoryName(this); - return firstNonNull(getCustomName(), getTileEntityName()); - } + final IMultiBlockController controller = getTarget(false); + if (controller == null) return null; - @Override - public int getInventoryStackLimit() { - final IMultiBlockController controller = getTarget(true); - return controller != null ? controller.getInventoryStackLimit(this) : 0; + return controller + .getItemLogic(modeSelected(ITEM_IN) ? InventoryType.Input : InventoryType.Output, lockedInventory); } @Override - public boolean isItemValidForSlot(int aSlot, ItemStack aStack) { - final IMultiBlockController controller = getTarget(true); - return controller != null && controller.isItemValidForSlot(this, aSlot, aStack); + @Nullable + public InventoryType getItemInventoryType() { + if (!modeSelected(ITEM_IN, ITEM_OUT)) return InventoryType.Both; + return modeSelected(ITEM_IN) ? InventoryType.Input : InventoryType.Output; } - // End Inventory + // #endregion Item // === Modular UI === @Override @@ -700,62 +592,6 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity return getTarget(true) != null; } - protected void addItemInventory(Builder builder, UIBuildContext buildContext) { - final IMultiBlockController controller = getTarget(false); - if (controller == null) { - return; - } - final IItemHandlerModifiable inv = controller.getInventoryForGUI(this); - final Scrollable scrollable = new Scrollable().setVerticalScroll(); - for (int rows = 0; rows * 4 < Math.min(inv.getSlots(), 128); rows++) { - int columnsToMake = Math.min(Math.min(inv.getSlots(), 128) - rows * 4, 4); - for (int column = 0; column < columnsToMake; column++) { - scrollable.widget( - new SlotWidget(inv, rows * 4 + column).setPos(column * 18, rows * 18) - .setSize(18, 18)); - } - } - builder.widget( - scrollable.setSize(18 * 4 + 4, 18 * 4) - .setPos(52, 18)); - DropDownWidget dropDown = new DropDownWidget(); - dropDown.addDropDownItemsSimple( - controller.getInventoryNames(this), - (buttonWidget, index, label, setSelected) -> buttonWidget.setOnClick((clickData, widget) -> { - if (getNameOfInventoryFromIndex(controller, index).equals(Controller.ALL_INVENTORIES_NAME)) { - mLockedInventory = GT_Values.E; - mLockedInventoryIndex = 0; - } else { - mLockedInventory = getNameOfInventoryFromIndex(controller, index); - mLockedInventoryIndex = index; - } - setSelected.run(); - }), - true); - builder.widget( - dropDown.setSelected(mLockedInventoryIndex) - .setExpandedMaxHeight(60) - .setDirection(DropDownWidget.Direction.DOWN) - .setPos(53, 5) - .setSize(70, 11)); - } - - protected String getNameOfInventoryFromIndex(final IMultiBlockController controller, int index) { - final List<String> invNames = controller.getInventoryIDs(this); - if (index > invNames.size()) { - return invNames.get(0); - } - return invNames.get(index); - } - - protected String getNameOfTankArrayFromIndex(final IMultiBlockController controller, int index) { - final List<String> tankNames = controller.getTankArrayIDs(this); - if (index > tankNames.size()) { - return tankNames.get(0); - } - return tankNames.get(index); - } - protected boolean isWrongFluid(Fluid fluid) { if (fluid == null) { return true; @@ -776,98 +612,34 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity return null; } - protected void addFluidInventory(Builder builder, UIBuildContext buildContext) { - final IMultiBlockController controller = getTarget(false); + @Override + public void addUIWidgets(Builder builder, UIBuildContext buildContext) { + super.addUIWidgets(builder, buildContext); + IMultiBlockController controller = getTarget(false); if (controller == null) { return; } - builder.widget( - new DrawableWidget().setDrawable(GT_UITextures.PICTURE_SCREEN_BLACK) - .setPos(7, 4) - .setSize(85, 95)); - if (modeSelected(FLUID_OUT)) { + if ((modeSelected(ITEM_IN, ITEM_OUT))) { builder.widget( - new DrawableWidget().setDrawable(GT_UITextures.PICTURE_SCREEN_BLACK) - .setPos(getGUIWidth() - 77, 4) - .setSize(70, 40)) - .widget( - new TextWidget("Locked Fluid").setDefaultColor(COLOR_TEXT_WHITE.get()) - .setPos(getGUIWidth() - 72, 8)); - } - final IFluidTank[] tanks = controller.getFluidTanksForGUI(this); - final Scrollable scrollable = new Scrollable().setVerticalScroll(); - for (int rows = 0; rows * 4 < tanks.length; rows++) { - int columnsToMake = Math.min(tanks.length - rows * 4, 4); - for (int column = 0; column < columnsToMake; column++) { - FluidSlotWidget fluidSlot = new FluidSlotWidget(tanks[rows * 4 + column]); - if (modeSelected(FLUID_OUT)) { - fluidSlot.setInteraction(true, false); - } - scrollable.widget( - fluidSlot.setPos(column * 18, rows * 18) - .setSize(18, 18)); - } + controller + .getItemLogic(modeSelected(ITEM_IN) ? InventoryType.Input : InventoryType.Output, lockedInventory) + .getGuiPart() + .setSize(18 * 4 + 4, 18 * 5) + .setPos(52, 7)); } - builder.widget( - scrollable.setSize(18 * 4 + 4, 18 * 4) - .setPos(12, 21)); - DropDownWidget dropDown = new DropDownWidget(); - dropDown.addDropDownItemsSimple( - controller.getTankArrayNames(this), - (buttonWidget, index, label, setSelected) -> buttonWidget.setOnClick((clickData, widget) -> { - if (getNameOfTankArrayFromIndex(controller, index).equals(Controller.ALL_INVENTORIES_NAME)) { - mLockedInventory = GT_Values.E; - mLockedInventoryIndex = 0; - } else { - mLockedInventory = getNameOfTankArrayFromIndex(controller, index); - mLockedInventoryIndex = index; - } - setSelected.run(); - }), - true); - builder.widget( - dropDown.setSelected(mLockedInventoryIndex) - .setExpandedMaxHeight(60) - .setDirection(DropDownWidget.Direction.DOWN) - .setPos(13, 8) - .setSize(70, 11)); - } - @Override - public void addUIWidgets(Builder builder, UIBuildContext buildContext) { - if (modeSelected(ITEM_IN, ITEM_OUT)) { - addItemInventory(builder, buildContext); - return; - } - if (modeSelected(FLUID_IN, FLUID_OUT)) { - addFluidInventory(builder, buildContext); - if (modeSelected(FLUID_OUT)) { - builder.widget( - SlotGroup.ofFluidTanks(Collections.singletonList(configurationTank), 1) - .startFromSlot(0) - .endAtSlot(0) - .phantom(true) - .build() - .setPos(getGUIWidth() - 72, 20)); - } - return; + if ((modeSelected(FLUID_IN, FLUID_OUT))) { + builder.widget( + controller + .getFluidLogic(modeSelected(FLUID_IN) ? InventoryType.Input : InventoryType.Output, lockedInventory) + .getGuiPart() + .setSize(18 * 4 + 4, 18 * 5) + .setPos(52, 7)); } } - @Override - public ModularWindow createWindow(UIBuildContext buildContext) { - if (isServerSide()) { - issueClientUpdate(); - } - System.out.println("MultiBlockPart::createWindow"); - if (modeSelected(NOTHING, ENERGY_IN, ENERGY_OUT) || mMode == NOTHING) { - IMultiBlockController controller = getTarget(false); - if (controller == null) { - return super.createWindow(buildContext); - } - return controller.createWindowGUI(buildContext); - } - return super.createWindow(buildContext); + protected boolean canOpenControllerGui() { + return true; } @Override @@ -891,4 +663,62 @@ public abstract class MultiBlockPart extends NonTickableMultiTileEntity super.addGregTechLogo(builder); } } + + @Override + public void addToolTips(List<String> list, ItemStack stack, boolean f3_h) { + list.add("A MultiTileEntity Casing"); + } + + public String getInventoryName() { + IMultiBlockController controller = getTarget(false); + if (controller == null) return ""; + if (modeSelected(ITEM_IN, ITEM_OUT)) { + InventoryType type = modeSelected(ITEM_IN) ? InventoryType.Input : InventoryType.Output; + ItemInventoryLogic itemLogic = controller.getItemLogic(type, lockedInventory); + return itemLogic.getDisplayName(); + } + if (modeSelected(FLUID_IN, FLUID_OUT)) { + InventoryType type = modeSelected(FLUID_IN) ? InventoryType.Input : InventoryType.Output; + FluidInventoryLogic fluidLogic = controller.getFluidLogic(type, lockedInventory); + return fluidLogic.getDisplayName(); + } + return ""; + } + + @Override + @Nonnull + public ForgeDirection getPowerOutputSide() { + if (!modeSelected(ENERGY_OUT)) return ForgeDirection.UNKNOWN; + return facing; + } + + @Nonnull + protected GUIProvider<?> createGUIProvider() { + return new PartGUIProvider<>(this); + } + + @Override + @Nonnull + public GUIProvider<?> getGUI(@Nonnull UIBuildContext uiContext) { + IMultiBlockController controller = getTarget(false); + if (controller == null) return guiProvider; + if (!modeSelected(NOTHING, ENERGY_IN, ENERGY_OUT)) return guiProvider; + if (!canOpenControllerGui()) return guiProvider; + if (uiContext.getPlayer() + .isSneaking()) return guiProvider; + GUIProvider<?> controllerGUI = controller.getGUI(uiContext); + return controllerGUI; + } + + @Override + public ItemStack getAsItem() { + return MultiTileEntityRegistry.getRegistry(getMultiTileEntityRegistryID()) + .getItem(getMultiTileEntityID()); + } + + @Override + public String getMachineName() { + return StatCollector.translateToLocal(getAsItem().getUnlocalizedName()); + } + } diff --git a/src/main/java/gregtech/api/multitileentity/multiblock/base/PowerController.java b/src/main/java/gregtech/api/multitileentity/multiblock/base/PowerController.java deleted file mode 100644 index 532f171717..0000000000 --- a/src/main/java/gregtech/api/multitileentity/multiblock/base/PowerController.java +++ /dev/null @@ -1,92 +0,0 @@ -package gregtech.api.multitileentity.multiblock.base; - -import java.util.List; - -import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.StatCollector; -import net.minecraft.world.World; -import net.minecraftforge.common.util.ForgeDirection; - -import gregtech.api.enums.GT_Values; -import gregtech.api.logic.PowerLogic; -import gregtech.api.logic.interfaces.PowerLogicHost; -import gregtech.api.util.GT_Utility; -import mcp.mobius.waila.api.IWailaConfigHandler; -import mcp.mobius.waila.api.IWailaDataAccessor; - -public abstract class PowerController<T extends PowerController<T>> extends Controller<T> implements PowerLogicHost { - - public PowerController() { - super(); - power = new PowerLogic().setType(PowerLogic.RECEIVER); - } - - protected PowerLogic power; - - @Override - public void writeMultiTileNBT(NBTTagCompound nbt) { - super.writeMultiTileNBT(nbt); - power.writeToNBT(nbt); - } - - @Override - public void readMultiTileNBT(NBTTagCompound nbt) { - super.readMultiTileNBT(nbt); - power.loadFromNBT(nbt); - } - - @Override - public PowerLogic getPowerLogic(ForgeDirection side) { - return power; - } - - @Override - public boolean checkMachine() { - boolean result = super.checkMachine(); - power.setEnergyCapacity(GT_Values.V[tier] * 2 * 60 * 20); - power.setAmperage(2); - power.setMaxVoltage(GT_Values.V[tier]); - return result; - } - - @Override - public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, - int z) { - super.getWailaNBTData(player, tile, tag, world, x, y, z); - tag.setBoolean("isActive", isActive()); - if (isActive()) { - tag.setLong("energyUsage", eut); - tag.setLong("energyTier", tier); - } - } - - @Override - public void getWailaBody(ItemStack itemStack, List<String> currentTip, IWailaDataAccessor accessor, - IWailaConfigHandler config) { - super.getWailaBody(itemStack, currentTip, accessor, config); - final NBTTagCompound tag = accessor.getNBTData(); - boolean isActive = tag.getBoolean("isActive"); - if (isActive) { - long energyTier = tag.getLong("energyTier"); - long actualEnergyUsage = tag.getLong("energyUsage"); - if (actualEnergyUsage > 0) { - currentTip.add( - StatCollector.translateToLocalFormatted( - "GT5U.waila.energy.use_with_amperage", - GT_Utility.formatNumbers(actualEnergyUsage), - GT_Utility.getAmperageForTier(actualEnergyUsage, (byte) energyTier), - GT_Utility.getColoredTierNameFromTier((byte) energyTier))); - } else if (actualEnergyUsage < 0) { - currentTip.add( - StatCollector.translateToLocalFormatted( - "GT5U.waila.energy.produce_with_amperage", - GT_Utility.formatNumbers(-actualEnergyUsage), - GT_Utility.getAmperageForTier(-actualEnergyUsage, (byte) energyTier), - GT_Utility.getColoredTierNameFromTier((byte) energyTier))); - } - } - } -} diff --git a/src/main/java/gregtech/api/multitileentity/multiblock/base/StackableController.java b/src/main/java/gregtech/api/multitileentity/multiblock/base/StackableController.java index 90a2742290..51feb363dd 100644 --- a/src/main/java/gregtech/api/multitileentity/multiblock/base/StackableController.java +++ b/src/main/java/gregtech/api/multitileentity/multiblock/base/StackableController.java @@ -4,11 +4,15 @@ import net.minecraft.item.ItemStack; import com.gtnewhorizon.structurelib.util.Vec3Impl; -public abstract class StackableController<T extends StackableController<T>> extends PowerController<T> { +import gregtech.api.logic.MuTEProcessingLogic; - protected static String STACKABLE_TOP = "STACKABLE_TOP"; +public abstract class StackableController<C extends StackableController<C, P>, P extends MuTEProcessingLogic<P>> + extends Controller<C, P> { + + protected static String STACKABLE_STOP = "STACKABLE_STOP"; protected static String STACKABLE_MIDDLE = "STACKABLE_MIDDLE"; - protected static String STACKABLE_BOTTOM = "STACKABLE_BOTTOM"; + protected static String STACKABLE_START = "STACKABLE_START"; + protected int stackCount = 0; /** * construct implementation for stackable multi-blocks @@ -19,16 +23,16 @@ public abstract class StackableController<T extends StackableController<T>> exte final int stackCount = Math.min(blueprintCount, getMaxStacks()); buildState.startBuilding(getStartingStructureOffset()); - buildPiece(STACKABLE_BOTTOM, trigger, hintsOnly, buildState.getCurrentOffset()); + buildPiece(getStackableStart(), trigger, hintsOnly, buildState.getCurrentOffset()); buildState.addOffset(getStartingStackOffset()); for (int i = 0; i < stackCount; i++) { - buildPiece(STACKABLE_MIDDLE, trigger, hintsOnly, buildState.getCurrentOffset()); + buildPiece(getStackableMiddle(i), trigger, hintsOnly, buildState.getCurrentOffset()); buildState.addOffset(getPerStackOffset()); } if (hasTop()) { buildState.addOffset(getAfterLastStackOffset()); - buildPiece(STACKABLE_TOP, trigger, hintsOnly, buildState.stopBuilding()); + buildPiece(getStackableStop(), trigger, hintsOnly, buildState.stopBuilding()); } else { buildState.stopBuilding(); } @@ -85,27 +89,40 @@ public abstract class StackableController<T extends StackableController<T>> exte */ @Override public boolean checkMachine() { - int stackCount = 0; + stackCount = 0; buildState.startBuilding(getStartingStructureOffset()); - if (!checkPiece(STACKABLE_BOTTOM, buildState.getCurrentOffset())) return buildState.failBuilding(); + if (!checkPiece(getStackableStart(), buildState.getCurrentOffset())) return buildState.failBuilding(); buildState.addOffset(getStartingStackOffset()); for (int i = 0; i < getMaxStacks(); i++) { - if (checkPiece(STACKABLE_MIDDLE, buildState.getCurrentOffset())) { - buildState.addOffset(getPerStackOffset()); - stackCount++; - } else { + if (!checkPiece(getStackableMiddle(i), buildState.getCurrentOffset())) { break; } + + buildState.addOffset(getPerStackOffset()); + stackCount++; + } if (stackCount < getMinStacks()) return buildState.failBuilding(); buildState.addOffset(getAfterLastStackOffset()); - if (!checkPiece(STACKABLE_TOP, buildState.stopBuilding())) { + if (!checkPiece(getStackableStop(), buildState.stopBuilding())) { return buildState.failBuilding(); } return super.checkMachine(); } + + protected String getStackableStop() { + return STACKABLE_STOP; + } + + protected String getStackableMiddle(int stackIndex) { + return STACKABLE_MIDDLE; + } + + protected String getStackableStart() { + return STACKABLE_START; + } } diff --git a/src/main/java/gregtech/api/multitileentity/multiblock/base/StackableModularController.java b/src/main/java/gregtech/api/multitileentity/multiblock/base/StackableModularController.java new file mode 100644 index 0000000000..1dfd497151 --- /dev/null +++ b/src/main/java/gregtech/api/multitileentity/multiblock/base/StackableModularController.java @@ -0,0 +1,77 @@ +package gregtech.api.multitileentity.multiblock.base; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.jetbrains.annotations.NotNull; + +import gregtech.api.logic.MuTEProcessingLogic; +import gregtech.api.multitileentity.interfaces.UpgradableModularMuTE; +import gregtech.api.util.GT_StructureUtilityMuTE.UpgradeCasings; + +public abstract class StackableModularController<C extends StackableModularController<C, P>, P extends MuTEProcessingLogic<P>> + extends StackableController<C, P> implements UpgradableModularMuTE { + + protected double durationMultiplier = 1; + protected double euTickMultiplier = 1; + + private Map<UpgradeCasings, int[]> mucMap; + + protected @NotNull Map<UpgradeCasings, int[]> getMucMap() { + if (mucMap == null) { + mucMap = createMucMap(); + } + return mucMap; + } + + protected static @NotNull Map<UpgradeCasings, int[]> createMucMap() { + Map<UpgradeCasings, int[]> mucCount = new HashMap<>(); + mucCount.put(UpgradeCasings.Heater, new int[] { 0, 0, 0, 0, 0 }); + mucCount.put(UpgradeCasings.Insulator, new int[] { 0, 0, 0, 0, 0 }); + return mucCount; + } + + @Override + public void increaseMucCount(UpgradeCasings casingType, int tier) { + Map<UpgradeCasings, int[]> mucCounters = getMucMap(); + int[] casingCount = mucCounters.get(casingType); + + switch (tier) { + case 0, 1, 2 -> casingCount[0] += 1; + case 3, 4, 5 -> casingCount[1] += 1; + case 6, 7, 8 -> casingCount[2] += 1; + case 9, 10, 11 -> casingCount[3] += 1; + default -> casingCount[4] += 1; + } + } + + @Override + public void resetMucCount() { + Map<UpgradeCasings, int[]> mucCounters = getMucMap(); + mucCounters.forEach((type, casingCount) -> { Arrays.fill(casingCount, 0); }); + } + + // Returns the cheapest MUC that is possible for the multi, which gets the minimum bonuses. + protected abstract UpgradeCasings getBaseMucType(); + + // Minimum parallel bonus per MUC. Higher tier MUCs multiply with this value for even more parallels. + protected abstract int getParallelFactor(); + + protected void calculateParallels() { + int parallelCount = 0; + int parallelFactor = getParallelFactor(); + int[] parallelCasingList = mucMap.get(getBaseMucType()); + + for (int i = 0; i < 5; i++) { + // (i * 3 + 1) -> Convert MUC tier into minimum GT tier, in groups of 3 (LV, EV, LuV, UHV, UMV) + // If higher than multi tier, upgrade casing has no effect + if (i * 3 + 1 <= tier) { + parallelCount += parallelCasingList[i] * (i + 1) * parallelFactor; + } + } + maxParallel = parallelCount == 0 ? 1 : parallelCount; + } + + protected abstract boolean calculateMucMultipliers(); +} diff --git a/src/main/java/gregtech/api/multitileentity/multiblock/base/WallShareablePart.java b/src/main/java/gregtech/api/multitileentity/multiblock/base/WallShareablePart.java index 62beb64022..ccde0c49e6 100644 --- a/src/main/java/gregtech/api/multitileentity/multiblock/base/WallShareablePart.java +++ b/src/main/java/gregtech/api/multitileentity/multiblock/base/WallShareablePart.java @@ -2,6 +2,7 @@ package gregtech.api.multitileentity.multiblock.base; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ChunkCoordinates; @@ -12,50 +13,39 @@ import gregtech.api.multitileentity.interfaces.IMultiBlockController; public class WallShareablePart extends MultiBlockPart { protected List<ChunkCoordinates> targetPositions = new ArrayList<>(); - protected List<IMultiBlockController> targets = new ArrayList<>(); @Override public void setTarget(IMultiBlockController aTarget, int aAllowedModes) { - if (targets.size() > 1 || targetPositions.size() > 1) { - mAllowedModes = 0; - mMode = 0; + if (targetPositions.size() >= 1) { + allowedModes = 0; + setMode((byte) 0); + targetPosition = null; } else { - mAllowedModes = aAllowedModes; + allowedModes = aAllowedModes; } if (aTarget == null) { return; } - targets.add(aTarget); targetPositions.add(aTarget.getCoords()); } @Override - public String getLockedInventory() { - issueClientUpdate(); - if (targets.size() > 1 || targetPositions.size() > 1) { + public UUID getLockedInventory() { + if (targetPositions.size() > 1) { return null; } - - IMultiBlockController controller = getTarget(false); - if (!getNameOfInventoryFromIndex(controller, mLockedInventoryIndex).equals(mLockedInventory)) { - mLockedInventory = getNameOfInventoryFromIndex(controller, mLockedInventoryIndex); - if (mLockedInventory.equals("all")) { - mLockedInventory = ""; - } - } - return mLockedInventory.equals("") ? null : mLockedInventory; + return super.getLockedInventory(); } @Override public IMultiBlockController getTarget(boolean aCheckValidity) { - if (targets.size() > 1 || targetPositions.size() > 1 || targets.size() <= 0 || targetPositions.size() <= 0) { + if (targetPositions.size() != 1) { return null; } - target = targets.get(0); - mTargetPos = targetPositions.get(0); + targetPosition = targetPositions.get(0); return super.getTarget(aCheckValidity); } diff --git a/src/main/java/gregtech/api/multitileentity/multiblock/casing/UpgradeCasing.java b/src/main/java/gregtech/api/multitileentity/multiblock/casing/UpgradeCasing.java index e3230eac02..fb045557e4 100644 --- a/src/main/java/gregtech/api/multitileentity/multiblock/casing/UpgradeCasing.java +++ b/src/main/java/gregtech/api/multitileentity/multiblock/casing/UpgradeCasing.java @@ -16,9 +16,12 @@ public abstract class UpgradeCasing extends MultiBlockPart { } @Override - public void setTarget(IMultiBlockController aTarget, int aAllowedModes) { - super.setTarget(aTarget, aAllowedModes); - if (target != null) customWork(target); + public void setTarget(IMultiBlockController newTarget, int aAllowedModes) { + super.setTarget(newTarget, aAllowedModes); + + if (getTarget(false) != null) { + customWork(getTarget(false)); + } } @Override @@ -28,4 +31,5 @@ public abstract class UpgradeCasing extends MultiBlockPart { } protected abstract void customWork(IMultiBlockController aTarget); + } diff --git a/src/main/java/gregtech/api/net/GT_Packet_MultiTileEntity.java b/src/main/java/gregtech/api/net/GT_Packet_MultiTileEntity.java index b9e334d67b..b7bd8dbc02 100644 --- a/src/main/java/gregtech/api/net/GT_Packet_MultiTileEntity.java +++ b/src/main/java/gregtech/api/net/GT_Packet_MultiTileEntity.java @@ -21,7 +21,7 @@ import io.netty.buffer.ByteBuf; public class GT_Packet_MultiTileEntity extends GT_Packet_New { public static final int COVERS = B[0], REDSTONE = B[1], MODES = B[2], CONTROLLER = B[3], INVENTORY_INDEX = B[4], - INVENTORY_NAME = B[5], BOOLEANS = B[6], SOUND = B[7]; + INVENTORY_NAME_ID = B[5], BOOLEANS = B[6], SOUND = B[7]; private int features = 0; @@ -32,14 +32,14 @@ public class GT_Packet_MultiTileEntity extends GT_Packet_New { private ChunkCoordinates mTargetPos = null; private int mLockedInventoryIndex; private String mInventoryName; - private int mInventoryLength; + private String inventoryID; private int booleans; private byte soundEvent; private int soundEventValue; // MultiBlockPart - private byte mMode; - private int mAllowedModes; + private int mode; + private int allowedModes; public GT_Packet_MultiTileEntity() { super(true); @@ -77,10 +77,10 @@ public class GT_Packet_MultiTileEntity extends GT_Packet_New { mRedstone = aRedstoneData; } - public void setModes(byte aMode, int aAllowedModes) { + public void setModes(int mode, int allowedModes) { features |= MODES; - mMode = aMode; - mAllowedModes = aAllowedModes; + this.mode = mode; + this.allowedModes = allowedModes; } public void setTargetPos(int aX, short aY, int aZ) { @@ -94,9 +94,10 @@ public class GT_Packet_MultiTileEntity extends GT_Packet_New { } - public void setInventoryName(String aInventoryName) { - features |= INVENTORY_NAME; + public void setInventoryName(String aInventoryName, String inventoryID) { + features |= INVENTORY_NAME_ID; mInventoryName = aInventoryName; + this.inventoryID = inventoryID; } /** @@ -140,8 +141,8 @@ public class GT_Packet_MultiTileEntity extends GT_Packet_New { aOut.writeByte(mRedstone); } if ((features & MODES) == MODES) { - aOut.writeByte(mMode); - aOut.writeInt(mAllowedModes); + aOut.writeInt(mode); + aOut.writeInt(allowedModes); } if ((features & CONTROLLER) == CONTROLLER) { aOut.writeInt(mTargetPos.posX); @@ -151,16 +152,20 @@ public class GT_Packet_MultiTileEntity extends GT_Packet_New { if ((features & INVENTORY_INDEX) == INVENTORY_INDEX) { aOut.writeInt(mLockedInventoryIndex); } - if ((features & INVENTORY_NAME) == INVENTORY_NAME) { + if ((features & INVENTORY_NAME_ID) == INVENTORY_NAME_ID) { if (mInventoryName != null && mInventoryName.length() > 0) { - mInventoryLength = mInventoryName.length(); - aOut.writeInt(mInventoryLength); - for (char tChar : mInventoryName.toCharArray()) { - aOut.writeChar(tChar); - } + byte[] bytes = mInventoryName.getBytes(); + aOut.writeInt(bytes.length); + aOut.writeBytes(bytes); + } else { + aOut.writeInt(0); + } + if (inventoryID != null && inventoryID.length() > 0) { + byte[] bytes = inventoryID.getBytes(); + aOut.writeInt(bytes.length); + aOut.writeBytes(bytes); } else { - mInventoryLength = 0; - aOut.writeInt(mInventoryLength); + aOut.writeInt(0); } } @@ -203,7 +208,7 @@ public class GT_Packet_MultiTileEntity extends GT_Packet_New { packet.setRedstoneData(aData.readByte()); } if ((packetFeatures & MODES) == MODES) { - packet.setModes(aData.readByte(), aData.readInt()); + packet.setModes(aData.readInt(), aData.readInt()); } if ((packetFeatures & CONTROLLER) == CONTROLLER) { packet.setTargetPos(aData.readInt(), aData.readShort(), aData.readInt()); @@ -211,19 +216,30 @@ public class GT_Packet_MultiTileEntity extends GT_Packet_New { if ((packetFeatures & INVENTORY_INDEX) == INVENTORY_INDEX) { packet.setInventoryIndex(aData.readInt()); } - if ((packetFeatures & INVENTORY_NAME) == INVENTORY_NAME) { - int tLength = aData.readInt(); - String tName; - if (tLength > 0) { - StringBuilder tNameBuilder = new StringBuilder(); - for (int i = 0; i < tLength; i++) { - tNameBuilder.append(aData.readChar()); + if ((packetFeatures & INVENTORY_NAME_ID) == INVENTORY_NAME_ID) { + int nameLength = aData.readInt(); + String inventoryName; + if (nameLength > 0) { + byte[] bytes = new byte[nameLength]; + for (int i = 0; i < nameLength; i++) { + bytes[i] = aData.readByte(); + } + inventoryName = new String(bytes); + } else { + inventoryName = null; + } + int idLength = aData.readInt(); + String inventoryID; + if (idLength > 0) { + byte[] bytes = new byte[idLength]; + for (int i = 0; i < idLength; i++) { + bytes[i] = aData.readByte(); } - tName = tNameBuilder.toString(); + inventoryID = new String(bytes); } else { - tName = null; + inventoryID = null; } - packet.setInventoryName(tName); + packet.setInventoryName(inventoryName, inventoryID); } if ((packetFeatures & BOOLEANS) == BOOLEANS) { @@ -246,19 +262,24 @@ public class GT_Packet_MultiTileEntity extends GT_Packet_New { if (tBlock instanceof MultiTileEntityBlock mteBlock) { final IMultiTileEntity mte = mteBlock.receiveMultiTileEntityData(aWorld, mX, mY, mZ, mRID, mID); if (mte == null) return; - mte.receiveClientEvent(GregTechTileClientEvents.CHANGE_COMMON_DATA, mCommonData); - mte.receiveClientEvent(GregTechTileClientEvents.CHANGE_COLOR, mColor); + mte.receiveClientData(GregTechTileClientEvents.CHANGE_COMMON_DATA, mCommonData); + mte.receiveClientData(GregTechTileClientEvents.CHANGE_COLOR, mColor); if ((features & COVERS) == COVERS) { mteBlock.receiveCoverData(mte, mC0, mC1, mC2, mC3, mC4, mC5); } if ((features & REDSTONE) == REDSTONE) { - mte.receiveClientEvent(GregTechTileClientEvents.CHANGE_REDSTONE_OUTPUT, mRedstone); + mte.receiveClientData(GregTechTileClientEvents.CHANGE_REDSTONE_OUTPUT, mRedstone); } if ((features & MODES) == MODES && mte instanceof IMultiTileEntity.IMTE_HasModes mteModes) { - mteModes.setMode(mMode); - mteModes.setAllowedModes(mAllowedModes); + mteModes.setMode(mode); + mteModes.setAllowedModes(allowedModes); + } + + if ((features & INVENTORY_NAME_ID) == INVENTORY_NAME_ID && mte instanceof Inventory invUpg) { + invUpg.setInventoryName(mInventoryName); + invUpg.setInventoryId(inventoryID); } if ((features & CONTROLLER) == CONTROLLER && mte instanceof IMultiBlockPart) { @@ -271,10 +292,6 @@ public class GT_Packet_MultiTileEntity extends GT_Packet_New { mtePart.setLockedInventoryIndex(mLockedInventoryIndex); } - if ((features & INVENTORY_NAME) == INVENTORY_NAME && mte instanceof Inventory invUpg) { - invUpg.setInventoryName(mInventoryName); - } - if ((features & BOOLEANS) == BOOLEANS && mte instanceof IMultiTileMachine) { final IMultiTileMachine machine = (IMultiTileMachine) mte; machine.setBooleans(booleans); @@ -287,6 +304,7 @@ public class GT_Packet_MultiTileEntity extends GT_Packet_New { } } catch (Exception e) { + e.printStackTrace(); GT_Mod.GT_FML_LOGGER.error( "Exception setting tile entity data for tile entity {} at ({}, {}, {})", tTileEntity, diff --git a/src/main/java/gregtech/api/objects/GT_ItemStack.java b/src/main/java/gregtech/api/objects/GT_ItemStack.java index 1273b7111d..210f807c5d 100644 --- a/src/main/java/gregtech/api/objects/GT_ItemStack.java +++ b/src/main/java/gregtech/api/objects/GT_ItemStack.java @@ -6,18 +6,20 @@ import net.minecraft.item.ItemStack; import gregtech.api.enums.GT_Values; import gregtech.api.util.GT_Utility; +import gregtech.api.util.item.ItemHolder; /** * An optimization of {@link ItemStack} to have a better {@code hashcode} and {@code equals} in order to improve * {@code HashMap} and {@code Set} performance */ -public class GT_ItemStack { +public class GT_ItemStack extends ItemHolder { public final Item mItem; public final byte mStackSize; public final short mMetaData; public GT_ItemStack(Item aItem, long aStackSize, long aMetaData) { + super(new ItemStack(aItem, 1, (int) aMetaData)); mItem = aItem; mStackSize = (byte) aStackSize; mMetaData = (short) aMetaData; diff --git a/src/main/java/gregtech/api/recipe/check/CheckRecipeResult.java b/src/main/java/gregtech/api/recipe/check/CheckRecipeResult.java index eeb01077de..8af5c58f5e 100644 --- a/src/main/java/gregtech/api/recipe/check/CheckRecipeResult.java +++ b/src/main/java/gregtech/api/recipe/check/CheckRecipeResult.java @@ -1,5 +1,7 @@ package gregtech.api.recipe.check; +import javax.annotation.Nonnull; + import net.minecraft.network.PacketBuffer; /** @@ -13,6 +15,7 @@ public interface CheckRecipeResult { /** * @return Unique registry ID */ + @Nonnull String getID(); /** @@ -23,17 +26,19 @@ public interface CheckRecipeResult { /** * @return Actual text to show on client GUI */ + @Nonnull String getDisplayString(); /** * Create new instance to receive packet. */ + @Nonnull CheckRecipeResult newInstance(); /** * Encode value to sync. */ - void encode(PacketBuffer buffer); + void encode(@Nonnull PacketBuffer buffer); /** * Decode synced value. diff --git a/src/main/java/gregtech/api/recipe/check/CheckRecipeResultRegistry.java b/src/main/java/gregtech/api/recipe/check/CheckRecipeResultRegistry.java index 4c089c7203..e141c39a67 100644 --- a/src/main/java/gregtech/api/recipe/check/CheckRecipeResultRegistry.java +++ b/src/main/java/gregtech/api/recipe/check/CheckRecipeResultRegistry.java @@ -3,6 +3,8 @@ package gregtech.api.recipe.check; import java.util.HashMap; import java.util.Map; +import javax.annotation.Nonnull; + public final class CheckRecipeResultRegistry { private static final Map<String, CheckRecipeResult> registry = new HashMap<>(); @@ -39,14 +41,17 @@ public final class CheckRecipeResultRegistry { /** * Successfully found recipe. */ + @Nonnull public static final CheckRecipeResult SUCCESSFUL = SimpleCheckRecipeResult.ofSuccess("success"); /** * All requirements met to generator power. */ + @Nonnull public static final CheckRecipeResult GENERATING = SimpleCheckRecipeResult.ofSuccess("generating"); /** * Cannot find recipe. */ + @Nonnull public static final CheckRecipeResult NO_RECIPE = SimpleCheckRecipeResult.ofFailure("no_recipe"); /** * Cannot process recipe because item output is full. @@ -59,6 +64,7 @@ public final class CheckRecipeResultRegistry { /** * Default unknown state. */ + @Nonnull public static final CheckRecipeResult NONE = SimpleCheckRecipeResult.ofFailure("none"); /** * Code crashed. @@ -67,26 +73,32 @@ public final class CheckRecipeResultRegistry { /** * Cannot find valid fuel for generator. */ + @Nonnull public static final CheckRecipeResult NO_FUEL_FOUND = SimpleCheckRecipeResult.ofFailure("no_fuel"); /** * Cannot find valid turbine. */ + @Nonnull public static final CheckRecipeResult NO_TURBINE_FOUND = SimpleCheckRecipeResult.ofFailure("no_turbine"); /** * No data sticks found for Assembly Line. */ + @Nonnull public static final CheckRecipeResult NO_DATA_STICKS = SimpleCheckRecipeResult.ofFailure("no_data_sticks"); /** * EU/t overflowed. */ + @Nonnull public static final CheckRecipeResult POWER_OVERFLOW = SimpleCheckRecipeResult.ofFailure("power_overflow"); /** * Progress time overflowed. */ + @Nonnull public static final CheckRecipeResult DURATION_OVERFLOW = SimpleCheckRecipeResult.ofFailure("duration_overflow"); /** * Machine had an internal error */ + @Nonnull public static final CheckRecipeResult INTERNAL_ERROR = SimpleCheckRecipeResult.ofFailure("internal_error"); /** Multiblock ore drill has no drilling fluid */ public static final CheckRecipeResult NO_DRILLING_FLUID = SimpleCheckRecipeResult.ofFailure("no_drilling_fluid"); @@ -99,6 +111,7 @@ public final class CheckRecipeResultRegistry { /** * Cannot process recipe because the machine cannot handle required EUt. */ + @Nonnull public static CheckRecipeResult insufficientPower(long required) { return new ResultInsufficientPower(required); } @@ -106,6 +119,7 @@ public final class CheckRecipeResultRegistry { /** * Cannot process recipe because the machine cannot handle its heat. */ + @Nonnull public static CheckRecipeResult insufficientHeat(int required) { return new ResultInsufficientHeat(required); } @@ -113,6 +127,7 @@ public final class CheckRecipeResultRegistry { /** * Cannot process recipe because the machine is tiered and its tier is too low. */ + @Nonnull public static CheckRecipeResult insufficientMachineTier(int required) { return new ResultInsufficientMachineTier(required); } @@ -120,6 +135,7 @@ public final class CheckRecipeResultRegistry { /** * Cannot process recipe because the machine doesn't have enough startup power. */ + @Nonnull public static CheckRecipeResult insufficientStartupPower(int required) { return new ResultInsufficientStartupPower(required); } diff --git a/src/main/java/gregtech/api/recipe/check/ResultInsufficientHeat.java b/src/main/java/gregtech/api/recipe/check/ResultInsufficientHeat.java index 96c8955130..26c3530ba3 100644 --- a/src/main/java/gregtech/api/recipe/check/ResultInsufficientHeat.java +++ b/src/main/java/gregtech/api/recipe/check/ResultInsufficientHeat.java @@ -1,5 +1,9 @@ package gregtech.api.recipe.check; +import java.util.Objects; + +import javax.annotation.Nonnull; + import net.minecraft.network.PacketBuffer; import net.minecraft.util.StatCollector; @@ -15,6 +19,7 @@ public class ResultInsufficientHeat implements CheckRecipeResult { } @Override + @Nonnull public String getID() { return "insufficient_heat"; } @@ -25,25 +30,28 @@ public class ResultInsufficientHeat implements CheckRecipeResult { } @Override + @Nonnull public String getDisplayString() { - return StatCollector.translateToLocalFormatted( - "GT5U.gui.text.insufficient_heat", - GT_Utility.formatNumbers(required), - HeatingCoilLevel.getDisplayNameFromHeat(required, true)); + return Objects.requireNonNull( + StatCollector.translateToLocalFormatted( + "GT5U.gui.text.insufficient_heat", + GT_Utility.formatNumbers(required), + HeatingCoilLevel.getDisplayNameFromHeat(required, true))); } @Override + @Nonnull public CheckRecipeResult newInstance() { return new ResultInsufficientHeat(0); } @Override - public void encode(PacketBuffer buffer) { + public void encode(@Nonnull PacketBuffer buffer) { buffer.writeVarIntToBuffer(required); } @Override - public void decode(PacketBuffer buffer) { + public void decode(@Nonnull PacketBuffer buffer) { required = buffer.readVarIntFromBuffer(); } diff --git a/src/main/java/gregtech/api/recipe/check/ResultInsufficientMachineTier.java b/src/main/java/gregtech/api/recipe/check/ResultInsufficientMachineTier.java index 1e00e791d1..742eb3ef7a 100644 --- a/src/main/java/gregtech/api/recipe/check/ResultInsufficientMachineTier.java +++ b/src/main/java/gregtech/api/recipe/check/ResultInsufficientMachineTier.java @@ -1,5 +1,9 @@ package gregtech.api.recipe.check; +import java.util.Objects; + +import javax.annotation.Nonnull; + import net.minecraft.network.PacketBuffer; import net.minecraft.util.StatCollector; @@ -14,6 +18,7 @@ public class ResultInsufficientMachineTier implements CheckRecipeResult { } @Override + @Nonnull public String getID() { return "insufficient_machine_tier"; } @@ -24,23 +29,27 @@ public class ResultInsufficientMachineTier implements CheckRecipeResult { } @Override + @Nonnull public String getDisplayString() { - return StatCollector - .translateToLocalFormatted("GT5U.gui.text.insufficient_machine_tier", GT_Utility.formatNumbers(required)); + return Objects.requireNonNull( + StatCollector.translateToLocalFormatted( + "GT5U.gui.text.insufficient_machine_tier", + GT_Utility.formatNumbers(required))); } @Override + @Nonnull public CheckRecipeResult newInstance() { return new ResultInsufficientMachineTier(0); } @Override - public void encode(PacketBuffer buffer) { + public void encode(@Nonnull PacketBuffer buffer) { buffer.writeVarIntToBuffer(required); } @Override - public void decode(PacketBuffer buffer) { + public void decode(@Nonnull PacketBuffer buffer) { required = buffer.readVarIntFromBuffer(); } diff --git a/src/main/java/gregtech/api/recipe/check/ResultInsufficientPower.java b/src/main/java/gregtech/api/recipe/check/ResultInsufficientPower.java index ca6b31ccef..fdc06c0c07 100644 --- a/src/main/java/gregtech/api/recipe/check/ResultInsufficientPower.java +++ b/src/main/java/gregtech/api/recipe/check/ResultInsufficientPower.java @@ -1,5 +1,9 @@ package gregtech.api.recipe.check; +import java.util.Objects; + +import javax.annotation.Nonnull; + import net.minecraft.network.PacketBuffer; import net.minecraft.util.StatCollector; @@ -14,6 +18,7 @@ public class ResultInsufficientPower implements CheckRecipeResult { } @Override + @Nonnull public String getID() { return "insufficient_power"; } @@ -24,25 +29,28 @@ public class ResultInsufficientPower implements CheckRecipeResult { } @Override + @Nonnull public String getDisplayString() { - return StatCollector.translateToLocalFormatted( - "GT5U.gui.text.insufficient_power", - GT_Utility.formatNumbers(required), - GT_Utility.getColoredTierNameFromVoltage(required)); + return Objects.requireNonNull( + StatCollector.translateToLocalFormatted( + "GT5U.gui.text.insufficient_power", + GT_Utility.formatNumbers(required), + GT_Utility.getColoredTierNameFromVoltage(required))); } @Override + @Nonnull public CheckRecipeResult newInstance() { return new ResultInsufficientPower(0); } @Override - public void encode(PacketBuffer buffer) { + public void encode(@Nonnull PacketBuffer buffer) { buffer.writeLong(required); } @Override - public void decode(PacketBuffer buffer) { + public void decode(@Nonnull PacketBuffer buffer) { required = buffer.readLong(); } diff --git a/src/main/java/gregtech/api/recipe/check/ResultInsufficientStartupPower.java b/src/main/java/gregtech/api/recipe/check/ResultInsufficientStartupPower.java index 42b352563d..62d2dd1fb2 100644 --- a/src/main/java/gregtech/api/recipe/check/ResultInsufficientStartupPower.java +++ b/src/main/java/gregtech/api/recipe/check/ResultInsufficientStartupPower.java @@ -1,5 +1,9 @@ package gregtech.api.recipe.check; +import java.util.Objects; + +import javax.annotation.Nonnull; + import net.minecraft.network.PacketBuffer; import net.minecraft.util.StatCollector; @@ -14,6 +18,7 @@ public class ResultInsufficientStartupPower implements CheckRecipeResult { } @Override + @Nonnull public String getID() { return "insufficient_startup_power"; } @@ -24,23 +29,27 @@ public class ResultInsufficientStartupPower implements CheckRecipeResult { } @Override + @Nonnull public String getDisplayString() { - return StatCollector - .translateToLocalFormatted("GT5U.gui.text.insufficient_startup_power", GT_Utility.formatNumbers(required)); + return Objects.requireNonNull( + StatCollector.translateToLocalFormatted( + "GT5U.gui.text.insufficient_startup_power", + GT_Utility.formatNumbers(required))); } @Override + @Nonnull public CheckRecipeResult newInstance() { return new ResultInsufficientStartupPower(0); } @Override - public void encode(PacketBuffer buffer) { + public void encode(@Nonnull PacketBuffer buffer) { buffer.writeVarIntToBuffer(required); } @Override - public void decode(PacketBuffer buffer) { + public void decode(@Nonnull PacketBuffer buffer) { required = buffer.readVarIntFromBuffer(); } diff --git a/src/main/java/gregtech/api/recipe/check/SimpleCheckRecipeResult.java b/src/main/java/gregtech/api/recipe/check/SimpleCheckRecipeResult.java index ed4c95f880..58c85bbe9d 100644 --- a/src/main/java/gregtech/api/recipe/check/SimpleCheckRecipeResult.java +++ b/src/main/java/gregtech/api/recipe/check/SimpleCheckRecipeResult.java @@ -2,6 +2,8 @@ package gregtech.api.recipe.check; import java.util.Objects; +import javax.annotation.Nonnull; + import net.minecraft.network.PacketBuffer; import net.minecraft.util.StatCollector; @@ -33,24 +35,26 @@ public class SimpleCheckRecipeResult implements CheckRecipeResult { } @Override + @Nonnull public String getDisplayString() { - return StatCollector.translateToLocal("GT5U.gui.text." + key); + return Objects.requireNonNull(StatCollector.translateToLocal("GT5U.gui.text." + key)); } @Override + @Nonnull public CheckRecipeResult newInstance() { return new SimpleCheckRecipeResult(false, "", false); } @Override - public void encode(PacketBuffer buffer) { + public void encode(@Nonnull PacketBuffer buffer) { buffer.writeBoolean(success); NetworkUtils.writeStringSafe(buffer, key); buffer.writeBoolean(persistsOnShutdown); } @Override - public void decode(PacketBuffer buffer) { + public void decode(@Nonnull PacketBuffer buffer) { success = buffer.readBoolean(); key = NetworkUtils.readStringSafe(buffer); persistsOnShutdown = buffer.readBoolean(); @@ -74,6 +78,7 @@ public class SimpleCheckRecipeResult implements CheckRecipeResult { * Creates new result with successful state. Add your localized description with `GT5U.gui.text.{key}`. * This is already registered to registry. */ + @Nonnull public static CheckRecipeResult ofSuccess(String key) { return new SimpleCheckRecipeResult(true, key, false); } @@ -82,6 +87,7 @@ public class SimpleCheckRecipeResult implements CheckRecipeResult { * Creates new result with failed state. Add your localized description with `GT5U.gui.text.{key}`. * This is already registered to registry. */ + @Nonnull public static CheckRecipeResult ofFailure(String key) { return new SimpleCheckRecipeResult(false, key, false); } diff --git a/src/main/java/gregtech/api/task/TaskHost.java b/src/main/java/gregtech/api/task/TaskHost.java new file mode 100644 index 0000000000..d6377949c1 --- /dev/null +++ b/src/main/java/gregtech/api/task/TaskHost.java @@ -0,0 +1,18 @@ +package gregtech.api.task; + +import javax.annotation.Nonnull; + +import org.jetbrains.annotations.ApiStatus; + +/** + * Classes implementing this interface can have {@link TickableTask} to run. Tasks with conflicting name should not be + * allowed, to prevent them from overwriting others' NBT load/save. + */ +public interface TaskHost { + + /** + * This method should be called ONLY by {@link TickableTask} constructor. + */ + @ApiStatus.OverrideOnly + void registerTask(@Nonnull TickableTask<?> task); +} diff --git a/src/main/java/gregtech/api/task/TickableTask.java b/src/main/java/gregtech/api/task/TickableTask.java new file mode 100644 index 0000000000..3bbeb216e7 --- /dev/null +++ b/src/main/java/gregtech/api/task/TickableTask.java @@ -0,0 +1,48 @@ +package gregtech.api.task; + +import javax.annotation.Nonnull; + +import net.minecraft.nbt.NBTTagCompound; + +/** + * This class aims at separating logic run on {@link TaskHost}, rather than using interface layers. + * It has two main functionalities: Run tick and Save/Load. + * + * @param <T> Type of the host + */ +public abstract class TickableTask<T extends TaskHost> { + + @Nonnull + protected final T taskHost; + + public TickableTask(@Nonnull T taskHost) { + this.taskHost = taskHost; + taskHost.registerTask(this); + } + + /** + * @return Name of this task. Tasks with conflicting name cannot be registered to the same machine. + */ + @Nonnull + public abstract String getName(); + + /** + * Called once per world tick. + */ + public abstract void update(long tick, boolean isServerSide); + + /** + * Save info to NBT. + */ + public void writeToNBT(@Nonnull NBTTagCompound nbt) {} + + /** + * Read info from NBT. + */ + public void readFromNBT(@Nonnull NBTTagCompound nbt) {} + + @Override + public String toString() { + return "TickableTask{" + "name=" + getName() + ", taskHost=" + taskHost + "}"; + } +} diff --git a/src/main/java/gregtech/api/task/tasks/PollutionTask.java b/src/main/java/gregtech/api/task/tasks/PollutionTask.java new file mode 100644 index 0000000000..060a91acab --- /dev/null +++ b/src/main/java/gregtech/api/task/tasks/PollutionTask.java @@ -0,0 +1,45 @@ +package gregtech.api.task.tasks; + +import javax.annotation.Nonnull; + +import net.minecraft.tileentity.TileEntity; + +import gregtech.api.enums.TickTime; +import gregtech.api.interfaces.tileentity.IMachineProgress; +import gregtech.api.task.TaskHost; +import gregtech.api.task.TickableTask; +import gregtech.common.GT_Pollution; + +public class PollutionTask<T extends TaskHost & IMachineProgress> extends TickableTask<T> { + + private int pollutionPerSecond; + private static final int POLLUTION_TICK = TickTime.SECOND; + + public PollutionTask(@Nonnull T taskHost) { + super(taskHost); + } + + public PollutionTask<T> setPollutionPerSecond(int pollutionPerSecond) { + this.pollutionPerSecond = pollutionPerSecond; + return this; + } + + public int getPollutionPerSecond() { + return pollutionPerSecond; + } + + @Nonnull + @Override + public String getName() { + return "pollution"; + } + + @Override + public void update(long tick, boolean isServerSide) { + if (isServerSide && tick % POLLUTION_TICK == 0 && taskHost.hasThingsToDo()) { + if (taskHost instanceof final TileEntity entity) { + GT_Pollution.addPollution(entity, getPollutionPerSecond()); + } + } + } +} diff --git a/src/main/java/gregtech/api/task/tasks/PowerOutputTask.java b/src/main/java/gregtech/api/task/tasks/PowerOutputTask.java new file mode 100644 index 0000000000..ef800635fb --- /dev/null +++ b/src/main/java/gregtech/api/task/tasks/PowerOutputTask.java @@ -0,0 +1,32 @@ +package gregtech.api.task.tasks; + +import javax.annotation.Nonnull; + +import gregtech.api.interfaces.tileentity.IMachineProgress; +import gregtech.api.logic.interfaces.PowerLogicHost; +import gregtech.api.task.TaskHost; +import gregtech.api.task.TickableTask; + +public class PowerOutputTask<T extends PowerLogicHost & TaskHost & IMachineProgress> extends TickableTask<T> { + + private static final String NAME = "powerOutput"; + + public PowerOutputTask(@Nonnull T taskHost) { + super(taskHost); + } + + @Override + @Nonnull + public String getName() { + return NAME; + } + + @Override + public void update(long tick, boolean isServerSide) { + if (!isServerSide) return; + if (!taskHost.isActive()) return; + if (!taskHost.isEnergyEmitter()) return; + taskHost.emitEnergyFromLogic(); + } + +} diff --git a/src/main/java/gregtech/api/task/tasks/ProcessingTask.java b/src/main/java/gregtech/api/task/tasks/ProcessingTask.java new file mode 100644 index 0000000000..410c8d7a6f --- /dev/null +++ b/src/main/java/gregtech/api/task/tasks/ProcessingTask.java @@ -0,0 +1,51 @@ +package gregtech.api.task.tasks; + +import javax.annotation.Nonnull; + +import gregtech.api.interfaces.tileentity.IMachineProgress; +import gregtech.api.logic.MuTEProcessingLogic; +import gregtech.api.logic.interfaces.ProcessingLogicHost; +import gregtech.api.task.TaskHost; +import gregtech.api.task.TickableTask; + +public class ProcessingTask<T extends TaskHost & ProcessingLogicHost<P> & IMachineProgress, P extends MuTEProcessingLogic<P>> + extends TickableTask<T> { + + public ProcessingTask(@Nonnull T taskHost) { + super(taskHost); + } + + private static final String NAME = "processing"; + + @Override + @Nonnull + public String getName() { + return NAME; + } + + @Override + public void update(long tick, boolean isServerSide) { + if (!isServerSide) return; + if (!taskHost.isAllowedToWork()) return; + final P logic = taskHost.getProcessingLogic(); + if (taskHost.needsUpdate()) { + taskHost.updateProcessingLogic(logic); + taskHost.setProcessingUpdate(false); + } + if (logic.canWork() && tick % 100 == 0) { + taskHost.setProcessingLogicPower(logic); + logic.startCheck(); + if (logic.getResult() + .wasSuccessful()) { + taskHost.setActive(true); + } + } + + if (taskHost.hasThingsToDo()) { + logic.progress(); + } else { + taskHost.setActive(false); + } + } + +} diff --git a/src/main/java/gregtech/api/util/GT_OverclockCalculator.java b/src/main/java/gregtech/api/util/GT_OverclockCalculator.java index 8e896fd8de..1b8748237d 100644 --- a/src/main/java/gregtech/api/util/GT_OverclockCalculator.java +++ b/src/main/java/gregtech/api/util/GT_OverclockCalculator.java @@ -152,6 +152,7 @@ public class GT_OverclockCalculator { /** * @param recipeEUt Sets the Recipe's starting voltage */ + @Nonnull public GT_OverclockCalculator setRecipeEUt(long recipeEUt) { this.recipeVoltage = recipeEUt; return this; @@ -160,6 +161,7 @@ public class GT_OverclockCalculator { /** * @param machineVoltage Sets the EUt that the machine can use. This is the voltage of the machine */ + @Nonnull public GT_OverclockCalculator setEUt(long machineVoltage) { this.machineVoltage = machineVoltage; return this; @@ -168,6 +170,7 @@ public class GT_OverclockCalculator { /** * @param duration Sets the duration of the recipe */ + @Nonnull public GT_OverclockCalculator setDuration(int duration) { this.duration = duration; return this; @@ -176,6 +179,7 @@ public class GT_OverclockCalculator { /** * @param machineAmperage Sets the Amperage that the machine can support */ + @Nonnull public GT_OverclockCalculator setAmperage(long machineAmperage) { this.machineAmperage = machineAmperage; return this; @@ -184,6 +188,7 @@ public class GT_OverclockCalculator { /** * @param recipeAmperage Sets the Amperage of the recipe */ + @Nonnull public GT_OverclockCalculator setRecipeAmperage(long recipeAmperage) { this.recipeAmperage = recipeAmperage; return this; @@ -192,6 +197,7 @@ public class GT_OverclockCalculator { /** * Enables Perfect OC in calculation */ + @Nonnull public GT_OverclockCalculator enablePerfectOC() { this.durationDecreasePerOC = 2; return this; @@ -200,6 +206,7 @@ public class GT_OverclockCalculator { /** * Set if we should be calculating overclocking using EBF's perfectOC */ + @Nonnull public GT_OverclockCalculator setHeatOC(boolean heatOC) { this.heatOC = heatOC; return this; @@ -208,6 +215,7 @@ public class GT_OverclockCalculator { /** * Sets if we should add a heat discount at the end of calculating an overclock, just like the EBF */ + @Nonnull public GT_OverclockCalculator setHeatDiscount(boolean heatDiscount) { this.heatDiscount = heatDiscount; return this; @@ -216,6 +224,7 @@ public class GT_OverclockCalculator { /** * Sets the starting heat of the recipe */ + @Nonnull public GT_OverclockCalculator setRecipeHeat(int recipeHeat) { this.recipeHeat = recipeHeat; return this; @@ -224,6 +233,7 @@ public class GT_OverclockCalculator { /** * Sets the heat of the coils on the machine */ + @Nonnull public GT_OverclockCalculator setMachineHeat(int machineHeat) { this.machineHeat = machineHeat; return this; @@ -232,6 +242,7 @@ public class GT_OverclockCalculator { /** * Sets an EUtDiscount. 0.9 is 10% less energy. 1.1 is 10% more energy */ + @Nonnull public GT_OverclockCalculator setEUtDiscount(float aEUtDiscount) { this.eutDiscount = aEUtDiscount; return this; @@ -240,6 +251,7 @@ public class GT_OverclockCalculator { /** * Sets a Speed Boost for the multiblock. 0.9 is 10% faster. 1.1 is 10% slower */ + @Nonnull public GT_OverclockCalculator setSpeedBoost(float aSpeedBoost) { this.speedBoost = aSpeedBoost; return this; @@ -248,6 +260,7 @@ public class GT_OverclockCalculator { /** * Sets the parallel that the multiblock uses */ + @Nonnull public GT_OverclockCalculator setParallel(int aParallel) { this.parallel = aParallel; return this; @@ -257,6 +270,7 @@ public class GT_OverclockCalculator { * Sets the heat discount during OC calculation if HeatOC is used. Default: 0.95 = 5% discount Used like a EU/t * Discount */ + @Nonnull public GT_OverclockCalculator setHeatDiscountMultiplier(float heatDiscountExponent) { this.heatDiscountExponent = heatDiscountExponent; return this; @@ -266,6 +280,7 @@ public class GT_OverclockCalculator { * Sets the Overclock that should be calculated when one. This uses BitShifting! Default is 2, which is a 4x * decrease */ + @Nonnull public GT_OverclockCalculator setHeatPerfectOC(int heatPerfectOC) { this.durationDecreasePerHeatOC = heatPerfectOC; return this; @@ -274,6 +289,7 @@ public class GT_OverclockCalculator { /** * Sets the amount that the EUt increases per overclock. This uses BitShifting! Default is 2, which is a 4x increase */ + @Nonnull public GT_OverclockCalculator setEUtIncreasePerOC(int aEUtIncreasePerOC) { this.eutIncreasePerOC = aEUtIncreasePerOC; return this; @@ -283,6 +299,7 @@ public class GT_OverclockCalculator { * Sets the amount that the duration decreases per overclock. This uses BitShifting! Default is 1, which halves the * duration */ + @Nonnull public GT_OverclockCalculator setDurationDecreasePerOC(int durationDecreasePerOC) { this.durationDecreasePerOC = durationDecreasePerOC; return this; @@ -292,6 +309,7 @@ public class GT_OverclockCalculator { * Set One Tick Discount on EUt based on Duration Decrease Per Overclock. This functions the same as single * blocks. */ + @Nonnull public GT_OverclockCalculator setOneTickDiscount(boolean oneTickDiscount) { this.oneTickDiscount = oneTickDiscount; return this; @@ -301,22 +319,26 @@ public class GT_OverclockCalculator { * Limit the amount of overclocks that can be performed, regardless of how much power is available. Mainly used for * fusion reactors. */ + @Nonnull public GT_OverclockCalculator limitOverclockCount(int maxOverclocks) { this.limitOverclocks = true; this.maxOverclocks = maxOverclocks; return this; } + @Nonnull public GT_OverclockCalculator setLaserOC(boolean laserOC) { this.laserOC = laserOC; return this; } + @Nonnull public GT_OverclockCalculator setAmperageOC(boolean amperageOC) { this.amperageOC = amperageOC; return this; } + @Nonnull public GT_OverclockCalculator setLaserOCPenalty(double laserOCPenalty) { this.laserOCPenalty = laserOCPenalty; return this; @@ -325,6 +347,7 @@ public class GT_OverclockCalculator { /** * Set a supplier for calculating custom duration for when its needed under one tick */ + @Nonnull public GT_OverclockCalculator setDurationUnderOneTickSupplier(Supplier<Double> supplier) { this.durationUnderOneTickSupplier = supplier; return this; @@ -333,6 +356,7 @@ public class GT_OverclockCalculator { /** * Sets if we should do overclocking or not */ + @Nonnull public GT_OverclockCalculator setNoOverclock(boolean noOverclock) { this.noOverclock = noOverclock; return this; @@ -341,6 +365,7 @@ public class GT_OverclockCalculator { /** * Call this when all values have been put it. */ + @Nonnull public GT_OverclockCalculator calculate() { if (calculated) { throw new IllegalStateException("Tried to calculate overclocks twice"); diff --git a/src/main/java/gregtech/api/util/GT_ParallelHelper.java b/src/main/java/gregtech/api/util/GT_ParallelHelper.java index 6ec736b15f..ff739664f4 100644 --- a/src/main/java/gregtech/api/util/GT_ParallelHelper.java +++ b/src/main/java/gregtech/api/util/GT_ParallelHelper.java @@ -13,6 +13,8 @@ import net.minecraftforge.fluids.FluidStack; import gregtech.api.interfaces.tileentity.IRecipeLockable; import gregtech.api.interfaces.tileentity.IVoidable; +import gregtech.api.logic.FluidInventoryLogic; +import gregtech.api.logic.ItemInventoryLogic; import gregtech.api.objects.XSTR; import gregtech.api.recipe.RecipeMap; import gregtech.api.recipe.check.CheckRecipeResult; @@ -61,6 +63,14 @@ public class GT_ParallelHelper { */ private ItemStack[] itemInputs; /** + * The inputs of the machine for current recipe check + */ + private ItemInventoryLogic itemInputInventory; + /** + * The output item inventory of the machine + */ + private ItemInventoryLogic itemOutputInventory; + /** * The outputs of the recipe with the applied parallel */ private ItemStack[] itemOutputs; @@ -69,6 +79,14 @@ public class GT_ParallelHelper { */ private FluidStack[] fluidInputs; /** + * The inputs of the machine for the current recipe check + */ + private FluidInventoryLogic fluidInputInventory; + /** + * The output fluid inventory of the machine; + */ + private FluidInventoryLogic fluidOutputInventory; + /** * The outputs of the recipe with the applied parallel */ private FluidStack[] fluidOutputs; @@ -117,18 +135,25 @@ public class GT_ParallelHelper { * Calculator to use for overclocking */ private GT_OverclockCalculator calculator; - + @Nonnull private CheckRecipeResult result = CheckRecipeResultRegistry.NONE; private Function<Integer, ItemStack[]> customItemOutputCalculation; private Function<Integer, FluidStack[]> customFluidOutputCalculation; + /** + * MuTE Mode this is a mode for changing how the GT_ParallelHelper works as Mutes don't use ItemStack and FluidStack + * arrays for inputs + */ + private boolean muteMode = false; + public GT_ParallelHelper() {} /** * Sets machine, with current configuration for void protection mode. */ + @Nonnull public GT_ParallelHelper setMachine(IVoidable machine) { return setMachine(machine, machine.protectsExcessItem(), machine.protectsExcessFluid()); } @@ -136,6 +161,7 @@ public class GT_ParallelHelper { /** * Sets machine, with void protection mode forcibly. */ + @Nonnull public GT_ParallelHelper setMachine(IVoidable machine, boolean protectExcessItem, boolean protectExcessFluid) { this.protectExcessItem = protectExcessItem; this.protectExcessFluid = protectExcessFluid; @@ -146,11 +172,13 @@ public class GT_ParallelHelper { /** * Sets the recipe, which will be used for the parallel calculation */ + @Nonnull public GT_ParallelHelper setRecipe(@Nonnull GT_Recipe aRecipe) { recipe = Objects.requireNonNull(aRecipe); return this; } + @Nonnull public GT_ParallelHelper setRecipeLocked(IRecipeLockable singleRecipeMachine, boolean isRecipeLocked) { this.singleRecipeMachine = singleRecipeMachine; this.isRecipeLocked = isRecipeLocked; @@ -160,6 +188,7 @@ public class GT_ParallelHelper { /** * Sets the items available for the recipe check */ + @Nonnull public GT_ParallelHelper setItemInputs(ItemStack... aItemInputs) { this.itemInputs = aItemInputs; return this; @@ -168,6 +197,7 @@ public class GT_ParallelHelper { /** * Sets the fluid inputs available for the recipe check */ + @Nonnull public GT_ParallelHelper setFluidInputs(FluidStack... aFluidInputs) { this.fluidInputs = aFluidInputs; return this; @@ -176,6 +206,7 @@ public class GT_ParallelHelper { /** * Sets the available eut when trying for more parallels */ + @Nonnull public GT_ParallelHelper setAvailableEUt(long aAvailableEUt) { this.availableEUt = aAvailableEUt; return this; @@ -184,11 +215,13 @@ public class GT_ParallelHelper { /** * Sets the modifier for recipe eut. 1 does nothing 0.9 is 10% less. 1.1 is 10% more */ + @Nonnull public GT_ParallelHelper setEUtModifier(float aEUtModifier) { this.eutModifier = aEUtModifier; return this; } + @Nonnull public GT_ParallelHelper setCalculator(GT_OverclockCalculator calculator) { this.calculator = calculator; return this; @@ -199,6 +232,7 @@ public class GT_ParallelHelper { * * @param consume Should we consume inputs */ + @Nonnull public GT_ParallelHelper setConsumption(boolean consume) { this.consume = consume; return this; @@ -207,6 +241,7 @@ public class GT_ParallelHelper { /** * Sets the MaxParallel a multi can handle */ + @Nonnull public GT_ParallelHelper setMaxParallel(int maxParallel) { this.maxParallel = maxParallel; return this; @@ -216,6 +251,7 @@ public class GT_ParallelHelper { * Enables Batch mode. Can do up to an additional processed recipes of mCurrentParallel * mBatchModifier A batch * modifier of 1 does nothing */ + @Nonnull public GT_ParallelHelper enableBatchMode(int batchModifier) { this.batchMode = batchModifier > 1; this.batchModifier = batchModifier; @@ -227,6 +263,7 @@ public class GT_ParallelHelper { * * @param calculateOutputs Should we calculate outputs with the helper or not */ + @Nonnull public GT_ParallelHelper setOutputCalculation(boolean calculateOutputs) { this.calculateOutputs = calculateOutputs; return this; @@ -236,6 +273,7 @@ public class GT_ParallelHelper { * Set a custom way to calculate item outputs. You are given the amount of parallels and must return an ItemStack * array */ + @Nonnull public GT_ParallelHelper setCustomItemOutputCalculation(Function<Integer, ItemStack[]> custom) { customItemOutputCalculation = custom; return this; @@ -245,11 +283,30 @@ public class GT_ParallelHelper { * Set a custom way to calculate item outputs. You are given the amount of parallels and must return a FluidStack * array */ + @Nonnull public GT_ParallelHelper setCustomFluidOutputCalculation(Function<Integer, FluidStack[]> custom) { customFluidOutputCalculation = custom; return this; } + @Nonnull + public GT_ParallelHelper setMuTEMode(boolean muteMode) { + this.muteMode = muteMode; + return this; + } + + @Nonnull + public GT_ParallelHelper setItemInputInventory(ItemInventoryLogic itemInputInventory) { + this.itemInputInventory = itemInputInventory; + return this; + } + + @Nonnull + public GT_ParallelHelper setFluidInputInventory(FluidInventoryLogic fluidInputInventory) { + this.fluidInputInventory = fluidInputInventory; + return this; + } + /** * Sets method for calculating max parallel from given inputs. */ @@ -266,9 +323,22 @@ public class GT_ParallelHelper { return this; } + @Nonnull + public GT_ParallelHelper setItemOutputInventory(ItemInventoryLogic itemOutputInventory) { + this.itemOutputInventory = itemOutputInventory; + return this; + } + + @Nonnull + public GT_ParallelHelper setFluidOutputInventory(FluidInventoryLogic fluidOutputInventory) { + this.fluidOutputInventory = fluidOutputInventory; + return this; + } + /** * Finishes the GT_ParallelHelper. Anything changed after this will not effect anything */ + @Nonnull public GT_ParallelHelper build() { if (built) { throw new IllegalStateException("Tried to build twice"); @@ -407,7 +477,7 @@ public class GT_ParallelHelper { // Let's look at how many parallels we can get with void protection if (protectExcessItem || protectExcessFluid) { - if (machine == null) { + if (machine == null && !muteMode) { throw new IllegalStateException("Tried to calculate void protection, but machine is not set"); } VoidProtectionHelper voidProtectionHelper = new VoidProtectionHelper(); @@ -415,6 +485,9 @@ public class GT_ParallelHelper { .setItemOutputs(truncatedItemOutputs) .setFluidOutputs(truncatedFluidOutputs) .setMaxParallel(maxParallel) + .setItemOutputInventory(itemOutputInventory) + .setFluidOutputInventory(fluidOutputInventory) + .setMuTEMode(muteMode) .build(); maxParallel = Math.min(voidProtectionHelper.getMaxParallel(), maxParallel); if (voidProtectionHelper.isItemFull()) { diff --git a/src/main/java/gregtech/api/util/GT_Recipe.java b/src/main/java/gregtech/api/util/GT_Recipe.java index 159ac1bbd1..0e4ef2162d 100644 --- a/src/main/java/gregtech/api/util/GT_Recipe.java +++ b/src/main/java/gregtech/api/util/GT_Recipe.java @@ -7,6 +7,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -23,6 +24,8 @@ import gregtech.GT_Mod; import gregtech.api.GregTech_API; import gregtech.api.enums.ItemList; import gregtech.api.enums.Materials; +import gregtech.api.logic.FluidInventoryLogic; +import gregtech.api.logic.ItemInventoryLogic; import gregtech.api.objects.GT_ItemStack; import gregtech.api.recipe.RecipeCategory; import gregtech.api.recipe.RecipeMap; @@ -31,6 +34,7 @@ import gregtech.api.recipe.RecipeMetadataKey; import gregtech.api.recipe.metadata.EmptyRecipeMetadataStorage; import gregtech.api.recipe.metadata.IRecipeMetadataStorage; import gregtech.api.util.extensions.ArrayExt; +import gregtech.api.util.item.ItemHolder; import ic2.core.Ic2Items; public class GT_Recipe implements Comparable<GT_Recipe> { @@ -548,6 +552,60 @@ public class GT_Recipe implements Comparable<GT_Recipe> { return currentParallel; } + public boolean isRecipePossible(@Nullable ItemInventoryLogic itemInput, @Nullable FluidInventoryLogic fluidInput) { + return getAmountOfRecipesDone(itemInput, fluidInput, 1, true) > 0; + } + + public long getAmountOfRecipesDone(@Nullable ItemInventoryLogic itemInput, @Nullable FluidInventoryLogic fluidInput, + long maxParallel, boolean simulate) { + if (itemInput == null) { + itemInput = new ItemInventoryLogic(0); + } + + if (fluidInput == null) { + fluidInput = new FluidInventoryLogic(0, 0); + } + + itemInput.startRecipeCheck(); + Map<ItemHolder, Long> recipeItems = getItemInputsAsItemMap(); + for (Entry<ItemHolder, Long> entry : recipeItems.entrySet()) { + maxParallel = Math + .min(maxParallel, itemInput.calculateAmountOfTimesItemCanBeTaken(entry.getKey(), entry.getValue())); + } + + for (FluidStack fluid : mFluidInputs) { + if (fluid == null) continue; + maxParallel = Math + .min(maxParallel, fluidInput.calculateAmountOfTimesFluidCanBeTaken(fluid.getFluid(), fluid.amount)); + } + + if (simulate) { + itemInput.stopRecipeCheck(); + return maxParallel; + } + + for (Entry<ItemHolder, Long> entry : recipeItems.entrySet()) { + itemInput.subtractItemAmount(entry.getKey(), entry.getValue() * maxParallel, false); + } + + for (FluidStack fluid : mFluidInputs) { + if (fluid == null) continue; + fluidInput.drain(fluid.getFluid(), fluid.amount * maxParallel, false); + } + itemInput.stopRecipeCheck(); + return maxParallel; + } + + private Map<ItemHolder, Long> getItemInputsAsItemMap() { + Map<ItemHolder, Long> items = new HashMap<>(); + for (ItemStack item : mInputs) { + if (item == null) continue; + ItemHolder itemHolder = new ItemHolder(item); + items.put(itemHolder, items.getOrDefault(itemHolder, 0L) + item.stackSize); + } + return items; + } + @Override public int compareTo(GT_Recipe recipe) { // first lowest tier recipes @@ -720,6 +778,25 @@ public class GT_Recipe implements Comparable<GT_Recipe> { return this; } + @Override + public boolean equals(Object other) { + if (other == this) return true; + if (!(other instanceof GT_Recipe recipe)) return false; + for (int i = 0; i < Math.min(mInputs.length, recipe.mInputs.length); i++) { + if (mInputs[i] == null && recipe.mInputs[i] == null) continue; + if (mInputs[i] == null || recipe.mInputs[i] == null) return false; + ItemHolder currentIH = new ItemHolder(mInputs[i]); + ItemHolder otherIH = new ItemHolder(recipe.mInputs[i]); + if (!currentIH.equals(otherIH)) return false; + } + for (int i = 0; i < Math.min(mFluidInputs.length, recipe.mFluidInputs.length); i++) { + if (mFluidInputs[i] == null && recipe.mFluidInputs[i] == null) continue; + if (mFluidInputs[i] == null || recipe.mFluidInputs[i] == null) return false; + if (!FluidStack.areFluidStackTagsEqual(mFluidInputs[i], recipe.mFluidInputs[i])) return false; + } + return mDuration == recipe.mDuration && mEUt == recipe.mEUt && mSpecialValue == recipe.mSpecialValue; + } + public static class GT_Recipe_AssemblyLine { public static final ArrayList<GT_Recipe_AssemblyLine> sAssemblylineRecipes = new ArrayList<>(); diff --git a/src/main/java/gregtech/api/util/GT_StructureUtilityMuTE.java b/src/main/java/gregtech/api/util/GT_StructureUtilityMuTE.java new file mode 100644 index 0000000000..8e8d027463 --- /dev/null +++ b/src/main/java/gregtech/api/util/GT_StructureUtilityMuTE.java @@ -0,0 +1,271 @@ +package gregtech.api.util; + +import static gregtech.GT_Mod.GT_FML_LOGGER; +import static gregtech.api.multitileentity.enums.GT_MultiTileComponentCasing.*; +import static gregtech.api.multitileentity.enums.GT_MultiTileUpgradeCasing.*; +import static gregtech.loaders.preload.GT_Loader_MultiTileEntities.*; + +import java.util.Arrays; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; + +import com.gtnewhorizon.structurelib.StructureLibAPI; +import com.gtnewhorizon.structurelib.structure.IStructureElement; + +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.enums.TextureSet; +import gregtech.api.multitileentity.MultiTileEntityContainer; +import gregtech.api.multitileentity.MultiTileEntityRegistry; +import gregtech.api.multitileentity.enums.GT_MultiTileUpgradeCasing; +import gregtech.api.multitileentity.interfaces.IMultiBlockController; +import gregtech.api.multitileentity.interfaces.IMultiTileEntity; +import gregtech.api.multitileentity.multiblock.base.Controller; +import gregtech.api.multitileentity.multiblock.base.MultiBlockPart; + +public class GT_StructureUtilityMuTE { + + public static final MuTEStructureCasing MOTOR_CASINGS = FunctionalCasings.Motor.getCasing(); + public static final MuTEStructureCasing PUMP_CASINGS = FunctionalCasings.Pump.getCasing(); + public static final MuTEStructureCasing CONVEYOR_CASINGS = FunctionalCasings.Conveyor.getCasing(); + public static final MuTEStructureCasing PISTON_CASINGS = FunctionalCasings.Piston.getCasing(); + public static final MuTEStructureCasing ROBOT_ARM_CASINGS = FunctionalCasings.RobotArm.getCasing(); + public static final MuTEStructureCasing EMITTER_CASINGS = FunctionalCasings.Emitter.getCasing(); + public static final MuTEStructureCasing SENSOR_CASINGS = FunctionalCasings.Sensor.getCasing(); + public static final MuTEStructureCasing FIELD_GENERATOR_CASINGS = FunctionalCasings.FieldGenerator.getCasing(); + public static final MuTEStructureCasing INVENTORY_CASINGS = UpgradeCasings.Inventory.getCasing(); + public static final MuTEStructureCasing TANK_CASINGS = UpgradeCasings.Tank.getCasing(); + public static final MuTEStructureCasing AMPERAGE_CASINGS = UpgradeCasings.Amperage.getCasing(); + public static final MuTEStructureCasing LASER_CASINGS = UpgradeCasings.Laser.getCasing(); + public static final MuTEStructureCasing WIRELESS_CASINGS = UpgradeCasings.Wireless.getCasing(); + public static final MuTEStructureCasing CLEANROOM_CASINGS = UpgradeCasings.Cleanroom.getCasing(); + public static final MuTEStructureCasing HEATER_CASINGS = UpgradeCasings.Heater.getCasing(); + public static final MuTEStructureCasing INSULATOR_CASINGS = UpgradeCasings.Insulator.getCasing(); + + public enum FunctionalCasings { + + Motor(COMPONENT_CASING_REGISTRY_NAME, LV_Motor.getId(), MV_Motor.getId(), HV_Motor.getId(), EV_Motor.getId(), + IV_Motor.getId(), LuV_Motor.getId(), ZPM_Motor.getId(), UV_Motor.getId(), UHV_Motor.getId(), + UEV_Motor.getId(), UIV_Motor.getId(), UMV_Motor.getId(), UXV_Motor.getId(), MAX_Motor.getId()), + + Pump(COMPONENT_CASING_REGISTRY_NAME, LV_Pump.getId(), MV_Pump.getId(), HV_Pump.getId(), EV_Pump.getId(), + IV_Pump.getId(), LuV_Pump.getId(), ZPM_Pump.getId(), UV_Pump.getId(), UHV_Pump.getId(), UEV_Pump.getId(), + UIV_Pump.getId(), UMV_Pump.getId(), UXV_Pump.getId(), MAX_Pump.getId()), + + Conveyor(COMPONENT_CASING_REGISTRY_NAME, LV_Conveyor.getId(), MV_Conveyor.getId(), HV_Conveyor.getId(), + EV_Conveyor.getId(), IV_Conveyor.getId(), LuV_Conveyor.getId(), ZPM_Conveyor.getId(), UV_Conveyor.getId(), + UHV_Conveyor.getId(), UEV_Conveyor.getId(), UIV_Conveyor.getId(), UMV_Conveyor.getId(), + UXV_Conveyor.getId(), MAX_Conveyor.getId()), + + Piston(COMPONENT_CASING_REGISTRY_NAME, LV_Piston.getId(), MV_Piston.getId(), HV_Piston.getId(), + EV_Piston.getId(), IV_Piston.getId(), LuV_Piston.getId(), ZPM_Piston.getId(), UV_Piston.getId(), + UHV_Piston.getId(), UEV_Piston.getId(), UIV_Piston.getId(), UMV_Piston.getId(), UXV_Piston.getId(), + MAX_Piston.getId()), + + RobotArm(COMPONENT_CASING_REGISTRY_NAME, LV_RobotArm.getId(), MV_RobotArm.getId(), HV_RobotArm.getId(), + EV_RobotArm.getId(), IV_RobotArm.getId(), LuV_RobotArm.getId(), ZPM_RobotArm.getId(), UV_RobotArm.getId(), + UHV_RobotArm.getId(), UEV_RobotArm.getId(), UIV_RobotArm.getId(), UMV_RobotArm.getId(), + UXV_RobotArm.getId(), MAX_RobotArm.getId()), + + Emitter(COMPONENT_CASING_REGISTRY_NAME, LV_Emitter.getId(), MV_Emitter.getId(), HV_Emitter.getId(), + EV_Emitter.getId(), IV_Emitter.getId(), LuV_Emitter.getId(), ZPM_Emitter.getId(), UV_Emitter.getId(), + UHV_Emitter.getId(), UEV_Emitter.getId(), UIV_Emitter.getId(), UMV_Emitter.getId(), UXV_Emitter.getId(), + MAX_Emitter.getId()), + + Sensor(COMPONENT_CASING_REGISTRY_NAME, LV_Sensor.getId(), MV_Sensor.getId(), HV_Sensor.getId(), + EV_Sensor.getId(), IV_Sensor.getId(), LuV_Sensor.getId(), ZPM_Sensor.getId(), UV_Sensor.getId(), + UHV_Sensor.getId(), UEV_Sensor.getId(), UIV_Sensor.getId(), UMV_Sensor.getId(), UXV_Sensor.getId(), + MAX_Sensor.getId()), + + FieldGenerator(COMPONENT_CASING_REGISTRY_NAME, LV_FieldGenerator.getId(), MV_FieldGenerator.getId(), + HV_FieldGenerator.getId(), EV_FieldGenerator.getId(), IV_FieldGenerator.getId(), LuV_FieldGenerator.getId(), + ZPM_FieldGenerator.getId(), UV_FieldGenerator.getId(), UHV_FieldGenerator.getId(), + UEV_FieldGenerator.getId(), UIV_FieldGenerator.getId(), UMV_FieldGenerator.getId(), + UXV_FieldGenerator.getId(), MAX_FieldGenerator.getId()); + + private final MuTEStructureCasing casing; + + FunctionalCasings(String registryName, Integer... validIds) { + casing = createMuTEStructureCasing(registryName, validIds); + } + + public MuTEStructureCasing getCasing() { + return casing; + } + } + + public enum UpgradeCasings { + + Inventory(UPGRADE_CASING_REGISTRY_NAME, ULV_Inventory.getId(), LV_Inventory.getId(), MV_Inventory.getId(), + HV_Inventory.getId(), EV_Inventory.getId(), IV_Inventory.getId(), LuV_Inventory.getId(), + ZPM_Inventory.getId(), UV_Inventory.getId(), UHV_Inventory.getId(), UEV_Inventory.getId(), + UIV_Inventory.getId(), UMV_Inventory.getId(), UXV_Inventory.getId(), MAX_Inventory.getId()), + + Tank(UPGRADE_CASING_REGISTRY_NAME, ULV_Tank.getId(), LV_Tank.getId(), MV_Tank.getId(), HV_Tank.getId(), + EV_Tank.getId(), IV_Tank.getId(), LuV_Tank.getId(), ZPM_Tank.getId(), UV_Tank.getId(), UHV_Tank.getId(), + UEV_Tank.getId(), UIV_Tank.getId(), UMV_Tank.getId(), UXV_Tank.getId(), MAX_Tank.getId()), + + Amperage(UPGRADE_CASING_REGISTRY_NAME, Amp_4.getId(), Amp_16.getId(), Amp_64.getId(), Amp_256.getId(), + Amp_1_024.getId(), Amp_4_096.getId(), Amp_16_384.getId(), Amp_65_536.getId(), Amp_262_144.getId(), + Amp_1_048_576.getId()), + + Laser(UPGRADE_CASING_REGISTRY_NAME, GT_MultiTileUpgradeCasing.Laser.getId()), + + Wireless(UPGRADE_CASING_REGISTRY_NAME, GT_MultiTileUpgradeCasing.Wireless.getId()), + + Cleanroom(UPGRADE_CASING_REGISTRY_NAME, GT_MultiTileUpgradeCasing.Cleanroom.getId()), + + Heater(UPGRADE_CASING_REGISTRY_NAME, Heater_Prototype.getId(), Heater_IndustrialGrade.getId(), + Heater_NextGen.getId(), Heater_Omnipotent.getId(), Heater_OmegaType.getId()), + + Insulator(UPGRADE_CASING_REGISTRY_NAME, Insulator_Prototype.getId(), Insulator_IndustrialGrade.getId(), + Insulator_NextGen.getId(), Insulator_Omnipotent.getId(), Insulator_OmegaType.getId()); + + private final MuTEStructureCasing casing; + + UpgradeCasings(String registryName, Integer... validIds) { + casing = createMuTEStructureCasing(registryName, validIds); + } + + public MuTEStructureCasing getCasing() { + return casing; + } + } + + /** + * Specify all casing sets that are valid for a multiblock structure position. The first casing will be used as + * default when doing auto place + * + * @param modes Allowed modes on the casings + * @param validCasings Allowed casing sets + * @return Structure Element + * @param <T> Multiblock class + */ + public static <T> IStructureElement<T> ofMuTECasings(int modes, MuTEStructureCasing... validCasings) { + if (validCasings == null || validCasings.length == 0) { + throw new IllegalArgumentException(); + } + return new IStructureElement<>() { + + final MuTEStructureCasing[] allowedCasings = validCasings; + private final static short[] DEFAULT = new short[] { 255, 255, 255, 0 }; + private static IIcon[] mIcons = null; + + @Override + public boolean check(T t, World world, int x, int y, int z) { + final TileEntity tileEntity = world.getTileEntity(x, y, z); + if (!(tileEntity instanceof MultiBlockPart part)) return false; + + for (MuTEStructureCasing casing : allowedCasings) { + if (casing.isCasingValid(part.getMultiTileEntityRegistryID(), part.getMultiTileEntityID())) { + final IMultiBlockController tTarget = part.getTarget(false); + if (tTarget != null && tTarget != t) return false; + + part.setTarget((IMultiBlockController) t, modes); + + ((Controller<?, ?>) t).registerSpecialCasings(part); + return true; + } + } + + return false; + } + + @Override + public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { + // Moved here from Controller. TODO: Proper implementation + if (mIcons == null) { + mIcons = new IIcon[6]; + Arrays.fill(mIcons, TextureSet.SET_NONE.mTextures[OrePrefixes.block.mTextureIndex].getIcon()); + } + final short[] RGBA = DEFAULT; + StructureLibAPI.hintParticleTinted(world, x, y, z, mIcons, RGBA); + return true; + } + + @Override + public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { + final MultiTileEntityRegistry tRegistry = MultiTileEntityRegistry + .getRegistry(validCasings[0].getRegistryId()); + if (tRegistry == null) { + GT_FML_LOGGER.error("NULL REGISTRY"); + return false; + } + final MultiTileEntityContainer tContainer = tRegistry + .getNewTileEntityContainer(world, x, y, z, validCasings[0].defaultMeta, null); + if (tContainer == null) { + GT_FML_LOGGER.error("NULL CONTAINER"); + return false; + } + final IMultiTileEntity te = ((IMultiTileEntity) tContainer.mTileEntity); + if (!(te instanceof MultiBlockPart)) { + GT_FML_LOGGER.error("Not a multiblock part"); + return false; + } + if (world.setBlock(x, y, z, tContainer.mBlock, 15 - tContainer.mBlockMetaData, 2)) { + tContainer.setMultiTile(world, x, y, z); + ((MultiBlockPart) te).setTarget((IMultiBlockController) t, modes); + + ((Controller<?, ?>) t).registerSpecialCasings((MultiBlockPart) te); + } + + return false; + } + }; + } + + public static MuTEStructureCasing createMuTEStructureCasing(String registryName, Integer... validIds) { + return new MuTEStructureCasing(registryName, validIds); + } + + /** + * Object used to store a set of casings (e.g. all motor casings) + */ + public static class MuTEStructureCasing { + + private String registryName; + private int registryId = GT_Values.W; + private final int defaultMeta; + private final Integer[] validIds; + + public MuTEStructureCasing(String registryName, Integer... validIds) { + MultiTileEntityRegistry registry = MultiTileEntityRegistry.getRegistry(registryName); + if (validIds == null || validIds.length == 0 || registry == null) { + throw new IllegalArgumentException(); + } + this.registryName = registryName; + this.validIds = validIds; + this.defaultMeta = validIds[0]; + } + + public boolean isCasingValid(int registryId, int id) { + if (getRegistryId() != registryId) { + return false; + } + for (Integer validId : validIds) { + if (validId == id) { + return true; + } + } + return false; + } + + public int getDefaultMeta() { + return defaultMeta; + } + + public int getRegistryId() { + // TODO: MuTE registry seems to somehow shift, probably due to NBT shenanigans. Lazy init circumvents this + // but it should be properly fixed in the future + if (registryId == GT_Values.W) { + MultiTileEntityRegistry registry = MultiTileEntityRegistry.getRegistry(registryName); + registryId = Block.getIdFromBlock(registry.mBlock); + } + return registryId; + } + } +} diff --git a/src/main/java/gregtech/api/util/VoidProtectionHelper.java b/src/main/java/gregtech/api/util/VoidProtectionHelper.java index 3a41bba934..245fc24bda 100644 --- a/src/main/java/gregtech/api/util/VoidProtectionHelper.java +++ b/src/main/java/gregtech/api/util/VoidProtectionHelper.java @@ -10,9 +10,12 @@ import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidStack; import com.gtnewhorizon.gtnhlib.util.map.ItemStackMap; +import com.gtnewhorizons.modularui.api.fluids.IFluidTankLong; import gregtech.api.interfaces.fluid.IFluidStore; import gregtech.api.interfaces.tileentity.IVoidable; +import gregtech.api.logic.FluidInventoryLogic; +import gregtech.api.logic.ItemInventoryLogic; /** * Helper class to calculate how many parallels of items / fluids can fit in the output buses / hatches. @@ -52,9 +55,21 @@ public class VoidProtectionHelper { */ private FluidStack[] fluidOutputs; /** + * The item output inventory + */ + private ItemInventoryLogic itemOutputInventory; + /** + * The fluid output inventory + */ + private FluidInventoryLogic fluidOutputInventory; + /** * Has this helper been built? */ private boolean built; + /** + * Is this helper working for a MuTE? + */ + private boolean muteMode; public VoidProtectionHelper() {} @@ -93,6 +108,21 @@ public class VoidProtectionHelper { return this; } + public VoidProtectionHelper setItemOutputInventory(ItemInventoryLogic itemOutputInventory) { + this.itemOutputInventory = itemOutputInventory; + return this; + } + + public VoidProtectionHelper setFluidOutputInventory(FluidInventoryLogic fluidOutputInventory) { + this.fluidOutputInventory = fluidOutputInventory; + return this; + } + + public VoidProtectionHelper setMuTEMode(boolean muteMode) { + this.muteMode = muteMode; + return this; + } + /** * Finishes the VoidProtectionHelper. Anything changed after this will not affect anything */ @@ -241,11 +271,95 @@ public class VoidProtectionHelper { return aParallelQueue.element().batch; } + private int calculateMaxFluidParallelsMuTE() { + if (fluidOutputs.length > fluidOutputInventory.getInventory() + .getTanks()) { + return 0; + } + + // A map to hold the items we will be 'inputting' into the output hatches. These fluidstacks are actually + // the recipe outputs. + Map<FluidStack, Integer> tFluidOutputMap = new HashMap<>(); + + // Map that keeps track of the number of parallel crafts we can accommodate for each fluid output. + // In the pair, we keep track of number of full crafts plus mb of fluid in a partial craft, to avoid + // issues with floating point math not being completely accurate when summing. + Map<FluidStack, ParallelData> tParallels = new HashMap<>(); + + // Iterate over the outputs, calculating require stack spacing they will require. + for (FluidStack aY : fluidOutputs) { + if (aY == null || aY.amount <= 0) { + continue; + } + tFluidOutputMap.merge(aY, aY.amount, Integer::sum); + tParallels.put(aY, new ParallelData(0, 0)); + } + + if (tFluidOutputMap.isEmpty()) { + // nothing to output, bail early + return maxParallel; + } + + for (int i = 0; i < fluidOutputInventory.getInventory() + .getTanks(); i++) { + IFluidTankLong tank = fluidOutputInventory.getInventory() + .getFluidTank(i); + long tSpaceLeft = tank.getCapacityLong() - tank.getFluidAmountLong(); + // check if hatch filled + if (tSpaceLeft <= 0) continue; + // check if hatch is empty and unrestricted + if (tank.getStoredFluid() == null) continue; + + for (Map.Entry<FluidStack, ParallelData> entry : tParallels.entrySet()) { + FluidStack tFluidOutput = entry.getKey(); + if (tank.fill(tFluidOutput.getFluid(), tFluidOutput.amount, false) == tFluidOutput.amount) continue; + // this fluid is not prevented by restrictions on output hatch + ParallelData tParallel = entry.getValue(); + Integer tCraftSize = tFluidOutputMap.get(tFluidOutput); + tParallel.batch += (tParallel.partial + tSpaceLeft) / tCraftSize; + tParallel.partial = (tParallel.partial + tSpaceLeft) % tCraftSize; + } + } + // now that all partial/restricted hatches have been counted, create a priority queue for our outputs + // the lowest priority fluid is the number of complete parallel crafts we can support + PriorityQueue<ParallelStackInfo<FluidStack>> aParallelQueue = new PriorityQueue<>( + Comparator.comparing(i -> i.batch)); + for (Map.Entry<FluidStack, ParallelData> entry : tParallels.entrySet()) { + aParallelQueue + .add(new ParallelStackInfo<>(entry.getValue().batch, entry.getValue().partial, entry.getKey())); + } + // add extra parallels for open slots as well + for (int i = 0; i < fluidOutputInventory.getInventory() + .getTanks(); i++) { + IFluidTankLong tank = fluidOutputInventory.getInventory() + .getFluidTank(i); + // partially filled or restricted hatch. done in the last pass + if (tank.getStoredFluid() != null) continue; + + ParallelStackInfo<FluidStack> tParallel = aParallelQueue.poll(); + assert tParallel != null; // will always be true, specifying assert here to avoid IDE/compiler warnings + Integer tCraftSize = tFluidOutputMap.get(tParallel.stack); + long tSpaceLeft = tank.getCapacityLong(); + tParallel.batch += (tParallel.partial + tSpaceLeft) / tCraftSize; + tParallel.partial = (tParallel.partial + tSpaceLeft) % tCraftSize; + aParallelQueue.add(tParallel); + } + + return aParallelQueue.element().batch; + } + /** * Calculates the max parallels one can do with items if void protection is on */ private int calculateMaxItemParallels() { - List<ItemStack> busStacks = machine.getItemOutputSlots(itemOutputs); + List<ItemStack> busStacks; + + if (muteMode) { + busStacks = itemOutputInventory.getInventory() + .getStacks(); + } else { + busStacks = machine.getItemOutputSlots(itemOutputs); + } // A map to hold the items we will be 'inputting' into the output buses. These itemstacks are actually the // recipe outputs. Map<ItemStack, Integer> tItemOutputMap = new ItemStackMap<>(); @@ -320,9 +434,9 @@ public class VoidProtectionHelper { private static class ParallelData { private int batch; - private int partial; + private long partial; - private ParallelData(int batch, int partial) { + private ParallelData(int batch, long partial) { this.batch = batch; this.partial = partial; } @@ -331,10 +445,10 @@ public class VoidProtectionHelper { private static class ParallelStackInfo<T> { private int batch; - private int partial; + private long partial; private final T stack; - private ParallelStackInfo(int batch, int partial, T stack) { + private ParallelStackInfo(int batch, long partial, T stack) { this.batch = batch; this.partial = partial; this.stack = stack; diff --git a/src/main/java/gregtech/api/util/item/ItemHolder.java b/src/main/java/gregtech/api/util/item/ItemHolder.java new file mode 100644 index 0000000000..4675d0ba0e --- /dev/null +++ b/src/main/java/gregtech/api/util/item/ItemHolder.java @@ -0,0 +1,79 @@ +package gregtech.api.util.item; + +import static net.minecraftforge.oredict.OreDictionary.getOreIDs; + +import java.util.Arrays; + +import javax.annotation.Nonnull; + +import net.minecraft.init.Items; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import gregtech.api.util.GT_Utility; + +public class ItemHolder { + + private final Item item; + private final int meta; + private final NBTTagCompound tag; + private final int[] oreIDs; + + public ItemHolder(@Nonnull ItemStack item) { + this.item = item.getItem(); + this.meta = Items.feather.getDamage(item); + this.tag = item.getTagCompound(); + this.oreIDs = getOreIDs(item); + } + + public Item getItem() { + return item; + } + + public int getMeta() { + return meta; + } + + public NBTTagCompound getNBT() { + return tag; + } + + public int[] getOreDictTagIDs() { + return oreIDs; + } + + @Override + public boolean equals(Object other) { + if (other == this) return true; + if (!(other instanceof ItemHolder otherIH)) return false; + if (Arrays.stream(oreIDs) + .anyMatch(id -> { + for (int i = 0; i < otherIH.getOreDictTagIDs().length; i++) { + if (id == otherIH.getOreDictTagIDs()[i]) return true; + } + return false; + })) { + return true; + } + + if (item != otherIH.getItem() || meta != otherIH.getMeta()) { + return false; + } + if (this.tag == null && otherIH.getNBT() == null) return true; + if (this.tag == null || otherIH.getNBT() == null) return false; + return this.tag.equals(otherIH); + } + + @Override + public int hashCode() { + return GT_Utility.stackToInt(toStack()); + } + + @Nonnull + private ItemStack toStack() { + ItemStack item = new ItemStack(this.item, 1, meta); + item.stackTagCompound = tag; + return item; + } +} diff --git a/src/main/java/gregtech/api/util/recipe/RecipeInputRequirements.java b/src/main/java/gregtech/api/util/recipe/RecipeInputRequirements.java new file mode 100644 index 0000000000..590c104101 --- /dev/null +++ b/src/main/java/gregtech/api/util/recipe/RecipeInputRequirements.java @@ -0,0 +1,77 @@ +package gregtech.api.util.recipe; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Nonnull; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.item.ItemHolder; + +public class RecipeInputRequirements { + + protected Map<ItemHolder, Long> itemInputs = new HashMap<>(); + protected Set<ItemHolder> itemInputsMet = new HashSet<>(); + protected boolean metAllItem = false; + protected Map<Fluid, Long> fluidInputs = new HashMap<>(); + protected Set<Fluid> fluidInputsMet = new HashSet<>(); + protected boolean metAllFluid = false; + + public RecipeInputRequirements(@Nonnull GT_Recipe recipe) { + this(recipe.mInputs, recipe.mFluidInputs); + } + + public RecipeInputRequirements(@Nonnull ItemStack[] itemInputs, @Nonnull FluidStack[] fluidInputs) { + for (ItemStack item : itemInputs) { + if (item == null) continue; + ItemHolder itemIH = new ItemHolder(item); + this.itemInputs.put(itemIH, this.itemInputs.getOrDefault(itemIH, 0L) + item.stackSize); + } + + for (FluidStack fluid : fluidInputs) { + if (fluid == null) continue; + this.fluidInputs.put(fluid.getFluid(), this.fluidInputs.getOrDefault(fluid.getFluid(), 0L) + fluid.amount); + } + } + + /** + * + * @param itemInputs we have and want to fill this request + * @return {@code true} when all item inputs are met + */ + public boolean tryToFillItemRequirements(Map<ItemHolder, Long> itemInputs) { + if (metAllItem) return metAllItem; + for (Entry<ItemHolder, Long> entry : itemInputs.entrySet()) { + if (itemInputsMet.contains(entry.getKey())) continue; + if (!this.itemInputs.containsKey(entry.getKey())) continue; + if (this.itemInputs.get(entry.getKey()) > entry.getValue()) continue; + itemInputsMet.add(entry.getKey()); + } + metAllItem = itemInputsMet.containsAll(this.itemInputs.keySet()); + return metAllItem; + } + + /** + * + * @param fluidInputs we have and want to fill this request + * @return {@code true} when all fluid inputs are met + */ + public boolean tryToFillFluidRequirements(Map<Fluid, Long> fluidInputs) { + if (metAllFluid) return metAllFluid; + for (Entry<Fluid, Long> entry : fluidInputs.entrySet()) { + if (fluidInputsMet.contains(entry.getKey())) continue; + if (!this.fluidInputs.containsKey(entry.getKey())) continue; + if (this.fluidInputs.get(entry.getKey()) > entry.getValue()) continue; + fluidInputsMet.add(entry.getKey()); + } + metAllFluid = fluidInputsMet.containsAll(this.fluidInputs.keySet()); + return metAllFluid; + } +} |