Compare commits

...

235 Commits

Author SHA1 Message Date
PrototypeTrousers 304f394497 cut crafting tree earlier if the item is available
fix job byte size to 8 per crafting + 1 per item used/stored
2021-11-02 15:33:14 -03:00
PrototypeTrousers 50f21125c8 log if non-patterned items go missing before starting a craft 2021-11-02 02:00:01 -03:00
PrototypeTrousers 30b85bd239 potential fix for showing proper item names when failing to start craft 2021-11-01 23:23:45 -03:00
PrototypeTrousers 9ce00d338f only try to extract if its already in the cache 2021-10-29 17:04:24 -03:00
PrototypeTrousers 11f5b71089 update directly instead of relying on forge events 2021-10-29 15:14:33 -03:00
PrototypeTrousers e7da72163b backported #5349 2021-10-29 15:13:46 -03:00
PrototypeTrousers 6d7c65dd70 potential fix for an infinite loop while adding nodes 2021-10-29 14:09:19 -03:00
PrototypeTrousers 5e21101619 n-to-n p2p
network monitor checks nesting by action source
2021-10-28 23:49:16 -03:00
PrototypeTrousers 3db8d0185f fix security terminal and portable cell stored items not showing 2021-10-23 17:56:15 -03:00
PrototypeTrousers 2f5ecfe638 energy fixes 2021-10-22 15:37:08 -03:00
PrototypeTrousers 75843e802d WIP 2021-10-21 12:22:00 -03:00
PrototypeTrousers e41b6943aa fix swapping cells giving wrong item/fluid count 2021-09-28 23:29:52 -03:00
PrototypeTrousers 92347ad2f5 fix looping item count and hopefully energy issues 2021-09-26 22:07:16 -03:00
PrototypeTrousers 517bd77df7 yet another try at energy issues
fix requesters not being added to the energy grid


partially revert the energy 'fixes'


potential desync on item count


energy and items change
2021-09-17 00:09:49 -03:00
PrototypeTrousers 19f928a9a5 fluid pass 2021-09-13 04:22:52 -03:00
PrototypeTrousers 73251a0fe5 more item count changes.... 2021-09-13 02:10:28 -03:00
PrototypeTrousers 9335daff7d Revert "fixes item showing incorrect amounts"
This reverts commit 618e9390c6.
2021-09-11 22:48:45 -03:00
PrototypeTrousers cc5377d53b fluid storage bus handler cache tweaks and simplify energy cache 2021-09-06 23:51:32 -03:00
Salomão 059f20d801 yet another try at fixing power issues 2021-09-05 20:28:37 -03:00
Salomão d229570495 try to fix energy issues again
fix issue with voiding p2p parts when shift-right clicking with a memory card
2021-09-04 18:59:46 -03:00
PrototypeTrousers c284748b6c fix p2p not updating properly on memory card loading 2021-09-02 20:42:02 -03:00
PrototypeTrousers 880a9c8821 another case of wrong item count caused by weak reset logic overriding
a full reset needed
2021-09-01 16:11:45 -03:00
PrototypeTrousers c68c02ef3b more cases of wrong item counting fixed 2021-08-26 22:03:23 -03:00
PrototypeTrousers 89c4d2736c borrowed some fancy, colored, fluid rendering from gregicality
thank you @Yefancy
2021-08-23 22:35:26 -03:00
PrototypeTrousers 01778794e5 try to fix #51 2021-08-22 23:59:02 -03:00
PrototypeTrousers 8f2a06e457 fix #49. you can now actually clear storage and conversion monitors 2021-08-20 23:26:33 -03:00
PrototypeTrousers 2d71b75019 actually fix it 2021-08-17 07:46:47 -03:00
PrototypeTrousers 9f09cd04d4 enforce cache reset of storage bus attached to interfaces were configs
changed
2021-08-16 21:55:35 -03:00
PrototypeTrousers b041fae0d5 fix storage/monitors wrong item count and interactions 2021-08-16 19:26:25 -03:00
Salomão c466a0e00e fix items in level emitters with crafting cards not showing up 2021-08-14 09:44:47 -03:00
PrototypeTrousers 618e9390c6 fixes item showing incorrect amounts 2021-08-13 00:17:53 -03:00
PrototypeTrousers 9a71bfb0f0 hash drawers handler by the amount of slots 2021-08-10 09:06:18 -03:00
PrototypeTrousers 9680123906 fix JEI targeting disabled slots as valid 2021-08-06 06:25:12 -03:00
PrototypeTrousers 87730894e9 Update CHANGES.md 2021-08-05 21:36:49 -03:00
PrototypeTrousers 71c944daea fix fluid storagebus NPE crash 2021-08-04 20:49:38 -03:00
PrototypeTrousers e96b4a698a fluid containers can now be drained/filled from fluid interfaces 2021-08-04 19:38:00 -03:00
PrototypeTrousers 1d5465a4b8 partially revert fda8c8 2021-08-04 09:28:47 -03:00
PrototypeTrousers 09cbfe96d6 fix NPE when configuring storage busses 2021-08-01 17:36:23 -03:00
PrototypeTrousers cbdad7c58e hopefully fix storage busses for good
1
2021-07-31 23:05:59 -03:00
PrototypeTrousers 6be96956a9 small optimization to import/export busses 2021-07-30 23:26:42 -03:00
PrototypeTrousers e376e002e9 actually fix #43 ? .... 2021-07-30 07:51:57 -03:00
PrototypeTrousers 0b9df31d4e fix broken recipes resulting in item dupes 2021-07-28 19:46:42 -03:00
PrototypeTrousers cef6dbf0d7 fix copy-paste error in the fluid storage bus constructor 2021-07-27 19:32:59 -03:00
Salomão e4af7b1947 fix adapters insert-only mode still reporting items 2021-07-27 12:51:24 -03:00
Salomão 6eadb8f861 fix IO-Port transfer stopping too soon 2021-07-27 11:10:45 -03:00
PrototypeTrousers b6b6a83563 do the same for fluid storage bus 2021-07-26 20:34:15 -03:00
PrototypeTrousers 32ab4c6af4 Merge remote-tracking branch 'PrototypeTrousers/AE2-Omnifactory' into AE2-Omnifactory 2021-07-26 18:25:24 -03:00
PrototypeTrousers fda8c87410 attempts to fix #42 and #43 2021-07-26 18:25:08 -03:00
PrototypeTrousers 389e060707 Merge pull request #41 from BalaM314/patch-1
Fix #27
2021-07-23 10:40:01 -03:00
BalaM314 0942a90ef4 Fix #27
Not sure exactly what method is causing a crash, but added a catch to just say it is located in another dimension
2021-07-23 15:11:07 +05:30
PrototypeTrousers 8cef06512a restore breaking API change 2021-07-22 21:50:56 -03:00
PrototypeTrousers 8e4658be20 fix power not going to sub-networks
renamed variables
2021-07-18 17:52:01 -03:00
PrototypeTrousers 0bd2bd6b5a dont pause main thread when calculating 2021-07-17 22:15:54 -03:00
PrototypeTrousers db2c4c4325 ensure the local energy cache is iterated last 2021-07-17 22:11:11 -03:00
Salomão ac793ee847 Merge branch 'delta' into AE2-Omnifactory 2021-07-17 14:48:22 -03:00
Salomão 6404f26cca Merge remote-tracking branch 'origin/fluid-terminal-multiple-containers' into AE2-Omnifactory 2021-07-16 14:22:21 -03:00
Salomão ced6ad865c re-introduce time-based calculation quota
player initiated crafting calculation is not affected
2021-07-16 14:22:09 -03:00
Salomão 24750f00b1 reworked how changes are propagated in the network 2021-07-16 14:13:48 -03:00
Salomão df08ce0513 Fluid terminal is now able to fill/empty stacked tanks 2021-07-04 10:28:36 -03:00
Salomão f9c274fb48 Reduce power flickering by increasing energy polling rate
in testing 84 dense cells could sustain MAX Integer on a FE p2p pair
2021-06-27 23:17:26 -03:00
Salomão 3582582e3f fix off-by-one voiding patterns when removing expansion cards 2021-06-26 10:25:47 -03:00
Salomão 6de48f8541 fixes #34
getAllIngredients() can contain nulls
2021-06-26 07:31:16 -03:00
Salomão 5a2c2d06d3 make pattern expansion recipe shapeless 2021-06-24 22:34:21 -03:00
Salomão 98d3cafdfd Merge branch 'oredictfixes' into AE2-Omnifactory 2021-06-23 10:19:02 -03:00
Salomão 904de49543 wip
fix substitution crafting, for real this time
wip 2


wip. still has NBT issues


fix semantic changes


fix interface with free slots on interface terminal


Auto stash before cherry pick of "fix interface with free slots on interface terminal"
2021-06-23 10:16:59 -03:00
Salomão b0772bf94c backport 223163aa0a
fixes #32
2021-06-21 22:48:25 -03:00
Salomão aa5d5e3623 set idle power usage of expanded interface to a power of four 2021-06-21 16:25:26 -03:00
Salomão 42f4ef2855 tweak GUIs 2021-06-21 15:54:40 -03:00
Salomão 3eb2582f29 Merge branch 'bigger-interfaces' into AE2-Omnifactory 2021-06-21 15:22:13 -03:00
Salomão 307f86ded8 increase AE energy polling rate from once every 90 to once every 3 ticks 2021-06-18 12:48:01 -03:00
Salomão 56f57e18a5 Merge branch 'wip' into AE2-Omnifactory 2021-06-17 23:32:34 -03:00
Salomão eab695b692 try to not void fluids in fluid terminal when running out of power 2021-06-17 23:32:16 -03:00
Salomão 0fb393820b half-undo wip 2021-06-17 00:07:06 -03:00
Salomão 01fe5c7a8b jei transfer tweaks..again 2021-06-16 19:22:52 -03:00
Salomão 8468b47443 workaround for damaged tools and gtce tools not being set as damageable 2021-06-15 12:46:44 -03:00
Salomão 6cb583c918 clear old NBT from cells 2021-06-15 12:41:51 -03:00
Salomão d69395a117 cache fixes 2021-06-14 12:57:49 -03:00
Salomão 59effe8131 save NBT properly 2021-06-14 11:51:17 -03:00
Salomão 6f42876963 Merge branch 'fastutil' into AE2-Omnifactory 2021-06-14 10:54:12 -03:00
Salomão 08952b48dd backported fastutil implementation of the item list 2021-06-14 10:53:50 -03:00
Salomão e3c9c4ce65 clear cells of craftable status
remove unsupported removal call
2021-06-14 10:20:58 -03:00
Salomão 7b91da58c0 resolve suspicious calls 2021-06-14 02:33:43 -03:00
Salomão 26c06bca15 fix IO-Port copying craftable boolean 2021-06-14 02:33:23 -03:00
Salomão 4458bd28ab refresh ETA not only when items are crafted 2021-06-13 20:30:52 -03:00
Salomão df3f00d978 try to fix remaining concurrent modifications to energy grid 2021-06-13 20:29:56 -03:00
Salomão 18ae994ee4 try to avoid CME by copying FE p2p outputs before iterating
backported 1c88ea7b78 and attempt to fix #25 with feedback
2021-06-10 21:13:41 -03:00
Salomão 47888b5546 reworked Adapter caches ( storage busses ) 2021-06-09 16:31:49 -03:00
Salomão e18593feb5 fix pattern inventory size mismatch 2021-06-08 23:46:37 -03:00
Salomão af4c3de55e fix client desync 2021-06-08 23:23:12 -03:00
Salomão bea29331a3 implement pattern expansion cards for interfaces
Maximum of 4 rows
Uses 4x the previous tier for crafting operations (4 rows = 64 interfaces consumption)
2021-06-08 23:23:12 -03:00
Salomão 9b9579b358 storage drawer cache optimisation 2021-06-08 23:22:00 -03:00
Salomão 52da4f9528 fix shift-clicking patterns from pattern slot sometimes voiding them 2021-06-05 18:54:26 -03:00
Salomão 50aac2c768 send the player a message if the crafting job succeeds on simulation
but fails on real extraction
2021-06-02 23:46:35 -03:00
Salomão 33946438bd fix JEI ghost fluids not working for filtering fluid storage bus 2021-05-30 13:40:21 -03:00
Salomão 9372cb2f14 Merge remote-tracking branch 'PrototypeTrousers/AE2-Omnifactory' into AE2-Omnifactory 2021-05-29 20:13:43 -03:00
Salomão 00037ace77 Blank Pattern Slot has priority when shift clicking blank patterns 2021-05-29 16:48:59 -03:00
PrototypeTrousers e13af643ba Update CHANGES.md 2021-05-29 14:32:51 -03:00
PrototypeTrousers ffcfd809d8 Add files via upload 2021-05-29 14:32:23 -03:00
Salomão 7c10a6b883 fix damaged tools not being selected for JEI recipe transfer 2021-05-27 17:15:19 -03:00
Salomão c2bddc30c4 fix NPE transfering recipes without an actual output 2021-05-26 16:09:40 -03:00
Salomão 024655f84d fix fluid terminal not having a recipe 2021-05-24 15:42:25 -03:00
Salomão 589e48ac01 restore depth on highlight
fixes #21
2021-05-23 18:14:07 -03:00
Salomão 43d3a2c1c0 add dimension info to the interface highlighting
implements #20
2021-05-23 17:46:28 -03:00
Salomão c432fa7200 automatically change between crafting/processing recipes on jei transfer 2021-05-23 01:06:39 -03:00
Salomão cc744ab8b9 Revert "level emitter changes"
This reverts commit 9d6026635d.
2021-05-17 21:11:08 -03:00
Salomão 8fe4229a8e add extra checks 2021-05-17 00:27:53 -03:00
Salomão 3f86884965 fix GTCE blocking mode 2021-05-16 23:28:05 -03:00
Salomão 1319ec79c9 allow GTCE blocking mode to work through phantom faces 2021-05-16 13:30:27 -03:00
Salomão 31a3afc18b revert inventory merging code to keep compatibility with ae2fc 2021-05-14 12:43:34 -03:00
Salomão 9d6026635d level emitter changes 2021-05-13 19:32:03 -03:00
Salomão 39038ac935 revert iitemrepository cache changes 2021-05-12 23:22:54 -03:00
Salomão 4f627b234c invert comparison 2021-05-12 03:26:12 -03:00
Salomão 6180c188e6 Revert "remove crafting failure penalty"
This reverts commit 0240a5d76a.
2021-05-12 02:42:34 -03:00
Salomão 7ada6d18ee small optimizations 2021-05-12 00:19:55 -03:00
Salomão f493767243 fix out of bounds crash 2021-05-09 22:00:20 -03:00
Salomão ba4cdbcb85 fix #16 2021-05-09 10:59:31 -03:00
Salomão f3877aa1ec Merge branch 'iir-cache' into AE2-Omnifactory 2021-05-08 22:46:56 -03:00
Salomão 366b31b3aa import bus optimization 2021-05-08 22:11:13 -03:00
Salomão 533fb5c34b initial test 2021-05-08 19:40:58 -03:00
Salomão 62d1d904c6 update item cache directly on insert/removal
import bus fails faster and throttles down when inventory is full
2021-05-08 19:08:21 -03:00
Salomão 03fb43db16 revert blocking mode to previous implementation 2021-05-05 19:45:25 -03:00
Salomão 9576bec855 renamed method. fixed round robin while blocking mode on 2021-05-04 22:51:20 -03:00
Salomão b5da6730a1 loop optimization 2021-05-04 15:15:09 -03:00
Salomão 039bab4811 drop items waiting to be injected when interface is broken 2021-05-04 11:07:31 -03:00
Salomão 4b5bdf9893 fix NPE 2021-05-04 10:57:01 -03:00
Salomão 3c3c23712d Merge branch 'rr-interfaces' into AE2-Omnifactory 2021-05-03 21:38:43 -03:00
Salomão af91c04ea1 re - implement blocking mode 2021-05-03 21:34:59 -03:00
Salomão 0240a5d76a remove crafting failure penalty 2021-05-03 21:09:03 -03:00
Salomão 0c0aafba2f make ItemSlots copy-able 2021-05-03 21:07:51 -03:00
Salomão b541025738 implement patterned input-based blocking mode
remove GTCE-specific handler and adaptor
2021-05-03 21:07:12 -03:00
Salomão 62f842d4ef visit crafting mediums in round-robin 2021-05-03 21:05:14 -03:00
Salomão fc154d8568 remove slotless capability implementation from inventory adaptor
affects  interface,import and export busses
2021-05-03 21:00:35 -03:00
Salomão 4641e48529 push patterns in round-robin 2021-04-30 12:20:36 -03:00
Salomão 0fae87afc7 allow left clicking on bookmarked items on GUIs without fake slots 2021-04-26 23:53:43 -03:00
Salomão ee1b6bb0d7 Add bookmarked ghost items support
fixed fluid dragging not working on servers
2021-04-18 21:01:09 -03:00
Salomão 36ca8b9f0a JEI Bookmark dragnDrop 2021-04-15 22:58:57 -03:00
Salomão 9c94c7342b Merge branch 'JEI-drag-phantom-items' into AE2-Omnifactory 2021-04-14 21:46:40 -03:00
Salomão 399d67b42c made jei recipe transfer more strict when keeping items on the table
few cleanup
2021-04-14 21:37:06 -03:00
Salomão 10761a1e9d missing click cancel 2021-04-14 00:04:07 -03:00
Salomão d1ddf53d99 wip 2 2021-04-13 14:54:52 -03:00
Salomão f776b4d548 wip 2021-04-13 12:36:20 -03:00
Salomão 41180792e1 Cellworkbench acts weird
missing bookmark dragging
2021-04-12 23:51:49 -03:00
Salomão 2269c05d98 implement #14
also fix tooltip position
2021-04-10 09:46:48 -03:00
Salomão 63616e5730 try fix #13 2021-04-10 09:30:44 -03:00
Salomão 6ca3e6e696 add tooltip to fluid level emitter number box 2021-04-05 00:11:30 -03:00
Salomão a4b5cfc3b9 fix lightning issue while tooltip is showing on interface terminal 2021-04-04 22:17:14 -03:00
Salomão 38b0a7a153 handle interface slots serverside 2021-04-04 01:29:27 -03:00
Salomão aa4863a979 Added Fluid support for the Storage Monitor and Conversion Monitor
Highlighted interfaces is turned off after switching dimensions
2021-04-02 08:31:14 -03:00
Salomão 44c7a46315 fix advancements not triggering 2021-04-02 08:29:32 -03:00
PrototypeTrousers c3b1dea7c5 better level emitting 2021-03-31 17:34:43 -03:00
Salomão 40ec517480 level emitters cache rework 2021-03-30 23:05:15 -03:00
Salomão 2fdc16d3a8 Merge remote-tracking branch 'ALongStringOfNumbers/recipeConditions' into AE2-Omnifactory 2021-03-30 21:58:46 -03:00
Salomão 053485a95a another try at fixing level emitters 2021-03-30 21:57:53 -03:00
ALongStringOfNumbers e910af7734 Fix advancements to check if their parent item is enabled to prevent more logging 2021-03-30 15:36:25 -07:00
Salomão 59d7bd6c16 JEI recipe transfer fixes
re-checks the amount of items in the recipe
only do fuzzy search for damageable items
2021-03-29 21:20:46 -03:00
Salomão 1a11462ddd can now drag encoded patterns on the interface terminal 2021-03-29 01:53:59 -03:00
Salomão 77d615559f Add proper button and tooltips to interface terminal 2021-03-28 16:20:37 -03:00
ALongStringOfNumbers 6878bfa4b0 Fix parts 2021-03-27 01:26:29 -07:00
ALongStringOfNumbers f1d50eca1a More minor fixes 2021-03-26 22:10:24 -07:00
ALongStringOfNumbers 4ee32dd0b0 Fix some recipes not showing up due to bad conditions 2021-03-26 21:48:03 -07:00
ALongStringOfNumbers 66e589324a Make recipes and advancements conditional
Fix crash when fluix was disabled
2021-03-26 19:12:49 -07:00
Salomão 362b001cb4 level emitter dying fix 2021-03-25 22:48:42 -03:00
Salomão b6fd4b3c0f changed priority of JEI items on the 2021-03-23 22:23:58 -03:00
Salomão e364603a5a Changed level emitters to update only once when they tick 2021-03-17 21:35:26 -03:00
Salomão c58bebc346 Fix gregtech tileentities showing up as unnamed or draconium lens 2021-03-07 23:59:39 -03:00
Salomão 97f11f0c61 Fix storage drawers showing up as nothing on interface terminal 2021-03-07 23:56:52 -03:00
Salomão 5c2fa72f95 mix pattern terminal multiplying items above maxitemstack size 2021-03-07 00:01:01 -03:00
Salomão ebd8501301 fix inaccessible items setting in storage bus not being respected 2021-03-07 00:00:16 -03:00
Salomão fa07247bd7 Revert "also shrink the fluid skiplist if the tanks change sizes"
This reverts commit 892c919ee2.
2021-03-04 23:08:08 -03:00
Salomão 95d25ddf47 Revert "Skip un-extractable slots."
This reverts commit e2e6f6e83f.
2021-03-04 23:07:58 -03:00
Salomão 7a45e1faf4 Revert "rebuild skipslotlist if the the inventory grows or shrinks"
This reverts commit 7796c6d4b6.
2021-03-04 23:07:34 -03:00
Salomão 1f88494832 fix not being able to swap patterns on interface terminal 2021-03-03 09:57:02 -03:00
PrototypeTrousers c629b4e0cf Merge pull request #4 from Theisyat/AE2-Omnifactory
Fixed 'Only show Empty' in Interface Terminal
2021-03-02 19:56:16 -03:00
PrototypeTrousers 65ca607134 Merge branch 'AE2-Omnifactory' into AE2-Omnifactory 2021-03-02 19:55:52 -03:00
Salomão 898c07ca01 fix toggling full interfaces hiding all interfaces 2021-03-02 18:45:14 -03:00
Theisyat 883c267aa8 Fixed Interface Terminal and Added Stuff
Fixed 'Hide Full' Button

First Free Molecular Assembler Button

Added Button in Interface Terminal, which Searches for 'Molecular
Assembler' and sets the Interface Terminal to only show Assemblers with
free Slots.
2021-03-02 07:00:48 +01:00
Salomão 22cf913708 highlight interfaces from interface terminal. 2021-02-28 21:32:11 -03:00
Salomão b4ba1af1ec bind BlockPos of the interface on the list 2021-02-28 02:03:00 -03:00
Salomão 892c919ee2 also shrink the fluid skiplist if the tanks change sizes 2021-02-24 18:08:57 -03:00
Salomão a65b3d2ceb fix interface terminal GUI 2021-02-24 13:24:04 -03:00
Salomão c826a3e24f Add second search bar to Interface Terminal 2021-02-23 20:48:45 -03:00
Salomão fc98505f22 even more JEI integration
get ingredient from the crafting calculation GUIs
2021-02-22 22:33:05 -03:00
Salomão ea54ccbcf5 More JEI integration 2021-02-22 18:35:46 -03:00
Salomão 7796c6d4b6 rebuild skipslotlist if the the inventory grows or shrinks 2021-02-22 14:33:06 -03:00
Salomão e2e6f6e83f Skip un-extractable slots. 2021-02-21 23:08:16 -03:00
Salomão a7a1a87cd8 Holding SHIFT with an empty hand will increase the amount of items set
on interfaces and on pattern terminal
2021-02-21 20:26:52 -03:00
Salomão e50eb7965f undo monitor ticking limit 2021-02-21 03:24:03 -03:00
Salomão d25a8a53a2 fix IItemRepository insert and extraction 2021-02-21 02:24:50 -03:00
Salomão 92b48f01a2 do not use java equals to compare stacks 2021-02-20 21:18:20 -03:00
Salomão 42f0d37c44 Merge branch 'IItemRepository' into AE2-Omnifactory 2021-02-18 23:26:49 -03:00
Salomão 088a1827be implement IItemRepository 2021-02-18 18:33:06 -03:00
Salomão 6a21968dab add storagedrawers to the gradle deps 2021-02-17 12:30:07 -03:00
Salomão 7c5ff5322a Fix JEI transfer fix. Typo correction. 2021-02-16 16:47:22 -03:00
Salomão 7834028459 Rebuild itemlist only once per tick
re-enabled level-emitters update
2021-02-15 15:41:48 -03:00
Salomão c43cbbef43 Switched JEI search to crafting terminal to fuzzy mode 2021-02-14 02:14:15 -03:00
Salomão ead6274ca4 FIX JEI transfer not working correctly
Missing on the crafting terminal
2021-02-13 21:48:37 -03:00
Salomão f1c41bab3f Implement MouseTweaks API
can now set item quantities in pattern terminal and interfaces by right clicking with the same configured item
2021-02-12 20:26:21 -03:00
Salomão 12e74dc0de Merge remote-tracking branch 'origin/AE2-Omnifactory' into AE2-Omnifactory 2021-02-11 23:07:43 -03:00
Salomão c10088d907 Fill pattern with items from JEI
Just Enough Energistics overrides this
2021-02-11 23:07:26 -03:00
PrototypeTrousers a12d29c4a0 Update README.md 2021-02-09 18:58:08 -03:00
PrototypeTrousers 2227510acf Update README.md 2021-02-09 18:55:22 -03:00
Salomão 97ae7e1f14 encoded patterns now stack up to 64 2021-02-08 22:14:37 -03:00
Salomão fc119070b2 Actually copy level emitters set values 2021-01-15 17:41:40 -03:00
Salomão 82e3a95f11 fix memory card not saving fluids an level emitters 2021-01-12 18:24:05 -03:00
Salomão e6998913e1 remove forced level emitters update
remove unneeded itemStack creation.
2021-01-04 14:18:07 -03:00
Salomão a3e69ce608 add hardcoded id range for molds and shapes for GTCE blocking mode 2020-12-08 22:42:04 -03:00
Salomão ceef176a2a remove time-based thread syncinc 2020-12-01 17:26:42 -03:00
Salomão c2e2696707 Fix fuzzy search for items that have metadata > maxdamage 2020-12-01 17:25:52 -03:00
Salomão 4d6c61dfcb backport e82093eec9459be3211564a83166455150c51259 2020-11-23 00:45:49 -03:00
Salomão 932141cc9e backport b7ca98d1e24e5797a8e42ca861ae4187ab5839ec 2020-11-23 00:45:49 -03:00
Salomão adf59774d4 Remove uneeded Forge Event Firing
improves crafting calculation performance
2020-11-18 20:22:40 -03:00
Salomão 9c6668b0f7 disable "smart" button
wasn't so smart
2020-11-13 17:42:41 -03:00
Salomão 1b7f11a12e buttons work and set quantities properly 2020-11-12 23:27:56 -03:00
Salomão 3cf4f9122c works..ish 2020-11-12 20:42:30 -03:00
Salomão d97996070a x2 button on the right place 2020-11-12 18:40:10 -03:00
Salomão 8a165bea09 ease punishment a bit 2020-10-28 19:50:57 -03:00
Salomão f707f95373 Revert "undo penalties"
This reverts commit d6499c16b0.
2020-10-28 19:49:23 -03:00
Salomão b2a660ec9b formating fixes 2020-10-28 17:50:40 -03:00
Salomão d6499c16b0 undo penalties 2020-10-28 16:59:51 -03:00
Salomão de3e0178a4 update forge and jei 2020-10-27 03:38:12 -03:00
Salomão 203522316c more tweaks testing 2020-10-25 18:57:42 -03:00
Salomão 719ea5090b move gtce blocking code out of generic item adaptor
fixes crash with ae2 fluid crafting
2020-10-25 01:04:48 -03:00
Salomão 00e19d67a2 Tune punishment 2020-10-23 21:39:36 -03:00
Salomão 169f6393d1 move penalty up the chain 2020-10-22 11:24:16 -03:00
Salomão 12bf337238 Re-do Blocking mode logic 2020-10-21 15:44:43 -03:00
Salomão 3b544c2486 Merge remote-tracking branch 'PrototypeTrousers/AE2-Omnifactory' into AE2-Omnifactory 2020-10-20 23:52:18 -03:00
Salomão 660e17d167 Merge remote-tracking branch 'talchas/on-upstream' into AE2-Omnifactory 2020-10-20 23:52:11 -03:00
Salomão b10246a67b Merge remote-tracking branch 'talchas/on-upstream' into AE2-Omnifactory 2020-10-20 23:04:44 -03:00
Salomão 74362bb543 Merge branch 'ae2-interface-export-bus-fixes' into AE2-Omnifactory 2020-10-20 23:02:53 -03:00
Salomão 81df58afa5 dont try to re-request craft immediately, if we cant craft it now 2020-10-20 23:01:09 -03:00
Salomão 535289e694 Change interface behavior
skip complete configured stacks
postpone crafting job start
2020-10-20 14:30:08 -03:00
yueh d730503378 Fixes #4388: Ensure correct ticking priority order (#4393) 2020-05-27 16:13:20 +02:00
talchas 5ac8db41e7 option for a blocking mode that actually works 2020-02-06 18:13:31 -08:00
talchas dfe5b82bda Safer implementation of CraftingGridCache updatePatterns coalescing 2019-12-31 10:57:23 -08:00
talchas c7f8f4249e Avoid quadratic behavior from rebuilding the entire crafting cache for
each interface visited. Instead rebuild it at most once per tick, like
cpu clusters.

This is particularly important when channels are disabled, since in
that case even adding a cable visits every grid node.
2019-12-31 10:57:23 -08:00
516 changed files with 12616 additions and 2894 deletions
+58
View File
@@ -0,0 +1,58 @@
Changes so far :
Design changes/breakages:
- Interfaces no longer spill items of one pattern on other faces
- Interfaces now push patterns in round-robin (Interfaces, then sides)
Fixes:
- Fix gregtech machines appearing with 'unnamed' or 'draconium lens' on the interface terminal on specific situations.
- Add memorycard support for fluid interfaces, import/export/storage busses and level emitters ( this fix was upstreamed to AE2 for MC 1.16)
- Storage busses now hide/show inaccessible items as configured.
- Exclusive Blocking mode for GTCE ( shapes, molds and configured circuits do not block GTCE machines )
- Blocking modes default to block on any item in the iventory the entity exposes
- Fuzzy includes items that report that they're damageable, but report a maxDamage of 0 ( auto-crafting of basic capacitors -> resonant capacitors is now possible ) <- Broken item implementation.
- Fix CME exceptions on the energy grid
- Fix AE going offline even with enough power by extracting from the local buffer always last
- Fix IO-Port copying craftable flag into items
- Fix NBT of old items not clearing on drives that reached 64 types once
Performance:
- Added @talchas fixes for insane channelless AE networks.
- Implemented StorageDrawers slotless itemrepository.
- Removed CraftedEvent calls (really bad lag with craftweaker versions before CraftTweaker2-1.12-4.1.20.626)
- Count items set in interfaces before queuing crafting for them needlessly
- Backported b7ca98d ( Avoid copying items on simulated item extraction )
- Cache some level emitters functions
- Reduced import bus insert simulation to 1 before real insertion (if possible)
- Backported itemlist re-implementation along with pattern changes to avoid CraftingManager fallback issues
- Instead of recalculating all the content of the network on every change, track the changes properly and apply them to the cached list of items
QOL:
- added highlight interface button to interface terminal ("?" button on the left of the interface slots)
- Added bar on the interface terminal that search by inputs ( The one on the LEFT, also searchs by interface name )
- Shortcut to molecular assemblers with free slots on the terminal interface by @Theisyat
- Toggle button on interface terminal to hide full interfaces
- JEI "U", "R" and "A" (Usages/Recipes/Bookmark) now work on the Crafting Status GUI. ( the one that shows the total items to craft, and whats missing)
- Patterns can now be made with items currently showing on JEI. ( This is overriden by Just Enough Energistics. )
- Added multiplier buttons to processing pattern gui
- Switched crafting terminal JEI search to fuzzy mode. If the recipe uses a damageable item, AE will try to grab it ( damaged tools )
- Encoded patterns stack up to 64 ( holding shift and clicking the encode arrow will transfer the encoded pattern to the player inventory)
- Encoded patterns can be draggred on the interface terminal.
- Storage Monitor and Conversion Monitor now also ccepts fluids
- Draggable JEI ghost items (also works on bookmarked items. SHIFT + Click will move the hovered item into the first free target slot)
- JEI auto switches between crafting and processing patterns
- GTCE Blocking mode work through phantom itemfaces
- Shift-clicking blank patterns into the pattern terminal will try to fill the blank pattern slots first
- Mismached simulated/real item count ( most often due to compacting drawers ) will now tell the player wich item cause the failure when trying to start a craft
- Added 'pattern expansion' cards that adds an extra row of patterns to interfaces. up to 3 card on an interface. (each card will increase the interface idle power draw by 4 times)
HOTKEYS:
- Implemented mousetweaks API. AE2 custom keybinds now work. (Try right clicking and use the scroll-wheel on the terminals)
- Holding SHIFT and scrolling UP and DOWN will increase the items set on the configured slots of Interfaces and Pattern Terminal (Processing mode)
+5 -216
View File
@@ -1,34 +1,15 @@
[![Travis](https://img.shields.io/travis/AppliedEnergistics/Applied-Energistics-2.svg?maxAge=2592000&style=flat-square)](https://travis-ci.org/AppliedEnergistics/Applied-Energistics-2)
[![Latest Release](https://img.shields.io/github/release/AppliedEnergistics/Applied-Energistics-2.svg?label=Latest%20Release&style=flat-square)](https://github.com/AppliedEnergistics/Applied-Energistics-2/releases)
This is a fork of AE2 i made for trying to solve issues for the [Omnifactory](https://www.curseforge.com/minecraft/modpacks/omnifactory) modpack.
# Applied Energistics 2
See https://github.com/PrototypeTrousers/Applied-Energistics-2/tree/AE2-Omnifactory branch for commits
and
https://github.com/PrototypeTrousers/Applied-Energistics-2/releases for the compiled jars.
## Table of Contents
* [About](#about)
* [Contacts](#contacts)
* [License](#license)
* [Downloads](#downloads)
* [Installation](#installation)
* [Issues](#issues)
* [Building](#building)
* [Contribution](#contribution)
* [API](#applied-energistics-2-api)
* [CraftTweaker](#applied-energistics-2-crafttweaker)
* [Localization](#applied-energistics-2-localization)
* [Credits](#credits)
# Applied Energistics 2 (PrototypeTrousers fork for Omnifactory)
## About
A Mod about Matter, Energy and using them to conquer the world..
## Contacts
* [Website](http://ae-mod.info/)
* [IRC #appliedenergistics on esper.net](http://webchat.esper.net/?channels=appliedenergistics&prompt=1)
* [GitHub](https://github.com/AppliedEnergistics/Applied-Energistics-2)
* [Discord](https://discord.gg/GygKjjm)
## License
* Applied Energistics 2 API
@@ -43,198 +24,6 @@ A Mod about Matter, Energy and using them to conquer the world..
* Text and Translations
- [![License](https://img.shields.io/badge/License-No%20Restriction-green.svg?style=flat-square)](https://creativecommons.org/publicdomain/zero/1.0/)
## Downloads
Downloads can be found on [CurseForge](http://www.curse.com/mc-mods/minecraft/223794-applied-energistics-2) or on the [official website](http://ae-mod.info/Downloads/).
## Installation
You install this mod by putting it into the `minecraft/mods/` folder. It has no additional hard dependencies.
## Issues
Applied Energistics 2 crashing, have a suggestion, found a bug? Create an issue now!
1. Make sure your issue has not already been answered or fixed and you are using the latest version. Also think about whether your issue is a valid one before submitting it.
* If it is already possible with vanilla and AE2 itself, the suggestion will be considered invalid.
* Asking for a smaller version, more compact version, or more efficient version of something will also be considered invalid.
2. Go to [the issues page](https://github.com/AppliedEnergistics/Applied-Energistics-2/issues) and click [new issue](https://github.com/AppliedEnergistics/Applied-Energistics-2/issues/new)
3. Enter your a title of your issue (something that summarizes your issue), and then create a detailed description of the issue.
* Do not tag it with something like `[Feature]`, `[Bug]`, or a version.
* Restrict it to a single bug or feature, it makes managing them way easier for us.
* The following details are required. Also refer to the issue template when creating one.
* Forge version
* AE2 version
* Crash log, when reporting a crash (Please make sure to use [pastebin](http://pastebin.com/))
* Never post an excerpt of what you consider important
* Always post the full log
* Other mods and their version, when reporting an issue between AE and another mod
* Also consider updating these before submitting a new issue, it might be already fixed
* A detailed description of the bug or feature
* To further help in resolving your issues please try to include the follow if applicable:
* What was expected?
* How to reproduce the problem?
* This is usually a great detail and allows us to fix it way faster
* Server or Single Player?
* Screen shots or Pictures of the problem
* Mod Pack using and version?
* Keep in mind that some mods might use an outdated version of AE2
* If so you should report it to your modpack
4. Click `Submit New Issue`, and wait for feedback!
Providing as many details as possible does help us to find and resolve the issue faster and also you getting a fixed version as fast as possible.
Please note that we might close any issue not matching these requirements.
## Building
1. Clone this repository via
- SSH `git clone git@github.com:AppliedEnergistics/Applied-Energistics-2.git` or
- HTTPS `git clone https://github.com/AppliedEnergistics/Applied-Energistics-2.git`
2. Setup workspace
- Decompiled source `gradlew setupDecompWorkspace`
- Obfuscated source `gradlew setupDevWorkspace`
- CI server `gradlew setupCIWorkspace`
3. Build `gradlew build`. Jar will be in `build/libs`
4. For core developer: Setup IDE
- IntelliJ: Import into IDE, execute `gradlew genIntellijRuns` and change RunConfiguration to `*_main` as quickfix for [ForgeGradle](https://github.com/MinecraftForge/ForgeGradle/issues/357)
- Eclipse: execute `gradlew eclipse`
5. For add-on developer: Core-Mod Detection
- In order to have FML detect AE from your dev environment, add the following VM Option to your run profile
- `-Dfml.coreMods.load=appeng.coremod.AppEngCore`
## Contribution
Before you want to add major changes, you might want to discuss them with us first, before wasting your time.
If you are still willing to contribute to this project, you can contribute via [Pull-Request](https://help.github.com/articles/creating-a-pull-request).
The [guidelines for contributing](https://github.com/AppliedEnergistics/Applied-Energistics-2/blob/master/.github/CONTRIBUTING.md) contain more detailed information about topics like the used code style and should also be considered.
Here are a few things to keep in mind that will help get your PR approved.
* A PR should be focused on content. Any PRs where the changes are only syntax will be rejected.
* Use the file you are editing as a style guide.
* Consider your feature. [Suggestion Guidelines](http://ae-mod.info/Suggestion-Guidelines/)
- Is your suggestion already possible using Vanilla + AE2?
- Make sure your feature isn't already in the works, or hasn't been rejected previously.
- Does your feature simplify another feature of AE2? These changes will not be accepted.
- If your feature can be done by any popular mod, discuss with us first.
**Getting Started**
1. Fork this repository
2. Clone the fork via
* SSH `git clone git@github.com:<your username>/Applied-Energistics-2.git` or
* HTTPS `git clone https://github.com/<your username>/Applied-Energistics-2.git`
3. Change code base
4. Add changes to git `git add -A`
5. Commit changes to your clone `git commit -m "<summary of made changes>"`
6. Push to your fork `git push`
7. Create a Pull-Request on GitHub
8. Wait for review
9. Squash commits for cleaner history
If you are only doing single file pull requests, GitHub supports using a quick way without the need of cloning your fork. Also read up about [synching](https://help.github.com/articles/syncing-a-fork) if you plan to contribute on regular basis.
## Applied Energistics 2 API
The API for Applied Energistics 2. It is open source to discuss changes, improve documentation, and provide better add-on support in general.
Universal builds obtained [Here](http://ae2.ae-mod.info/Downloads/) should work in a development environment.
### Maven
When compiling against the AE2 API you can use gradle dependencies, just add
dependencies {
compile "appeng:appliedenergistics2:rv_-_____-__:api"
}
or add the compile line to your existing dependencies task to your build.gradle
Where the __ are filled in with the correct version criteria; AE2 is available from the default forge maven so no additional repositories are necessary.
An example string would be `appeng:appliedenergistics2:rv5-stable-1:api` for the API only or `appeng:appliedenergistics2:rv5-stable-1` for the whole mod.
## Applied Energistics 2 CraftTweaker
### Inscriber
Add a recipe. When `inscribe` is true the bottom and top inputs are not consumed.
mods.appliedenergistics2.Inscriber.addRecipe(ItemStack output, ItemStack input, boolean inscribe,
@Optional ItemStack topInput, @Optional ItemStack bottomInput );
Remove all recipes for this output stack.
mods.appliedenergistics2.Inscriber.removeRecipe(ItemStack output);
### Grindstone
Add a recipe.
mods.appliedenergistics2.Grinder.addRecipe( ItemStack output, ItemStack input, int turns,
@Optional ItemStack secondary1Output, @Optional float secondary1Chance,
@Optional ItemStack secondary2Output, @Optional float secondary2Chance);
Remove recipes for this input.
mods.appliedenergistics2.Grinder.removeRecipe(ItemStack input);
### Spatial
Whitelist a TileEntity class for Spatial IO.
mods.appliedenergistics2.Spatial.whitelistEntity( String fullEntityClassName );
### Attunement
Attune a ItemStack or ModID to a specific P2P-Tunnel type. ModID's are used as fallback when no ItemStack was found.
mods.appliedenergistics2.Attunement.attuneME( ItemStack itemStack );
mods.appliedenergistics2.Attunement.attuneME( String modID );
mods.appliedenergistics2.Attunement.attuneItem( ItemStack itemStack );
mods.appliedenergistics2.Attunement.attuneItem( String modID );
mods.appliedenergistics2.Attunement.attuneFluid( ItemStack itemStack );
mods.appliedenergistics2.Attunement.attuneFluid( String modID );
mods.appliedenergistics2.Attunement.attuneRedstone( ItemStack itemStack );
mods.appliedenergistics2.Attunement.attuneRedstone( String modID );
mods.appliedenergistics2.Attunement.attuneRF( ItemStack itemStack );
mods.appliedenergistics2.Attunement.attuneRF( String modID );
mods.appliedenergistics2.Attunement.attuneIC2( ItemStack itemStack );
mods.appliedenergistics2.Attunement.attuneIC2( String modID );
mods.appliedenergistics2.Attunement.attuneLight( ItemStack itemStack );
mods.appliedenergistics2.Attunement.attuneLight( String modID );
### Cannon
Add ammo types for the matter cannon.
mods.appliedenergistics2.Cannon.registerAmmo( ItemStack itemStack, double weight );
## Applied Energistics 2 Localization
### English Text
`en_US` is included in this repository, fixes to typos are welcome.
### Encoding
Files must be encoded as UTF-8.
### New or updated Translations
The language files are located in `/src/main/resources/assets/appliedenergistics2/lang/` and use the [appropriate locale code](http://minecraft.gamepedia.com/Language) as name and `.lang` as extension.
To update an translation edit the corresponding file and improve/correct the existing entry. Or copy any entries from `en_US.lang` for missing translation.
To create a new translation, copy the contents of `en_US.lang`, create a new file with appropriate filename, and translate it to your language.
Please keep in mind that we use [String format](https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html) to pass additional data to the text for displaying.
Therefore you should preserve parts like `%s` or `%1$d%%`, which allows us to replace them with the correct values while you still have the option to change their order for match the rules of grammar.
This might not be possible for some languages. Should this be the case, please contact us.
### Final Note
If you have have issues localizing something feel free to contact us on IRC, at #AppliedEnergistics on Esper.net
Thanks to everyone helping out to improve localization of AE2.
## Credits
Thanks to
+1 -1
View File
@@ -57,7 +57,7 @@ tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
version = aeversion + "-" + aechannel + "-" + aebuild
version = aeversion + "-" + aechannel + "-" + aebuild + " " + trousers
group = aegroup
archivesBaseName = aebasename
+5 -4
View File
@@ -1,15 +1,16 @@
aeversion=rv6
aechannel=alpha
aebuild=0
aechannel=stable
aebuild=7
aegroup=appeng
aebasename=appliedenergistics2
trousers=omni-fixes-v49b
#########################################################
# Versions #
#########################################################
minecraft_version=1.12.2
mcp_mappings=snapshot_20171003
forge_version=14.23.5.2768
forge_version=14.23.5.2847
#########################################################
# Installable #
@@ -19,7 +20,7 @@ hwyla_version=1.8.26-B41_1.12.2
#########################################################
# Provided APIs #
#########################################################
jei_version=4.13.0.219
jei_version=4.16.1.302
tesla_version=1.0.63
ic2_version=2.8.73-ex112
top_version=1.12-1.4.23-16
+8 -5
View File
@@ -34,6 +34,11 @@ repositories {
url "http://maven.mcmoddev.com"
}
maven {
name "Ellpeck"
url "https://maven.ellpeck.de"
}
maven {
name = "IC2 repo"
url = "http://maven.ic2.player.to"
@@ -54,11 +59,6 @@ repositories {
url "http://maven.k-4u.nl/"
}
maven { // Hwyla
name 'tehnut'
url "http://tehnut.info/maven"
}
maven { // CraftTweaker
name 'jared maven'
url "http://maven.blamejared.com/"
@@ -80,6 +80,8 @@ configurations {
}
dependencies {
compileOnly "gregtechce:gregtech:1.12.2:1.15.1.735"
// installable runtime dependencies
mods "mcp.mobius.waila:Hwyla:${hwyla_version}"
mods "net.industrial-craft:industrialcraft-2:${ic2_version}:dev"
@@ -95,6 +97,7 @@ dependencies {
compileOnly "CraftTweaker2:CraftTweaker2-API:${crafttweaker_version}"
compileOnly "inventory-tweaks:InventoryTweaks:${inventorytweaks_version}:api"
compileOnly "team.chisel.ctm:CTM:${ctm_version}"
compileOnly "de.ellpeck.actuallyadditions:ActuallyAdditions:1.12.2-r152.16:api"
// at runtime, use the full JEI jar
runtime "mezz.jei:jei_${minecraft_version}:${jei_version}"
@@ -26,5 +26,20 @@ package appeng.api.config;
public enum ActionItems
{
WRENCH, CLOSE, STASH, ENCODE, SUBSTITUTION
WRENCH,
CLOSE,
STASH,
ENCODE,
SUBSTITUTION,
MULTIPLY_BY_TWO,
MULTIPLY_BY_THREE,
INCREASE_BY_ONE,
DIVIDE_BY_TWO,
DIVIDE_BY_THREE,
DECREASE_BY_ONE,
MAX_COUNT,
FREE_MOLECULAR_SLOT_SHORTCUT,
TOGGLE_SHOW_FULL_INTERFACES_ON,
TOGGLE_SHOW_FULL_INTERFACES_OFF,
HIGHLIGHT_INTERFACE
}
+2 -1
View File
@@ -46,7 +46,8 @@ public enum Upgrades
*/
FUZZY( 1 ),
SPEED( 1 ),
INVERTER( 1 );
INVERTER( 1 ),
PATTERN_EXPANSION(1);
private final int tier;
private final Map<ItemStack, Integer> supportedMax = new HashMap<>();
@@ -89,6 +89,8 @@ public interface IMaterials
IItemDefinition cardCapacity();
IItemDefinition cardPatternExpansion();
IItemDefinition cardFuzzy();
IItemDefinition cardInverter();
@@ -31,6 +31,9 @@ import net.minecraft.world.World;
import appeng.api.implementations.ICraftingPatternItem;
import appeng.api.storage.data.IAEItemStack;
import java.util.Collections;
import java.util.List;
/**
* do not implement provided by {@link ICraftingPatternItem}
@@ -84,6 +87,11 @@ public interface ICraftingPatternDetails
*/
boolean canSubstitute();
default List<IAEItemStack> getSubstituteInputs( int slot )
{
return Collections.emptyList();
}
/**
* Allow using this INSTANCE of the pattern details to preform the crafting action with performance enhancements.
*
@@ -44,10 +44,7 @@ public interface IStackWatcherHost
/**
* Called when a watched item changes amounts.
*
* @param o changed item list
* @param fullStack old stack
* @param diffStack new stack
* @param src action source
* @param chan storage channel
*/
void onStackChange( IItemList<?> o, IAEStack<?> fullStack, IAEStack<?> diffStack, IActionSource src, IStorageChannel<?> chan );
@@ -51,6 +51,7 @@ public interface IStorageGrid extends IGridCache, IStorageMonitorable
* @param input injected items
*/
void postAlterationOfStoredItems( IStorageChannel<?> chan, Iterable<? extends IAEStack<?>> input, IActionSource src );
void postCraftablesChanges( IStorageChannel<?> chan, Iterable<? extends IAEStack<?>> input, IActionSource src);
/**
* Used to add a cell provider to the storage system
@@ -112,4 +112,13 @@ public interface IAEItemStack extends IAEStack<IAEItemStack>
* @return definition stack
*/
ItemStack getDefinition();
/**
* Compare this AE item stack to another item stack, but ignores
* the amount. It checks the item type, NBT and damage values.
*
* @param is An item stack
*/
boolean equals(ItemStack is);
}
@@ -0,0 +1,143 @@
package com.jaquadro.minecraft.storagedrawers.api.capabilities;
import net.minecraft.item.ItemStack;
import net.minecraft.util.NonNullList;
import javax.annotation.Nonnull;
import java.util.function.Predicate;
/**
* An interface for treating an inventory as a slotless, central repository of items.
*
* For all operations that accept a predicate, if a predicate is supplied, a stored ItemStack must pass the predicate
* in order to be considered for the given operation.
*
* An IItemRepository implementation MAY relax or eliminate its own internal tests when a predicate is supplied. If
* the predicate is derived from DefaultPredicate, then the implementation MUST apply any tests it would have applied
* had no predicate been provided at all, in addition to testing the predicate itself.
*/
public interface IItemRepository
{
/**
* Gets a list of all items in the inventory. The same item may appear multiple times with varying counts.
* @return A list of zero or more items in the inventory.
*/
@Nonnull
NonNullList<ItemRecord> getAllItems ();
/**
* Inserts an ItemStack into the inventory and returns the remainder.
*
* @param stack ItemStack to insert.
* @param simulate If true, the insertion is only simulated
* @param predicate See interface notes about predicates. Passing null specifies default matching.
* @return The remaining ItemStack that was not inserted. If the entire stack was accepted, returns
* ItemStack.EMPTY instead.
*/
@Nonnull
ItemStack insertItem (@Nonnull ItemStack stack, boolean simulate, Predicate<ItemStack> predicate);
@Nonnull
default ItemStack insertItem (@Nonnull ItemStack stack, boolean simulate) {
return insertItem(stack, simulate, null);
}
/**
* Tries to extract the given ItemStack from the inventory. The returned value will be a matching ItemStack
* with a stack size equal to or less than amount, or the empty ItemStack if the item could not be found at all.
* The returned stack size may exceed the ItemStack's getMaxStackSize() value.
* @param stack The item to extract. The stack size is ignored.
* @param amount Amount to extract (may be greater than the stacks max limit)
* @param simulate If true, the extraction is only simulated
* @param predicate See interface notes about predicates. Passing null specifies default matching.
* @return ItemStack extracted from the inventory, or ItemStack.EMPTY if nothing could be extracted.
*/
@Nonnull
ItemStack extractItem (@Nonnull ItemStack stack, int amount, boolean simulate, Predicate<ItemStack> predicate);
@Nonnull
default ItemStack extractItem (@Nonnull ItemStack stack, int amount, boolean simulate) {
return extractItem(stack, amount, simulate, null);
}
/**
* Gets the number of items matching the given ItemStack stored by the inventory.
* @param stack ItemStack to query.
* @param predicate See interface notes about predicates. Passing null specifies default matching.
* @return The number of stored matching items. A value of Integer.MAX_VALUE may indicate an infinite item source.
*/
default int getStoredItemCount (@Nonnull ItemStack stack, Predicate<ItemStack> predicate) {
ItemStack amount = extractItem(stack, Integer.MAX_VALUE, true, predicate);
return amount.getCount();
}
default int getStoredItemCount (@Nonnull ItemStack stack) {
return getStoredItemCount(stack, null);
}
/**
* Gets the number items matching the given ItemStack that additionally still be stored by the inventory.
* Remaining capacity may include space that is internally empty or unassigned to any given item.
*
* @param stack ItemStack to query.
* @param predicate See interface notes about predicates. Passing null specifies default matching.
* @return The available remaining space for matching items.
*/
default int getRemainingItemCapacity (@Nonnull ItemStack stack, Predicate<ItemStack> predicate) {
stack = stack.copy();
stack.setCount(Integer.MAX_VALUE);
ItemStack remainder = insertItem(stack, true, predicate);
return Integer.MAX_VALUE - remainder.getCount();
}
default int getRemainingItemCapacity (@Nonnull ItemStack stack) {
return getRemainingItemCapacity(stack, null);
}
/**
* Gets the total inventory capacity for items matching the given ItemStack.
* Total capacity may include space that is internally empty or unassigned to any given item.
*
* @param stack ItemStack to query.
* @param predicate See interface notes about predicates. Passing null specifies default matching.
* @return The total capacity for matching items.
*/
default int getItemCapacity (@Nonnull ItemStack stack, Predicate<ItemStack> predicate) {
long capacity = getStoredItemCount(stack, predicate) + getRemainingItemCapacity(stack, predicate);
if (capacity > Integer.MAX_VALUE)
return Integer.MAX_VALUE;
return (int)capacity;
}
default int getItemCapacity (@Nonnull ItemStack stack) {
return getItemCapacity(stack, null);
}
/**
* An item record representing an item and the amount stored.
*
* The ItemStack held by itemPrototype always reports a stack size of 1.
* IT IS IMPORTANT THAT YOU NEVER MODIFY itemPrototype.
*/
class ItemRecord
{
@Nonnull
public final ItemStack itemPrototype;
public final int count;
public ItemRecord (@Nonnull ItemStack itemPrototype, int count) {
this.itemPrototype = itemPrototype;
this.count = count;
}
}
/**
* A variant of the standard Predicate interface that when passed to IItemRepository functions, will ask the
* internal default predicate to be tested in addition to the custom predicate. An IItemRepository function
* may choose to enforce its own predicate regardless.
*/
interface DefaultPredicate<T> extends Predicate<T> { }
}
@@ -0,0 +1,87 @@
package yalter.mousetweaks.api;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.Slot;
/**
* This is the interface you want to implement in your GuiScreen to make it compatible with Mouse Tweaks.
* If this interface is not enough (for example, you need a custom slot click function, or if you use a custom Container
* which happens to be incompatible), check IMTModGuiContainer2Ex instead.
* If you just need to disable Mouse Tweaks or the wheel tweak, see the MouseTweaksIgnore
* or the MouseTweaksDisableWheelTweak annotations.
*/
public interface IMTModGuiContainer2 {
/**
* If you want to disable Mouse Tweaks in your GuiScreen, return true from this method.
*
* @return True if Mouse Tweaks should be disabled, false otherwise.
*/
boolean MT_isMouseTweaksDisabled();
/**
* If you want to disable the Wheel Tweak in your GuiScreen, return true from this method.
*
* @return True if the Wheel Tweak should be disabled, false otherwise.
*/
boolean MT_isWheelTweakDisabled();
/**
* Returns the Container.
*
* @return Container that is currently in use.
*/
Container MT_getContainer();
/**
* Returns the Slot that is currently selected by the player, or null if no Slot is selected.
*
* @return Slot that is located under the mouse, or null if no Slot it currently under the mouse.
*/
Slot MT_getSlotUnderMouse();
/**
* Return true if the given Slot behaves like the vanilla crafting output slots (inside the crafting table,
* or the furnace output slot, or the anvil output slot, etc.). These slots are handled differently by Mouse Tweaks.
*
* @param slot the slot to check
* @return True if slot is a crafting output slot.
*/
boolean MT_isCraftingOutput(Slot slot);
/**
* Return true if the given Slot should be ignored by Mouse Tweaks. Examples of ignored slots are the item select
* slots and the Destroy Item slot in the vanilla creative inventory.
*
* @param slot the slot to check
* @return Tru if slot should be ignored by Mouse Tweaks.
*/
boolean MT_isIgnored(Slot slot);
/**
* If your container has an RMB dragging functionality (like vanilla containers), disable it inside this method.
* This method is called every frame (render tick), which is after all mouseClicked / mouseClickMove / mouseReleased
* events are handled (although note these events are handled every game tick, which is far less frequent than every
* render tick).<br><br>
*
* If true is returned from this method, Mouse Tweaks (after checking other conditions like isIgnored) will click
* the slot on which the right mouse button was initially pressed (in most cases this is the slot currently under
* mouse). This is needed because the vanilla RMB dragging functionality prevents the initial slot click.<br><br>
*
* For vanilla containers this method looks like this:
* <pre>
* this.ignoreMouseUp = true;
*
* if (this.dragSplitting) {
* if (this.dragSplittingButton == 1) {
* this.dragSplitting = false;
* return true;
* }
* }
*
* return false;
* </pre>
*
* @return True if Mouse Tweaks should click the slot on which the RMB was pressed.
*/
boolean MT_disableRMBDraggingFunctionality();
}
@@ -19,6 +19,7 @@
package appeng.capabilities;
import com.jaquadro.minecraft.storagedrawers.api.capabilities.IItemRepository;
import net.darkhax.tesla.api.ITeslaConsumer;
import net.darkhax.tesla.api.ITeslaHolder;
import net.minecraft.nbt.NBTBase;
@@ -54,6 +55,8 @@ public final class Capabilities
public static Capability<IEnergyStorage> FORGE_ENERGY;
public static Capability<IItemRepository> ITEM_REPOSITORY_CAPABILITY;
/**
* Register AE2 provided capabilities.
*/
@@ -99,6 +102,9 @@ public final class Capabilities
FORGE_ENERGY = cap;
}
@CapabilityInject( IItemRepository.class )
private static void capIItemRepositoryRegistered( Capability<IItemRepository> cap ) { ITEM_REPOSITORY_CAPABILITY = cap; }
// Create a storage implementation that does not do anything
private static <T> Capability.IStorage<T> createNullStorage()
{
+33 -3
View File
@@ -25,7 +25,11 @@ import java.util.EnumMap;
import java.util.List;
import java.util.Random;
import appeng.client.gui.AEBaseGui;
import appeng.container.interfaces.IJEIGhostIngredients;
import appeng.helpers.HighlighterHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.entity.player.EntityPlayer;
@@ -35,9 +39,7 @@ import net.minecraft.util.EnumHand;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.client.event.MouseEvent;
import net.minecraftforge.client.event.RenderLivingEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.client.event.*;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.common.ForgeModContainer;
import net.minecraftforge.common.MinecraftForge;
@@ -73,6 +75,7 @@ import appeng.hooks.TickHandler;
import appeng.hooks.TickHandler.PlayerColor;
import appeng.server.ServerHelper;
import appeng.util.Platform;
import org.lwjgl.input.Mouse;
public class ClientHelper extends ServerHelper
@@ -106,6 +109,11 @@ public class ClientHelper extends ServerHelper
}
}
@SubscribeEvent
public void renderWorldLastEvent( RenderWorldLastEvent event) {
HighlighterHandler.tick(event);
}
@Override
public World getWorld()
{
@@ -308,6 +316,28 @@ public class ClientHelper extends ServerHelper
Minecraft.getMinecraft().effectRenderer.addEffect( fx );
}
@SubscribeEvent
public void MouseClickEvent( final GuiScreenEvent.MouseInputEvent.Pre me )
{
final Minecraft mc = Minecraft.getMinecraft();
if( mc.currentScreen instanceof IJEIGhostIngredients )
{
AEBaseGui gui = ( (AEBaseGui) mc.currentScreen );
Object ingredient = gui.getBookmarkedIngredient();
if( ingredient != null )
{
if( GuiScreen.isShiftKeyDown() )
{
me.setCanceled( true );
}
else if( Mouse.isButtonDown( 0 ) )
{
me.setCanceled( true );
}
}
}
}
@SubscribeEvent
public void wheelEvent( final MouseEvent me )
{
+255 -24
View File
@@ -19,6 +19,7 @@
package appeng.client.gui;
import java.awt.*;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.ParseException;
@@ -31,10 +32,16 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import appeng.container.slot.*;
import com.google.common.base.Joiner;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import mezz.jei.api.gui.IGhostIngredientHandler;
import net.minecraft.client.gui.Gui;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fml.common.Optional;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
@@ -68,17 +75,7 @@ import appeng.client.me.SlotDisconnected;
import appeng.client.me.SlotME;
import appeng.client.render.StackSizeRenderer;
import appeng.container.AEBaseContainer;
import appeng.container.slot.AppEngCraftingSlot;
import appeng.container.slot.AppEngSlot;
import appeng.container.slot.AppEngSlot.hasCalculatedValidness;
import appeng.container.slot.IOptionalSlot;
import appeng.container.slot.SlotCraftingTerm;
import appeng.container.slot.SlotDisabled;
import appeng.container.slot.SlotFake;
import appeng.container.slot.SlotInaccessible;
import appeng.container.slot.SlotOutput;
import appeng.container.slot.SlotPatternTerm;
import appeng.container.slot.SlotRestrictedInput;
import appeng.core.AELog;
import appeng.core.AppEng;
import appeng.core.sync.network.NetworkHandler;
@@ -87,9 +84,14 @@ import appeng.core.sync.packets.PacketSwapSlots;
import appeng.fluids.client.render.FluidStackSizeRenderer;
import appeng.fluids.container.slots.IMEFluidSlot;
import appeng.helpers.InventoryAction;
import yalter.mousetweaks.api.IMTModGuiContainer2;
import static appeng.integration.modules.jei.JEIPlugin.aeGuiHandler;
import static appeng.integration.modules.jei.JEIPlugin.runtime;
public abstract class AEBaseGui extends GuiContainer
@Optional.Interface( iface = "yalter.mousetweaks.api.IMTModGuiContainer2", modid = "mousetweaks" )
public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContainer2
{
private final List<InternalSlotME> meSlots = new ArrayList<>();
// drag y
@@ -101,6 +103,28 @@ public abstract class AEBaseGui extends GuiContainer
private Stopwatch dbl_clickTimer = Stopwatch.createStarted();
private ItemStack dbl_whichItem = ItemStack.EMPTY;
private Slot bl_clicked;
private Stopwatch lastClicked = Stopwatch.createStarted();
private List<IGhostIngredientHandler.Target<Object>> hoveredIngredientTargets = new ArrayList<>();
private Object bookmarkedIngredient;
private boolean isDraggingJeiGhostItem;
public void setJeiGhostItem( boolean jeiGhostItem )
{
isJeiGhostItem = jeiGhostItem;
}
private boolean isJeiGhostItem;
public Object getBookmarkedIngredient()
{
return bookmarkedIngredient;
}
public List<GuiCustomSlot> getGuiSlots()
{
return guiSlots;
}
protected final List<GuiCustomSlot> guiSlots = new ArrayList<>();
public AEBaseGui( final Container container )
@@ -183,6 +207,65 @@ public abstract class AEBaseGui extends GuiContainer
this.drawTooltip( (ITooltip) c, mouseX, mouseY );
}
}
GlStateManager.enableDepth();
bookmarkedJEIghostItem(mouseX,mouseY);
GlStateManager.disableDepth();
}
void bookmarkedJEIghostItem(final int mouseX, final int mouseY) {
if (!isJeiGhostItem)
{
bookmarkedIngredient = runtime.getBookmarkOverlay().getIngredientUnderMouse();
}
if( bookmarkedIngredient != null )
{
hoveredIngredientTargets = aeGuiHandler.getTargets( this, bookmarkedIngredient, false );
ItemStack dragItem = ItemStack.EMPTY;
if( hoveredIngredientTargets.size() > 0 )
{
if( isShiftKeyDown() && Mouse.isButtonDown( 0 ) && this.lastClicked.elapsed( TimeUnit.MILLISECONDS ) > 200 )
{
this.lastClicked = Stopwatch.createStarted();
aeGuiHandler.getTargets( this, bookmarkedIngredient, true );
}
else if( Mouse.isButtonDown( 0 ) && this.lastClicked.elapsed( TimeUnit.MILLISECONDS ) > 200 )
{
this.lastClicked = Stopwatch.createStarted();
if( bookmarkedIngredient instanceof ItemStack )
{
dragItem = ( (ItemStack) bookmarkedIngredient );
}
else if( bookmarkedIngredient instanceof FluidStack )
{
dragItem = FluidUtil.getFilledBucket( ( (FluidStack) bookmarkedIngredient ) );
}
mc.player.inventory.setItemStack( dragItem.copy() );
this.isJeiGhostItem = true;
}
drawTargets( mouseX, mouseY );
}
}
}
private void drawTargets(int mouseX, int mouseY) {
GlStateManager.disableLighting();
for( IGhostIngredientHandler.Target target : hoveredIngredientTargets )
{
Rectangle area = target.getArea();
Color color;
if( area.contains( mouseX, mouseY ) )
{
color = new Color( 76, 201, 25, 128 );
}
else
{
color = new Color( 19, 201, 10, 64 );
}
Gui.drawRect( area.x, area.y, area.x + area.width, area.y + area.height, color.getRGB() );
}
GlStateManager.color( 1f, 1f, 1f, 1f );
GlStateManager.enableDepth();
}
protected void drawGuiSlot( GuiCustomSlot slot, int mouseX, int mouseY, float partialTicks )
@@ -315,7 +398,6 @@ public abstract class AEBaseGui extends GuiContainer
{
slot.drawBackground( ox, oy );
}
}
@Override
@@ -375,6 +457,43 @@ public abstract class AEBaseGui extends GuiContainer
}
}
}
else if( slot instanceof SlotDisconnected )
{
this.drag_click.add( slot );
if( this.drag_click.size() > 1 )
{
if( !itemstack.isEmpty() )
{
for( final Slot dr : this.drag_click )
{
if( slot.getStack().isEmpty() )
{
InventoryAction action = InventoryAction.SPLIT_OR_PLACE_SINGLE;
final PacketInventoryAction p = new PacketInventoryAction( action, dr.getSlotIndex(), ( (SlotDisconnected) slot ).getSlot().getId() );
NetworkHandler.instance().sendToServer( p );
}
}
}
else if( isShiftKeyDown() )
{
for( final Slot dr : this.drag_click )
{
InventoryAction action = null;
if( !slot.getStack().isEmpty() )
{
action = InventoryAction.SHIFT_CLICK;
}
if( action != null )
{
final PacketInventoryAction p = new PacketInventoryAction( action, dr.getSlotIndex(), ( (SlotDisconnected) slot ).getSlot().getId() );
NetworkHandler.instance().sendToServer( p );
}
}
}
}
}
else
{
super.mouseClickMove( x, y, c, d );
@@ -387,18 +506,56 @@ public abstract class AEBaseGui extends GuiContainer
{
final EntityPlayer player = Minecraft.getMinecraft().player;
if( slot instanceof SlotFake )
if( this.isJeiGhostItem && isDraggingJeiGhostItem)
{
final InventoryAction action = mouseButton == 1 ? InventoryAction.SPLIT_OR_PLACE_SINGLE : InventoryAction.PICKUP_OR_SET_DOWN;
for( IGhostIngredientHandler.Target target : hoveredIngredientTargets )
{
Rectangle area = target.getArea();
final int x = Mouse.getEventX() * this.width / this.mc.displayWidth;
final int y = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1;
if( area.contains( x, y ) )
{
target.accept( bookmarkedIngredient );
break;
}
}
this.isJeiGhostItem = false;
this.isDraggingJeiGhostItem = false;
ItemStack dragItem = ItemStack.EMPTY;
if( runtime.getBookmarkOverlay().getIngredientUnderMouse() != null )
{
bookmarkedJEIghostItem( Mouse.getX(), this.mc.displayHeight - Mouse.getY() );
if( bookmarkedIngredient instanceof ItemStack )
{
dragItem = ( (ItemStack) bookmarkedIngredient );
}
else if( bookmarkedIngredient instanceof FluidStack )
{
dragItem = FluidUtil.getFilledBucket( ( (FluidStack) bookmarkedIngredient ) );
}
mc.player.inventory.setItemStack( dragItem.copy() );
this.isJeiGhostItem = true;
}
else
{
mc.player.inventory.setItemStack( dragItem );
}
}
else if( slot instanceof SlotFake )
{
final InventoryAction action;
action = mouseButton == 1 ? InventoryAction.SPLIT_OR_PLACE_SINGLE : InventoryAction.PICKUP_OR_SET_DOWN;
if( this.drag_click.size() > 1 )
{
return;
}
final PacketInventoryAction p = new PacketInventoryAction( action, slotIdx, 0 );
PacketInventoryAction p = new PacketInventoryAction( action, slotIdx, 0 );
NetworkHandler.instance().sendToServer( p );
return;
}
@@ -468,12 +625,24 @@ public abstract class AEBaseGui extends GuiContainer
if( slot instanceof SlotDisconnected )
{
if( this.drag_click.size() > 1 )
{
return;
}
InventoryAction action = null;
switch( clickType )
switch ( clickType )
{
case PICKUP: // pickup / set-down.
action = ( mouseButton == 1 ) ? InventoryAction.SPLIT_OR_PLACE_SINGLE : InventoryAction.PICKUP_OR_SET_DOWN;
if( slot.getStack().isEmpty() && !player.inventory.getItemStack().isEmpty() )
{
action = InventoryAction.SPLIT_OR_PLACE_SINGLE;
}
if( !slot.getStack().isEmpty() && player.inventory.getItemStack().getCount() <= 1 )
{
action = InventoryAction.PICKUP_OR_SET_DOWN;
}
break;
case QUICK_MOVE:
action = ( mouseButton == 1 ) ? InventoryAction.PICKUP_SINGLE : InventoryAction.SHIFT_CLICK;
@@ -506,14 +675,13 @@ public abstract class AEBaseGui extends GuiContainer
InventoryAction action = null;
IAEItemStack stack = null;
switch( clickType )
switch ( clickType )
{
case PICKUP: // pickup / set-down.
action = ( mouseButton == 1 ) ? InventoryAction.SPLIT_OR_PLACE_SINGLE : InventoryAction.PICKUP_OR_SET_DOWN;
stack = ( (SlotME) slot ).getAEStack();
if( stack != null && action == InventoryAction.PICKUP_OR_SET_DOWN && stack.getStackSize() == 0 && player.inventory.getItemStack()
.isEmpty() )
if( stack != null && action == InventoryAction.PICKUP_OR_SET_DOWN && stack.getStackSize() == 0 && player.inventory.getItemStack().isEmpty() )
{
action = InventoryAction.AUTO_CRAFT;
}
@@ -580,9 +748,7 @@ public abstract class AEBaseGui extends GuiContainer
final List<Slot> slots = this.getInventorySlots();
for( final Slot inventorySlot : slots )
{
if( inventorySlot != null && inventorySlot.canTakeStack(
this.mc.player ) && inventorySlot.getHasStack() && inventorySlot.isSameInventory( slot ) && Container.canAddItemToSlot(
inventorySlot, this.dbl_whichItem, true ) )
if( inventorySlot != null && inventorySlot.canTakeStack( this.mc.player ) && inventorySlot.getHasStack() && inventorySlot.isSameInventory( slot ) && Container.canAddItemToSlot( inventorySlot, this.dbl_whichItem, true ) )
{
this.handleMouseClick( inventorySlot, inventorySlot.slotNumber, 0, ClickType.QUICK_MOVE );
}
@@ -593,6 +759,11 @@ public abstract class AEBaseGui extends GuiContainer
this.disableShiftClick = false;
}
if (clickType == ClickType.PICKUP && isJeiGhostItem && !isDraggingJeiGhostItem) {
this.isDraggingJeiGhostItem = true;
return;
}
super.handleMouseClick( slot, slotIdx, mouseButton, clickType );
}
@@ -702,6 +873,16 @@ public abstract class AEBaseGui extends GuiContainer
}
}
}
if( slot instanceof SlotFake )
{
final ItemStack stack = ( (SlotFake) slot ).getStack();
if( stack != ItemStack.EMPTY )
{
InventoryAction direction = wheel > 0 ? InventoryAction.PLACE_SINGLE : InventoryAction.PICKUP_SINGLE;
final PacketInventoryAction p = new PacketInventoryAction( direction , slot.slotNumber , 0);
NetworkHandler.instance().sendToServer( p );
}
}
}
protected boolean enableSpaceClicking()
@@ -961,4 +1142,54 @@ public abstract class AEBaseGui extends GuiContainer
{
return this.meSlots;
}
@Override
@Optional.Method( modid = "mousetweaks" )
public boolean MT_isMouseTweaksDisabled()
{
return false;
}
@Override
@Optional.Method( modid = "mousetweaks" )
public boolean MT_isWheelTweakDisabled()
{
return true;
}
@Override
@Optional.Method( modid = "mousetweaks" )
public Container MT_getContainer()
{
return this.inventorySlots;
}
@Override
@Optional.Method( modid = "mousetweaks" )
public Slot MT_getSlotUnderMouse()
{
return getSlotUnderMouse();
}
@Override
@Optional.Method( modid = "mousetweaks" )
public boolean MT_isCraftingOutput( Slot slot )
{
return slot instanceof SlotOutput || slot instanceof AppEngCraftingSlot;
}
@Override
@Optional.Method( modid = "mousetweaks" )
public boolean MT_isIgnored( Slot slot )
{
return false;
}
@Override
@Optional.Method( modid = "mousetweaks" )
public boolean MT_disableRMBDraggingFunctionality()
{
return false;
}
}
@@ -0,0 +1,144 @@
package appeng.client.gui;
import javax.annotation.Nullable;
import appeng.api.storage.data.IAEItemStack;
import appeng.client.gui.implementations.*;
import appeng.container.interfaces.IJEIGhostIngredients;
import appeng.container.slot.SlotFake;
import appeng.fluids.client.gui.widgets.GuiFluidSlot;
import mezz.jei.api.gui.IAdvancedGuiHandler;
import mezz.jei.api.gui.IGhostIngredientHandler;
import net.minecraft.client.gui.GuiScreen;
import org.lwjgl.input.Mouse;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class AEGuiHandler implements IAdvancedGuiHandler<AEBaseGui>, IGhostIngredientHandler<AEBaseGui>
{
@Override
public Class<AEBaseGui> getGuiContainerClass()
{
return AEBaseGui.class;
}
@Nullable
@Override
public List<Rectangle> getGuiExtraAreas( AEBaseGui guiContainer )
{
return Collections.emptyList();
}
@Nullable
@Override
public Object getIngredientUnderMouse( AEBaseGui guiContainer, int mouseX, int mouseY )
{
List<IAEItemStack> visual;
int guiSlotIdx;
Object result = null;
if( guiContainer instanceof GuiCraftConfirm )
{
guiSlotIdx = getSlotidx( guiContainer, mouseX, mouseY, ( (GuiCraftConfirm) guiContainer ).getDisplayedRows() );
visual = ( (GuiCraftConfirm) guiContainer ).getVisual();
if( guiSlotIdx < visual.size() && guiSlotIdx != -1 )
{
result = visual.get( guiSlotIdx ).getDefinition();
}
else
{
return null;
}
}
if( guiContainer instanceof GuiCraftingCPU )
{
guiSlotIdx = getSlotidx( guiContainer, mouseX, mouseY, ( (GuiCraftingCPU) guiContainer ).getDisplayedRows() );
visual = ( (GuiCraftingCPU) guiContainer ).getVisual();
if( guiSlotIdx < visual.size() && guiSlotIdx != -1 )
{
result = visual.get( guiSlotIdx ).getDefinition();
}
else
{
return null;
}
}
if( guiContainer instanceof GuiCraftAmount )
{
if( guiContainer.getSlotUnderMouse() != null )
{
result = guiContainer.getSlotUnderMouse().getStack();
}
}
return result;
}
private int getSlotidx(AEBaseGui guiContainer, int mouseX, int mouseY, int rows)
{
int guileft = guiContainer.getGuiLeft();
int guitop = guiContainer.getGuiTop();
int currentScroll = guiContainer.getScrollBar().getCurrentScroll();
final int xo = 9;
final int yo = 19;
int guiSlotx = ( mouseX - guileft - xo ) / 67;
if( guiSlotx > 2 || mouseX < guileft + xo ) return -1;
int guiSloty = ( mouseY - guitop - yo ) / 23;
if( guiSloty > ( rows - 1 ) || mouseY < guitop + yo ) return -1;
return ( guiSloty * 3 ) + guiSlotx + ( currentScroll * 3 );
}
@Override
public <I> List<Target<I>> getTargets( AEBaseGui gui, I ingredient, boolean doStart )
{
ArrayList<Target<I>> targets = new ArrayList<>();
if( gui instanceof IJEIGhostIngredients )
{
IJEIGhostIngredients g = (IJEIGhostIngredients) gui;
List<Target<?>> phantomTargets = g.getPhantomTargets( ingredient );
targets.addAll( (List<Target<I>>) (Object) phantomTargets );
}
if( doStart && GuiScreen.isShiftKeyDown() && Mouse.isButtonDown( 0 ) )
{
if( gui instanceof GuiUpgradeable || gui instanceof GuiPatternTerm )
{
IJEIGhostIngredients ghostGui = ( (IJEIGhostIngredients) gui );
for( Target<I> target : targets )
{
if( ghostGui.getFakeSlotTargetMap().get( target ) instanceof SlotFake )
{
if( ( (SlotFake) ghostGui.getFakeSlotTargetMap().get( target ) ).getStack().isEmpty() )
{
target.accept( ingredient );
break;
}
}
else if( ghostGui.getFakeSlotTargetMap().get( target ) instanceof GuiFluidSlot )
{
if( ( (GuiFluidSlot) ghostGui.getFakeSlotTargetMap().get( target ) ).getFluidStack() == null )
{
target.accept( ingredient );
break;
}
}
}
}
}
return targets;
}
@Override
public void onComplete(){
}
@Override
public boolean shouldHighlightTargets()
{
return true;
}
}
@@ -582,4 +582,14 @@ public class GuiCraftConfirm extends AEBaseGui
}
}
}
public List<IAEItemStack> getVisual()
{
return visual;
}
public int getDisplayedRows()
{
return this.rows;
}
}
@@ -493,4 +493,14 @@ public class GuiCraftingCPU extends AEBaseGui implements ISortSource
{
return ViewItems.ALL;
}
public List<IAEItemStack> getVisual()
{
return visual;
}
public int getDisplayedRows()
{
return DISPLAYED_ROWS;
}
}
@@ -50,7 +50,7 @@ public class GuiInterface extends GuiUpgradeable
public GuiInterface( final InventoryPlayer inventoryPlayer, final IInterfaceHost te )
{
super( new ContainerInterface( inventoryPlayer, te ) );
this.ySize = 211;
this.ySize = 256;
}
@Override
@@ -62,8 +62,7 @@ public class GuiInterface extends GuiUpgradeable
this.BlockMode = new GuiImgButton( this.guiLeft - 18, this.guiTop + 8, Settings.BLOCK, YesNo.NO );
this.buttonList.add( this.BlockMode );
this.interfaceMode = new GuiToggleButton( this.guiLeft - 18, this.guiTop + 26, 84, 85, GuiText.InterfaceTerminal
.getLocal(), GuiText.InterfaceTerminalHint.getLocal() );
this.interfaceMode = new GuiToggleButton( this.guiLeft - 18, this.guiTop + 26, 84, 85, GuiText.InterfaceTerminal.getLocal(), GuiText.InterfaceTerminalHint.getLocal() );
this.buttonList.add( this.interfaceMode );
}
@@ -86,13 +85,20 @@ public class GuiInterface extends GuiUpgradeable
this.fontRenderer.drawString( GuiText.StoredItems.getLocal(), 8, 6 + 60 + 7, 4210752 );
this.fontRenderer.drawString( GuiText.Patterns.getLocal(), 8, 6 + 73 + 7, 4210752 );
this.fontRenderer.drawString( GuiText.inventory.getLocal(), 8, this.ySize - 96 + 3, 4210752 );
}
@Override
protected String getBackground()
{
return "guis/interface.png";
int upgrades = ( (ContainerInterface) this.cvb ).getPatternUpgrades();
if( upgrades == 0 )
{
return "guis/newinterface.png";
}
else
{
return "guis/newinterface" + upgrades + ".png";
}
}
@Override
@@ -117,4 +123,5 @@ public class GuiInterface extends GuiUpgradeable
NetworkHandler.instance().sendToServer( new PacketConfigButton( this.BlockMode.getSetting(), backwards ) );
}
}
}
@@ -20,20 +20,23 @@ package appeng.client.gui.implementations;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.*;
import appeng.api.config.ActionItems;
import appeng.api.config.Settings;
import appeng.api.config.Upgrades;
import appeng.client.gui.widgets.GuiImgButton;
import appeng.core.worlddata.IWorldPlayerMapping;
import appeng.helpers.DualityInterface;
import appeng.parts.misc.PartInterface;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.tile.misc.TileInterface;
import appeng.util.BlockPosUtils;
import com.google.common.collect.HashMultimap;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
@@ -49,6 +52,14 @@ import appeng.container.implementations.ContainerInterfaceTerminal;
import appeng.core.localization.GuiText;
import appeng.parts.reporting.PartInterfaceTerminal;
import appeng.util.Platform;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentString;
import net.minecraftforge.common.DimensionManager;
import org.lwjgl.input.Mouse;
import static appeng.client.render.BlockPosHighlighter.hilightBlock;
public class GuiInterfaceTerminal extends AEBaseGui
@@ -57,26 +68,36 @@ public class GuiInterfaceTerminal extends AEBaseGui
private static final int LINES_ON_PAGE = 6;
// TODO: copied from GuiMEMonitorable. It looks not changed, maybe unneeded?
private final int offsetX = 9;
private final int offsetX = 21;
private final HashMap<Long, ClientDCInternalInv> byId = new HashMap<>();
private final HashMultimap<String, ClientDCInternalInv> byName = HashMultimap.create();
private final HashMap<ClientDCInternalInv,BlockPos> blockPosHashMap = new HashMap<>();
private final HashMap<GuiButton,ClientDCInternalInv> guiButtonHashMap = new HashMap<>();
private final Map<ClientDCInternalInv,Integer> numUpgradesMap = new HashMap<>();
private final ArrayList<String> names = new ArrayList<>();
private final ArrayList<Object> lines = new ArrayList<>();
private final Set<Object> matchedStacks = new HashSet<>();
private final Map<String, Set<Object>> cachedSearches = new WeakHashMap<>();
private boolean refreshList = false;
private MEGuiTextField searchField;
private MEGuiTextField searchFieldOutputs;
private MEGuiTextField searchFieldInputs;
private PartInterfaceTerminal partInterfaceTerminal;
private GuiButton guiButtonHide;
private GuiButton guiButtonNextAssembler;
private HashMap<ClientDCInternalInv,Integer> dimHashMap = new HashMap<>();
public GuiInterfaceTerminal( final InventoryPlayer inventoryPlayer, final PartInterfaceTerminal te )
{
super( new ContainerInterfaceTerminal( inventoryPlayer, te ) );
this.partInterfaceTerminal = te;
final GuiScrollbar scrollbar = new GuiScrollbar();
this.setScrollBar( scrollbar );
this.xSize = 195;
this.ySize = 222;
this.xSize = 208;
this.ySize = 255;
}
@Override
@@ -84,45 +105,79 @@ public class GuiInterfaceTerminal extends AEBaseGui
{
super.initGui();
this.getScrollBar().setLeft( 175 );
this.getScrollBar().setLeft( 189 );
this.getScrollBar().setHeight( 106 );
this.getScrollBar().setTop( 18 );
this.getScrollBar().setTop( 51 );
this.searchField = new MEGuiTextField( this.fontRenderer, this.guiLeft + Math.max( 104, this.offsetX ), this.guiTop + 4, 65, 12 );
this.searchField.setEnableBackgroundDrawing( false );
this.searchField.setMaxStringLength( 25 );
this.searchField.setTextColor( 0xFFFFFF );
this.searchField.setVisible( true );
this.searchField.setFocused( true );
this.searchFieldInputs = new MEGuiTextField( this.fontRenderer, this.guiLeft + Math.max( 32, this.offsetX ), this.guiTop + 25, 65, 12 );
this.searchFieldInputs.setEnableBackgroundDrawing( false );
this.searchFieldInputs.setMaxStringLength( 25 );
this.searchFieldInputs.setTextColor( 0xFFFFFF );
this.searchFieldInputs.setVisible( true );
this.searchFieldInputs.setFocused( false );
this.searchFieldOutputs = new MEGuiTextField( this.fontRenderer, this.guiLeft + Math.max( 32, this.offsetX ), this.guiTop + 38, 65, 12 );
this.searchFieldOutputs.setEnableBackgroundDrawing( false );
this.searchFieldOutputs.setMaxStringLength( 25 );
this.searchFieldOutputs.setTextColor( 0xFFFFFF );
this.searchFieldOutputs.setVisible( true );
this.searchFieldOutputs.setFocused( true );
this.searchFieldInputs.setText( partInterfaceTerminal.in );
this.searchFieldOutputs.setText( partInterfaceTerminal.out );
}
@Override
public void onGuiClosed()
{
partInterfaceTerminal.saveSearchStrings( this.searchFieldInputs.getText().toLowerCase(), this.searchFieldOutputs.getText().toLowerCase() );
super.onGuiClosed();
}
@Override
public void drawFG( final int offsetX, final int offsetY, final int mouseX, final int mouseY )
{
this.buttonList.clear();
this.fontRenderer.drawString( this.getGuiDisplayName( GuiText.InterfaceTerminal.getLocal() ), 8, 6, 4210752 );
this.fontRenderer.drawString( GuiText.inventory.getLocal(), 8, this.ySize - 96 + 3, 4210752 );
this.fontRenderer.drawString( GuiText.inventory.getLocal(), this.offsetX + 2, this.ySize - 96 + 3, 4210752 );
final int ex = this.getScrollBar().getCurrentScroll();
final int currentScroll = this.getScrollBar().getCurrentScroll();
final Iterator<Slot> o = this.inventorySlots.inventorySlots.iterator();
while( o.hasNext() )
this.guiButtonNextAssembler = new GuiImgButton( guiLeft + 123, guiTop + 25, Settings.ACTIONS, ActionItems.FREE_MOLECULAR_SLOT_SHORTCUT );
this.buttonList.add( guiButtonNextAssembler );
guiButtonHide = new GuiImgButton( guiLeft + 141, guiTop + 25, Settings.ACTIONS, this.partInterfaceTerminal.onlyInterfacesWithFreeSlots ? ActionItems.TOGGLE_SHOW_FULL_INTERFACES_OFF : ActionItems.TOGGLE_SHOW_FULL_INTERFACES_ON );
this.buttonList.add( guiButtonHide );
this.inventorySlots.inventorySlots.removeIf( slot -> slot instanceof SlotDisconnected );
int offset = 52;
int linesDraw = 0;
for( int x = 0; x < LINES_ON_PAGE && linesDraw < LINES_ON_PAGE && currentScroll + x < this.lines.size(); x++ )
{
if( o.next() instanceof SlotDisconnected )
{
o.remove();
}
}
int offset = 17;
for( int x = 0; x < LINES_ON_PAGE && ex + x < this.lines.size(); x++ )
{
final Object lineObj = this.lines.get( ex + x );
final Object lineObj = this.lines.get( currentScroll + x );
if( lineObj instanceof ClientDCInternalInv )
{
final ClientDCInternalInv inv = (ClientDCInternalInv) lineObj;
for( int z = 0; z < inv.getInventory().getSlots(); z++ )
GuiButton guiButton = new GuiImgButton( guiLeft + 4, guiTop + offset, Settings.ACTIONS, ActionItems.HIGHLIGHT_INTERFACE );
guiButtonHashMap.put( guiButton, inv );
this.buttonList.add( guiButton );
int extraLines = numUpgradesMap.get( inv );
for( int row = 0; row < 1 + extraLines && linesDraw < LINES_ON_PAGE ; ++row )
{
this.inventorySlots.inventorySlots.add( new SlotDisconnected( inv, z, z * 18 + 8, 1 + offset ) );
for( int z = 0; z < 9 ; z++ )
{
this.inventorySlots.inventorySlots.add( new SlotDisconnected( inv, z + ( row * 9 ), ( z * 18 + 22 ), offset ) );
if( this.matchedStacks.contains( inv.getInventory().getStackInSlot( z + ( row * 9 ) ) ) )
{
drawRect( z * 18 + 22, offset, z * 18 + 22 + 16, offset + 16, 0x2A00FF00 );
}
}
linesDraw++;
offset += 18;
}
}
else if( lineObj instanceof String )
@@ -134,57 +189,130 @@ public class GuiInterfaceTerminal extends AEBaseGui
name = name + " (" + rows + ')';
}
while( name.length() > 2 && this.fontRenderer.getStringWidth( name ) > 155 )
while ( name.length() > 2 && this.fontRenderer.getStringWidth( name ) > 155 )
{
name = name.substring( 0, name.length() - 1 );
}
this.fontRenderer.drawString( name, 10, 6 + offset, 4210752 );
this.fontRenderer.drawString( name, this.offsetX + 2, 5 + offset, 4210752 );
linesDraw++;
offset += 18;
}
offset += 18;
}
if( searchFieldInputs.isMouseIn( mouseX, mouseY ) ) drawTooltip( Mouse.getEventX() * this.width / this.mc.displayWidth - offsetX, mouseY - guiTop, "Inputs OR names" );
else if( searchFieldOutputs.isMouseIn( mouseX, mouseY ) ) drawTooltip( Mouse.getEventX() * this.width / this.mc.displayWidth - offsetX, mouseY - guiTop, "Outputs OR names" );
}
@Override
protected void mouseClicked( final int xCoord, final int yCoord, final int btn ) throws IOException
{
this.searchField.mouseClicked( xCoord, yCoord, btn );
this.searchFieldInputs.mouseClicked( xCoord, yCoord, btn );
if( btn == 1 && this.searchField.isMouseIn( xCoord, yCoord ) )
if( btn == 1 && this.searchFieldInputs.isMouseIn( xCoord, yCoord ) )
{
this.searchField.setText( "" );
this.searchFieldInputs.setText( "" );
this.refreshList();
}
this.searchFieldOutputs.mouseClicked( xCoord, yCoord, btn );
if( btn == 1 && this.searchFieldOutputs.isMouseIn( xCoord, yCoord ) )
{
this.searchFieldOutputs.setText( "" );
this.refreshList();
}
super.mouseClicked( xCoord, yCoord, btn );
}
@Override
protected void actionPerformed( final GuiButton btn ) throws IOException
{
if( guiButtonHashMap.containsKey( btn ) )
{
BlockPos blockPos = blockPosHashMap.get( guiButtonHashMap.get( this.selectedButton ) );
BlockPos blockPos2 = mc.player.getPosition();
int playerDim = mc.world.provider.getDimension();
int interfaceDim = dimHashMap.get( guiButtonHashMap.get( this.selectedButton ) );
if( playerDim != interfaceDim )
{
try {
mc.player.sendStatusMessage( new TextComponentString( "Interface located at dimension: " + interfaceDim + " [" + DimensionManager.getWorld( interfaceDim ).provider.getDimensionType().getName() + "] and cant be highlighted" ), false );
} catch(Exception e){
mc.player.sendStatusMessage( new TextComponentString( "Interface is located in another dimension and cannot be highlighted" ), false );
}
}
else
{
hilightBlock( blockPos, System.currentTimeMillis() + 500 * BlockPosUtils.getDistance( blockPos, blockPos2 ), playerDim );
mc.player.sendStatusMessage( new TextComponentString( "The interface is now highlighted at " + "X: " + blockPos.getX() + " Y: " + blockPos.getY() + " Z: " + blockPos.getZ() ), false );
}
mc.player.closeScreen();
}
if (btn == guiButtonHide)
{
partInterfaceTerminal.onlyInterfacesWithFreeSlots = !partInterfaceTerminal.onlyInterfacesWithFreeSlots;
this.refreshList();
}
if (btn == guiButtonNextAssembler)
{
// Set Search to "Molecular Assembler" and set "Only Free Interface"
boolean currentOnlyInterfacesWithFreeSlots = this.partInterfaceTerminal.onlyInterfacesWithFreeSlots;
String currentSearchText = this.searchFieldOutputs.getText();
this.partInterfaceTerminal.onlyInterfacesWithFreeSlots = true;
this.searchFieldOutputs.setText("Molecular Assembler");
this.refreshList();
this.partInterfaceTerminal.onlyInterfacesWithFreeSlots = currentOnlyInterfacesWithFreeSlots;
this.searchFieldOutputs.setText(currentSearchText);
}
}
@Override
public void drawBG( final int offsetX, final int offsetY, final int mouseX, final int mouseY )
{
this.bindTexture( "guis/interfaceterminal.png" );
this.bindTexture( "guis/newinterfaceterminal.png" );
this.drawTexturedModalRect( offsetX, offsetY, 0, 0, this.xSize, this.ySize );
int offset = 17;
int offset = 51;
final int ex = this.getScrollBar().getCurrentScroll();
for( int x = 0; x < LINES_ON_PAGE && ex + x < this.lines.size(); x++ )
int linesDraw = 0;
for( int x = 0; x < LINES_ON_PAGE && linesDraw < LINES_ON_PAGE && ex + x < this.lines.size(); x++ )
{
final Object lineObj = this.lines.get( ex + x );
if( lineObj instanceof ClientDCInternalInv )
{
final ClientDCInternalInv inv = (ClientDCInternalInv) lineObj;
GlStateManager.color( 1, 1, 1, 1 );
final int width = inv.getInventory().getSlots() * 18;
this.drawTexturedModalRect( offsetX + 7, offsetY + offset, 7, 139, width, 18 );
final int width = 9 * 18;
int extraLines = numUpgradesMap.get( lineObj );
for( int row = 0; row < 1 + extraLines && linesDraw < LINES_ON_PAGE; ++row )
{
this.drawTexturedModalRect( offsetX + 20, offsetY + offset , 20, 173, width, 18 );
offset += 18;
linesDraw++;
}
}
else {
offset += 18;
linesDraw++;
}
offset += 18;
}
if( this.searchField != null )
if( this.searchFieldInputs != null )
{
this.searchField.drawTextBox();
this.searchFieldInputs.drawTextBox();
}
if( this.searchFieldOutputs != null )
{
this.searchFieldOutputs.drawTextBox();
}
}
@@ -193,15 +321,21 @@ public class GuiInterfaceTerminal extends AEBaseGui
{
if( !this.checkHotbarKeys( key ) )
{
if( character == ' ' && this.searchField.getText().isEmpty() )
if( character == ' ' && this.searchFieldInputs.getText().isEmpty() && this.searchFieldInputs.isFocused() )
{
return;
}
if( this.searchField.textboxKeyTyped( character, key ) )
if( character == ' ' && this.searchFieldOutputs.getText().isEmpty() && this.searchFieldOutputs.isFocused())
{
return;
}
if( this.searchFieldInputs.textboxKeyTyped( character, key ) || this.searchFieldOutputs.textboxKeyTyped( character, key ))
{
this.refreshList();
}
else
{
super.keyTyped( character, key );
@@ -227,6 +361,9 @@ public class GuiInterfaceTerminal extends AEBaseGui
final long id = Long.parseLong( key.substring( 1 ), Character.MAX_RADIX );
final NBTTagCompound invData = in.getCompoundTag( key );
final ClientDCInternalInv current = this.getById( id, invData.getLong( "sortBy" ), invData.getString( "un" ) );
blockPosHashMap.put( current, NBTUtil.getPosFromTag( invData.getCompoundTag( "pos" )) );
dimHashMap.put( current, invData.getInteger( "dim" ));
numUpgradesMap.put( current, invData.getInteger("numUpgrades"));
for( int x = 0; x < current.getInventory().getSlots(); x++ )
{
@@ -260,41 +397,73 @@ public class GuiInterfaceTerminal extends AEBaseGui
private void refreshList()
{
this.byName.clear();
this.buttonList.clear();
this.matchedStacks.clear();
final String searchFilterLowerCase = this.searchField.getText().toLowerCase();
final String searchFieldInputs = this.searchFieldInputs.getText().toLowerCase();
final String searchFieldOutputs = this.searchFieldOutputs.getText().toLowerCase();
final Set<Object> cachedSearch = this.getCacheForSearchTerm( searchFilterLowerCase );
final Set<Object> cachedSearch = this.getCacheForSearchTerm( "IN:" + searchFieldInputs + " OUT:" + searchFieldOutputs + partInterfaceTerminal.onlyInterfacesWithFreeSlots);
final boolean rebuild = cachedSearch.isEmpty();
for( final ClientDCInternalInv entry : this.byId.values() )
{
// ignore inventory if not doing a full rebuild or cache already marks it as miss.
// ignore inventory if not doing a full rebuild and cache already marks it as miss.
if( !rebuild && !cachedSearch.contains( entry ) )
{
continue;
}
// Shortcut to skip any filter if search term is ""/empty
boolean found = searchFilterLowerCase.isEmpty();
boolean found = (searchFieldInputs.isEmpty() && searchFieldOutputs.isEmpty() && !partInterfaceTerminal.onlyInterfacesWithFreeSlots);
boolean interfaceHasFreeSlots = false;
// Search if the current inventory holds a pattern containing the search term.
if( !found && !searchFilterLowerCase.isEmpty() )
if( !found )
{
int slot = 0;
for( final ItemStack itemStack : entry.getInventory() )
{
found = this.itemStackMatchesSearchTerm( itemStack, searchFilterLowerCase );
if( found )
{
if (slot > 8 + numUpgradesMap.get(entry) * 9) {
break;
}
if( !searchFieldInputs.isEmpty() && !searchFieldOutputs.isEmpty() ) {
if (this.itemStackMatchesSearchTerm(itemStack, searchFieldInputs, 0) || this.itemStackMatchesSearchTerm(itemStack, searchFieldOutputs, 1)) {
found = true;
matchedStacks.add(itemStack);
}
}
else if( !searchFieldInputs.isEmpty() ) {
if (this.itemStackMatchesSearchTerm(itemStack, searchFieldInputs, 0)) {
found = true;
matchedStacks.add(itemStack);
}
}
else if( !searchFieldOutputs.isEmpty() ) {
if (this.itemStackMatchesSearchTerm(itemStack, searchFieldOutputs, 1)) {
found = true;
matchedStacks.add(itemStack);
}
}
// If only Interfaces with empty slots should be shown, check that here
if(itemStack.isEmpty())
interfaceHasFreeSlots = true;
slot++;
}
}
// if found, filter skipped or machine name matching the search term, add it
if( found || entry.getName().toLowerCase().contains( searchFilterLowerCase ) )
if( found || (entry.getName().toLowerCase().contains( searchFieldInputs ) && entry.getName().toLowerCase().contains( searchFieldOutputs )))
{
this.byName.put( entry.getName(), entry );
cachedSearch.add( entry );
if (!partInterfaceTerminal.onlyInterfacesWithFreeSlots)
{
this.byName.put( entry.getName(), entry );
cachedSearch.add( entry );
}
else if ( interfaceHasFreeSlots ){
this.byName.put( entry.getName(), entry );
cachedSearch.add( entry );
}
}
else
{
@@ -321,10 +490,10 @@ public class GuiInterfaceTerminal extends AEBaseGui
this.lines.addAll( clientInventories );
}
this.getScrollBar().setRange( 0, this.lines.size() - LINES_ON_PAGE, 2 );
this.getScrollBar().setRange( 0, this.lines.size() - 1, 1 );
}
private boolean itemStackMatchesSearchTerm( final ItemStack itemStack, final String searchTerm )
private boolean itemStackMatchesSearchTerm( final ItemStack itemStack, final String searchTerm,int pass )
{
if( itemStack.isEmpty() )
{
@@ -338,14 +507,21 @@ public class GuiInterfaceTerminal extends AEBaseGui
return false;
}
// Potential later use to filter by input
// NBTTagList inTag = encodedValue.getTagList( "in", 10 );
final NBTTagList outTag = encodedValue.getTagList( "out", 10 );
NBTTagList tag = new NBTTagList();
for( int i = 0; i < outTag.tagCount(); i++ )
if (pass == 0)
{
tag = encodedValue.getTagList( "in", 10 );
}
else
{
tag = encodedValue.getTagList( "out", 10 );
}
for( int i = 0; i < tag.tagCount(); i++ )
{
final ItemStack parsedItemStack = new ItemStack( outTag.getCompoundTagAt( i ) );
final ItemStack parsedItemStack = new ItemStack( tag.getCompoundTagAt( i ) );
if( !parsedItemStack.isEmpty() )
{
final String displayName = Platform
@@ -404,7 +580,7 @@ public class GuiInterfaceTerminal extends AEBaseGui
if( o == null )
{
this.byId.put( id, o = new ClientDCInternalInv( 9, id, sortBy, string ) );
this.byId.put( id, o = new ClientDCInternalInv( DualityInterface.NUMBER_OF_PATTERN_SLOTS, id, sortBy, string ) );
this.refreshList = true;
}
@@ -19,11 +19,21 @@
package appeng.client.gui.implementations;
import java.awt.*;
import java.io.IOException;
import java.util.*;
import java.util.List;
import appeng.container.interfaces.IJEIGhostIngredients;
import appeng.container.slot.SlotFake;
import appeng.core.sync.packets.PacketInventoryAction;
import appeng.helpers.InventoryAction;
import appeng.util.item.AEItemStack;
import mezz.jei.api.gui.IGhostIngredientHandler.Target;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import appeng.api.config.ActionItems;
@@ -40,7 +50,7 @@ import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketValueConfig;
public class GuiPatternTerm extends GuiMEMonitorable
public class GuiPatternTerm extends GuiMEMonitorable implements IJEIGhostIngredients
{
private static final String BACKGROUND_CRAFTING_MODE = "guis/pattern.png";
@@ -60,6 +70,14 @@ public class GuiPatternTerm extends GuiMEMonitorable
private GuiImgButton substitutionsDisabledBtn;
private GuiImgButton encodeBtn;
private GuiImgButton clearBtn;
private GuiImgButton x2Btn;
private GuiImgButton x3Btn;
private GuiImgButton plusOneBtn;
private GuiImgButton divTwoBtn;
private GuiImgButton divThreeBtn;
private GuiImgButton minusOneBtn;
private GuiImgButton maxCountBtn;
public Map<Target<?>,Object> mapTargetSlot = new HashMap<>();
public GuiPatternTerm( final InventoryPlayer inventoryPlayer, final ITerminalHost te )
{
@@ -85,7 +103,13 @@ public class GuiPatternTerm extends GuiMEMonitorable
if( this.encodeBtn == btn )
{
NetworkHandler.instance().sendToServer( new PacketValueConfig( "PatternTerminal.Encode", "1" ) );
if ( isShiftKeyDown() ){
NetworkHandler.instance().sendToServer( new PacketValueConfig( "PatternTerminal.Encode", "2" ) );
}
else
{
NetworkHandler.instance().sendToServer( new PacketValueConfig( "PatternTerminal.Encode", "1" ) );
}
}
if( this.clearBtn == btn )
@@ -93,6 +117,41 @@ public class GuiPatternTerm extends GuiMEMonitorable
NetworkHandler.instance().sendToServer( new PacketValueConfig( "PatternTerminal.Clear", "1" ) );
}
if( this.x2Btn == btn )
{
NetworkHandler.instance().sendToServer( new PacketValueConfig( "PatternTerminal.MultiplyByTwo", "1" ) );
}
if( this.x3Btn == btn )
{
NetworkHandler.instance().sendToServer( new PacketValueConfig( "PatternTerminal.MultiplyByThree", "1" ) );
}
if( this.divTwoBtn == btn )
{
NetworkHandler.instance().sendToServer( new PacketValueConfig( "PatternTerminal.DivideByTwo", "1" ) );
}
if( this.divThreeBtn == btn )
{
NetworkHandler.instance().sendToServer( new PacketValueConfig( "PatternTerminal.DivideByThree", "1" ) );
}
if( this.plusOneBtn == btn )
{
NetworkHandler.instance().sendToServer( new PacketValueConfig( "PatternTerminal.IncreaseByOne", "1" ) );
}
if( this.minusOneBtn == btn )
{
NetworkHandler.instance().sendToServer( new PacketValueConfig( "PatternTerminal.DecreaseByOne", "1" ) );
}
if( this.maxCountBtn == btn )
{
NetworkHandler.instance().sendToServer( new PacketValueConfig( "PatternTerminal.MaximizeCount", "1" ) );
}
if( this.substitutionsEnabledBtn == btn || this.substitutionsDisabledBtn == btn )
{
NetworkHandler.instance()
@@ -131,6 +190,34 @@ public class GuiPatternTerm extends GuiMEMonitorable
this.clearBtn.setHalfSize( true );
this.buttonList.add( this.clearBtn );
this.x3Btn = new GuiImgButton( this.guiLeft + 128, this.guiTop + this.ySize - 158, Settings.ACTIONS, ActionItems.MULTIPLY_BY_THREE );
this.x3Btn.setHalfSize( true );
this.buttonList.add( this.x3Btn );
this.x2Btn = new GuiImgButton( this.guiLeft + 128, this.guiTop + this.ySize - 148, Settings.ACTIONS, ActionItems.MULTIPLY_BY_TWO );
this.x2Btn.setHalfSize( true );
this.buttonList.add( this.x2Btn );
this.plusOneBtn = new GuiImgButton( this.guiLeft + 128, this.guiTop + this.ySize - 138, Settings.ACTIONS, ActionItems.INCREASE_BY_ONE );
this.plusOneBtn.setHalfSize( true );
this.buttonList.add( this.plusOneBtn );
this.divThreeBtn = new GuiImgButton( this.guiLeft + 100, this.guiTop + this.ySize - 158, Settings.ACTIONS, ActionItems.DIVIDE_BY_THREE );
this.divThreeBtn.setHalfSize( true );
this.buttonList.add( this.divThreeBtn );
this.divTwoBtn = new GuiImgButton( this.guiLeft + 100, this.guiTop + this.ySize - 148, Settings.ACTIONS, ActionItems.DIVIDE_BY_TWO );
this.divTwoBtn.setHalfSize( true );
this.buttonList.add( this.divTwoBtn );
this.minusOneBtn = new GuiImgButton( this.guiLeft + 100, this.guiTop + this.ySize - 138, Settings.ACTIONS, ActionItems.DECREASE_BY_ONE );
this.minusOneBtn.setHalfSize( true );
this.buttonList.add( this.minusOneBtn );
//this.maxCountBtn = new GuiImgButton( this.guiLeft + 128, this.guiTop + this.ySize - 108, Settings.ACTIONS, ActionItems.MAX_COUNT );
//this.maxCountBtn.setHalfSize( true );
//this.buttonList.add( this.maxCountBtn );
this.encodeBtn = new GuiImgButton( this.guiLeft + 147, this.guiTop + this.ySize - 142, Settings.ACTIONS, ActionItems.ENCODE );
this.buttonList.add( this.encodeBtn );
}
@@ -142,6 +229,13 @@ public class GuiPatternTerm extends GuiMEMonitorable
{
this.tabCraftButton.visible = true;
this.tabProcessButton.visible = false;
this.x2Btn.visible = false;
this.x3Btn.visible = false;
this.divTwoBtn.visible = false;
this.divThreeBtn.visible = false;
this.plusOneBtn.visible = false;
this.minusOneBtn.visible = false;
//this.maxCountBtn.visible = false;
if( this.container.substitute )
{
@@ -160,6 +254,13 @@ public class GuiPatternTerm extends GuiMEMonitorable
this.tabProcessButton.visible = true;
this.substitutionsEnabledBtn.visible = false;
this.substitutionsDisabledBtn.visible = false;
this.x2Btn.visible = true;
this.x3Btn.visible = true;
this.divTwoBtn.visible = true;
this.divThreeBtn.visible = true;
this.plusOneBtn.visible = true;
this.minusOneBtn.visible = true;
//this.maxCountBtn.visible = true;
}
super.drawFG( offsetX, offsetY, mouseX, mouseY );
@@ -184,4 +285,52 @@ public class GuiPatternTerm extends GuiMEMonitorable
s.yPos = s.getY() + this.ySize - 78 - offsetPlayerSide;
}
@Override
public List<Target<?>> getPhantomTargets(Object ingredient) {
if (!(ingredient instanceof ItemStack )) {
return Collections.emptyList();
}
List<Target<?>> targets = new ArrayList<>();
for( Slot slot : this.inventorySlots.inventorySlots )
{
if( slot instanceof SlotFake )
{
ItemStack itemStack = (ItemStack) ingredient;
Target<Object> target = new Target<Object>()
{
@Override
public Rectangle getArea()
{
return new Rectangle( getGuiLeft() + slot.xPos, getGuiTop() + slot.yPos, 16, 16 );
}
@Override
public void accept( Object ingredient )
{
final PacketInventoryAction p;
try
{
p = new PacketInventoryAction( InventoryAction.PLACE_JEI_GHOST_ITEM, (SlotFake) slot, AEItemStack.fromItemStack( itemStack ) );
NetworkHandler.instance().sendToServer( p );
}
catch( IOException e )
{
e.printStackTrace();
}
}
};
targets.add( target );
mapTargetSlot.putIfAbsent( target, slot );
}
}
return targets;
}
@Override
public Map<Target<?>, Object> getFakeSlotTargetMap()
{
return mapTargetSlot;
}
}
@@ -19,8 +19,24 @@
package appeng.client.gui.implementations;
import java.awt.*;
import java.io.IOException;
import java.util.*;
import java.util.List;
import appeng.client.gui.widgets.GuiCustomSlot;
import appeng.container.interfaces.IJEIGhostIngredients;
import appeng.container.slot.IJEITargetSlot;
import appeng.container.slot.SlotFake;
import appeng.core.sync.packets.PacketInventoryAction;
import appeng.fluids.client.gui.widgets.GuiFluidSlot;
import appeng.fluids.util.AEFluidStack;
import appeng.helpers.InventoryAction;
import appeng.util.item.AEItemStack;
import mezz.jei.api.gui.IGhostIngredientHandler.Target;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.*;
import org.lwjgl.input.Mouse;
import net.minecraft.client.gui.GuiButton;
@@ -43,9 +59,9 @@ import appeng.parts.automation.PartExportBus;
import appeng.parts.automation.PartImportBus;
public class GuiUpgradeable extends AEBaseGui
public class GuiUpgradeable extends AEBaseGui implements IJEIGhostIngredients
{
private final Map<Target<?>,Object> mapTargetSlot = new HashMap<>();
protected final ContainerUpgradeable cvb;
protected final IUpgradeableHost bc;
@@ -200,4 +216,111 @@ public class GuiUpgradeable extends AEBaseGui
NetworkHandler.instance().sendToServer( new PacketConfigButton( this.schedulingMode.getSetting(), backwards ) );
}
}
@Override
public List<Target<?>> getPhantomTargets(Object ingredient)
{
mapTargetSlot.clear();
FluidStack fluidStack = null;
ItemStack itemStack = ItemStack.EMPTY;
if( ingredient instanceof ItemStack )
{
itemStack = (ItemStack) ingredient;
fluidStack = FluidUtil.getFluidContained( itemStack );
}
else if( ingredient instanceof FluidStack )
{
fluidStack = (FluidStack) ingredient;
}
if( !( ingredient instanceof ItemStack ) && !( ingredient instanceof FluidStack ) )
return Collections.emptyList();
List<Target<?>> targets = new ArrayList<>();
List<IJEITargetSlot> slots = new ArrayList<>();
if( this.inventorySlots.inventorySlots.size() > 0 )
{
for( Slot slot : this.inventorySlots.inventorySlots )
{
if( slot instanceof SlotFake && ( !itemStack.isEmpty() || this instanceof GuiCellWorkbench && fluidStack != null ) )
{
slots.add( (IJEITargetSlot) slot );
}
}
}
if( this.getGuiSlots().size() > 0 )
{
for( GuiCustomSlot slot : this.getGuiSlots() )
{
if( slot instanceof GuiFluidSlot && fluidStack != null )
{
slots.add( (IJEITargetSlot) slot );
}
}
}
for( Object slot : slots )
{
ItemStack finalItemStack = itemStack;
FluidStack finalFluidStack = fluidStack;
Target<Object> targetItem = new Target<Object>()
{
@Override
public Rectangle getArea()
{
if( slot instanceof SlotFake && ( (SlotFake) slot ).isSlotEnabled() )
{
return new Rectangle( getGuiLeft() + ( (SlotFake) slot ).xPos, getGuiTop() + ( (SlotFake) slot ).yPos, 16, 16 );
}
else if( slot instanceof GuiFluidSlot && ( (GuiFluidSlot) slot ).isSlotEnabled() )
{
return new Rectangle( getGuiLeft() + ( (GuiFluidSlot) slot ).xPos(), getGuiTop() + ( (GuiFluidSlot) slot ).yPos(), 16, 16 );
}
return new Rectangle();
}
@Override
public void accept( Object ingredient )
{
PacketInventoryAction p = null;
try
{
if( slot instanceof SlotFake && ( (SlotFake) slot ).isSlotEnabled() )
{
if( finalItemStack.isEmpty() && finalFluidStack != null )
{
p = new PacketInventoryAction( InventoryAction.PLACE_JEI_GHOST_ITEM, (IJEITargetSlot) slot, AEItemStack.fromItemStack( FluidUtil.getFilledBucket( finalFluidStack ) ) );
}
else if( !finalItemStack.isEmpty() )
{
p = new PacketInventoryAction( InventoryAction.PLACE_JEI_GHOST_ITEM, (IJEITargetSlot) slot, AEItemStack.fromItemStack( finalItemStack ) );
}
}
else
{
if( finalFluidStack == null ) return;
p = new PacketInventoryAction( InventoryAction.PLACE_JEI_GHOST_ITEM, (IJEITargetSlot) slot, AEItemStack.fromItemStack( AEFluidStack.fromFluidStack( finalFluidStack ).asItemStackRepresentation() ) );
}
NetworkHandler.instance().sendToServer( p );
}
catch( IOException e )
{
e.printStackTrace();
}
}
};
targets.add( targetItem );
mapTargetSlot.putIfAbsent( targetItem, slot );
}
return targets;
}
@Override
public Map<Target<?>, Object> getFakeSlotTargetMap()
{
return mapTargetSlot;
}
}
@@ -10,9 +10,9 @@ import net.minecraft.item.ItemStack;
public abstract class GuiCustomSlot extends Gui implements ITooltip
{
private final int x;
private final int y;
private final int id;
protected final int x;
protected final int y;
protected final int id;
public GuiCustomSlot( final int id, final int x, final int y )
{
@@ -134,6 +134,19 @@ public class GuiImgButton extends GuiButton implements ITooltip
this.registerApp( 6, Settings.ACTIONS, ActionItems.CLOSE, ButtonToolTips.Clear, ButtonToolTips.ClearSettings );
this.registerApp( 6, Settings.ACTIONS, ActionItems.STASH, ButtonToolTips.Stash, ButtonToolTips.StashDesc );
this.registerApp( 6 + 4 * 16, Settings.ACTIONS, ActionItems.MULTIPLY_BY_TWO, ButtonToolTips.MultiplyByTwo, ButtonToolTips.MultiplyByTwoDesc );
this.registerApp( 7 + 4 * 16, Settings.ACTIONS, ActionItems.MULTIPLY_BY_THREE, ButtonToolTips.MultiplyByThree, ButtonToolTips.MultiplyByThreeDesc );
this.registerApp( 8 + 4 * 16, Settings.ACTIONS, ActionItems.INCREASE_BY_ONE, ButtonToolTips.IncreaseByOne, ButtonToolTips.IncreaseByOneDesc );
this.registerApp( 9 + 4 * 16, Settings.ACTIONS, ActionItems.DIVIDE_BY_TWO, ButtonToolTips.DivideByTwo, ButtonToolTips.DivideByTwoDesc );
this.registerApp( 10 + 4 * 16, Settings.ACTIONS, ActionItems.DIVIDE_BY_THREE, ButtonToolTips.DivideByThree, ButtonToolTips.DivideByThreeDesc );
this.registerApp( 11 + 4 * 16, Settings.ACTIONS, ActionItems.DECREASE_BY_ONE, ButtonToolTips.DecreaseByOne, ButtonToolTips.DecreaseByOneDesc );
this.registerApp( 12 + 4 * 16, Settings.ACTIONS, ActionItems.MAX_COUNT, ButtonToolTips.MaxCount, ButtonToolTips.MaxCountDesc );
this.registerApp( 6 + 5 * 16, Settings.ACTIONS, ActionItems.FREE_MOLECULAR_SLOT_SHORTCUT, ButtonToolTips.FreeMolecularSlotShortcut, ButtonToolTips.FreeMolecularSlotShortcutDesc );
this.registerApp( 7 + 5 * 16, Settings.ACTIONS, ActionItems.TOGGLE_SHOW_FULL_INTERFACES_ON, ButtonToolTips.ToggleShowFullInterfaces, ButtonToolTips.ToggleShowFullInterfacesOnDesc );
this.registerApp( 8 + 5 * 16, Settings.ACTIONS, ActionItems.TOGGLE_SHOW_FULL_INTERFACES_OFF, ButtonToolTips.ToggleShowFullInterfaces, ButtonToolTips.ToggleShowFullInterfacesOffDesc );
this.registerApp( 6 + 6 * 16, Settings.ACTIONS, ActionItems.HIGHLIGHT_INTERFACE, ButtonToolTips.HighlightInterface, "" );
this.registerApp( 8, Settings.ACTIONS, ActionItems.ENCODE, ButtonToolTips.Encode, ButtonToolTips.EncodeDescription );
this.registerApp( 4 + 3 * 16, Settings.ACTIONS, ItemSubstitution.ENABLED, ButtonToolTips.Substitutions, ButtonToolTips.SubstitutionsDescEnabled );
this.registerApp( 7 + 3 * 16, Settings.ACTIONS, ItemSubstitution.DISABLED, ButtonToolTips.Substitutions, ButtonToolTips.SubstitutionsDescDisabled );
@@ -37,7 +37,7 @@ public class ClientDCInternalInv implements Comparable<ClientDCInternalInv>
public ClientDCInternalInv( final int size, final long id, final long sortBy, final String unlocalizedName )
{
this.inventory = new AppEngInternalInventory( null, size );
this.inventory = new AppEngInternalInventory( null, size, 1 );
this.unlocalizedName = unlocalizedName;
this.id = id;
this.sortBy = sortBy;
@@ -0,0 +1,34 @@
package appeng.client.render;
import net.minecraft.util.math.BlockPos;
// taken from McJty's McJtyLib
public class BlockPosHighlighter
{
private static BlockPos hilightedBlock;
private static long expireHilight;
private static int dimension;
public static void hilightBlock( BlockPos c, long expireHilight, int dimension ) {
hilightedBlock = c;
BlockPosHighlighter.expireHilight = expireHilight;
BlockPosHighlighter.dimension = dimension;
}
public static BlockPos getHilightedBlock() {
return hilightedBlock;
}
public static long getExpireHilight() {
return expireHilight;
}
public static int getDimension()
{
return dimension;
}
}
@@ -19,17 +19,21 @@
package appeng.client.render;
import appeng.api.storage.data.IAEFluidStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderItem;
import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import appeng.api.storage.data.IAEItemStack;
import appeng.util.IWideReadableNumberConverter;
import appeng.util.ReadableNumberConverter;
import net.minecraftforge.fluids.FluidStack;
import org.lwjgl.opengl.GL11;
/**
@@ -119,6 +123,49 @@ public class TesrRenderHelper
}
}
public static void renderFluid2d( FluidStack fluidStack, float scale )
{
if( fluidStack != null )
{
GlStateManager.pushMatrix();
int color = fluidStack.getFluid().getColor( fluidStack );
float r = ( color >> 16 & 255 ) / 255.0f;
float g = ( color >> 8 & 255 ) / 255.0f;
float b = ( color & 255 ) / 255.0f;
TextureAtlasSprite sprite = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite( fluidStack.getFluid().getStill( fluidStack ).toString() );
GlStateManager.enableBlend();
GlStateManager.blendFunc( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA );
GlStateManager.disableAlpha();
GlStateManager.disableLighting();
Minecraft.getMinecraft().getTextureManager().bindTexture( TextureMap.LOCATION_BLOCKS_TEXTURE );
Tessellator tess = Tessellator.getInstance();
BufferBuilder buf = tess.getBuffer();
float width = 0.4f;
float height = 0.4f;
float alpha = 1.0f;
float z = 0.0001f;
float x = -0.20f;
float y = -0.25f;
buf.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR );
double uMin = sprite.getInterpolatedU( 16D - width * 16D ), uMax = sprite.getInterpolatedU( width * 16D );
double vMin = sprite.getMinV(), vMax = sprite.getInterpolatedV( height * 16D );
buf.pos( x, y, z ).tex( uMin, vMin ).color( r, g, b, alpha ).endVertex();
buf.pos( x, y + height, z ).tex( uMin, vMax ).color( r, g, b, alpha ).endVertex();
buf.pos( x + width, y + height, z ).tex( uMax, vMax ).color( r, g, b, alpha ).endVertex();
buf.pos( x + width, y, z ).tex( uMax, vMin ).color( r, g, b, alpha ).endVertex();
tess.draw();
GlStateManager.enableLighting();
GlStateManager.enableAlpha();
GlStateManager.disableBlend();
GlStateManager.color( 1F, 1F, 1F, 1F );
GlStateManager.popMatrix();
}
}
/**
* Render an item in 2D and the given text below it.
*
@@ -143,4 +190,23 @@ public class TesrRenderHelper
}
public static void renderFluid2dWithAmount( IAEFluidStack fluidStack, float scale, float spacing )
{
final FluidStack renderStack = fluidStack.getFluidStack();
TesrRenderHelper.renderFluid2d( renderStack, scale );
final long stackSize = fluidStack.getStackSize() / 1000;
final String renderedStackSize = NUMBER_CONVERTER.toWideReadableForm( stackSize ) + "B";
// Render the item count
final FontRenderer fr = Minecraft.getMinecraft().fontRenderer;
final int width = fr.getStringWidth( renderedStackSize );
GlStateManager.translate( 0.0f, spacing, 0 );
GlStateManager.scale( 1.0f / 62.0f, 1.0f / 62.0f, 1.0f / 62.0f );
GlStateManager.translate( -0.5f * width, 0.0f, 0.5f );
fr.drawString( renderedStackSize, 0, 0, 0 );
}
}
@@ -699,8 +699,23 @@ public abstract class AEBaseContainer extends Container
is.setCount( 1 );
s.putStack( is );
}
else
{
final ItemStack is = s.getStack().copy();
if (is.getCount() < is.getMaxStackSize())
is.grow( 1 );
s.putStack( is );
}
break;
case PICKUP_SINGLE:
if( hand.isEmpty() )
{
final ItemStack is = s.getStack().copy();
if (is.getCount() > 1)
is.shrink( 1 );
s.putStack( is );
}
break;
case SPLIT_OR_PLACE_SINGLE:
ItemStack is = s.getStack();
@@ -51,6 +51,12 @@ public class ContainerCraftAmount extends AEBaseContainer
this.addSlotToContainer( this.getCraftingItem() );
}
@Override
public Slot getSlot( int slotId )
{
return super.getSlot( 0 );
}
@Override
public void detectAndSendChanges()
{
@@ -159,56 +159,58 @@ public class ContainerCraftingCPU extends AEBaseContainer implements IMEMonitorH
@Override
public void detectAndSendChanges()
{
if( Platform.isServer() && this.getMonitor() != null && !this.list.isEmpty() )
if( Platform.isServer() && this.getMonitor() != null )
{
try
if( this.getEstimatedTime() >= 0 )
{
if( this.getEstimatedTime() >= 0 )
final long elapsedTime = this.getMonitor().getElapsedTime();
final double remainingItems = this.getMonitor().getRemainingItemCount();
final double startItems = this.getMonitor().getStartItemCount();
final long eta = (long) ( elapsedTime / Math.max( 1d, ( startItems - remainingItems ) ) * remainingItems );
this.setEstimatedTime( eta );
}
if( !this.list.isEmpty() )
{
try
{
final long elapsedTime = this.getMonitor().getElapsedTime();
final double remainingItems = this.getMonitor().getRemainingItemCount();
final double startItems = this.getMonitor().getStartItemCount();
final long eta = (long) ( elapsedTime / Math.max( 1d, ( startItems - remainingItems ) ) * remainingItems );
this.setEstimatedTime( eta );
}
final PacketMEInventoryUpdate a = new PacketMEInventoryUpdate( (byte) 0 );
final PacketMEInventoryUpdate b = new PacketMEInventoryUpdate( (byte) 1 );
final PacketMEInventoryUpdate c = new PacketMEInventoryUpdate( (byte) 2 );
final PacketMEInventoryUpdate a = new PacketMEInventoryUpdate( (byte) 0 );
final PacketMEInventoryUpdate b = new PacketMEInventoryUpdate( (byte) 1 );
final PacketMEInventoryUpdate c = new PacketMEInventoryUpdate( (byte) 2 );
for( final IAEItemStack out : this.list )
{
a.appendItem( this.getMonitor().getItemStack( out, CraftingItemList.STORAGE ) );
b.appendItem( this.getMonitor().getItemStack( out, CraftingItemList.ACTIVE ) );
c.appendItem( this.getMonitor().getItemStack( out, CraftingItemList.PENDING ) );
}
this.list.resetStatus();
for( final Object g : this.listeners )
{
if( g instanceof EntityPlayer )
for( final IAEItemStack out : this.list )
{
if( !a.isEmpty() )
{
NetworkHandler.instance().sendTo( a, (EntityPlayerMP) g );
}
a.appendItem( this.getMonitor().getItemStack( out, CraftingItemList.STORAGE ) );
b.appendItem( this.getMonitor().getItemStack( out, CraftingItemList.ACTIVE ) );
c.appendItem( this.getMonitor().getItemStack( out, CraftingItemList.PENDING ) );
}
if( !b.isEmpty() )
{
NetworkHandler.instance().sendTo( b, (EntityPlayerMP) g );
}
this.list.resetStatus();
if( !c.isEmpty() )
for( final Object g : this.listeners )
{
if( g instanceof EntityPlayer )
{
NetworkHandler.instance().sendTo( c, (EntityPlayerMP) g );
if( !a.isEmpty() )
{
NetworkHandler.instance().sendTo( a, (EntityPlayerMP) g );
}
if( !b.isEmpty() )
{
NetworkHandler.instance().sendTo( b, (EntityPlayerMP) g );
}
if( !c.isEmpty() )
{
NetworkHandler.instance().sendTo( c, (EntityPlayerMP) g );
}
}
}
}
}
catch( final IOException e )
{
// :P
catch( final IOException e )
{
// :P
}
}
}
super.detectAndSendChanges();
@@ -19,6 +19,9 @@
package appeng.container.implementations;
import appeng.api.config.Upgrades;
import appeng.container.slot.*;
import appeng.util.Platform;
import net.minecraft.entity.player.InventoryPlayer;
import appeng.api.config.SecurityPermissions;
@@ -26,14 +29,11 @@ import appeng.api.config.Settings;
import appeng.api.config.YesNo;
import appeng.api.util.IConfigManager;
import appeng.container.guisync.GuiSync;
import appeng.container.slot.SlotFake;
import appeng.container.slot.SlotNormal;
import appeng.container.slot.SlotRestrictedInput;
import appeng.helpers.DualityInterface;
import appeng.helpers.IInterfaceHost;
public class ContainerInterface extends ContainerUpgradeable
public class ContainerInterface extends ContainerUpgradeable implements IOptionalSlotHost
{
private final DualityInterface myDuality;
@@ -44,16 +44,22 @@ public class ContainerInterface extends ContainerUpgradeable
@GuiSync( 4 )
public YesNo iTermMode = YesNo.YES;
@GuiSync( 7 )
public int patternExpansions = 0;
public ContainerInterface( final InventoryPlayer ip, final IInterfaceHost te )
{
super( ip, te.getInterfaceDuality().getHost() );
this.myDuality = te.getInterfaceDuality();
for( int x = 0; x < DualityInterface.NUMBER_OF_PATTERN_SLOTS; x++ )
for (int row = 0 ; row < 4 ; ++row)
{
this.addSlotToContainer( new SlotRestrictedInput( SlotRestrictedInput.PlacableItemType.ENCODED_PATTERN, this.myDuality
.getPatterns(), x, 8 + 18 * x, 90 + 7, this.getInventoryPlayer() ) );
for( int x = 0; x < 9; x++ )
{
this.addSlotToContainer( new OptionalSlotRestrictedInput( SlotRestrictedInput.PlacableItemType.ENCODED_PATTERN, this.myDuality
.getPatterns(), this, x + row * 9, 8 + 18 * x, 97 + ( 18 * row ), row, this.getInventoryPlayer() ).setStackLimit( 1 ) );
}
}
for( int x = 0; x < DualityInterface.NUMBER_OF_CONFIG_SLOTS; x++ )
@@ -70,7 +76,7 @@ public class ContainerInterface extends ContainerUpgradeable
@Override
protected int getHeight()
{
return 211;
return 256;
}
@Override
@@ -82,16 +88,35 @@ public class ContainerInterface extends ContainerUpgradeable
@Override
public int availableUpgrades()
{
return 1;
return 4;
}
@Override
public boolean isSlotEnabled( final int idx )
{
return myDuality.getInstalledUpgrades(Upgrades.PATTERN_EXPANSION) >= idx;
}
@Override
public void detectAndSendChanges()
{
this.verifyPermissions( SecurityPermissions.BUILD, false );
if (patternExpansions != getPatternUpgrades())
{
patternExpansions = getPatternUpgrades();
this.myDuality.dropExcessPatterns();
}
super.detectAndSendChanges();
}
@Override
public void onUpdate( final String field, final Object oldValue, final Object newValue ) {
super.onUpdate(field, oldValue, newValue);
if ( Platform.isClient() && field.equals("patternExpansions"))
this.myDuality.dropExcessPatterns();
}
@Override
protected void loadSettingsFromHost( final IConfigManager cm )
{
@@ -118,4 +143,9 @@ public class ContainerInterface extends ContainerUpgradeable
{
this.iTermMode = iTermMode;
}
public int getPatternUpgrades()
{
return this.myDuality.getInstalledUpgrades( Upgrades.PATTERN_EXPANSION );
}
}
@@ -24,10 +24,13 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import appeng.api.config.Upgrades;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.items.IItemHandler;
import appeng.api.config.Settings;
@@ -78,7 +81,7 @@ public final class ContainerInterfaceTerminal extends AEBaseContainer
this.grid = anchor.getActionableNode().getGrid();
}
this.bindPlayerInventory( ip, 0, 222 - /* height of player inventory */82 );
this.bindPlayerInventory( ip, 14, 256 - /* height of player inventory */82 );
}
@Override
@@ -213,35 +216,48 @@ public final class ContainerInterfaceTerminal extends AEBaseContainer
final IItemHandler theSlot = new WrapperFilteredItemHandler( new WrapperRangeItemHandler( inv.server, slot, slot + 1 ), new PatternSlotFilter() );
final InventoryAdaptor interfaceSlot = new AdaptorItemHandler( theSlot );
switch( action )
IItemHandler interfaceHandler = inv.server;
boolean canInsert = true;
switch ( action )
{
case PICKUP_OR_SET_DOWN:
if( hasItemInHand )
{
ItemStack inSlot = theSlot.getStackInSlot( 0 );
if( inSlot.isEmpty() )
for( int s = 0; s < interfaceHandler.getSlots(); s++ )
{
player.inventory.setItemStack( interfaceSlot.addItems( player.inventory.getItemStack() ) );
}
else
{
inSlot = inSlot.copy();
final ItemStack inHand = player.inventory.getItemStack().copy();
ItemHandlerUtil.setStackInSlot( theSlot, 0, ItemStack.EMPTY );
player.inventory.setItemStack( ItemStack.EMPTY );
player.inventory.setItemStack( interfaceSlot.addItems( inHand.copy() ) );
if( player.inventory.getItemStack().isEmpty() )
if( Platform.itemComparisons().isSameItem( interfaceHandler.getStackInSlot( s ), player.inventory.getItemStack() ) )
{
player.inventory.setItemStack( inSlot );
canInsert = false;
break;
}
}
if( canInsert )
{
ItemStack inSlot = theSlot.getStackInSlot( 0 );
if( inSlot.isEmpty() )
{
player.inventory.setItemStack( interfaceSlot.addItems( player.inventory.getItemStack() ) );
}
else
{
player.inventory.setItemStack( inHand );
ItemHandlerUtil.setStackInSlot( theSlot, 0, inSlot );
inSlot = inSlot.copy();
final ItemStack inHand = player.inventory.getItemStack().copy();
ItemHandlerUtil.setStackInSlot( theSlot, 0, ItemStack.EMPTY );
player.inventory.setItemStack( ItemStack.EMPTY );
player.inventory.setItemStack( interfaceSlot.addItems( inHand.copy() ) );
if( player.inventory.getItemStack().isEmpty() )
{
player.inventory.setItemStack( inSlot );
}
else
{
player.inventory.setItemStack( inHand );
ItemHandlerUtil.setStackInSlot( theSlot, 0, inSlot );
}
}
}
}
@@ -252,17 +268,27 @@ public final class ContainerInterfaceTerminal extends AEBaseContainer
break;
case SPLIT_OR_PLACE_SINGLE:
if( hasItemInHand )
{
ItemStack extra = playerHand.removeItems( 1, ItemStack.EMPTY, null );
if( !extra.isEmpty() )
for( int s = 0; s < interfaceHandler.getSlots(); s++ )
{
extra = interfaceSlot.addItems( extra );
if( Platform.itemComparisons().isSameItem( interfaceHandler.getStackInSlot( s ), player.inventory.getItemStack() ) )
{
canInsert = false;
break;
}
}
if( !extra.isEmpty() )
if( canInsert )
{
playerHand.addItems( extra );
ItemStack extra = playerHand.removeItems( 1, ItemStack.EMPTY, null );
if( !extra.isEmpty() && !interfaceSlot.containsItems() )
{
extra = interfaceSlot.addItems( extra );
}
if( !extra.isEmpty() )
{
playerHand.addItems( extra );
}
}
}
else if( !is.isEmpty() )
@@ -378,6 +404,9 @@ public final class ContainerInterfaceTerminal extends AEBaseContainer
{
tag.setLong( "sortBy", inv.sortBy );
tag.setString( "un", inv.unlocalizedName );
tag.setTag( "pos", NBTUtil.createPosTag( inv.pos ) );
tag.setInteger( "dim", inv.dim );
tag.setInteger( "numUpgrades", inv.numUpgrades );
}
for( int x = 0; x < length; x++ )
@@ -408,6 +437,9 @@ public final class ContainerInterfaceTerminal extends AEBaseContainer
private final String unlocalizedName;
private final IItemHandler client;
private final IItemHandler server;
private final BlockPos pos;
private final int dim;
private final int numUpgrades;
public InvTracker( final DualityInterface dual, final IItemHandler patterns, final String unlocalizedName )
{
@@ -415,6 +447,9 @@ public final class ContainerInterfaceTerminal extends AEBaseContainer
this.client = new AppEngInternalInventory( null, this.server.getSlots() );
this.unlocalizedName = unlocalizedName;
this.sortBy = dual.getSortValue();
this.pos = dual.getLocation().getPos();
this.dim = dual.getLocation().getWorld().provider.getDimension();
this.numUpgrades = dual.getInstalledUpgrades( Upgrades.PATTERN_EXPANSION);
}
}
@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import appeng.container.slot.*;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
@@ -51,12 +52,6 @@ import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList;
import appeng.container.ContainerNull;
import appeng.container.guisync.GuiSync;
import appeng.container.slot.IOptionalSlotHost;
import appeng.container.slot.OptionalSlotFake;
import appeng.container.slot.SlotFakeCraftingMatrix;
import appeng.container.slot.SlotPatternOutputs;
import appeng.container.slot.SlotPatternTerm;
import appeng.container.slot.SlotRestrictedInput;
import appeng.core.sync.packets.PacketPatternSlot;
import appeng.helpers.IContainerCraftingPacket;
import appeng.items.storage.ItemViewCell;
@@ -132,6 +127,28 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA
this.updateOrderOfOutputSlots();
}
@Override
public ItemStack transferStackInSlot( final EntityPlayer p, final int idx )
{
if( Platform.isClient() )
{
return ItemStack.EMPTY;
}
if( this.inventorySlots.get( idx ) instanceof SlotPlayerInv || this.inventorySlots.get( idx ) instanceof SlotPlayerHotBar )
{
final AppEngSlot clickSlot = ( AppEngSlot ) this.inventorySlots.get( idx ); // require AE SLots!
ItemStack itemStack = clickSlot.getStack();
if( AEApi.instance().definitions().materials().blankPattern().isSameAs( itemStack ) )
{
IItemHandler patternInv = this.getPatternTerminal().getInventoryByName( "pattern" );
ItemStack remainder = patternInv.insertItem( 0, itemStack, false );
clickSlot.putStack( remainder );
}
}
return super.transferStackInSlot( p, idx );
}
private void updateOrderOfOutputSlots()
{
if( !this.isCraftingMode() )
@@ -203,6 +220,19 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA
}
public void encodeAndMoveToInventory()
{
encode();
ItemStack output = this.patternSlotOUT.getStack();
if ( !output.isEmpty() )
{
if (!getPlayerInv().addItemStackToInventory( output )){
getPlayerInv().player.dropItem( output , false );
}
this.patternSlotOUT.putStack( ItemStack.EMPTY );
}
}
public void encode()
{
ItemStack output = this.patternSlotOUT.getStack();
@@ -269,6 +299,212 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA
output.setTagCompound( encodedValue );
}
public void multiply(int multiple)
{
ItemStack[] input = new ItemStack[9];
boolean canMultiplyInputs = true;
boolean canMultiplyOutputs = true;
for( int x = 0; x < this.craftingSlots.length; x++ )
{
input[x] = this.craftingSlots[x].getStack();
if( !input[x].isEmpty() && input[x].getCount() * multiple > input[x].getMaxStackSize() )
{
canMultiplyInputs = false;
}
}
for( final OptionalSlotFake outputSlot : this.outputSlots )
{
final ItemStack out = outputSlot.getStack();
if( !out.isEmpty() && out.getCount() * multiple > out.getMaxStackSize() )
{
canMultiplyOutputs = false;
}
}
if( canMultiplyInputs && canMultiplyOutputs )
{
for( SlotFakeCraftingMatrix craftingSlot : this.craftingSlots )
{
ItemStack stack = craftingSlot.getStack();
if( !stack.isEmpty() )
craftingSlot.getStack().setCount( stack.getCount() * multiple );
}
for( OptionalSlotFake outputSlot : this.outputSlots )
{
ItemStack stack = outputSlot.getStack();
if( !stack.isEmpty() )
outputSlot.getStack().setCount( stack.getCount() * multiple );
}
}
}
public void divide(int divide)
{
ItemStack[] input = new ItemStack[9];
boolean canDivideInputs = true;
boolean canDivideOutputs = true;
for( int x = 0; x < this.craftingSlots.length; x++ )
{
input[x] = this.craftingSlots[x].getStack();
if( !input[x].isEmpty() && input[x].getCount() % divide != 0 )
{
canDivideInputs = false;
}
}
for( final OptionalSlotFake outputSlot : this.outputSlots )
{
final ItemStack out = outputSlot.getStack();
if( !out.isEmpty() && out.getCount() % divide != 0 )
{
canDivideOutputs = false;
}
}
if( canDivideInputs && canDivideOutputs )
{
for( SlotFakeCraftingMatrix craftingSlot : this.craftingSlots )
{
ItemStack stack = craftingSlot.getStack();
if( !stack.isEmpty() )
craftingSlot.getStack().setCount( stack.getCount() / divide );
}
for( OptionalSlotFake outputSlot : this.outputSlots )
{
ItemStack stack = outputSlot.getStack();
if( !stack.isEmpty() )
outputSlot.getStack().setCount( stack.getCount() / divide );
}
}
}
public void increase(int increase)
{
ItemStack[] input = new ItemStack[9];
boolean canIncreaseInputs = true;
boolean canIncreaseOutputs = true;
for( int x = 0; x < this.craftingSlots.length; x++ )
{
input[x] = this.craftingSlots[x].getStack();
if( !input[x].isEmpty() && input[x].getCount() + increase > input[x].getMaxStackSize() )
{
canIncreaseInputs = false;
}
}
for( final OptionalSlotFake outputSlot : this.outputSlots )
{
final ItemStack out = outputSlot.getStack();
if( !out.isEmpty() && out.getCount() + increase > out.getMaxStackSize() )
{
canIncreaseOutputs = false;
}
}
if( canIncreaseInputs && canIncreaseOutputs )
{
for( SlotFakeCraftingMatrix craftingSlot : this.craftingSlots )
{
ItemStack stack = craftingSlot.getStack();
if( !stack.isEmpty() )
craftingSlot.getStack().setCount( stack.getCount() + increase );
}
for( OptionalSlotFake outputSlot : this.outputSlots )
{
ItemStack stack = outputSlot.getStack();
if( !stack.isEmpty() )
outputSlot.getStack().setCount( stack.getCount() + increase );
}
}
}
public void decrease(int decrease)
{
ItemStack[] input = new ItemStack[9];
boolean canDecreaseInputs = true;
boolean canDecreaseOutputs = true;
for( int x = 0; x < this.craftingSlots.length; x++ )
{
input[x] = this.craftingSlots[x].getStack();
if( !input[x].isEmpty() && input[x].getCount() - decrease < 1 )
{
canDecreaseInputs = false;
}
}
for( final OptionalSlotFake outputSlot : this.outputSlots )
{
final ItemStack out = outputSlot.getStack();
if( !out.isEmpty() && out.getCount() - decrease < 1 )
{
canDecreaseOutputs = false;
}
}
if( canDecreaseInputs && canDecreaseOutputs )
{
for( SlotFakeCraftingMatrix craftingSlot : this.craftingSlots )
{
ItemStack stack = craftingSlot.getStack();
if( !stack.isEmpty() )
craftingSlot.getStack().setCount( stack.getCount() - decrease );
}
for( OptionalSlotFake outputSlot : this.outputSlots )
{
ItemStack stack = outputSlot.getStack();
if( !stack.isEmpty() )
outputSlot.getStack().setCount( stack.getCount() - decrease );
}
}
}
public void maximizeCount()
{
ItemStack[] input = new ItemStack[9];
boolean canGrowInputs = true;
boolean canGrowOutputs = true;
int maxInputStackGrowth = 0;
int maxOutputStackGrowth = 0;
for( int x = 0; x < this.craftingSlots.length; x++ )
{
input[x] = this.craftingSlots[x].getStack();
if( !input[x].isEmpty() && input[x].getMaxStackSize() - input[x].getCount() > maxInputStackGrowth )
{
maxInputStackGrowth = input[x].getMaxStackSize() - input[x].getCount();
}
if( !input[x].isEmpty() && input[x].getCount() + maxInputStackGrowth > input[x].getMaxStackSize() )
{
canGrowInputs = false;
}
}
for( final OptionalSlotFake outputSlot : this.outputSlots )
{
final ItemStack out = outputSlot.getStack();
{
maxOutputStackGrowth = out.getMaxStackSize() - out.getCount();
}
if( !out.isEmpty() && out.getCount() + maxOutputStackGrowth > out.getMaxStackSize() )
{
canGrowOutputs = false;
}
}
if( canGrowInputs && canGrowOutputs )
{
int maxStackGrowth = Math.min(maxInputStackGrowth,maxOutputStackGrowth);
for( SlotFakeCraftingMatrix craftingSlot : this.craftingSlots )
{
ItemStack stack = craftingSlot.getStack();
if( !stack.isEmpty() )
craftingSlot.getStack().setCount( stack.getCount() + maxStackGrowth );
}
for( OptionalSlotFake outputSlot : this.outputSlots )
{
ItemStack stack = outputSlot.getStack();
if( !stack.isEmpty() )
outputSlot.getStack().setCount( stack.getCount() + maxStackGrowth );
}
}
}
private ItemStack[] getInputs()
{
final ItemStack[] input = new ItemStack[9];
@@ -0,0 +1,18 @@
package appeng.container.interfaces;
import mezz.jei.api.gui.IGhostIngredientHandler.Target;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public interface IJEIGhostIngredients
{
List<Target<?>> getPhantomTargets( Object ingredient );
default Map<Target<?>, Object> getFakeSlotTargetMap(){
return new HashMap<>();
}
}
@@ -157,7 +157,7 @@ public class AppEngSlot extends Slot
{
if( this.isSlotEnabled() )
{
return !this.itemHandler.extractItem( this.index, 1, true ).isEmpty();
return !this.itemHandler.extractItem( this.index, Integer.MAX_VALUE, true ).isEmpty();
}
return false;
}
@@ -0,0 +1,4 @@
package appeng.container.slot;
public interface IJEITargetSlot {
}
@@ -24,7 +24,7 @@ import net.minecraft.item.ItemStack;
import net.minecraftforge.items.IItemHandler;
public class SlotFake extends AppEngSlot
public class SlotFake extends AppEngSlot implements IJEITargetSlot
{
public SlotFake( final IItemHandler inv, final int idx, final int x, final int y )
@@ -363,6 +363,8 @@ final class Registration
// Interface
Upgrades.CRAFTING.registerItem( parts.iface(), 1 );
Upgrades.CRAFTING.registerItem( blocks.iface(), 1 );
Upgrades.PATTERN_EXPANSION.registerItem( parts.iface(), 3 );
Upgrades.PATTERN_EXPANSION.registerItem( blocks.iface(), 3 );
// IO Port!
Upgrades.SPEED.registerItem( blocks.iOPort(), 3 );
@@ -175,7 +175,7 @@ public class ApiStorage implements IStorageHelper
@Override
public int transferFactor()
{
return 125;
return 1000;
}
@Override
@@ -616,7 +616,12 @@ public final class ApiBlocks implements IBlocks
private static IBlockDefinition makeStairs( String registryName, FeatureFactory registry, IBlockDefinition block )
{
return registry.block( registryName, () -> new BlockStairCommon( block.maybeBlock().get(), block.identifier() ) )
if( !block.maybeBlock().isPresent() )
{
return new BlockDefinition( registryName, null, null );
}
IBlockDefinition stairs = registry.block( registryName, () -> new BlockStairCommon( block.maybeBlock().get(), block.identifier() ) )
.features( AEFeature.DECORATIVE_BLOCKS )
.rendering( new BlockRenderingCustomizer()
{
@@ -629,6 +634,10 @@ public final class ApiBlocks implements IBlocks
}
} )
.build();
Verify.verify(stairs.maybeBlock().isPresent());
return stairs;
}
@Override
@@ -86,6 +86,7 @@ public final class ApiMaterials implements IMaterials
private final IItemDefinition cardRedstone;
private final IItemDefinition cardSpeed;
private final IItemDefinition cardCapacity;
private final IItemDefinition cardPatternExpansion;
private final IItemDefinition cardFuzzy;
private final IItemDefinition cardInverter;
private final IItemDefinition cardCrafting;
@@ -204,6 +205,7 @@ public final class ApiMaterials implements IMaterials
this.cardRedstone = new DamagedItemDefinition( "material.card.redstone", materials.createMaterial( MaterialType.CARD_REDSTONE ) );
this.cardSpeed = new DamagedItemDefinition( "material.card.acceleration", materials.createMaterial( MaterialType.CARD_SPEED ) );
this.cardCapacity = new DamagedItemDefinition( "material.card.capacity", materials.createMaterial( MaterialType.CARD_CAPACITY ) );
this.cardPatternExpansion = new DamagedItemDefinition( "material.card.pattern.expansion", materials.createMaterial(MaterialType.CARD_PATTERN_EXPANSION) );
this.cardFuzzy = new DamagedItemDefinition( "material.card.fuzzy", materials.createMaterial( MaterialType.CARD_FUZZY ) );
this.cardInverter = new DamagedItemDefinition( "material.card.inverter", materials.createMaterial( MaterialType.CARD_INVERTER ) );
this.cardCrafting = new DamagedItemDefinition( "material.card.crafting", materials.createMaterial( MaterialType.CARD_CRAFTING ) );
@@ -424,6 +426,9 @@ public final class ApiMaterials implements IMaterials
return this.cardCapacity;
}
@Override
public IItemDefinition cardPatternExpansion(){ return this.cardPatternExpansion;}
@Override
public IItemDefinition cardFuzzy()
{
@@ -19,6 +19,7 @@
package appeng.core.localization;
import appeng.api.config.SchedulingMode;
import net.minecraft.util.text.translation.I18n;
@@ -137,6 +138,28 @@ public enum ButtonToolTips
BlockPlacementYes,
BlockPlacementNo,
MultiplyByTwo,
MultiplyByTwoDesc,
MultiplyByThree,
MultiplyByThreeDesc,
IncreaseByOne,
IncreaseByOneDesc,
DivideByTwo,
DivideByTwoDesc,
DivideByThree,
DivideByThreeDesc,
DecreaseByOne,
DecreaseByOneDesc,
MaxCount,
MaxCountDesc,
FreeMolecularSlotShortcut,
FreeMolecularSlotShortcutDesc,
ToggleShowFullInterfaces,
ToggleShowFullInterfacesOnDesc,
ToggleShowFullInterfacesOffDesc,
HighlightInterface,
HighlightInterfaceDesc,
// Used in the tooltips of the items in the terminal, when moused over
ItemsStored,
ItemsRequestable,
@@ -31,8 +31,10 @@ public enum WailaText
DeviceMissingChannel,
P2PUnlinked,
P2PInputOneOutput,
P2PInputManyOutputs,
P2P_INPUT_ONE_OUTPUT,
P2P_INPUT_MANY_OUTPUTS,
P2P_OUTPUT_ONE_INPUT,
P2P_OUTPUT_MANY_INPUTS,
P2POutput,
Locked,
@@ -20,7 +20,16 @@ package appeng.core.sync.packets;
import java.io.IOException;
import java.util.Collections;
import appeng.api.storage.data.IAEFluidStack;
import appeng.container.slot.IJEITargetSlot;
import appeng.container.slot.SlotFake;
import appeng.core.AELog;
import appeng.core.sync.network.NetworkHandler;
import appeng.fluids.client.gui.widgets.GuiFluidSlot;
import appeng.fluids.container.ContainerFluidConfigurable;
import appeng.fluids.util.AEFluidStack;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
@@ -40,6 +49,7 @@ import appeng.core.sync.network.INetworkInfo;
import appeng.helpers.InventoryAction;
import appeng.util.Platform;
import appeng.util.item.AEItemStack;
import net.minecraftforge.fluids.FluidStack;
public class PacketInventoryAction extends AppEngPacket
@@ -57,6 +67,7 @@ public class PacketInventoryAction extends AppEngPacket
this.slot = stream.readInt();
this.id = stream.readLong();
final boolean hasItem = stream.readBoolean();
if( hasItem )
{
this.slotItem = AEItemStack.fromPacket( stream );
@@ -70,7 +81,6 @@ public class PacketInventoryAction extends AppEngPacket
// api
public PacketInventoryAction( final InventoryAction action, final int slot, final IAEItemStack slotItem ) throws IOException
{
if( Platform.isClient() )
{
throw new IllegalStateException( "invalid packet, client cannot post inv actions with stacks." );
@@ -101,6 +111,36 @@ public class PacketInventoryAction extends AppEngPacket
this.configureWrite( data );
}
public PacketInventoryAction(final InventoryAction action, final IJEITargetSlot slot, final IAEItemStack slotItem ) throws IOException
{
this.action = action;
if (slot instanceof SlotFake)
this.slot = ((SlotFake) slot).slotNumber;
else this.slot = ((GuiFluidSlot) slot).getId();
this.id = 0;
this.slotItem = slotItem;
final ByteBuf data = Unpooled.buffer();
data.writeInt( this.getPacketID() );
data.writeInt( action.ordinal() );
data.writeInt( this.slot );
data.writeLong( this.id );
if( slotItem == null )
{
data.writeBoolean( false );
}
else
{
data.writeBoolean( true );
slotItem.writeToPacket( data );
}
this.configureWrite( data );
}
// api
public PacketInventoryAction( final InventoryAction action, final int slot, final long id )
{
@@ -150,6 +190,48 @@ public class PacketInventoryAction extends AppEngPacket
}
}
}
else if( this.action == InventoryAction.PLACE_JEI_GHOST_ITEM )
{
if( sender.openContainer.inventorySlots.get( this.slot ) instanceof SlotFake )
{
if( this.slotItem != null )
{
sender.openContainer.inventorySlots.get( this.slot ).putStack( this.slotItem.createItemStack() );
if( sender.openContainer.inventorySlots.get( this.slot ).getStack().isEmpty() )
{
IAEFluidStack aefs = AEFluidStack.fromNBT( this.slotItem.getDefinition().getTagCompound() );
if( aefs != null )
{
FluidStack fluid = aefs.getFluidStack();
sender.openContainer.inventorySlots.get( this.slot ).putStack( AEFluidStack.fromFluidStack( fluid ).asItemStackRepresentation() );
}
}
}
else sender.openContainer.inventorySlots.get( this.slot ).putStack( ItemStack.EMPTY );
try
{
NetworkHandler.instance().sendTo( new PacketInventoryAction( InventoryAction.UPDATE_HAND, 0, AEItemStack.fromItemStack( ItemStack.EMPTY ) ), sender );
}
catch( final IOException e )
{
AELog.debug( e );
}
}
if( sender.openContainer instanceof ContainerFluidConfigurable )
{
if( this.slotItem != null )
{
IAEFluidStack aefs = AEFluidStack.fromNBT( this.slotItem.getDefinition().getTagCompound() );
if( aefs != null )
{
aefs.setStackSize( 1000 );
( (ContainerFluidConfigurable) sender.openContainer ).getFluidConfigInventory().setFluidInSlot( this.slot, aefs );
NetworkHandler.instance().sendToServer( new PacketFluidSlot( Collections.singletonMap( this.slot, aefs ) ) );
}
}
}
}
else
{
baseContainer.doAction( sender, this.action, this.slot, this.id );
@@ -23,7 +23,13 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import appeng.api.config.FuzzyMode;
import appeng.api.storage.data.IItemList;
import appeng.container.implementations.ContainerPatternTerm;
import gregtech.common.items.MetaTool;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
@@ -64,6 +70,8 @@ public class PacketJEIRecipe extends AppEngPacket
{
private ItemStack[][] recipe;
private ItemStack[] output;
// automatic.
public PacketJEIRecipe( final ByteBuf stream ) throws IOException
@@ -86,7 +94,19 @@ public class PacketJEIRecipe extends AppEngPacket
}
}
}
if ( comp.hasKey("outputs") ) {
final NBTTagList outputList = comp.getTagList("outputs", 10);
this.output = new ItemStack[3];
for( int x = 0; x < this.output.length; x++ )
{
if( outputList.tagCount() > 0 )
{
this.output[x] = new ItemStack(outputList.getCompoundTagAt( x ));
}
}
}
}
}
// api
@@ -152,6 +172,11 @@ public class PacketJEIRecipe extends AppEngPacket
// already the correct item?
ItemStack newItem = this.canUseInSlot( x, currentItem );
if ( !cct.useRealItems() && this.recipe[x] != null ) {
if (this.recipe[x].length > 0 )
currentItem.setCount( recipe[x][0].getCount() );
}
// put away old item
if( newItem != currentItem && security.hasPermission( player, SecurityPermissions.INJECT ) )
{
@@ -185,6 +210,24 @@ public class PacketJEIRecipe extends AppEngPacket
if( cct.useRealItems() )
{
out = Platform.poweredExtraction( energy, storage, request, cct.getActionSource() );
if( out == null )
{
if( request.getItem().isDamageable() || ( Platform.isModLoaded( "gregtech" ) && request.getItem() instanceof MetaTool ) )
{
Collection<IAEItemStack> outList = inv.getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ).getStorageList().findFuzzy( request, FuzzyMode.IGNORE_ALL );
for( IAEItemStack is : outList )
{
if( is.getDefinition().getMetadata() == request.getDefinition().getMetadata() )
{
out = Platform.poweredExtraction( energy, storage, is.copy().setStackSize( 1 ), cct.getActionSource() );
}
if( out != null )
{
break;
}
}
}
}
}
else
{
@@ -202,6 +245,10 @@ public class PacketJEIRecipe extends AppEngPacket
if( out != null )
{
if (!cct.useRealItems())
{
out.setStackSize( recipe[x][y].getCount() );
}
currentItem = out.createItemStack();
}
}
@@ -213,19 +260,37 @@ public class PacketJEIRecipe extends AppEngPacket
if( cct.useRealItems() )
{
currentItem = ad.removeItems( 1, this.recipe[x][y], null );
currentItem = ad.removeSimilarItems(1, this.recipe[x][y],FuzzyMode.IGNORE_ALL, null );
}
else
{
currentItem = ad.simulateRemove( 1, this.recipe[x][y], null );
currentItem = ad.simulateSimilarRemove(recipe[x][y].getCount(), this.recipe[x][y],FuzzyMode.IGNORE_ALL, null );
}
}
}
}
if (!cct.useRealItems())
{
if( currentItem.isEmpty() && this.recipe[x] != null )
{
currentItem = this.recipe[x][0].copy();
}
}
}
ItemHandlerUtil.setStackInSlot( craftMatrix, x, currentItem );
}
con.onCraftMatrixChanged( new WrapperInvItemHandler( craftMatrix ) );
if( this.output != null && con instanceof ContainerPatternTerm && !( (ContainerPatternTerm) con ).isCraftingMode() )
{
IItemHandler outputSlots = cct.getInventoryByName( "output" );
for( int i = 0; i < this.output.length; ++i )
{
if( this.output[i] == null ) continue;
ItemHandlerUtil.setStackInSlot( outputSlots, i, this.output[i] );
}
}
}
}
@@ -241,7 +306,7 @@ public class PacketJEIRecipe extends AppEngPacket
{
for( ItemStack option : this.recipe[slot] )
{
if( is.isItemEqual( option ) )
if( ItemStack.areItemStacksEqual( is, option ) )
{
return is;
}
@@ -19,6 +19,7 @@
package appeng.core.sync.packets;
import appeng.fluids.container.ContainerFluidInterface;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
@@ -90,5 +91,9 @@ public class PacketTargetFluidStack extends AppEngPacket
{
( (ContainerFluidTerminal) player.openContainer ).setTargetStack( this.stack );
}
else if( player.openContainer instanceof ContainerFluidInterface )
{
( (ContainerFluidInterface) player.openContainer ).setTargetStack( this.stack );
}
}
}
@@ -175,12 +175,46 @@ public class PacketValueConfig extends AppEngPacket
}
else if( this.Name.equals( "PatternTerminal.Encode" ) )
{
cpt.encode();
if (this.Value.equals( "2" )) {
cpt.encodeAndMoveToInventory();
}
else
{
cpt.encode();
}
}
else if( this.Name.equals( "PatternTerminal.Clear" ) )
{
cpt.clear();
}
else if( this.Name.equals( "PatternTerminal.MultiplyByTwo" ) )
{
cpt.multiply(2);
}
else if( this.Name.equals( "PatternTerminal.MultiplyByThree" ) )
{
cpt.multiply(3);
}
else if( this.Name.equals( "PatternTerminal.DivideByTwo" ) )
{
cpt.divide(2);
}
else if( this.Name.equals( "PatternTerminal.DivideByThree" ) )
{
cpt.divide(3);
}
else if( this.Name.equals( "PatternTerminal.IncreaseByOne" ) )
{
cpt.increase(1);
}
else if( this.Name.equals( "PatternTerminal.DecreaseByOne" ) )
{
cpt.decrease(1);
}
else if( this.Name.equals( "PatternTerminal.MaximizeCount" ) )
{
cpt.maximizeCount();
}
else if( this.Name.equals( "PatternTerminal.Substitute" ) )
{
cpt.getPatternTerminal().setSubstitution( this.Value.equals( "1" ) );
+12 -31
View File
@@ -69,8 +69,8 @@ public class CraftingJob implements Runnable, ICraftingJob
private final ICraftingCallback callback;
private boolean running = false;
private boolean done = false;
private int time = 5;
private int incTime = Integer.MAX_VALUE;
private int time;
private int incTime;
private World wrapWorld( final World w )
{
@@ -221,11 +221,10 @@ public class CraftingJob implements Runnable, ICraftingJob
void handlePausing() throws InterruptedException
{
if( this.incTime > 100 )
if( !this.actionSrc.player().isPresent() && this.incTime > 100 )
{
this.incTime = 0;
synchronized( this.monitor )
synchronized ( this.monitor )
{
if( this.watch.elapsed( TimeUnit.MICROSECONDS ) > this.time )
{
@@ -238,7 +237,7 @@ public class CraftingJob implements Runnable, ICraftingJob
{
AELog.craftingDebug( "crafting job will now sleep" );
while( !this.running )
while ( !this.running )
{
this.monitor.wait();
}
@@ -310,43 +309,25 @@ public class CraftingJob implements Runnable, ICraftingJob
}
/**
* returns true if this needs more simulation.
*
* @param milli milliseconds of simulation
*
* @return true if this needs more simulation
*/
public boolean simulateFor( final int milli )
public boolean simulateFor(final int milli)
{
this.time = milli;
synchronized( this.monitor )
synchronized ( this.monitor )
{
if( this.done )
{
return false;
}
this.watch.reset();
this.watch.start();
this.running = true;
AELog.craftingDebug( "main thread is now going to sleep" );
this.monitor.notify();
while( this.running )
if( !this.actionSrc.player().isPresent() )
{
try
{
this.monitor.wait();
}
catch( final InterruptedException ignored )
{
}
this.watch.reset();
this.watch.start();
this.monitor.notify();
}
AELog.craftingDebug( "main thread is now active" );
this.running = true;
}
return true;
@@ -25,6 +25,7 @@ import java.util.List;
import com.google.common.collect.Lists;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
import appeng.api.AEApi;
@@ -120,18 +121,47 @@ public class CraftingTreeNode
IAEItemStack request( final MECraftingInventory inv, long l, final IActionSource src ) throws CraftBranchFailure, InterruptedException
{
this.job.handlePausing();
final List<IAEItemStack> thingsUsed = new ArrayList<>();
this.what.setStackSize( l );
if( this.getSlot() >= 0 && this.parent != null && this.parent.details.isCraftable() )
IAEItemStack available = inv.extractItems( this.what, Actionable.MODULATE, src );
if( available != null )
{
if( !this.exhausted )
{
final IAEItemStack is = this.job.checkUse( available );
if( is != null )
{
thingsUsed.add( is.copy() );
this.used.add( is );
}
}
this.bytes += available.getStackSize();
l -= available.getStackSize();
if( l == 0 )
{
return available;
}
}
else if( this.getSlot() >= 0 && this.parent != null && this.parent.details.isCraftable() )
{
final Collection<IAEItemStack> itemList;
final IItemList<IAEItemStack> inventoryList = inv.getItemList();
if( this.parent.details.canSubstitute() )
{
itemList = inventoryList.findFuzzy( this.what, FuzzyMode.IGNORE_ALL );
final List<IAEItemStack> substitutes = this.parent.details.getSubstituteInputs( this.slot );
itemList = new ArrayList<>( substitutes.size() );
for( IAEItemStack stack : substitutes )
{
itemList.addAll( inventoryList.findFuzzy( stack, FuzzyMode.IGNORE_ALL ) );
}
}
else
{
@@ -152,7 +182,7 @@ public class CraftingTreeNode
fuzz = fuzz.copy();
fuzz.setStackSize( l );
final IAEItemStack available = inv.extractItems( fuzz, Actionable.MODULATE, src );
available = inv.extractItems( fuzz, Actionable.MODULATE, src );
if( available != null )
{
@@ -178,32 +208,6 @@ public class CraftingTreeNode
}
}
}
else
{
final IAEItemStack available = inv.extractItems( this.what, Actionable.MODULATE, src );
if( available != null )
{
if( !this.exhausted )
{
final IAEItemStack is = this.job.checkUse( available );
if( is != null )
{
thingsUsed.add( is.copy() );
this.used.add( is );
}
}
this.bytes += available.getStackSize();
l -= available.getStackSize();
if( l == 0 )
{
return available;
}
}
}
if( this.canEmit )
{
@@ -222,7 +226,7 @@ public class CraftingTreeNode
{
final CraftingTreeProcess pro = this.nodes.get( 0 );
while( pro.possible && l > 0 )
while ( pro.possible && l > 0 )
{
final IAEItemStack madeWhat = pro.getAmountCrafted( this.what );
@@ -230,7 +234,7 @@ public class CraftingTreeNode
madeWhat.setStackSize( l );
final IAEItemStack available = inv.extractItems( madeWhat, Actionable.MODULATE, src );
available = inv.extractItems( madeWhat, Actionable.MODULATE, src );
if( available != null )
{
@@ -254,13 +258,13 @@ public class CraftingTreeNode
{
try
{
while( pro.possible && l > 0 )
while ( pro.possible && l > 0 )
{
final MECraftingInventory subInv = new MECraftingInventory( inv, true, true, true );
pro.request( subInv, 1, src );
this.what.setStackSize( l );
final IAEItemStack available = subInv.extractItems( this.what, Actionable.MODULATE, src );
available = subInv.extractItems( this.what, Actionable.MODULATE, src );
if( available != null )
{
@@ -317,7 +321,7 @@ public class CraftingTreeNode
}
// missing = 0;
job.addBytes( 8 + this.bytes );
job.addBytes( this.bytes );
for( final CraftingTreeProcess pro : this.nodes )
{
@@ -354,6 +358,10 @@ public class CraftingTreeNode
if( ex == null || ex.getStackSize() != i.getStackSize() )
{
if( src.player().isPresent() )
{
src.player().get().sendStatusMessage( new TextComponentString( "System reported " + i.getStackSize() + " " + i.getDefinition().getItem().getItemStackDisplayName( i.getDefinition() ) + " available but could not extract anything" ), false );
}
throw new CraftBranchFailure( i, i.getStackSize() );
}
@@ -77,8 +77,6 @@ public class CraftingTreeProcess
ic.setInventorySlotContents( x, is[x] == null ? ItemStack.EMPTY : is[x].createItemStack() );
}
FMLCommonHandler.instance().firePlayerCraftingEvent( Platform.getPlayer( (WorldServer) world ), details.getOutput( ic, world ), ic );
for( int x = 0; x < ic.getSizeInventory(); x++ )
{
final ItemStack g = ic.getStackInSlot( x );
@@ -188,7 +186,6 @@ public class CraftingTreeProcess
void request( final MECraftingInventory inv, final long i, final IActionSource src ) throws CraftBranchFailure, InterruptedException
{
this.job.handlePausing();
if( this.fullSimulation )
{
final InventoryCrafting ic = new InventoryCrafting( new ContainerNull(), 3, 3 );
@@ -201,8 +198,6 @@ public class CraftingTreeProcess
ic.setInventorySlotContents( entry.getKey().getSlot(), stack.createItemStack() );
}
FMLCommonHandler.instance().firePlayerCraftingEvent( Platform.getPlayer( (WorldServer) this.world ), this.details.getOutput( ic, this.world ), ic );
for( int x = 0; x < ic.getSizeInventory(); x++ )
{
ItemStack is = ic.getStackInSlot( x );
@@ -246,7 +241,6 @@ public class CraftingTreeProcess
o.setStackSize( o.getStackSize() * i );
inv.injectItems( o, Actionable.MODULATE, src );
}
this.crafts += i;
}
@@ -258,14 +252,14 @@ public class CraftingTreeProcess
pro.dive( job );
}
job.addBytes( 8 + this.crafts + this.bytes );
job.addBytes( this.crafts * 8 + this.bytes );
}
IAEItemStack getAmountCrafted( IAEItemStack what2 )
{
for( final IAEItemStack is : this.details.getCondensedOutputs() )
{
if( is.equals( what2 ) )
if( is.isSameType( what2 ) )
{
what2 = what2.copy();
what2.setStackSize( is.getStackSize() );
@@ -28,7 +28,9 @@ import appeng.api.storage.IStorageChannel;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList;
import appeng.me.helpers.PlayerSource;
import appeng.util.inv.ItemListIgnoreCrafting;
import net.minecraft.util.text.TextComponentString;
public class MECraftingInventory implements IMEInventory<IAEItemStack>
@@ -307,8 +309,19 @@ public class MECraftingInventory implements IMEInventory<IAEItemStack>
if( result == null || result.getStackSize() != extra.getStackSize() )
{
if( src.player().isPresent() )
{
if( result == null )
{
src.player().get().sendStatusMessage( new TextComponentString( "System reported " + extra.getStackSize() + " " + extra.getDefinition().getItem().getItemStackDisplayName( extra.getDefinition() ) + " available but could not extract anything" ), false );
}
else
{
src.player().get().sendStatusMessage( new TextComponentString( "System reported " + extra.getStackSize() + " " + extra.getDefinition().getItem().getItemStackDisplayName( extra.getDefinition() ) + " available but could only extract " + result.getStackSize() ), false );
}
}
failed = true;
break;
if( !src.player().isPresent() ) break;
}
}
}
@@ -21,6 +21,9 @@ package appeng.fluids.client.gui;
import java.io.IOException;
import appeng.api.util.IConfigManager;
import appeng.client.gui.widgets.GuiCustomSlot;
import appeng.util.IConfigManagerHost;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.entity.player.InventoryPlayer;
@@ -38,11 +41,12 @@ import appeng.fluids.helper.IFluidInterfaceHost;
import appeng.fluids.util.IAEFluidTank;
public class GuiFluidInterface extends GuiUpgradeable
public class GuiFluidInterface extends GuiUpgradeable implements IConfigManagerHost
{
public final static int ID_BUTTON_TANK = 222;
private final IFluidInterfaceHost host;
private final ContainerFluidInterface container;
private GuiTabButton priority;
public GuiFluidInterface( final InventoryPlayer ip, final IFluidInterfaceHost te )
@@ -50,6 +54,8 @@ public class GuiFluidInterface extends GuiUpgradeable
super( new ContainerFluidInterface( ip, te ) );
this.ySize = 231;
this.host = te;
( this.container = (ContainerFluidInterface) this.inventorySlots ).setGui( this );
}
@Override
@@ -62,9 +68,7 @@ public class GuiFluidInterface extends GuiUpgradeable
for( int i = 0; i < DualityFluidInterface.NUMBER_OF_TANKS; ++i )
{
final GuiFluidTank guiTank = new GuiFluidTank( fluidTank, i, DualityFluidInterface.NUMBER_OF_TANKS + i, this.getGuiLeft() + 35 + 18 * i, this
.getGuiTop() + 53, 16, 68 );
this.buttonList.add( guiTank );
this.guiSlots.add( new GuiFluidTank( fluidTank, i, DualityFluidInterface.NUMBER_OF_TANKS + i, 36 + 18 * i, 53, 16, 68 ) );
this.guiSlots.add( new GuiFluidSlot( configFluids, i, i, 35 + 18 * i, 35 ) );
}
@@ -104,9 +108,33 @@ public class GuiFluidInterface extends GuiUpgradeable
}
}
@Override
protected void mouseClicked( int xCoord, int yCoord, int btn ) throws IOException
{
for( GuiCustomSlot slot : this.guiSlots )
{
if( slot instanceof GuiFluidTank )
{
if( this.isPointInRegion( slot.xPos(), slot.yPos(), slot.getWidth(), slot.getHeight(), xCoord, yCoord ) && slot.canClick( this.mc.player ) )
{
this.container.setTargetStack( ( (GuiFluidTank) slot ).getFluidStack() );
slot.slotClicked( this.mc.player.inventory.getItemStack(), btn );
return;
}
}
}
super.mouseClicked( xCoord, yCoord, btn );
}
@Override
protected boolean drawUpgrades()
{
return false;
}
@Override
public void updateSetting( IConfigManager manager, Enum settingName, Enum newValue )
{
}
}
@@ -90,6 +90,13 @@ public class GuiFluidLevelEmitter extends GuiUpgradeable
this.level.drawTextBox();
}
@Override
public void drawFG( int offsetX, int offsetY, int mouseX, int mouseY )
{
if( isPointInRegion( 24, 43,89,this.fontRenderer.FONT_HEIGHT,mouseX,mouseY ) ) drawTooltip( mouseX - guiLeft - 7, mouseY - guiTop + 25, "Amount in millibuckets" );
super.drawFG( offsetX, offsetY, mouseX, mouseY );
}
@Override
protected boolean drawUpgrades()
{
@@ -4,6 +4,7 @@ package appeng.fluids.client.gui.widgets;
import java.util.Collections;
import appeng.container.slot.IJEITargetSlot;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
@@ -23,7 +24,7 @@ import appeng.fluids.util.AEFluidStack;
import appeng.fluids.util.IAEFluidTank;
public class GuiFluidSlot extends GuiCustomSlot
public class GuiFluidSlot extends GuiCustomSlot implements IJEITargetSlot
{
private final IAEFluidTank fluids;
private final int slot;
@@ -19,42 +19,50 @@
package appeng.fluids.client.gui.widgets;
import appeng.client.gui.widgets.GuiCustomSlot;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketInventoryAction;
import appeng.helpers.InventoryAction;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import appeng.api.storage.data.IAEFluidStack;
import appeng.api.util.AEColor;
import appeng.client.gui.widgets.ITooltip;
import appeng.fluids.util.IAEFluidTank;
@SideOnly( Side.CLIENT )
public class GuiFluidTank extends GuiButton implements ITooltip
public class GuiFluidTank extends GuiCustomSlot implements ITooltip
{
private final IAEFluidTank tank;
private final int slot;
private final int width;
private final int height;
public GuiFluidTank( IAEFluidTank tank, int slot, int id, int x, int y, int w, int h )
{
super( id, x, y, w, h, "" );
super( id, x, y );
this.tank = tank;
this.slot = slot;
this.width = w;
this.height = h;
}
@Override
public void drawButton( final Minecraft mc, final int mouseX, final int mouseY, final float partialTicks )
public void drawContent( Minecraft mc, int mouseX, int mouseY, float partialTicks )
{
if( this.visible )
final IAEFluidStack fs = this.getFluidStack();
if( fs != null )
{
GlStateManager.disableBlend();
GlStateManager.disableLighting();
drawRect( this.x, this.y, this.x + this.width, this.y + this.height, AEColor.GRAY.blackVariant | 0xFF000000 );
//drawRect( this.x, this.y, this.x + this.width, this.y + this.height, AEColor.GRAY.blackVariant | 0xFF000000 );
final IAEFluidStack fluid = this.tank.getFluidInSlot( this.slot );
if( fluid != null && fluid.getStackSize() > 0 )
@@ -69,17 +77,16 @@ public class GuiFluidTank extends GuiButton implements ITooltip
TextureAtlasSprite sprite = mc.getTextureMapBlocks().getAtlasSprite( fluid.getFluid().getStill().toString() );
final int scaledHeight = (int) ( this.height * ( (float) fluid.getStackSize() / this.tank.getTankProperties()[this.slot].getCapacity() ) );
int iconHeightRemainder = scaledHeight % 16;
int iconHeightRemainder = scaledHeight % this.getHeight();
if( iconHeightRemainder > 0 )
{
this.drawTexturedModalRect( this.x, this.y + this.height - iconHeightRemainder, sprite, 16, iconHeightRemainder );
this.drawTexturedModalRect( this.xPos(), this.yPos() + this.getHeight() - iconHeightRemainder, sprite, this.getWidth(), iconHeightRemainder );
}
for( int i = 0; i < scaledHeight / 16; i++ )
for( int i = 0; i < scaledHeight / this.getHeight(); i++ )
{
this.drawTexturedModalRect( this.x, this.y + this.height - iconHeightRemainder - ( i + 1 ) * 16, sprite, 16, 16 );
this.drawTexturedModalRect( this.xPos(), this.yPos() + this.getHeight() - iconHeightRemainder - ( i + 1 ) * 16, sprite, this.getWidth(), this.getHeight() );
}
}
}
}
@@ -100,25 +107,25 @@ public class GuiFluidTank extends GuiButton implements ITooltip
@Override
public int xPos()
{
return this.x - 2;
return this.x - 1;
}
@Override
public int yPos()
{
return this.y - 2;
return this.y - 1;
}
@Override
public int getWidth()
{
return this.width + 4;
return this.width;
}
@Override
public int getHeight()
{
return this.height + 4;
return this.height + 1;
}
@Override
@@ -127,4 +134,24 @@ public class GuiFluidTank extends GuiButton implements ITooltip
return true;
}
public IAEFluidStack getFluidStack()
{
return this.tank.getFluidInSlot( this.slot );
}
@Override
public void slotClicked( ItemStack clickStack, final int mouseButton )
{
if( getFluidStack() != null )
{
NetworkHandler.instance().sendToServer( new PacketInventoryAction( InventoryAction.FILL_ITEM, slot, 0 ) );
}
else
{
NetworkHandler.instance().sendToServer( new PacketInventoryAction( InventoryAction.EMPTY_ITEM, slot, 0 ) );
}
}
}
@@ -19,9 +19,17 @@
package appeng.fluids.container;
import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.Map;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketTargetFluidStack;
import appeng.fluids.util.AEFluidStack;
import appeng.helpers.InventoryAction;
import appeng.util.IConfigManagerHost;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.IContainerListener;
@@ -33,12 +41,19 @@ import appeng.fluids.helper.FluidSyncHelper;
import appeng.fluids.helper.IFluidInterfaceHost;
import appeng.fluids.util.IAEFluidTank;
import appeng.util.Platform;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
public class ContainerFluidInterface extends ContainerFluidConfigurable
public class ContainerFluidInterface extends ContainerFluidConfigurable implements IConfigManagerHost
{
private final DualityFluidInterface myDuality;
private final FluidSyncHelper tankSync;
private IConfigManagerHost gui;
// Holds the fluid the client wishes to extract, or null for insert
private IAEFluidStack clientRequestedTargetFluid = null;
public ContainerFluidInterface( final InventoryPlayer ip, final IFluidInterfaceHost te )
{
@@ -60,6 +75,15 @@ public class ContainerFluidInterface extends ContainerFluidConfigurable
return this.myDuality.getConfig();
}
@Override
public void updateSetting( IConfigManager manager, Enum settingName, Enum newValue )
{
if( this.getGui() != null )
{
this.getGui().updateSetting( manager, settingName, newValue );
}
}
@Override
public void detectAndSendChanges()
{
@@ -97,6 +121,126 @@ public class ContainerFluidInterface extends ContainerFluidConfigurable
this.tankSync.readPacket( fluids );
}
private IConfigManagerHost getGui()
{
return this.gui;
}
public void setGui( @Nonnull final IConfigManagerHost gui )
{
this.gui = gui;
}
public void doAction( EntityPlayerMP player, InventoryAction action, int slot, long id )
{
if( action != InventoryAction.FILL_ITEM && action != InventoryAction.EMPTY_ITEM )
{
super.doAction( player, action, slot, id );
return;
}
final ItemStack held = player.inventory.getItemStack();
ItemStack heldCopy = held.copy();
heldCopy.setCount( 1 );
IFluidHandlerItem fh = FluidUtil.getFluidHandler( heldCopy );
if( fh == null )
{
// only fluid handlers items
return;
}
if( action == InventoryAction.FILL_ITEM && this.clientRequestedTargetFluid != null )
{
final IAEFluidStack stack = this.clientRequestedTargetFluid.copy();
// Check how much we can store in the item
stack.setStackSize( Integer.MAX_VALUE );
int amountAllowed = fh.fill( stack.getFluidStack(), false );
int heldAmount = held.getCount();
for( int i = 0; i < heldAmount; i++ )
{
ItemStack copiedFluidContainer = held.copy();
copiedFluidContainer.setCount( 1 );
fh = FluidUtil.getFluidHandler( copiedFluidContainer );
FluidStack extractableFluid = this.myDuality.getTanks().drain( stack.setStackSize( amountAllowed ).getFluidStack(), false );
if( extractableFluid == null || extractableFluid.amount == 0 )
{
break;
}
int fillableAmount = fh.fill( extractableFluid, false );
if( fillableAmount > 0 )
{
FluidStack extractedFluid = this.myDuality.getTanks().drain( extractableFluid, true );
fh.fill( extractedFluid, true );
}
if( held.getCount() == 1 )
{
player.inventory.setItemStack( fh.getContainer() );
}
else
{
player.inventory.getItemStack().shrink( 1 );
if( !player.inventory.addItemStackToInventory( fh.getContainer() ) )
{
player.dropItem( fh.getContainer(), false );
}
}
}
}
else if( action == InventoryAction.EMPTY_ITEM )
{
int heldAmount = held.getCount();
for( int i = 0; i < heldAmount; i++ )
{
ItemStack copiedFluidContainer = held.copy();
copiedFluidContainer.setCount( 1 );
fh = FluidUtil.getFluidHandler( copiedFluidContainer );
FluidStack drainable = fh.drain( this.myDuality.getTanks().getTankProperties()[slot].getCapacity(), false );
if( drainable != null )
{
fh.drain( drainable, true );
this.myDuality.getTanks().fill( drainable, true );
}
if( held.getCount() == 1 )
{
player.inventory.setItemStack( fh.getContainer() );
}
else
{
player.inventory.getItemStack().shrink( 1 );
if( !player.inventory.addItemStackToInventory( fh.getContainer() ) )
{
player.dropItem( fh.getContainer(), false );
}
}
}
}
this.updateHeld( player );
}
public void setTargetStack( final IAEFluidStack stack )
{
if( Platform.isClient() )
{
if( stack == null && this.clientRequestedTargetFluid == null )
{
return;
}
if( stack != null && this.clientRequestedTargetFluid != null && stack.getFluidStack().isFluidEqual( this.clientRequestedTargetFluid.getFluidStack() ) )
{
return;
}
NetworkHandler.instance().sendToServer( new PacketTargetFluidStack( (AEFluidStack) stack ) );
}
this.clientRequestedTargetFluid = stack == null ? null : stack.copy();
}
@Override
protected boolean supportCapacity()
{
@@ -24,6 +24,9 @@ import java.nio.BufferOverflowException;
import javax.annotation.Nonnull;
import appeng.container.slot.AppEngSlot;
import appeng.container.slot.SlotPlayerHotBar;
import appeng.container.slot.SlotPlayerInv;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
@@ -70,6 +73,7 @@ import appeng.me.helpers.ChannelPowerSrc;
import appeng.util.ConfigManager;
import appeng.util.IConfigManagerHost;
import appeng.util.Platform;
import net.minecraftforge.items.IItemHandler;
/**
@@ -342,6 +346,89 @@ public class ContainerFluidTerminal extends AEBaseContainer implements IConfigMa
}
}
@Override
public ItemStack transferStackInSlot( final EntityPlayer p, final int idx )
{
if( Platform.isClient() )
{
return ItemStack.EMPTY;
}
EntityPlayerMP player = (EntityPlayerMP) p;
if( this.inventorySlots.get( idx ) instanceof SlotPlayerInv || this.inventorySlots.get( idx ) instanceof SlotPlayerHotBar )
{
final AppEngSlot clickSlot = (AppEngSlot) this.inventorySlots.get( idx ); // require AE SLots!
ItemStack itemStack = clickSlot.getStack();
ItemStack copy = itemStack.copy();
copy.setCount( 1 );
IFluidHandlerItem fh = FluidUtil.getFluidHandler( copy );
if( fh == null )
{
// only fluid handlers items
return ItemStack.EMPTY;
}
int heldAmount = itemStack.getCount();
for( int i = 0; i < heldAmount; i++ )
{
copy = itemStack.copy();
copy.setCount( 1 );
fh = FluidUtil.getFluidHandler( copy );
final FluidStack extract = fh.drain( Integer.MAX_VALUE, false );
if( extract == null || extract.amount < 1 )
{
return ItemStack.EMPTY;
}
// Check if we can push into the system
final IAEFluidStack notStorable = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ), this.getActionSource(), Actionable.SIMULATE );
if( notStorable != null && notStorable.getStackSize() > 0 )
{
final int toStore = (int) ( extract.amount - notStorable.getStackSize() );
final FluidStack storable = fh.drain( toStore, false );
if( storable == null || storable.amount == 0 )
{
return ItemStack.EMPTY;
}
else
{
extract.amount = storable.amount;
}
}
// Actually drain
final FluidStack drained = fh.drain( extract, true );
extract.amount = drained.amount;
final IAEFluidStack notInserted = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ), this.getActionSource() );
if( notInserted != null && notInserted.getStackSize() > 0 )
{
IAEFluidStack spill = this.monitor.injectItems( notInserted, Actionable.MODULATE, this.getActionSource() );
if( spill != null && spill.getStackSize() > 0 )
{
fh.fill( spill.getFluidStack(), true );
}
}
if( notInserted == null )
{
if( !player.inventory.addItemStackToInventory( fh.getContainer() ) )
{
player.dropItem( fh.getContainer(), false );
}
clickSlot.decrStackSize( 1 );
}
}
this.detectAndSendChanges();
return ItemStack.EMPTY;
}
return super.transferStackInSlot( p, idx );
}
@Override
public void doAction( EntityPlayerMP player, InventoryAction action, int slot, long id )
{
@@ -352,13 +439,9 @@ public class ContainerFluidTerminal extends AEBaseContainer implements IConfigMa
}
final ItemStack held = player.inventory.getItemStack();
if( held.getCount() != 1 )
{
// only support stacksize 1 for now
return;
}
final IFluidHandlerItem fh = FluidUtil.getFluidHandler( held );
ItemStack heldCopy = held.copy();
heldCopy.setCount( 1 );
IFluidHandlerItem fh = FluidUtil.getFluidHandler( heldCopy );
if( fh == null )
{
// only fluid handlers items
@@ -372,84 +455,122 @@ public class ContainerFluidTerminal extends AEBaseContainer implements IConfigMa
// Check how much we can store in the item
stack.setStackSize( Integer.MAX_VALUE );
int amountAllowed = fh.fill( stack.getFluidStack(), false );
stack.setStackSize( amountAllowed );
// Check if we can pull out of the system
final IAEFluidStack canPull = Platform.poweredExtraction( this.getPowerSource(), this.monitor, stack, this.getActionSource(), Actionable.SIMULATE );
if( canPull == null || canPull.getStackSize() < 1 )
int heldAmount = held.getCount();
for( int i = 0; i < heldAmount; i++ )
{
return;
}
ItemStack copiedFluidContainer = held.copy();
copiedFluidContainer.setCount( 1 );
fh = FluidUtil.getFluidHandler( copiedFluidContainer );
// How much could fit into the container
final int canFill = fh.fill( canPull.getFluidStack(), false );
if( canFill == 0 )
{
return;
}
// Now actually pull out of the system
stack.setStackSize( canFill );
final IAEFluidStack pulled = Platform.poweredExtraction( this.getPowerSource(), this.monitor, stack, this.getActionSource() );
if( pulled == null || pulled.getStackSize() < 1 )
{
// Something went wrong
AELog.error( "Unable to pull fluid out of the ME system even though the simulation said yes " );
return;
}
// Actually fill
final int used = fh.fill( pulled.getFluidStack(), true );
if( used != canFill )
{
AELog.error( "Fluid item [%s] reported a different possible amount than it actually accepted.", held.getDisplayName() );
}
player.inventory.setItemStack( fh.getContainer() );
this.updateHeld( player );
}
else if( action == InventoryAction.EMPTY_ITEM )
{
// See how much we can drain from the item
final FluidStack extract = fh.drain( Integer.MAX_VALUE, false );
if( extract == null || extract.amount < 1 )
{
return;
}
// Check if we can push into the system
final IAEFluidStack notStorable = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ),
this.getActionSource(), Actionable.SIMULATE );
if( notStorable != null && notStorable.getStackSize() > 0 )
{
final int toStore = (int) ( extract.amount - notStorable.getStackSize() );
final FluidStack storable = fh.drain( toStore, false );
if( storable == null || storable.amount == 0 )
// Check if we can pull out of the system
final IAEFluidStack canPull = Platform.poweredExtraction( this.getPowerSource(), this.monitor, stack.setStackSize( amountAllowed ), this.getActionSource(), Actionable.SIMULATE );
if( canPull == null || canPull.getStackSize() < 1 )
{
return;
}
// How much could fit into the container
final int canFill = fh.fill( canPull.getFluidStack(), false );
if( canFill == 0 )
{
return;
}
// Now actually pull out of the system
final IAEFluidStack pulled = Platform.poweredExtraction( this.getPowerSource(), this.monitor, stack.setStackSize( canFill ), this.getActionSource() );
if( pulled == null || pulled.getStackSize() < 1 )
{
// Something went wrong
AELog.error( "Unable to pull fluid out of the ME system even though the simulation said yes " );
return;
}
// Actually fill
final int used = fh.fill( pulled.getFluidStack(), true );
if( used != canFill )
{
AELog.error( "Fluid item [%s] reported a different possible amount than it actually accepted.", held.getDisplayName() );
}
if( held.getCount() == 1 )
{
player.inventory.setItemStack( fh.getContainer() );
}
else
{
extract.amount = storable.amount;
player.inventory.getItemStack().shrink( 1 );
if( !player.inventory.addItemStackToInventory( fh.getContainer() ) )
{
player.dropItem( fh.getContainer(), false );
}
}
}
this.updateHeld( player );
// Actually drain
final FluidStack drained = fh.drain( extract, true );
extract.amount = drained.amount;
final IAEFluidStack notInserted = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ),
this.getActionSource() );
if( notInserted != null && notInserted.getStackSize() > 0 )
}
else if( action == InventoryAction.EMPTY_ITEM )
{
int heldAmount = held.getCount();
for( int i = 0; i < heldAmount; i++ )
{
AELog.error( "Fluid item [%s] reported a different possible amount to drain than it actually provided.", held.getDisplayName() );
}
ItemStack copiedFluidContainer = held.copy();
copiedFluidContainer.setCount( 1 );
fh = FluidUtil.getFluidHandler( copiedFluidContainer );
player.inventory.setItemStack( fh.getContainer() );
// See how much we can drain from the item
final FluidStack extract = fh.drain( Integer.MAX_VALUE, false );
if( extract == null || extract.amount < 1 )
{
return;
}
// Check if we can push into the system
final IAEFluidStack notStorable = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ), this.getActionSource(), Actionable.SIMULATE );
if( notStorable != null && notStorable.getStackSize() > 0 )
{
final int toStore = (int) ( extract.amount - notStorable.getStackSize() );
final FluidStack storable = fh.drain( toStore, false );
if( storable == null || storable.amount == 0 )
{
return;
}
else
{
extract.amount = storable.amount;
}
}
// Actually drain
final FluidStack drained = fh.drain( extract, true );
extract.amount = drained.amount;
final IAEFluidStack notInserted = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ), this.getActionSource() );
if( notInserted != null && notInserted.getStackSize() > 0 )
{
IAEFluidStack spill = this.monitor.injectItems( notInserted, Actionable.MODULATE, this.getActionSource() );
if( spill != null && spill.getStackSize() > 0 )
{
fh.fill( spill.getFluidStack(), true );
}
}
if( held.getCount() == 1 )
{
player.inventory.setItemStack( fh.getContainer() );
}
else
{
player.inventory.getItemStack().shrink( 1 );
if( !player.inventory.addItemStackToInventory( fh.getContainer() ) )
{
player.dropItem( fh.getContainer(), false );
}
}
}
this.updateHeld( player );
}
}
@@ -28,6 +28,7 @@ import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.items.IItemHandler;
import appeng.api.AEApi;
@@ -72,7 +73,7 @@ import appeng.util.IConfigManagerHost;
import appeng.util.Platform;
public class DualityFluidInterface implements IGridTickable, IStorageMonitorable, IAEFluidInventory, IUpgradeableHost, IConfigManagerHost
public class DualityFluidInterface implements IGridTickable, IStorageMonitorable, IAEFluidInventory, IUpgradeableHost, IConfigManagerHost, IConfigurableFluidInventory
{
public static final int NUMBER_OF_TANKS = 6;
public static final int TANK_CAPACITY = Fluid.BUCKET_VOLUME * 4;
@@ -90,12 +91,10 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
private int isWorking = -1;
private int priority;
private final MEMonitorPassThrough<IAEItemStack> items = new MEMonitorPassThrough<>( new NullInventory<IAEItemStack>(), AEApi.instance()
.storage()
.getStorageChannel( IItemStorageChannel.class ) );
private final MEMonitorPassThrough<IAEFluidStack> fluids = new MEMonitorPassThrough<>( new NullInventory<IAEFluidStack>(), AEApi.instance()
.storage()
.getStorageChannel( IFluidStorageChannel.class ) );
private final MEMonitorPassThrough<IAEItemStack> items = new MEMonitorPassThrough<>( new NullInventory<IAEItemStack>(), AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) );
private final MEMonitorPassThrough<IAEFluidStack> fluids = new MEMonitorPassThrough<>( new NullInventory<IAEFluidStack>(), AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) );
private boolean resetConfigCache;
private IMEMonitor<IAEFluidStack> configCachedHandler;
public DualityFluidInterface( final AENetworkProxy networkProxy, final IFluidInterfaceHost ih )
{
@@ -145,7 +144,12 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
{
if( this.hasConfig() )
{
return (IMEMonitor<T>) new InterfaceInventory( this );
if( resetConfigCache )
{
resetConfigCache = false;
configCachedHandler = new InterfaceInventory( this );
}
return (IMEMonitor<T>) configCachedHandler;
}
return (IMEMonitor<T>) this.fluids;
@@ -382,7 +386,7 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
{
changed = true;
}
else
else if( this.gridProxy.getStorage().getInventory( AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) ).getStorageList().findPrecise( work ) != null )
{
final IAEFluidStack acquired = Platform.poweredExtraction( src, dest, work, this.interfaceRequestSource );
if( acquired != null )
@@ -449,7 +453,12 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
if( inventory == this.config )
{
boolean cfg = hasConfig();
this.readConfig();
if( cfg != hasConfig )
{
resetConfigCache = true;
}
}
else if( inventory == this.tanks )
{
@@ -554,7 +563,6 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
InterfaceInventory( final DualityFluidInterface tileInterface )
{
super( tileInterface.tanks );
this.setActionSource( new MachineSource( tileInterface.iHost ) );
}
@Override
@@ -603,6 +611,14 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
return null;
}
@Override
public IFluidHandler getFluidInventoryByName( final String name) {
if (name.equals("config")) {
return this.config;
}
return null;
}
@Override
public int getInstalledUpgrades( Upgrades u )
{
@@ -0,0 +1,11 @@
package appeng.fluids.helper;
import net.minecraftforge.fluids.capability.IFluidHandler;
public interface IConfigurableFluidInventory
{
default IFluidHandler getFluidInventoryByName( String name )
{
return null;
}
}
@@ -19,13 +19,15 @@
package appeng.fluids.parts;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.*;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Settings;
import appeng.api.config.StorageFilter;
import appeng.api.storage.data.IAEItemStack;
import appeng.me.GridAccessException;
import appeng.util.inv.ItemSlot;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
@@ -42,7 +44,6 @@ import appeng.api.storage.channels.IFluidStorageChannel;
import appeng.api.storage.data.IAEFluidStack;
import appeng.api.storage.data.IItemList;
import appeng.fluids.util.AEFluidStack;
import appeng.me.GridAccessException;
import appeng.me.helpers.IGridProxyable;
import appeng.me.storage.ITickingMonitor;
@@ -61,12 +62,21 @@ public class FluidHandlerAdapter implements IMEInventory<IAEFluidStack>, IBaseMo
private final IFluidHandler fluidHandler;
private final IGridProxyable proxyable;
private final FluidHandlerAdapter.InventoryCache cache;
private StorageFilter mode;
private AccessRestriction access;
FluidHandlerAdapter( IFluidHandler fluidHandler, IGridProxyable proxy )
{
this.fluidHandler = fluidHandler;
this.proxyable = proxy;
this.cache = new FluidHandlerAdapter.InventoryCache( this.fluidHandler );
if( this.proxyable instanceof PartFluidStorageBus )
{
PartFluidStorageBus partFluidStorageBus = (PartFluidStorageBus) this.proxyable;
this.mode = ( (StorageFilter) partFluidStorageBus.getConfigManager().getSetting( Settings.STORAGE_FILTER ) );
this.access = ( (AccessRestriction) partFluidStorageBus.getConfigManager().getSetting( Settings.ACCESS ) );
}
this.cache = new FluidHandlerAdapter.InventoryCache( this.fluidHandler, this.mode );
this.cache.update();
}
@Override
@@ -85,11 +95,14 @@ public class FluidHandlerAdapter implements IMEInventory<IAEFluidStack>, IBaseMo
if( type == Actionable.MODULATE )
{
IAEFluidStack added = input.copy().setStackSize( input.getStackSize() - remaining );
this.cache.currentlyCached.add( added );
this.postDifference( Collections.singletonList( added ) );
try
{
this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() );
}
catch( GridAccessException ignore )
catch( GridAccessException ex )
{
// meh
}
@@ -114,25 +127,32 @@ public class FluidHandlerAdapter implements IMEInventory<IAEFluidStack>, IBaseMo
return null;
}
IAEFluidStack gatheredAEFluidstack = AEFluidStack.fromFluidStack( gathered );
if( mode == Actionable.MODULATE )
{
IAEFluidStack cachedStack = this.cache.currentlyCached.findPrecise( request );
if( cachedStack != null )
{
cachedStack.decStackSize( gatheredAEFluidstack.getStackSize() );
this.postDifference( Collections.singletonList( gatheredAEFluidstack.copy().setStackSize( -gatheredAEFluidstack.getStackSize() ) ) );
}
try
{
this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() );
}
catch( GridAccessException ignore )
catch( GridAccessException ex )
{
// meh
}
}
return AEFluidStack.fromFluidStack( gathered );
return gatheredAEFluidstack;
}
@Override
public TickRateModulation onTick()
{
List<IAEFluidStack> changes = this.cache.update();
if( !changes.isEmpty() )
if( !changes.isEmpty() && access.hasPermission( AccessRestriction.READ ) )
{
this.postDifference( changes );
return TickRateModulation.URGENT;
@@ -193,11 +213,13 @@ public class FluidHandlerAdapter implements IMEInventory<IAEFluidStack>, IBaseMo
private static class InventoryCache
{
private IAEFluidStack[] cachedAeStacks = new IAEFluidStack[0];
private final IFluidHandler fluidHandler;
private final StorageFilter mode;
IItemList<IAEFluidStack> currentlyCached = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList();
public InventoryCache( IFluidHandler fluidHandler )
public InventoryCache( IFluidHandler fluidHandler, StorageFilter mode )
{
this.mode = mode;
this.fluidHandler = fluidHandler;
}
@@ -205,96 +227,46 @@ public class FluidHandlerAdapter implements IMEInventory<IAEFluidStack>, IBaseMo
{
final List<IAEFluidStack> changes = new ArrayList<>();
final IFluidTankProperties[] tankProperties = this.fluidHandler.getTankProperties();
final int slots = tankProperties.length;
// Make room for new slots
if( slots > this.cachedAeStacks.length )
IItemList<IAEFluidStack> currentlyOnStorage = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList();
for( IFluidTankProperties tankProperty : tankProperties )
{
this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, slots );
}
for( int slot = 0; slot < slots; slot++ )
{
// Save the old stuff
final IAEFluidStack oldAEFS = this.cachedAeStacks[slot];
final FluidStack newFS = tankProperties[slot].getContents();
this.handlePossibleSlotChanges( slot, oldAEFS, newFS, changes );
}
// Handle cases where the number of slots actually is lower now than before
if( slots < this.cachedAeStacks.length )
{
for( int slot = slots; slot < this.cachedAeStacks.length; slot++ )
if( this.mode == StorageFilter.EXTRACTABLE_ONLY && this.fluidHandler.drain( 1, false ) == null )
{
final IAEFluidStack aeStack = this.cachedAeStacks[slot];
if( aeStack != null )
{
final IAEFluidStack a = aeStack.copy();
a.setStackSize( -a.getStackSize() );
changes.add( a );
}
continue;
}
this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, slots );
currentlyOnStorage.add( AEFluidStack.fromFluidStack( tankProperty.getContents() ) );
}
for ( final IAEFluidStack is : currentlyCached )
{
is.setStackSize( -is.getStackSize() );
}
for ( final IAEFluidStack is : currentlyOnStorage )
{
currentlyCached.add( is );
}
for ( final IAEFluidStack is : currentlyCached )
{
if( is.getStackSize() != 0 )
{
changes.add( is );
}
}
currentlyCached = currentlyOnStorage;
return changes;
}
public IItemList<IAEFluidStack> getAvailableItems( IItemList<IAEFluidStack> out )
{
Arrays.stream( this.cachedAeStacks ).forEach( out::add );
currentlyCached.iterator().forEachRemaining( out::add );
return out;
}
private void handlePossibleSlotChanges( int slot, IAEFluidStack oldAeFS, FluidStack newFS, List<IAEFluidStack> changes )
{
if( oldAeFS != null && oldAeFS.getFluidStack().isFluidEqual( newFS ) )
{
this.handleStackSizeChanged( slot, oldAeFS, newFS, changes );
}
else
{
this.handleFluidChanged( slot, oldAeFS, newFS, changes );
}
}
private void handleStackSizeChanged( int slot, IAEFluidStack oldAeFS, FluidStack newFS, List<IAEFluidStack> changes )
{
// Still the same fluid, but amount might have changed
final long diff = newFS.amount - oldAeFS.getStackSize();
if( diff != 0 )
{
final IAEFluidStack stack = oldAeFS.copy();
stack.setStackSize( newFS.amount );
this.cachedAeStacks[slot] = stack;
final IAEFluidStack a = stack.copy();
a.setStackSize( diff );
changes.add( a );
}
}
private void handleFluidChanged( int slot, IAEFluidStack oldAeFS, FluidStack newFS, List<IAEFluidStack> changes )
{
// Completely different fluid
this.cachedAeStacks[slot] = AEFluidStack.fromFluidStack( newFS );
// If we had a stack previously in this slot, notify the network about its disappearance
if( oldAeFS != null )
{
oldAeFS.setStackSize( -oldAeFS.getStackSize() );
changes.add( oldAeFS );
}
// Notify the network about the new stack. Note that this is null if newFS was null
if( this.cachedAeStacks[slot] != null )
{
changes.add( this.cachedAeStacks[slot] );
}
}
}
}
@@ -6,6 +6,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import appeng.fluids.helper.IConfigurableFluidInventory;
import net.minecraft.block.Block;
import net.minecraft.block.BlockLiquid;
import net.minecraft.block.state.IBlockState;
@@ -51,9 +52,10 @@ import appeng.parts.automation.PartAbstractFormationPlane;
import appeng.parts.automation.PlaneModels;
import appeng.util.Platform;
import appeng.util.prioritylist.PrecisePriorityList;
import net.minecraftforge.fluids.capability.IFluidHandler;
public class PartFluidFormationPlane extends PartAbstractFormationPlane<IAEFluidStack> implements IAEFluidInventory
public class PartFluidFormationPlane extends PartAbstractFormationPlane<IAEFluidStack> implements IAEFluidInventory, IConfigurableFluidInventory
{
private static final PlaneModels MODELS = new PlaneModels( "part/fluid_formation_plane_", "part/fluid_formation_plane_on_" );
@@ -176,8 +178,9 @@ public class PartFluidFormationPlane extends PartAbstractFormationPlane<IAEFluid
this.stateChanged();
}
@Override
@MENetworkEventSubscribe
public void updateChannels( final MENetworkChannelsChanged changedChannels )
public void chanRender( final MENetworkChannelsChanged changedChannels )
{
this.stateChanged();
}
@@ -202,7 +205,7 @@ public class PartFluidFormationPlane extends PartAbstractFormationPlane<IAEFluid
@Override
public List<IMEInventoryHandler> getCellArray( final IStorageChannel channel )
{
if( this.getProxy().isActive() && channel == AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) )
if( channel == AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) )
{
final List<IMEInventoryHandler> handler = new ArrayList<>( 1 );
handler.add( this.myHandler );
@@ -222,6 +225,14 @@ public class PartFluidFormationPlane extends PartAbstractFormationPlane<IAEFluid
return this.config;
}
@Override
public IFluidHandler getFluidInventoryByName( final String name) {
if (name.equals("config")) {
return this.config;
}
return null;
}
@Override
public ItemStack getItemStackRepresentation()
{
@@ -21,6 +21,7 @@ package appeng.fluids.parts;
import java.util.EnumSet;
import appeng.fluids.helper.IConfigurableFluidInventory;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
@@ -30,6 +31,7 @@ import net.minecraft.util.EnumHand;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.items.IItemHandler;
import appeng.api.AEApi;
@@ -61,7 +63,7 @@ import appeng.parts.PartModel;
import appeng.util.Platform;
public class PartFluidInterface extends PartBasicState implements IGridTickable, IStorageMonitorable, IFluidInterfaceHost, IPriorityHost
public class PartFluidInterface extends PartBasicState implements IGridTickable, IStorageMonitorable, IFluidInterfaceHost, IPriorityHost, IConfigurableFluidInventory
{
public static final ResourceLocation MODEL_BASE = new ResourceLocation( AppEng.MOD_ID, "part/fluid_interface_base" );
@@ -88,14 +90,16 @@ public class PartFluidInterface extends PartBasicState implements IGridTickable,
return this.duality;
}
@Override
@MENetworkEventSubscribe
public void stateChange( final MENetworkChannelsChanged c )
public void chanRender( final MENetworkChannelsChanged c )
{
this.duality.notifyNeighbors();
}
@Override
@MENetworkEventSubscribe
public void stateChange( final MENetworkPowerStatusChange c )
public void powerRender( final MENetworkPowerStatusChange c )
{
this.duality.notifyNeighbors();
}
@@ -233,6 +237,11 @@ public class PartFluidInterface extends PartBasicState implements IGridTickable,
return this.duality.getInventoryByName( name );
}
@Override
public IFluidHandler getFluidInventoryByName( final String name) {
return this.duality.getFluidInventoryByName(name);
}
@Override
public ItemStack getItemStackRepresentation()
{
@@ -4,6 +4,9 @@ package appeng.fluids.parts;
import java.util.Random;
import appeng.api.storage.data.IItemList;
import appeng.fluids.helper.IConfigurableFluidInventory;
import appeng.me.cache.NetworkMonitor;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
@@ -33,7 +36,6 @@ import appeng.api.storage.IStorageChannel;
import appeng.api.storage.channels.IFluidStorageChannel;
import appeng.api.storage.data.IAEFluidStack;
import appeng.api.storage.data.IAEStack;
import appeng.api.storage.data.IItemList;
import appeng.api.util.AECableType;
import appeng.api.util.AEPartLocation;
import appeng.api.util.IConfigManager;
@@ -48,9 +50,10 @@ import appeng.parts.PartModel;
import appeng.parts.automation.PartUpgradeable;
import appeng.util.IConfigManagerHost;
import appeng.util.Platform;
import net.minecraftforge.fluids.capability.IFluidHandler;
public class PartFluidLevelEmitter extends PartUpgradeable implements IStackWatcherHost, IConfigManagerHost, IAEFluidInventory, IMEMonitorHandlerReceiver<IAEFluidStack>
public class PartFluidLevelEmitter extends PartUpgradeable implements IStackWatcherHost, IConfigManagerHost, IAEFluidInventory, IMEMonitorHandlerReceiver<IAEFluidStack>, IConfigurableFluidInventory
{
@PartModels
public static final ResourceLocation MODEL_BASE_OFF = new ResourceLocation( AppEng.MOD_ID, "part/level_emitter_base_off" );
@@ -112,7 +115,7 @@ public class PartFluidLevelEmitter extends PartUpgradeable implements IStackWatc
@Override
public void onStackChange( IItemList<?> o, IAEStack<?> fullStack, IAEStack<?> diffStack, IActionSource src, IStorageChannel<?> chan )
{
if( chan == AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) && fullStack.equals( this.config.getFluidInSlot( 0 ) ) )
if( chan == AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) && diffStack.equals( this.config.getFluidInSlot( 0 ) ) )
{
this.lastReportedValue = fullStack.getStackSize();
this.updateState();
@@ -125,15 +128,25 @@ public class PartFluidLevelEmitter extends PartUpgradeable implements IStackWatc
this.configureWatchers();
}
@Override
@MENetworkEventSubscribe
public void channelChanged( final MENetworkChannelsChanged c )
public void powerRender( final MENetworkPowerStatusChange powerEvent )
{
if (this.getProxy().isActive())
{
onListUpdate();
}
this.updateState();
}
@Override
@MENetworkEventSubscribe
public void powerChanged( final MENetworkPowerStatusChange c )
public void chanRender( final MENetworkChannelsChanged c )
{
if (this.getProxy().isActive())
{
onListUpdate();
}
this.updateState();
}
@@ -245,10 +258,9 @@ public class PartFluidLevelEmitter extends PartUpgradeable implements IStackWatc
if( myStack == null )
{
this.lastReportedValue = 0;
for( final IAEFluidStack st : monitor.getStorageList() )
if( monitor instanceof NetworkMonitor )
{
this.lastReportedValue += st.getStackSize();
this.lastReportedValue = ( (NetworkMonitor<IAEFluidStack>) monitor ).getGridCurrentCount();
}
}
else
@@ -354,6 +366,14 @@ public class PartFluidLevelEmitter extends PartUpgradeable implements IStackWatc
return this.config;
}
@Override
public IFluidHandler getFluidInventoryByName( final String name) {
if (name.equals("config")) {
return this.config;
}
return null;
}
@Override
public void readFromNBT( final NBTTagCompound data )
{
@@ -25,6 +25,11 @@ import java.util.Objects;
import javax.annotation.Nonnull;
import appeng.api.networking.storage.IStorageGrid;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.fluids.helper.IConfigurableFluidInventory;
import appeng.me.cache.GridStorageCache;
import appeng.util.ConfigManager;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
@@ -87,7 +92,7 @@ import appeng.util.prioritylist.PrecisePriorityList;
* @version rv6 - 22/05/2018
* @since rv6 22/05/2018
*/
public class PartFluidStorageBus extends PartSharedStorageBus implements IMEMonitorHandlerReceiver<IAEFluidStack>, IAEFluidInventory
public class PartFluidStorageBus extends PartSharedStorageBus implements IMEMonitorHandlerReceiver<IAEFluidStack>, IAEFluidInventory, IConfigurableFluidInventory
{
public static final ResourceLocation MODEL_BASE = new ResourceLocation( AppEng.MOD_ID, "part/fluid_storage_bus_base" );
@PartModels
@@ -166,11 +171,27 @@ public class PartFluidStorageBus extends PartSharedStorageBus implements IMEMoni
final boolean fullReset = this.resetCacheLogic == 2;
this.resetCacheLogic = 0;
final IMEInventory<IAEFluidStack> in = this.getInternalHandler();
final MEInventoryHandler<IAEFluidStack> in = this.getInternalHandler();
IItemList<IAEFluidStack> before = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList();
if( in != null )
{
before = in.getAvailableItems( before );
if( accessChanged )
{
AccessRestriction currentAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS );
AccessRestriction oldAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getOldSetting( Settings.ACCESS );
if( oldAccess.hasPermission( AccessRestriction.READ ) && !currentAccess.hasPermission( AccessRestriction.READ ) )
{
readOncePass = true;
}
in.setBaseAccess( oldAccess );
before = in.getAvailableItems( before );
in.setBaseAccess( currentAccess );
accessChanged = false;
}
else
{
before = in.getAvailableItems( before );
}
}
this.cached = false;
@@ -179,11 +200,11 @@ public class PartFluidStorageBus extends PartSharedStorageBus implements IMEMoni
this.handlerHash = 0;
}
final IMEInventory<IAEFluidStack> out = this.getInternalHandler();
final MEInventoryHandler<IAEFluidStack> out = this.getInternalHandler();
IItemList<IAEFluidStack> after = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList();
if( in != out )
{
IItemList<IAEFluidStack> after = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList();
if( out != null )
{
after = out.getAvailableItems( after );
@@ -206,7 +227,7 @@ public class PartFluidStorageBus extends PartSharedStorageBus implements IMEMoni
{
this.resetCacheLogic = 2;
}
else
else if( this.resetCacheLogic < 2 )
{
this.resetCacheLogic = 1;
}
@@ -263,18 +284,34 @@ public class PartFluidStorageBus extends PartSharedStorageBus implements IMEMoni
@Override
public void postChange( final IBaseMonitor<IAEFluidStack> monitor, final Iterable<IAEFluidStack> change, final IActionSource source )
{
try
if( this.getProxy().isActive() )
{
if( this.getProxy().isActive() )
AccessRestriction currentAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS );
if( readOncePass )
{
this.getProxy()
.getStorage()
.postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ), change, this.source );
readOncePass = false;
try
{
this.getProxy().getStorage().postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ), change, source );
}
catch( final GridAccessException e )
{
// :(
}
return;
}
if( !currentAccess.hasPermission( AccessRestriction.READ ) )
{
return;
}
try
{
this.getProxy().getStorage().postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ), change, source );
}
catch( final GridAccessException e )
{
// :(
}
}
catch( final GridAccessException e )
{
// :(
}
}
@@ -299,6 +336,10 @@ public class PartFluidStorageBus extends PartSharedStorageBus implements IMEMoni
this.handlerHash = newHandlerHash;
this.handler = null;
if( this.monitor != null )
{
( (IBaseMonitor<IAEFluidStack>) monitor ).removeListener( this );
}
this.monitor = null;
if( target != null )
{
@@ -306,7 +347,8 @@ public class PartFluidStorageBus extends PartSharedStorageBus implements IMEMoni
if( inv instanceof ITickingMonitor )
{
this.monitor = (ITickingMonitor) inv;
this.monitor.setActionSource( new MachineSource( this ) );
this.monitor.setActionSource( this.source );
this.monitor.setMode( (StorageFilter) this.getConfigManager().getSetting( Settings.STORAGE_FILTER ) );
}
if( inv != null )
@@ -343,7 +385,10 @@ public class PartFluidStorageBus extends PartSharedStorageBus implements IMEMoni
if( inv instanceof IBaseMonitor )
{
( (IBaseMonitor<IAEFluidStack>) inv ).addListener( this, this.handler );
if( ( (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS ) ).hasPermission( AccessRestriction.READ ) )
{
( (IBaseMonitor<IAEFluidStack>) inv ).addListener( this, this.handler );
}
}
}
}
@@ -372,7 +417,7 @@ public class PartFluidStorageBus extends PartSharedStorageBus implements IMEMoni
try
{
// force grid to update handlers...
this.getProxy().getGrid().postEvent( new MENetworkCellArrayUpdate() );
(( GridStorageCache ) this.getProxy().getGrid().getCache( IStorageGrid.class )).cellUpdate( null );
}
catch( final GridAccessException ignore )
{
@@ -413,7 +458,7 @@ public class PartFluidStorageBus extends PartSharedStorageBus implements IMEMoni
{
if( channel == this.getStorageChannel() )
{
final IMEInventoryHandler<IAEFluidStack> out = this.getProxy().isActive() ? this.getInternalHandler() : null;
final IMEInventoryHandler<IAEFluidStack> out = this.getInternalHandler();
if( out != null )
{
return Collections.singletonList( out );
@@ -469,6 +514,14 @@ public class PartFluidStorageBus extends PartSharedStorageBus implements IMEMoni
return this.config;
}
@Override
public IFluidHandler getFluidInventoryByName(final String name) {
if (name.equals("config")) {
return this.config;
}
return null;
}
@Nonnull
@Override
public IPartModel getStaticModels()
@@ -19,6 +19,7 @@
package appeng.fluids.parts;
import appeng.fluids.helper.IConfigurableFluidInventory;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
@@ -44,6 +45,7 @@ import appeng.fluids.util.IAEFluidTank;
import appeng.me.GridAccessException;
import appeng.parts.automation.PartUpgradeable;
import appeng.util.Platform;
import net.minecraftforge.fluids.capability.IFluidHandler;
/**
@@ -51,7 +53,7 @@ import appeng.util.Platform;
* @version rv6 - 30/04/2018
* @since rv6 30/04/2018
*/
public abstract class PartSharedFluidBus extends PartUpgradeable implements IGridTickable
public abstract class PartSharedFluidBus extends PartUpgradeable implements IGridTickable, IConfigurableFluidInventory
{
private final AEFluidInventory config = new AEFluidInventory( null, 9 );
@@ -176,6 +178,14 @@ public abstract class PartSharedFluidBus extends PartUpgradeable implements IGri
return this.config;
}
@Override
public IFluidHandler getFluidInventoryByName( final String name) {
if (name.equals("config")) {
return this.config;
}
return null;
}
protected IFluidStorageChannel getChannel()
{
return AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class );
@@ -23,11 +23,13 @@ import java.util.EnumSet;
import javax.annotation.Nullable;
import appeng.fluids.helper.IConfigurableFluidInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.items.IItemHandler;
import appeng.api.AEApi;
@@ -50,7 +52,7 @@ import appeng.helpers.IPriorityHost;
import appeng.tile.grid.AENetworkTile;
public class TileFluidInterface extends AENetworkTile implements IGridTickable, IFluidInterfaceHost, IPriorityHost
public class TileFluidInterface extends AENetworkTile implements IGridTickable, IFluidInterfaceHost, IPriorityHost, IConfigurableFluidInventory
{
private final DualityFluidInterface duality = new DualityFluidInterface( this.getProxy(), this );
@@ -176,6 +178,11 @@ public class TileFluidInterface extends AENetworkTile implements IGridTickable,
return this.duality.getInventoryByName( name );
}
@Override
public IFluidHandler getFluidInventoryByName(final String name) {
return this.duality.getFluidInventoryByName(name);
}
@Override
public ItemStack getItemStackRepresentation()
{
@@ -19,18 +19,19 @@
package appeng.helpers;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.*;
import javax.annotation.Nullable;
import appeng.integration.modules.gregtech.GTCEInventoryAdaptor;
import appeng.util.*;
import appeng.util.inv.*;
import com.google.common.collect.ImmutableSet;
import de.ellpeck.actuallyadditions.api.tile.IPhantomTile;
import gregtech.api.block.machines.BlockMachine;
import gregtech.api.metatileentity.MetaTileEntity;
import gregtech.api.metatileentity.MetaTileEntityHolder;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Items;
@@ -46,6 +47,7 @@ import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.wrapper.RangedWrapper;
@@ -99,23 +101,18 @@ import appeng.parts.automation.StackUpgradeInventory;
import appeng.parts.automation.UpgradeInventory;
import appeng.tile.inventory.AppEngInternalAEInventory;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.util.ConfigManager;
import appeng.util.IConfigManagerHost;
import appeng.util.InventoryAdaptor;
import appeng.util.Platform;
import appeng.util.inv.AdaptorItemHandler;
import appeng.util.inv.IAEAppEngInventory;
import appeng.util.inv.IInventoryDestination;
import appeng.util.inv.InvOperation;
import appeng.util.item.AEItemStack;
import static gregtech.api.block.machines.BlockMachine.getMetaTileEntity;
public class DualityInterface implements IGridTickable, IStorageMonitorable, IInventoryDestination, IAEAppEngInventory, IConfigManagerHost, ICraftingProvider, IUpgradeableHost
{
private int[] failedCraftTriesSlot = {0,0,0,0,0,0,0,0,0};
public static final int NUMBER_OF_STORAGE_SLOTS = 9;
public static final int NUMBER_OF_CONFIG_SLOTS = 9;
public static final int NUMBER_OF_PATTERN_SLOTS = 9;
public static final int NUMBER_OF_PATTERN_SLOTS = 36;
private static final Collection<Block> BAD_BLOCKS = new HashSet<>( 100 );
private final IAEItemStack[] requireWork = { null, null, null, null, null, null, null, null, null };
@@ -129,11 +126,11 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
private final AppEngInternalInventory storage = new AppEngInternalInventory( this, NUMBER_OF_STORAGE_SLOTS );
private final AppEngInternalInventory patterns = new AppEngInternalInventory( this, NUMBER_OF_PATTERN_SLOTS );
private final MEMonitorPassThrough<IAEItemStack> items = new MEMonitorPassThrough<>( new NullInventory<IAEItemStack>(), AEApi.instance()
.storage()
.getStorageChannel( IItemStorageChannel.class ) );
.storage()
.getStorageChannel( IItemStorageChannel.class ) );
private final MEMonitorPassThrough<IAEFluidStack> fluids = new MEMonitorPassThrough<>( new NullInventory<IAEFluidStack>(), AEApi.instance()
.storage()
.getStorageChannel( IFluidStorageChannel.class ) );
.storage()
.getStorageChannel( IFluidStorageChannel.class ) );
private final UpgradeInventory upgrades;
private boolean hasConfig = false;
private int priority;
@@ -142,13 +139,18 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
private IMEInventory<IAEItemStack> destination;
private int isWorking = -1;
private final Accessor accessor = new Accessor();
private EnumSet<EnumFacing> visitedFaces = EnumSet.noneOf( EnumFacing.class );
private EnumMap<EnumFacing, List<ItemStack>> waitingToSendFacing = new EnumMap<>( EnumFacing.class );
private GTCEInventoryAdaptor GTad;
private boolean resetConfigCache = true;
private IMEMonitor<IAEItemStack> configCachedHandler;
public DualityInterface( final AENetworkProxy networkProxy, final IInterfaceHost ih )
{
this.gridProxy = networkProxy;
this.gridProxy.setFlags( GridFlags.REQUIRE_CHANNEL );
this.upgrades = new StackUpgradeInventory( this.gridProxy.getMachineRepresentation(), this, 1 );
this.upgrades = new StackUpgradeInventory( this.gridProxy.getMachineRepresentation(), this, 4 );
this.cm.registerSetting( Settings.BLOCK, YesNo.NO );
this.cm.registerSetting( Settings.INTERFACE_TERMINAL, YesNo.YES );
@@ -176,10 +178,14 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
{
return;
}
if( inv == this.config )
if( inv == this.config && ( !removed.isEmpty() || !added.isEmpty() ) )
{
boolean cfg = hasConfig();
this.readConfig();
if( cfg != hasConfig )
{
resetConfigCache = true;
}
}
else if( inv == this.patterns && ( !removed.isEmpty() || !added.isEmpty() ) )
{
@@ -235,6 +241,27 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
}
}
data.setTag( "waitingToSend", waitingToSend );
NBTTagCompound sidedWaitList = new NBTTagCompound();
if (this.waitingToSendFacing != null)
{
for( EnumFacing s : this.iHost.getTargets() )
{
NBTTagList waitingListSided = new NBTTagList();
if (this.waitingToSendFacing.containsKey( s ))
{
for( final ItemStack is : this.waitingToSendFacing.get( s ) )
{
final NBTTagCompound item = new NBTTagCompound();
is.writeToNBT( item );
waitingListSided.appendTag( item );
}
sidedWaitList.setTag( s.name(), waitingListSided );
}
}
}
data.setTag( "sidedWaitList", sidedWaitList );
}
public void readFromNBT( final NBTTagCompound data )
@@ -254,9 +281,44 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
}
}
this.waitingToSendFacing = null;
final NBTTagCompound waitingListSided = data.getCompoundTag( "sidedWaitList" );
for( EnumFacing s : EnumFacing.values() )
if( waitingListSided.hasKey( s.name() ) )
{
NBTTagList w = waitingListSided.getTagList( s.name(), 10 );
for( int x = 0; x < w.tagCount(); x++ )
{
final NBTTagCompound c = w.getCompoundTagAt( x );
if( c != null )
{
final ItemStack is = new ItemStack( c );
this.addToSendListFacing( is, EnumFacing.getFront( s.getIndex() ) );
}
}
}
this.craftingTracker.readFromNBT( data );
// fix upgrade slot size mismatch
NBTTagCompound up = data.getCompoundTag( "upgrades" );
if( up.hasKey( "Size" ) && up.getInteger( "Size" ) != this.upgrades.getSlots() )
{
up.setInteger( "Size", this.upgrades.getSlots() );
this.upgrades.writeToNBT( up, "upgrades" );
}
this.upgrades.readFromNBT( data, "upgrades" );
this.config.readFromNBT( data, "config" );
NBTTagCompound pa = data.getCompoundTag( "patterns" );
if( pa.hasKey( "Size" ) && pa.getInteger( "Size" ) != this.patterns.getSlots() )
{
pa.setInteger( "Size", this.patterns.getSlots() );
this.upgrades.writeToNBT( pa, "patterns" );
}
this.patterns.readFromNBT( data, "patterns" );
this.storage.readFromNBT( data, "storage" );
this.priority = data.getInteger( "priority" );
@@ -289,6 +351,30 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
}
}
private void addToSendListFacing( final ItemStack is, EnumFacing f )
{
if( is.isEmpty() )
{
return;
}
if (this.waitingToSendFacing == null){
this.waitingToSendFacing = new EnumMap<>(EnumFacing.class);
}
this.waitingToSendFacing.computeIfAbsent( f, k -> new ArrayList<>() );
this.waitingToSendFacing.get( f ).add( is );
try
{
this.gridProxy.getTick().wakeDevice( this.gridProxy.getNode() );
}
catch( final GridAccessException e )
{
// :P
}
}
private void readConfig()
{
this.hasConfig = false;
@@ -335,9 +421,8 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
private void updateCraftingList()
{
final Boolean[] accountedFor = { false, false, false, false, false, false, false, false, false }; // 9...
assert ( accountedFor.length == this.patterns.getSlots() );
final Boolean[] accountedFor = new Boolean[this.patterns.getSlots()];
Arrays.fill( accountedFor, false );
if( !this.gridProxy.isReady() )
{
@@ -352,7 +437,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
final ICraftingPatternDetails details = i.next();
boolean found = false;
for( int x = 0; x < accountedFor.length; x++ )
for( int x = 0; x < accountedFor.length ; x++ )
{
final ItemStack is = this.patterns.getStackInSlot( x );
if( details.getPattern() == is )
@@ -368,7 +453,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
}
}
for( int x = 0; x < accountedFor.length; x++ )
for( int x = 0; x < accountedFor.length ; x++ )
{
if( !accountedFor[x] )
{
@@ -386,24 +471,22 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
}
}
private boolean hasWorkToDo()
{
if( this.hasItemsToSend() )
{
private boolean hasWorkToDo() {
if (hasItemsToSend()){
return true;
}
else
{
for( final IAEItemStack requiredWork : this.requireWork )
{
if( requiredWork != null )
{
return true;
}
}
return false;
if(hasItemsToSendFacing()){
return true;
}
for (final IAEItemStack requiredWork : this.requireWork) {
if (requiredWork != null) {
return true;
}
}
return false;
}
private void updatePlan( final int slot )
@@ -430,14 +513,18 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
this.requireWork[slot] = req.copy();
return;
}
else if( req.isSameType( stored ) ) // same type ( qty different? )!
else if( req.isSameType( stored ) ) // same type and quantity )!
{
if( req.getStackSize() != stored.getCount() )
if( req.getStackSize() == stored.getCount() )
{
this.requireWork[slot] = null;
}
else // same type ( qty different? )!
{
this.requireWork[slot] = req.copy();
this.requireWork[slot].setStackSize( req.getStackSize() - stored.getCount() );
return;
}
return;
}
else
// Stored != null; dispose!
@@ -504,6 +591,45 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
return this.waitingToSend != null && !this.waitingToSend.isEmpty();
}
private boolean hasItemsToSendFacing()
{
if (waitingToSendFacing != null)
{
for( EnumFacing enumFacing : waitingToSendFacing.keySet() )
{
if( !waitingToSendFacing.get( enumFacing ).isEmpty() )
{
return true;
}
}
}
return false;
}
public void dropExcessPatterns()
{
IItemHandler patterns = getPatterns();
List<ItemStack> dropList = new ArrayList<>();
for( int invSlot = 0; invSlot < patterns.getSlots(); invSlot++ )
{
if( invSlot > 8 + this.getInstalledUpgrades( Upgrades.PATTERN_EXPANSION ) * 9 )
{
ItemStack is = patterns.getStackInSlot( invSlot );
if( is.isEmpty() ) continue;
dropList.add( patterns.extractItem( invSlot, Integer.MAX_VALUE, false ) );
}
}
if( dropList.size() > 0 )
{
World world = this.getLocation().getWorld();
BlockPos blockPos = this.getLocation().getPos();
Platform.spawnDrops( world, blockPos, dropList );
}
this.gridProxy.setIdlePowerUsage( Math.pow( 4, ( this.getInstalledUpgrades( Upgrades.PATTERN_EXPANSION ) ) ) );
}
@Override
public boolean canInsert( final ItemStack stack )
{
@@ -575,11 +701,21 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
return TickRateModulation.SLEEP;
}
//Previous version might have items saved in this list
//recover them
if( this.hasItemsToSend() )
{
this.pushItemsOut( this.iHost.getTargets() );
}
if (hasItemsToSendFacing())
{
for( EnumFacing enumFacing : waitingToSendFacing.keySet() )
{
this.pushItemsOut( enumFacing );
}
}
final boolean couldDoWork = this.updateStorage();
return this.hasWorkToDo() ? ( couldDoWork ? TickRateModulation.URGENT : TickRateModulation.SLOWER ) : TickRateModulation.SLEEP;
}
@@ -640,6 +776,47 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
}
}
private void pushItemsOut( final EnumFacing s )
{
if (!this.waitingToSendFacing.containsKey(s) ||
(this.waitingToSendFacing.containsKey(s) && this.waitingToSendFacing.get( s ).isEmpty())) {
return;
}
final TileEntity tile = this.iHost.getTileEntity();
final World w = tile.getWorld();
final TileEntity te = w.getTileEntity( tile.getPos().offset( s ) );
if( te == null )
{
return;
}
final Iterator<ItemStack> i = this.waitingToSendFacing.get( s ).iterator();
while ( i.hasNext() )
{
ItemStack whatToSend = i.next();
final InventoryAdaptor ad = InventoryAdaptor.getAdaptor( te, s.getOpposite() );
if( ad != null )
{
final ItemStack result = ad.addItems( whatToSend );
if( !result.isEmpty() )
{
whatToSend.setCount( whatToSend.getCount() - ( whatToSend.getCount() - result.getCount() ) );
}
else
{
i.remove();
}
}
}
if( this.waitingToSendFacing.get( s ).isEmpty() )
{
this.waitingToSendFacing.remove( s );
}
}
private boolean updateStorage()
{
boolean didSomething = false;
@@ -679,19 +856,26 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
throw new GridAccessException();
}
final IAEItemStack acquired = Platform.poweredExtraction( src, this.destination, itemStack, this.interfaceRequestSource );
if( acquired != null )
IAEItemStack storedStack = this.gridProxy.getStorage().getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ).getStorageList().findPrecise( itemStack );
if( storedStack != null )
{
changed = true;
final ItemStack issue = adaptor.addItems( acquired.createItemStack() );
if( !issue.isEmpty() )
if( storedStack.getStackSize() > 0 )
{
throw new IllegalStateException( "bad attempt at managing inventory. ( addItems )" );
final IAEItemStack acquired = Platform.poweredExtraction( src, this.destination, itemStack, this.interfaceRequestSource );
if( acquired != null )
{
changed = true;
final ItemStack issue = adaptor.addItems( acquired.createItemStack() );
if( !issue.isEmpty() )
{
throw new IllegalStateException( "bad attempt at managing inventory. ( addItems )" );
}
}
}
else if( storedStack.isCraftable() )
{
changed = this.handleCrafting( x, adaptor, itemStack ) || changed;
}
}
else
{
changed = this.handleCrafting( x, adaptor, itemStack ) || changed;
}
}
else if( itemStack.getStackSize() < 0 )
@@ -759,8 +943,17 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
{
if( this.getInstalledUpgrades( Upgrades.CRAFTING ) > 0 && itemStack != null )
{
return this.craftingTracker.handleCrafting( x, itemStack.getStackSize(), itemStack, d, this.iHost.getTileEntity().getWorld(),
if (this.failedCraftTriesSlot[x] <= 0)
{
boolean crafted = this.craftingTracker.handleCrafting( x, itemStack.getStackSize(), itemStack, d, this.iHost.getTileEntity().getWorld(),
this.gridProxy.getGrid(), this.gridProxy.getCrafting(), this.mySource );
if (crafted) this.failedCraftTriesSlot[x] = 0;
else{
this.failedCraftTriesSlot[x] += 2;
}
}
this.failedCraftTriesSlot[x] -= 1;
}
}
catch( final GridAccessException e )
@@ -794,7 +987,12 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
{
if( this.hasConfig() )
{
return (IMEMonitor<T>) new InterfaceInventory( this );
if( resetConfigCache )
{
resetConfigCache = false;
configCachedHandler = new InterfaceInventory( this );
}
return (IMEMonitor<T>) configCachedHandler;
}
return (IMEMonitor<T>) this.items;
@@ -893,10 +1091,20 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
};
}
private boolean invIsBlocked( InventoryAdaptor inv )
{
return (inv.containsItems());
}
private static boolean invIsBlockedGTCE( GTCEInventoryAdaptor inv )
{
return ( !inv.canRemoveAllExceptCircuits() );
}
@Override
public boolean pushPattern( final ICraftingPatternDetails patternDetails, final InventoryCrafting table )
{
if( this.hasItemsToSend() || !this.gridProxy.isActive() || !this.craftingList.contains( patternDetails ) )
if( this.hasItemsToSend() || this.hasItemsToSendFacing() || !this.gridProxy.isActive() || !this.craftingList.contains( patternDetails ) )
{
return false;
}
@@ -904,8 +1112,12 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
final TileEntity tile = this.iHost.getTileEntity();
final World w = tile.getWorld();
final EnumSet<EnumFacing> possibleDirections = this.iHost.getTargets();
for( final EnumFacing s : possibleDirections )
if( this.visitedFaces.isEmpty() )
{
this.visitedFaces = this.iHost.getTargets();
}
for( final EnumFacing s : visitedFaces )
{
final TileEntity te = w.getTileEntity( tile.getPos().offset( s ) );
if( te instanceof IInterfaceHost )
@@ -914,6 +1126,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
{
if( ( (IInterfaceHost) te ).getInterfaceDuality().sameGrid( this.gridProxy.getGrid() ) )
{
visitedFaces.remove( s );
continue;
}
}
@@ -928,6 +1141,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
final ICraftingMachine cm = (ICraftingMachine) te;
if( cm.acceptsPlans() )
{
visitedFaces.remove( s );
if( cm.pushPattern( patternDetails, table, s.getOpposite() ) )
{
return true;
@@ -941,42 +1155,67 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
{
if( this.isBlocking() )
{
if( !ad.simulateRemove( 1, ItemStack.EMPTY, null ).isEmpty() )
IPhantomTile phantomTE = null;
if( Loader.isModLoaded( "actuallyadditions" ) && Loader.isModLoaded( "gregtech" ) && te instanceof IPhantomTile )
{
phantomTE = ( (IPhantomTile) te );
if( phantomTE.hasBoundPosition() )
{
TileEntity phantom = w.getTileEntity( phantomTE.getBoundPosition() );
if( phantom instanceof MetaTileEntityHolder && isGTCEblocked( phantom, s ) )
{
visitedFaces.remove( s );
continue;
}
}
}
else if( Loader.isModLoaded( "gregtech" ) && te instanceof MetaTileEntityHolder )
{
if( isGTCEblocked( te, s ) )
{
visitedFaces.remove( s );
continue;
}
}
else if( invIsBlocked( ad ) )
{
visitedFaces.remove( s );
continue;
}
}
if( this.acceptsItems( ad, table ) )
{
visitedFaces.remove( s );
for( int x = 0; x < table.getSizeInventory(); x++ )
{
final ItemStack is = table.getStackInSlot( x );
if( !is.isEmpty() )
{
final ItemStack added = ad.addItems( is );
this.addToSendList( added );
addToSendListFacing( is, s );
}
}
this.pushItemsOut( possibleDirections );
pushItemsOut( s );
return true;
}
}
visitedFaces.remove( s );
}
return false;
}
@Override
public boolean isBusy()
{
if( this.hasItemsToSend() )
boolean busy = false;
if( this.hasItemsToSend() || hasItemsToSendFacing() )
{
return true;
}
boolean busy = false;
if( this.isBlocking() )
{
final EnumSet<EnumFacing> possibleDirections = this.iHost.getTargets();
@@ -988,24 +1227,52 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
for( final EnumFacing s : possibleDirections )
{
final TileEntity te = w.getTileEntity( tile.getPos().offset( s ) );
IPhantomTile phantomTE = null;
final InventoryAdaptor ad = InventoryAdaptor.getAdaptor( te, s.getOpposite() );
if( ad != null )
{
if( ad.simulateRemove( 1, ItemStack.EMPTY, null ).isEmpty() )
if( Loader.isModLoaded( "actuallyadditions") && Loader.isModLoaded( "gregtech" ) && te instanceof IPhantomTile )
{
phantomTE = ( (IPhantomTile) te );
if( phantomTE.hasBoundPosition() )
{
TileEntity phantom = w.getTileEntity( phantomTE.getBoundPosition() );
if( phantom instanceof MetaTileEntityHolder && !isGTCEblocked( phantom, s ) )
{
allAreBusy = false;
break;
}
}
}
else if( Loader.isModLoaded( "gregtech" ) && te instanceof MetaTileEntityHolder )
{
if( !isGTCEblocked( te, s ) )
{
allAreBusy = false;
break;
}
}
else if( !invIsBlocked( ad ) )
{
allAreBusy = false;
break;
}
}
}
busy = allAreBusy;
}
return busy;
}
boolean isGTCEblocked(TileEntity te, EnumFacing s)
{
GTad = GTCEInventoryAdaptor.getAdaptor( te, s.getOpposite() );
return invIsBlockedGTCE( GTad );
}
private boolean sameGrid( final IGrid grid ) throws GridAccessException
{
return grid == this.gridProxy.getGrid();
@@ -1061,6 +1328,20 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
}
}
if( this.waitingToSendFacing != null )
{
for (List<ItemStack> itemList : waitingToSendFacing.values())
{
for (final ItemStack is : itemList)
{
if (!is.isEmpty())
{
drops.add(is);
}
}
}
}
for( final ItemStack is : this.upgrades )
{
if( !is.isEmpty() )
@@ -1184,6 +1465,13 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
final IBlockState directedBlockState = hostWorld.getBlockState( targ );
final Block directedBlock = directedBlockState.getBlock();
ItemStack what = new ItemStack( directedBlock, 1, directedBlock.getMetaFromState( directedBlockState ) );
if ( Loader.isModLoaded("gregtech") && directedBlock instanceof BlockMachine )
{
MetaTileEntity metaTileEntity = getMetaTileEntity(hostWorld, targ);
return metaTileEntity.getMetaFullName();
}
try
{
Vec3d from = new Vec3d( hostTile.getPos().getX() + 0.5, hostTile.getPos().getY() + 0.5, hostTile.getPos().getZ() + 0.5 );
@@ -1312,7 +1600,6 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
public InterfaceInventory( final DualityInterface tileInterface )
{
super( new AdaptorItemHandler( tileInterface.storage ) );
this.setActionSource( new MachineSource( DualityInterface.this.iHost ) );
}
@Override
@@ -0,0 +1,98 @@
package appeng.helpers;
import appeng.client.render.BlockPosHighlighter;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import org.lwjgl.opengl.GL11;
// taken from McJty's McJtyLib
public class HighlighterHandler
{
public static void tick( RenderWorldLastEvent event ) {
renderHilightedBlock(event);
}
private static void renderHilightedBlock( RenderWorldLastEvent event ) {
BlockPos c = BlockPosHighlighter.getHilightedBlock();
if (c == null) {
return;
}
Minecraft mc = Minecraft.getMinecraft();
int dimension = mc.world.provider.getDimension();
long time = System.currentTimeMillis();
if (time > BlockPosHighlighter.getExpireHilight() || dimension != BlockPosHighlighter.getDimension()) {
BlockPosHighlighter.hilightBlock(null, -1, BlockPosHighlighter.getDimension() );
return;
}
if (((time / 500) & 1) == 0) {
return;
}
EntityPlayerSP p = mc.player;
double doubleX = p.lastTickPosX + (p.posX - p.lastTickPosX) * event.getPartialTicks();
double doubleY = p.lastTickPosY + (p.posY - p.lastTickPosY) * event.getPartialTicks();
double doubleZ = p.lastTickPosZ + (p.posZ - p.lastTickPosZ) * event.getPartialTicks();
GlStateManager.pushMatrix();
GlStateManager.color(1.0f, 0, 0);
GlStateManager.glLineWidth(3);
GlStateManager.translate(-doubleX, -doubleY, -doubleZ);
GlStateManager.disableDepth();
GlStateManager.disableTexture2D();
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
float mx = c.getX();
float my = c.getY();
float mz = c.getZ();
buffer.begin( GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR);
renderHighLightedBlocksOutline(buffer, mx, my, mz, 1.0f, 0.0f, 0.0f, 1.0f);
tessellator.draw();
GlStateManager.enableTexture2D();
GlStateManager.enableDepth();
GlStateManager.popMatrix();
}
public static void renderHighLightedBlocksOutline(BufferBuilder buffer, float mx, float my, float mz, float r, float g, float b, float a) {
buffer.pos(mx, my, mz).color(r, g, b, a).endVertex();
buffer.pos(mx + 1, my, mz).color(r, g, b, a).endVertex();
buffer.pos(mx, my, mz).color(r, g, b, a).endVertex();
buffer.pos(mx, my + 1, mz).color(r, g, b, a).endVertex();
buffer.pos(mx, my, mz).color(r, g, b, a).endVertex();
buffer.pos(mx, my, mz + 1).color(r, g, b, a).endVertex();
buffer.pos(mx + 1, my + 1, mz + 1).color(r, g, b, a).endVertex();
buffer.pos(mx, my + 1, mz + 1).color(r, g, b, a).endVertex();
buffer.pos(mx + 1, my + 1, mz + 1).color(r, g, b, a).endVertex();
buffer.pos(mx + 1, my, mz + 1).color(r, g, b, a).endVertex();
buffer.pos(mx + 1, my + 1, mz + 1).color(r, g, b, a).endVertex();
buffer.pos(mx + 1, my + 1, mz).color(r, g, b, a).endVertex();
buffer.pos(mx, my + 1, mz).color(r, g, b, a).endVertex();
buffer.pos(mx, my + 1, mz + 1).color(r, g, b, a).endVertex();
buffer.pos(mx, my + 1, mz).color(r, g, b, a).endVertex();
buffer.pos(mx + 1, my + 1, mz).color(r, g, b, a).endVertex();
buffer.pos(mx + 1, my, mz).color(r, g, b, a).endVertex();
buffer.pos(mx + 1, my, mz + 1).color(r, g, b, a).endVertex();
buffer.pos(mx + 1, my, mz).color(r, g, b, a).endVertex();
buffer.pos(mx + 1, my + 1, mz).color(r, g, b, a).endVertex();
buffer.pos(mx, my, mz + 1).color(r, g, b, a).endVertex();
buffer.pos(mx + 1, my, mz + 1).color(r, g, b, a).endVertex();
buffer.pos(mx, my, mz + 1).color(r, g, b, a).endVertex();
buffer.pos(mx, my + 1, mz + 1).color(r, g, b, a).endVertex();
}
}
@@ -43,5 +43,6 @@ public enum InventoryAction
ROLL_UP,
ROLL_DOWN,
AUTO_CRAFT,
PLACE_SINGLE
PLACE_SINGLE,
PLACE_JEI_GHOST_ITEM
}
+114 -46
View File
@@ -19,21 +19,18 @@
package appeng.helpers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;
import java.util.*;
import java.util.stream.Collectors;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.NonNullList;
import net.minecraft.world.World;
import appeng.api.AEApi;
@@ -46,11 +43,17 @@ import appeng.core.AELog;
import appeng.core.features.AEFeature;
import appeng.util.Platform;
import appeng.util.item.AEItemStack;
import net.minecraftforge.common.crafting.IShapedRecipe;
public class PatternHelper implements ICraftingPatternDetails, Comparable<PatternHelper>
{
private static final int CRAFTING_GRID_DIMENSION = 3;
private static final int ALL_INPUT_LIMIT = CRAFTING_GRID_DIMENSION * CRAFTING_GRID_DIMENSION;
private static final int CRAFTING_OUTPUT_LIMIT = 1;
private static final int PROCESSING_OUTPUT_LIMIT = 3;
private final ItemStack patternItem;
private final InventoryCrafting crafting = new InventoryCrafting( new ContainerNull(), 3, 3 );
private final InventoryCrafting testFrame = new InventoryCrafting( new ContainerNull(), 3, 3 );
@@ -60,6 +63,7 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
private final IAEItemStack[] condensedOutputs;
private final IAEItemStack[] inputs;
private final IAEItemStack[] outputs;
private final Map<Integer, List<IAEItemStack>> substituteInputs;
private final boolean isCrafting;
private final boolean canSubstitute;
private final Set<TestLookup> failCache = new HashSet<>();
@@ -143,9 +147,11 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
}
}
}
final int outputLength = out.size();
this.outputs = out.toArray( new IAEItemStack[out.size()] );
this.inputs = in.toArray( new IAEItemStack[in.size()] );
this.inputs = in.toArray(new IAEItemStack[ALL_INPUT_LIMIT]);
this.outputs = out.toArray(new IAEItemStack[outputLength]);
this.substituteInputs = new HashMap<>(ALL_INPUT_LIMIT);
final Map<IAEItemStack, IAEItemStack> tmpOutputs = new HashMap<>();
@@ -257,6 +263,14 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
this.testFrame.setInventorySlotContents( slotIndex, i );
// If we cannot substitute, the items must match exactly
if (!canSubstitute && slotIndex < inputs.length) {
if (!inputs[slotIndex].isSameType(i)) {
this.markItemAs(slotIndex, i, TestStatus.DECLINE);
return false;
}
}
if( this.standardRecipe.matches( this.testFrame, w ) )
{
final ItemStack testOutput = this.standardRecipe.getCraftingResult( this.testFrame );
@@ -268,25 +282,6 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
return true;
}
}
else if( AEConfig.instance().isFeatureEnabled( AEFeature.CRAFTING_MANAGER_FALLBACK ) )
{
final ItemStack testOutput = CraftingManager.findMatchingResult( this.testFrame, w );
if( Platform.itemComparisons().isSameItem( this.correctOutput, testOutput ) )
{
this.testFrame.setInventorySlotContents( slotIndex, this.crafting.getStackInSlot( slotIndex ) );
this.markItemAs( slotIndex, i, TestStatus.ACCEPT );
if( AELog.isCraftingDebugLogEnabled() )
{
this.warnAboutCraftingManager( true );
}
return true;
}
this.warnAboutCraftingManager( false );
}
this.markItemAs( slotIndex, i, TestStatus.DECLINE );
return false;
@@ -328,6 +323,97 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
return this.canSubstitute;
}
@Override
public List<IAEItemStack> getSubstituteInputs(int slot) {
if (this.inputs[slot] == null) {
return Collections.emptyList();
}
return this.substituteInputs.computeIfAbsent(slot, value -> {
ItemStack[] matchingStacks = getRecipeIngredient(slot).getMatchingStacks();
List<IAEItemStack> itemList = new ArrayList<>(matchingStacks.length + 1);
for (ItemStack matchingStack : matchingStacks) {
itemList.add(AEItemStack.fromItemStack(matchingStack));
}
// Ensure that the specific item put in by the user is at the beginning,
// so that it takes precedence over substitutions
itemList.add(0, this.inputs[slot]);
return itemList;
});
}
/**
* Gets the {@link Ingredient} from the actual used recipe for a given slot-index into {@link #getInputs()}.
* <p/>
* Conversion is needed for two reasons: our sparse ingredients are always organized in a 3x3 grid, while Vanilla's
* ingredient list will be condensed to the actual recipe's grid size. In addition, in our 3x3 grid, the user can
* shift the actual recipe input to the right and down.
*/
private Ingredient getRecipeIngredient(int slot) {
if (standardRecipe instanceof IShapedRecipe ) {
IShapedRecipe shapedRecipe = (IShapedRecipe) standardRecipe;
return getShapedRecipeIngredient(slot, shapedRecipe.getRecipeWidth());
} else {
return getShapelessRecipeIngredient(slot);
}
}
private Ingredient getShapedRecipeIngredient(int slot, int recipeWidth) {
// Compute the offset of the user's input vs. crafting grid origin
// Which is >0 if they have empty rows above or to the left of their input
int topOffset = 0;
if (inputs[0] == null && inputs[1] == null && inputs[2] == null) {
topOffset++; // First row is fully empty
if (inputs[3] == null && inputs[4] == null && inputs[5] == null) {
topOffset++; // Second row is fully empty
}
}
int leftOffset = 0;
if (inputs[0] == null && inputs[3] == null && inputs[6] == null) {
leftOffset++; // First column is fully empty
if (inputs[1] == null && inputs[4] == null && inputs[7] == null) {
leftOffset++; // Second column is fully empty
}
}
// Compute the x,y of the slot, as-if the recipe was anchored to 0,0
int slotX = slot % CRAFTING_GRID_DIMENSION - leftOffset;
int slotY = slot / CRAFTING_GRID_DIMENSION - topOffset;
// Compute the index into the recipe's ingredient list now
int ingredientIndex = slotY * recipeWidth + slotX;
NonNullList<Ingredient> ingredients = standardRecipe.getIngredients();
if (ingredientIndex < 0 || ingredientIndex > ingredients.size()) {
return Ingredient.EMPTY;
}
return ingredients.get(ingredientIndex);
}
private Ingredient getShapelessRecipeIngredient(int slot) {
// We map the list of *filled* sparse inputs to the shapeless (ergo unordered)
// ingredients. While these do not actually correspond to each other,
// since both lists have the same length, the mapping is at least stable.
int ingredientIndex = 0;
for (int i = 0; i < slot; i++) {
if (inputs[i] != null) {
ingredientIndex++;
}
}
NonNullList<Ingredient> ingredients = standardRecipe.getIngredients();
if (ingredientIndex < ingredients.size()) {
return ingredients.get(ingredientIndex);
}
return Ingredient.EMPTY;
}
@Override
public ItemStack getOutput( final InventoryCrafting craftingInv, final World w )
{
@@ -406,24 +492,6 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
return this.pattern.hashCode();
}
private void warnAboutCraftingManager( boolean foundAlternative )
{
final String foundAlternativeRecipe = foundAlternative ? "Found alternative recipe." : "NOT FOUND, please report.";
final StringJoiner joinActualInputs = new StringJoiner( ", " );
for( int j = 0; j < this.testFrame.getSizeInventory(); j++ )
{
final ItemStack stack = this.testFrame.getStackInSlot( j );
if( !stack.isEmpty() )
{
joinActualInputs.add( stack.toString() );
}
}
AELog.warn( "Using CraftingManager fallback: Recipe <%s> for output <%s> rejected inputs [%s]. %s",
this.standardRecipe.getRegistryName(), this.standardRecipe.getRecipeOutput(), joinActualInputs, foundAlternativeRecipe );
}
@Override
public boolean equals( final Object obj )
{
+7 -13
View File
@@ -187,21 +187,15 @@ public class TickHandler
if( ev.type == Type.WORLD && ev.phase == Phase.END )
{
final WorldTickEvent wte = (WorldTickEvent) ev;
synchronized( this.craftingJobs )
synchronized ( this.craftingJobs )
{
final Collection<CraftingJob> jobSet = this.craftingJobs.get( wte.world );
if( !jobSet.isEmpty() )
{
final int simTime = Math.max( 1, AEConfig.instance().getCraftingCalculationTimePerTick() / jobSet.size() );
final Iterator<CraftingJob> i = jobSet.iterator();
while( i.hasNext() )
{
final CraftingJob cj = i.next();
if( !cj.simulateFor( simTime ) )
{
i.remove();
}
}
if (!jobSet.isEmpty()) {
final int jobSize = jobSet.size();
final int microSecondsPerTick = AEConfig.instance().getCraftingCalculationTimePerTick() * 1000;
final int simTime = Math.max(1, microSecondsPerTick / jobSize);
jobSet.removeIf( cj -> !cj.simulateFor( simTime ) );
}
}
}
@@ -0,0 +1,26 @@
package appeng.integration.modules.gregtech;
import appeng.util.inv.ItemSlot;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
public abstract class GTCEInventoryAdaptor implements Iterable<ItemSlot>
{
public static GTCEInventoryAdaptor getAdaptor(final TileEntity te, final EnumFacing d)
{
if (te != null && te.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, d))
{
// Attempt getting an IItemHandler for the given side via caps
IItemHandler itemHandler = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, d);
if (itemHandler != null)
{
return new GTCEItemHandler(itemHandler);
}
}
return null;
}
public abstract boolean canRemoveAllExceptCircuits();
}
@@ -0,0 +1,58 @@
package appeng.integration.modules.gregtech;
import appeng.util.inv.ItemHandlerIterator;
import appeng.util.inv.ItemSlot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.items.IItemHandler;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
public class GTCEItemHandler extends GTCEInventoryAdaptor
{
ArrayList<Integer> GTCElenses = new ArrayList<>(Arrays.asList(15085,15214,15092,15111,15113,15219,15218,15243,15244,15209,15117,15206,15216,15331,15212,15213,15154,15122,15157,15190,15247));
ArrayList<Integer> GTCEmolds = new ArrayList<>(Arrays.asList(32301,32303,32304,32305,32306,32307,32308,32309,32313,32314,32315,32317,32350,32351,32352,32353,32354,32355,32356,32358,32359,32360,32361,32363,32364,32365,32366,32367,32368,32369,32370,32371,32372,32373));
Item smallGearExtruderShape = Item.getByNameOrId("contenttweaker:smallgearextrudershape");
Item creativePortableTankMold = Item.getByNameOrId("contenttweaker:creativeportabletankmold");
protected final IItemHandler itemHandler;
public GTCEItemHandler(IItemHandler itemHandler)
{
this.itemHandler = itemHandler;
}
boolean isBlockableItem(ItemStack stack)
{
if ( stack.getItem() == Item.getByNameOrId("gregtech:meta_item_1") ) {
int metadata = stack.getItemDamage();
if ( metadata == 32766 || GTCElenses.contains(metadata) || GTCEmolds.contains(metadata)) {
return false;
}
}
if ( stack.getItem() == smallGearExtruderShape ) return false;
if ( stack.getItem() == creativePortableTankMold) return false;
return true;
}
@Override
public boolean canRemoveAllExceptCircuits()
{
int slots = this.itemHandler.getSlots();
for ( int slot = 0; slot < slots; slot++ ) {
ItemStack is = this.itemHandler.getStackInSlot(slot);
if ( is.isEmpty() || !isBlockableItem(is) ) continue;
return false;
}
return true;
}
@Override
public Iterator<ItemSlot> iterator()
{
return new ItemHandlerIterator( this.itemHandler );
}
}
@@ -19,20 +19,21 @@
package appeng.integration.modules.jei;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import appeng.client.gui.AEGuiHandler;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import mezz.jei.api.*;
import mezz.jei.config.Constants;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import mezz.jei.api.IJeiRuntime;
import mezz.jei.api.IModPlugin;
import mezz.jei.api.IModRegistry;
import mezz.jei.api.ISubtypeRegistry;
import mezz.jei.api.recipe.IRecipeCategoryRegistration;
import mezz.jei.api.recipe.VanillaRecipeCategoryUid;
@@ -55,6 +56,9 @@ import appeng.items.parts.ItemFacade;
@mezz.jei.api.JEIPlugin
public class JEIPlugin implements IModPlugin
{
public static IJeiRuntime runtime;
public static AEGuiHandler aeGuiHandler;
@Override
public void registerItemSubtypes( ISubtypeRegistry subtypeRegistry )
{
@@ -91,7 +95,11 @@ public class JEIPlugin implements IModPlugin
VanillaRecipeCategoryUid.CRAFTING );
registry.getRecipeTransferRegistry()
.addRecipeTransferHandler( new RecipeTransferHandler<>( ContainerPatternTerm.class ),
VanillaRecipeCategoryUid.CRAFTING );
Constants.UNIVERSAL_RECIPE_TRANSFER_UID );
aeGuiHandler = new AEGuiHandler();
registry.addAdvancedGuiHandlers(aeGuiHandler);
registry.addGhostIngredientHandler( aeGuiHandler.getGuiContainerClass(), aeGuiHandler);
}
private void registerDescriptions( IDefinitions definitions, IModRegistry registry )
@@ -214,5 +222,6 @@ public class JEIPlugin implements IModPlugin
{
JEIModule jeiModule = (JEIModule) Integrations.jei();
jeiModule.setJei( new JeiRuntimeAdapter( jeiRuntime ) );
runtime = jeiRuntime;
}
}
@@ -26,6 +26,12 @@ import java.util.Map;
import javax.annotation.Nullable;
import appeng.container.implementations.ContainerPatternTerm;
import appeng.core.sync.packets.PacketValueConfig;
import mezz.jei.api.recipe.VanillaRecipeCategoryUid;
import mezz.jei.transfer.RecipeTransferErrorInternal;
import mezz.jei.transfer.RecipeTransferErrorTooltip;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.Slot;
@@ -66,15 +72,47 @@ class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandl
@Override
public IRecipeTransferError transferRecipe( T container, IRecipeLayout recipeLayout, EntityPlayer player, boolean maxTransfer, boolean doTransfer )
{
final String recipeType = recipeLayout.getRecipeCategory().getUid();
if (recipeType.equals( VanillaRecipeCategoryUid.INFORMATION) || recipeType.equals(VanillaRecipeCategoryUid.FUEL))
{
return RecipeTransferErrorInternal.INSTANCE;
}
if( !doTransfer )
{
return null;
}
if( container instanceof ContainerPatternTerm )
{
try
{
if( !( (ContainerPatternTerm) container ).isCraftingMode() )
{
if( recipeType.equals( VanillaRecipeCategoryUid.CRAFTING ) )
{
NetworkHandler.instance().sendToServer( new PacketValueConfig( "PatternTerminal.CraftMode", "1" ) );
}
}
else if( !recipeType.equals( VanillaRecipeCategoryUid.CRAFTING ) )
{
NetworkHandler.instance().sendToServer( new PacketValueConfig( "PatternTerminal.CraftMode", "0" ) );
}
}
catch( IOException e )
{
e.printStackTrace();
}
}
Map<Integer, ? extends IGuiIngredient<ItemStack>> ingredients = recipeLayout.getItemStacks().getGuiIngredients();
final NBTTagCompound recipe = new NBTTagCompound();
final NBTTagList outputs = new NBTTagList();
int slotIndex = 0;
for( Map.Entry<Integer, ? extends IGuiIngredient<ItemStack>> ingredientEntry : ingredients.entrySet() )
@@ -82,6 +120,13 @@ class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandl
IGuiIngredient<ItemStack> ingredient = ingredientEntry.getValue();
if( !ingredient.isInput() )
{
ItemStack output = ingredient.getDisplayedIngredient();
if( output != null )
{
final NBTTagCompound tag = new NBTTagCompound();
output.writeToNBT( tag );
outputs.appendTag( tag );
}
continue;
}
@@ -102,8 +147,12 @@ class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandl
}
// prefer pure crystals.
for( ItemStack stack : ingredient.getAllIngredients() )
for ( ItemStack stack : ingredient.getAllIngredients() )
{
if( stack == null )
{
continue;
}
if( Platform.isRecipePrioritized( stack ) )
{
list.add( 0, stack );
@@ -114,7 +163,7 @@ class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandl
}
}
for( final ItemStack is : list )
for ( final ItemStack is : list )
{
final NBTTagCompound tag = new NBTTagCompound();
is.writeToNBT( tag );
@@ -130,6 +179,8 @@ class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandl
slotIndex++;
}
recipe.setTag( "outputs", outputs );
try
{
NetworkHandler.instance().sendToServer( new PacketJEIRecipe( recipe ) );
@@ -35,6 +35,8 @@ public enum TheOneProbeText
P2P_UNLINKED,
P2P_INPUT_ONE_OUTPUT,
P2P_INPUT_MANY_OUTPUTS,
P2P_OUTPUT_ONE_INPUT,
P2P_OUTPUT_MANY_INPUTS,
P2P_OUTPUT,
P2P_FREQUENCY,
@@ -57,11 +57,11 @@ public class P2PStateInfoProvider implements IPartProbInfoProvider
// The default state
int state = STATE_UNLINKED;
int outputCount = 0;
int outputCount = getOutputCount( tunnel );
int inputCount = getInputCount( tunnel );
if( !tunnel.isOutput() )
{
outputCount = getOutputCount( tunnel );
if( outputCount > 0 )
{
// Only set it to INPUT if we know there are any outputs
@@ -70,8 +70,7 @@ public class P2PStateInfoProvider implements IPartProbInfoProvider
}
else
{
final PartP2PTunnel input = tunnel.getInput();
if( input != null )
if( inputCount > 0 )
{
state = STATE_OUTPUT;
}
@@ -83,7 +82,7 @@ public class P2PStateInfoProvider implements IPartProbInfoProvider
probeInfo.text( TheOneProbeText.P2P_UNLINKED.getLocal() );
break;
case STATE_OUTPUT:
probeInfo.text( TheOneProbeText.P2P_OUTPUT.getLocal() );
probeInfo.text( getInputText( inputCount ) );
break;
case STATE_INPUT:
probeInfo.text( getOutputText( outputCount ) );
@@ -110,6 +109,19 @@ public class P2PStateInfoProvider implements IPartProbInfoProvider
}
}
private static int getInputCount( PartP2PTunnel tunnel )
{
try
{
return Iterators.size( tunnel.getInputs().iterator() );
}
catch( GridAccessException e )
{
// Well... unknown size it is!
return 0;
}
}
private static String getOutputText( int outputs )
{
if( outputs <= 1 )
@@ -122,4 +134,16 @@ public class P2PStateInfoProvider implements IPartProbInfoProvider
}
}
private static String getInputText( int inputs )
{
if( inputs <= 1 )
{
return TheOneProbeText.P2P_OUTPUT_ONE_INPUT.getLocal();
}
else
{
return String.format( TheOneProbeText.P2P_OUTPUT_MANY_INPUTS.getLocal(), inputs );
}
}
}
@@ -21,6 +21,7 @@ package appeng.integration.modules.waila.part;
import java.util.List;
import appeng.integration.modules.theoneprobe.TheOneProbeText;
import com.google.common.collect.Iterators;
import net.minecraft.entity.player.EntityPlayerMP;
@@ -117,11 +118,11 @@ public final class P2PStateWailaDataProvider extends BasePartWailaDataProvider
// The default state
int state = STATE_UNLINKED;
int outputCount = 0;
int outputCount = getOutputCount( tunnel );
int inputCount = getInputCount( tunnel );
if( !tunnel.isOutput() )
{
outputCount = getOutputCount( tunnel );
if( outputCount > 0 )
{
// Only set it to INPUT if we know there are any outputs
@@ -130,8 +131,7 @@ public final class P2PStateWailaDataProvider extends BasePartWailaDataProvider
}
else
{
PartP2PTunnel input = tunnel.getInput();
if( input != null )
if( inputCount > 0 )
{
state = STATE_OUTPUT;
}
@@ -160,15 +160,40 @@ public final class P2PStateWailaDataProvider extends BasePartWailaDataProvider
}
}
private static int getInputCount( PartP2PTunnel tunnel )
{
try
{
return Iterators.size( tunnel.getInputs().iterator() );
}
catch( GridAccessException e )
{
// Well... unknown size it is!
return 0;
}
}
private static String getOutputText( int outputs )
{
if( outputs <= 1 )
{
return WailaText.P2PInputOneOutput.getLocal();
return WailaText.P2P_INPUT_ONE_OUTPUT.getLocal();
}
else
{
return String.format( WailaText.P2PInputManyOutputs.getLocal(), outputs );
return String.format( WailaText.P2P_INPUT_MANY_OUTPUTS.getLocal(), outputs );
}
}
private static String getInputText( int inputs )
{
if( inputs <= 1 )
{
return WailaText.P2P_OUTPUT_ONE_INPUT.getLocal();
}
else
{
return String.format( WailaText.P2P_OUTPUT_MANY_INPUTS.getLocal(), inputs );
}
}
@@ -19,6 +19,7 @@
package appeng.items.contents;
import appeng.api.networking.security.IActionSource;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
@@ -42,6 +43,8 @@ import appeng.me.helpers.MEMonitorHandler;
import appeng.util.ConfigManager;
import appeng.util.Platform;
import java.util.Collections;
public class PortableCellViewer extends MEMonitorHandler<IAEItemStack> implements IPortableCell, IInventorySlotAware
{
@@ -83,6 +86,34 @@ public class PortableCellViewer extends MEMonitorHandler<IAEItemStack> implement
return usePowerMultiplier.divide( this.ips.extractAEPower( this.target, amt, Actionable.MODULATE ) );
}
@Override
public IAEItemStack injectItems( IAEItemStack input, Actionable mode, IActionSource src )
{
final long size = input.getStackSize();
final IAEItemStack injected = super.injectItems( input, mode, src );
if( mode == Actionable.MODULATE && ( injected == null || injected.getStackSize() != size ) )
{
this.notifyListenersOfChange( Collections.singletonList( input.copy().setStackSize( input.getStackSize() - ( injected == null ? 0 : injected.getStackSize() ) ) ), null);
}
return injected;
}
@Override
public IAEItemStack extractItems( IAEItemStack request, Actionable mode, IActionSource src )
{
final IAEItemStack extractable = super.extractItems( request, mode, src );
if( mode == Actionable.MODULATE && extractable != null )
{
this.notifyListenersOfChange( Collections.singletonList( request.copy().setStackSize( -extractable.getStackSize() ) ), null );
}
return extractable;
}
@Override
public <T extends IAEStack<T>> IMEMonitor<T> getInventory( IStorageChannel<T> channel )
{
@@ -164,6 +164,8 @@ public final class ItemMaterial extends AEBaseItem implements IStorageComponent,
return Upgrades.INVERTER;
case CARD_CRAFTING:
return Upgrades.CRAFTING;
case CARD_PATTERN_EXPANSION:
return Upgrades.PATTERN_EXPANSION;
default:
return null;
}
@@ -118,7 +118,10 @@ public enum MaterialType
FLUID_CELL1K_PART( 54, "material_fluid_cell1k_part", EnumSet.of( AEFeature.STORAGE_CELLS ) ),
FLUID_CELL4K_PART( 55, "material_fluid_cell4k_part", EnumSet.of( AEFeature.STORAGE_CELLS ) ),
FLUID_CELL16K_PART( 56, "material_fluid_cell16k_part", EnumSet.of( AEFeature.STORAGE_CELLS ) ),
FLUID_CELL64K_PART( 57, "material_fluid_cell64k_part", EnumSet.of( AEFeature.STORAGE_CELLS ) );
FLUID_CELL64K_PART( 57, "material_fluid_cell64k_part", EnumSet.of( AEFeature.STORAGE_CELLS ) ),
CARD_PATTERN_EXPANSION( 58, "material_card_pattern_expansion", EnumSet.of( AEFeature.ADVANCED_CARDS ) );
private final Set<AEFeature> features;
private final ModelResourceLocation model;
@@ -56,7 +56,7 @@ public class ItemEncodedPattern extends AEBaseItem implements ICraftingPatternIt
public ItemEncodedPattern()
{
this.setMaxStackSize( 1 );
this.setMaxStackSize( 64 );
}
@Override
@@ -403,7 +403,7 @@ public class ToolMatterCannon extends AEBasePoweredItem implements IStorageCell<
}
else if( pos.entityHit.attackEntityFrom( dmgSrc, dmg ) )
{
hasDestroyed = true;
hasDestroyed = pos.entityHit.isEntityAlive();
}
}
else if( pos.typeOfHit == RayTraceResult.Type.BLOCK )
+5 -1
View File
@@ -39,6 +39,7 @@ import appeng.api.util.IReadOnlyCollection;
import appeng.core.worlddata.WorldData;
import appeng.hooks.TickHandler;
import appeng.util.ReadOnlyCollection;
import appeng.me.cache.CraftingGridCache;
public class Grid implements IGrid
@@ -219,7 +220,10 @@ public class Grid implements IGrid
@Override
public MENetworkEvent postEvent( final MENetworkEvent ev )
{
return this.eventBus.postEvent( this, ev );
CraftingGridCache.pauseRebuilds();
final MENetworkEvent ret = this.eventBus.postEvent( this, ev );
CraftingGridCache.unpauseRebuilds();
return ret;
}
@Override
+6 -2
View File
@@ -55,6 +55,7 @@ import appeng.api.util.IReadOnlyCollection;
import appeng.core.AELog;
import appeng.core.worlddata.WorldData;
import appeng.hooks.TickHandler;
import appeng.me.cache.CraftingGridCache;
import appeng.me.pathfinding.IPathItem;
import appeng.util.IWorldCallable;
import appeng.util.ReadOnlyCollection;
@@ -164,6 +165,8 @@ public class GridNode implements IGridNode, IPathItem
{
final Object tracker = new Object();
CraftingGridCache.pauseRebuilds();
Deque<GridNode> nextRun = new ArrayDeque<>();
nextRun.add( this );
@@ -203,6 +206,7 @@ public class GridNode implements IGridNode, IPathItem
}
}
}
CraftingGridCache.unpauseRebuilds();
}
@Override
@@ -629,10 +633,10 @@ public class GridNode implements IGridNode, IPathItem
this.usedChannels = 0;
}
final int idx = this.connections.indexOf( fast );
final int idx = this.connections.indexOf( (IGridConnection) fast );
if( idx > 0 )
{
this.connections.remove( fast );
this.connections.remove( (IGridConnection) fast );
this.connections.add( 0, (IGridConnection) fast );
}
}
+89 -16
View File
@@ -30,7 +30,6 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@@ -42,6 +41,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import it.unimi.dsi.fastutil.objects.*;
import net.minecraft.world.World;
import appeng.api.AEApi;
@@ -105,8 +105,8 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
private final Set<ICraftingProvider> craftingProviders = new HashSet<>();
private final Map<IGridNode, ICraftingWatcher> craftingWatchers = new HashMap<>();
private final IGrid grid;
private final Map<ICraftingPatternDetails, List<ICraftingMedium>> craftingMethods = new HashMap<>();
private final Map<IAEItemStack, ImmutableList<ICraftingPatternDetails>> craftableItems = new HashMap<>();
private final Object2ObjectMap<ICraftingPatternDetails, List<ICraftingMedium>> craftingMethods = new Object2ObjectOpenHashMap<>();
private final Object2ObjectMap<IAEItemStack, ImmutableList<ICraftingPatternDetails>> craftableItems = new Object2ObjectOpenHashMap<>();
private final Set<IAEItemStack> emitableItems = new HashSet<>();
private final Map<String, CraftingLinkNexus> craftingLinks = new HashMap<>();
private final Multimap<IAEStack, CraftingWatcher> interests = HashMultimap.create();
@@ -114,6 +114,8 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
private IStorageGrid storageGrid;
private IEnergyGrid energyGrid;
private boolean updateList = false;
private static int pauseRebuilds = 0;
private static Set<CraftingGridCache> rebuildNeeded = new HashSet<>();
public CraftingGridCache( final IGrid grid )
{
@@ -158,11 +160,11 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
{
if( machine instanceof ICraftingWatcherHost )
{
final ICraftingWatcher craftingWatcher = this.craftingWatchers.get( machine );
final ICraftingWatcher craftingWatcher = this.craftingWatchers.get( gridNode );
if( craftingWatcher != null )
{
craftingWatcher.reset();
this.craftingWatchers.remove( machine );
this.craftingWatchers.remove( gridNode );
}
}
@@ -240,26 +242,49 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
// nothing!
}
public static void pauseRebuilds()
{
pauseRebuilds++;
}
public static void unpauseRebuilds()
{
pauseRebuilds--;
if (pauseRebuilds == 0 && rebuildNeeded.size() > 0)
{
ImmutableSet<CraftingGridCache> needed = ImmutableSet.copyOf(rebuildNeeded);
rebuildNeeded.clear();
for ( CraftingGridCache cache: needed )
{
cache.updatePatterns();
}
}
}
private void updatePatterns()
{
final Map<IAEItemStack, ImmutableList<ICraftingPatternDetails>> oldItems = this.craftableItems;
// coalesce change events during a grid traversal to a single rebuild
if (pauseRebuilds != 0)
{
rebuildNeeded.add(this);
return;
}
final Object2ObjectMap<IAEItemStack, ImmutableList<ICraftingPatternDetails>> oldItems = new Object2ObjectOpenHashMap<>(this.craftableItems);
final Set<IAEItemStack> oldEmitableItems = new HashSet<>(this.emitableItems);
// erase list.
this.craftingMethods.clear();
this.craftableItems.clear();
this.emitableItems.clear();
// update the stuff that was in the list...
this.storageGrid.postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ), oldItems.keySet(),
new BaseActionSource() );
// re-create list..
for( final ICraftingProvider provider : this.craftingProviders )
{
provider.provideCrafting( this );
}
final Map<IAEItemStack, Set<ICraftingPatternDetails>> tmpCraft = new HashMap<>();
final Object2ObjectMap<IAEItemStack, ObjectSet<ICraftingPatternDetails>> tmpCraft = new Object2ObjectOpenHashMap<>();
// new craftables!
for( final ICraftingPatternDetails details : this.craftingMethods.keySet() )
@@ -270,11 +295,11 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
out.reset();
out.setCraftable( true );
Set<ICraftingPatternDetails> methods = tmpCraft.get( out );
ObjectSet<ICraftingPatternDetails> methods = tmpCraft.get( out );
if( methods == null )
{
tmpCraft.put( out, methods = new TreeSet<>( COMPARATOR ) );
tmpCraft.put( out, methods = new ObjectRBTreeSet<>( COMPARATOR ) );
}
methods.add( details );
@@ -282,12 +307,56 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
}
// make them immutable
for( final Entry<IAEItemStack, Set<ICraftingPatternDetails>> e : tmpCraft.entrySet() )
for( final Entry<IAEItemStack, ObjectSet<ICraftingPatternDetails>> e : tmpCraft.entrySet() )
{
this.craftableItems.put( e.getKey(), ImmutableList.copyOf( e.getValue() ) );
}
this.storageGrid.postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ), this.craftableItems.keySet(),
Object2ObjectMap<IAEItemStack, ImmutableList<ICraftingPatternDetails>> craftablesChanged = new Object2ObjectArrayMap<>();
ObjectSet<Entry<IAEItemStack, ImmutableList<ICraftingPatternDetails>>> i = oldItems.entrySet();
for ( Entry<IAEItemStack, ImmutableList<ICraftingPatternDetails>> ais : i) {
if (!this.craftableItems.containsKey( ais.getKey() )) {
IAEItemStack changedStack = ais.getKey().copy();
changedStack.reset();
changedStack.setCraftable( false );
craftablesChanged.put( changedStack, ais.getValue() );
}
}
ObjectSet<Entry<IAEItemStack, ImmutableList<ICraftingPatternDetails>>> j = this.craftableItems.entrySet();
for ( Entry<IAEItemStack, ImmutableList<ICraftingPatternDetails>> ais : j) {
if (!oldItems.containsKey( ais )){
IAEItemStack changedStack = ais.getKey().copy();
changedStack.reset();
changedStack.setCraftable( true );
craftablesChanged.put( changedStack, ais.getValue() );
}
}
for( final IAEItemStack st : oldEmitableItems )
{
if( !emitableItems.contains( st ) )
{
IAEItemStack changedStack = st.copy();
changedStack.reset();
changedStack.setCraftable( false );
craftablesChanged.put( changedStack, null );
}
}
for( final IAEItemStack st : this.emitableItems )
{
if( !oldEmitableItems.contains( st ) )
{
IAEItemStack changedStack = st.copy();
changedStack.reset();
changedStack.setCraftable( true );
craftablesChanged.put( changedStack, null );
}
}
this.storageGrid.postCraftablesChanges( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ), craftablesChanged.keySet(),
new BaseActionSource() );
}
@@ -607,7 +676,11 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
public boolean hasCpu( final ICraftingCPU cpu )
{
return this.craftingCPUClusters.contains( cpu );
if (cpu instanceof CraftingCPUCluster)
{
return this.craftingCPUClusters.contains( (CraftingCPUCluster) cpu );
}
return false;
}
public GenericInterestManager<CraftingWatcher> getInterestManager()
+177 -41
View File
@@ -30,6 +30,7 @@ import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Set;
import com.google.common.base.Preconditions;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;
import com.google.common.collect.Sets;
@@ -63,12 +64,10 @@ import appeng.me.energy.EnergyWatcher;
public class EnergyGridCache implements IEnergyGrid
{
private static final double MAX_BUFFER_STORAGE = 200;
private static final Comparator<IEnergyGridProvider> COMPARATOR_HIGHEST_AMOUNT_STORED_FIRST = ( o1, o2 ) -> Double.compare( o2.getProviderStoredEnergy(),
o1.getProviderStoredEnergy() );
private static final double MAX_BUFFER_STORAGE = 800;
private static final Comparator<IEnergyGridProvider> COMPARATOR_HIGHEST_AMOUNT_STORED_FIRST = ( o1, o2 ) -> Double.compare( o2.getProviderStoredEnergy(), o1.getProviderStoredEnergy() );
private static final Comparator<IEnergyGridProvider> COMPARATOR_LOWEST_PERCENTAGE_FIRST = ( o1, o2 ) ->
{
private static final Comparator<IEnergyGridProvider> COMPARATOR_LOWEST_PERCENTAGE_FIRST = ( o1, o2 ) -> {
final double percent1 = ( o1.getProviderStoredEnergy() + 1 ) / ( o1.getProviderMaxEnergy() + 1 );
final double percent2 = ( o2.getProviderStoredEnergy() + 1 ) / ( o2.getProviderMaxEnergy() + 1 );
@@ -76,9 +75,24 @@ public class EnergyGridCache implements IEnergyGrid
};
private final NavigableSet<EnergyThreshold> interests = Sets.newTreeSet();
// Should only be modified from the add/remove methods below to guard against
// concurrent modifications
private final double averageLength = 40.0;
private final Set<IAEPowerStorage> providers = new LinkedHashSet<>();
// Used to track whether an extraction is currently in progress, to fail fast
// when something externally
// modifies the energy grid.
private boolean ongoingExtractOperation = false;
// Should only be modified from the add/remove methods below to guard against
// concurrent modifications
private final Set<IAEPowerStorage> requesters = new LinkedHashSet<>();
// Used to track whether an injection is currently in progress, to fail fast
// when something externally
// modifies the energy grid.
private boolean ongoingInjectOperation = false;
private final Multiset<IEnergyGridProvider> energyGridProviders = HashMultiset.create();
private final IGrid myGrid;
private final HashMap<IGridNode, IEnergyWatcher> watchers = new HashMap<>();
@@ -110,6 +124,10 @@ public class EnergyGridCache implements IEnergyGrid
private double lastStoredPower = -1;
private final GridPowerStorage localStorage = new GridPowerStorage();
private Set<IAEPowerStorage> providerToRemove = new HashSet<>();
private Set<IAEPowerStorage> requesterToRemove = new HashSet<>();
private Set<IAEPowerStorage> providersToAdd = new HashSet<>();
private Set<IAEPowerStorage> requesterToAdd = new HashSet<>();
public EnergyGridCache( final IGrid g )
{
@@ -143,20 +161,33 @@ public class EnergyGridCache implements IEnergyGrid
{
if( ev.storage.isAEPublicPowerStorage() )
{
switch( ev.type )
if( ev.type == PowerEventType.PROVIDE_POWER )
{
case PROVIDE_POWER:
if( ev.storage.getPowerFlow() != AccessRestriction.WRITE )
if( ev.storage.getPowerFlow() != AccessRestriction.WRITE )
{
if( !ongoingExtractOperation )
{
this.providers.add( ev.storage );
addProvider( ev.storage );
}
break;
case REQUEST_POWER:
if( ev.storage.getPowerFlow() != AccessRestriction.READ )
else
{
this.requesters.add( ev.storage );
this.providersToAdd.add( ev.storage );
}
break;
}
}
else if( ev.type == PowerEventType.REQUEST_POWER )
{
if( ev.storage.getPowerFlow() != AccessRestriction.READ )
{
if( !ongoingInjectOperation )
{
addRequester( ev.storage );
}
else
{
this.requesterToAdd.add( ev.storage );
}
}
}
}
else
@@ -301,19 +332,56 @@ public class EnergyGridCache implements IEnergyGrid
{
double extractedPower = 0;
this.providers.addAll( providersToAdd );
providersToAdd.clear();
providers.removeIf( providerToRemove::contains );
this.providerToRemove.clear();
final Iterator<IAEPowerStorage> it = this.providers.iterator();
while( extractedPower < amt && it.hasNext() )
ongoingExtractOperation = true;
boolean ls = false;
try
{
final IAEPowerStorage node = it.next();
final double req = amt - extractedPower;
final double newPower = node.extractAEPower( req, mode, PowerMultiplier.ONE );
extractedPower += newPower;
if( newPower < req && mode == Actionable.MODULATE )
while ( extractedPower < amt && it.hasNext() )
{
it.remove();
final IAEPowerStorage node = it.next();
if( node != null )
{
if( node == localStorage && mode == Actionable.MODULATE )
{
ls = true;
continue;
}
final double req = amt - extractedPower;
final double newPower = node.extractAEPower( req, mode, PowerMultiplier.ONE );
extractedPower += newPower;
if( newPower < req && mode == Actionable.MODULATE )
{
it.remove();
}
}
else
{
it.remove();
}
}
} finally
{
ongoingExtractOperation = false;
if( ls && extractedPower < amt )
{
final double req = amt - extractedPower;
final double newPower = localStorage.extractAEPower( req, mode, PowerMultiplier.ONE );
extractedPower += newPower;
if( newPower < req )
{
providers.remove( localStorage );
}
}
}
@@ -338,17 +406,37 @@ public class EnergyGridCache implements IEnergyGrid
{
final double originalAmount = amt;
this.requesters.addAll( requesterToAdd );
requesterToAdd.clear();
requesters.removeIf( requesterToRemove::contains );
this.requesterToRemove.clear();
final Iterator<IAEPowerStorage> it = this.requesters.iterator();
while( amt > 0 && it.hasNext() )
ongoingInjectOperation = true;
try
{
final IAEPowerStorage node = it.next();
amt = node.injectAEPower( amt, mode );
if( amt > 0 && mode == Actionable.MODULATE )
while ( amt > 0 && it.hasNext() )
{
it.remove();
final IAEPowerStorage node = it.next();
if( node != null )
{
amt = node.injectAEPower( amt, mode );
if( amt > 0 && mode == Actionable.MODULATE )
{
it.remove();
}
}
else
{
it.remove();
}
}
} finally
{
ongoingInjectOperation = false;
}
final double overflow = Math.max( 0.0, amt );
@@ -367,7 +455,7 @@ public class EnergyGridCache implements IEnergyGrid
double required = 0;
final Iterator<IAEPowerStorage> it = this.requesters.iterator();
while( required < maxRequired && it.hasNext() )
while ( required < maxRequired && it.hasNext() )
{
final IAEPowerStorage node = it.next();
if( node.getPowerFlow() != AccessRestriction.READ )
@@ -428,11 +516,7 @@ public class EnergyGridCache implements IEnergyGrid
@Override
public double getStoredPower()
{
if( this.availableTicksSinceUpdate > 90 )
{
this.refreshPower();
}
this.refreshPower();
return Math.max( 0.0, this.globalAvailablePower );
}
@@ -505,9 +589,22 @@ public class EnergyGridCache implements IEnergyGrid
this.globalMaxPower -= ps.getAEMaxPower();
this.globalAvailablePower -= ps.getAECurrentPower();
}
this.providers.remove( ps );
this.requesters.remove( ps );
if( !ongoingExtractOperation )
{
removeProvider( ps );
}
else
{
this.providerToRemove.add( ps );
}
if( !ongoingInjectOperation )
{
removeRequester( ps );
}
else
{
this.requesterToRemove.add( ps );
}
}
}
@@ -523,6 +620,31 @@ public class EnergyGridCache implements IEnergyGrid
}
}
private void addRequester( IAEPowerStorage requester )
{
Preconditions.checkState( !ongoingInjectOperation, "Cannot modify energy requesters while energy is being injected." );
this.requesters.add( requester );
}
private void removeRequester( IAEPowerStorage requester )
{
Preconditions.checkState( !ongoingInjectOperation, "Cannot modify energy requesters while energy is being injected." );
this.requesters.remove( requester );
}
private void addProvider( IAEPowerStorage provider )
{
Preconditions.checkState( !ongoingExtractOperation, "Cannot modify energy providers while energy is being extracted." );
this.providers.add( provider );
}
private void removeProvider( IAEPowerStorage provider )
{
Preconditions.checkState( !ongoingExtractOperation, "Cannot modify energy providers while energy is being extracted." );
this.providers.remove( provider );
}
@Override
public void addNode( final IGridNode node, final IGridHost machine )
{
@@ -554,12 +676,26 @@ public class EnergyGridCache implements IEnergyGrid
if( current > 0 && ps.getPowerFlow() != AccessRestriction.WRITE )
{
this.globalAvailablePower += current;
this.providers.add( ps );
if( !ongoingExtractOperation )
{
addProvider( ps );
}
else
{
this.providersToAdd.add( ps );
}
}
if( current < max && ps.getPowerFlow() != AccessRestriction.READ )
{
this.requesters.add( ps );
if( !ongoingInjectOperation )
{
addRequester( ps );
}
else
{
this.requesterToAdd.add( ps );
}
}
}
}
@@ -686,4 +822,4 @@ public class EnergyGridCache implements IEnergyGrid
}
}
}
}
}
+15 -8
View File
@@ -94,19 +94,19 @@ public class GridStorageCache implements IStorageGrid
this.removeCellProvider( cc, tracker );
this.inactiveCellProviders.remove( cc );
this.getGrid().postEvent( new MENetworkCellArrayUpdate() );
cellUpdate( null );
tracker.applyChanges();
}
if( machine instanceof IStackWatcherHost )
{
final IStackWatcher myWatcher = this.watchers.get( machine );
final IStackWatcher myWatcher = this.watchers.get( node );
if( myWatcher != null )
{
myWatcher.reset();
this.watchers.remove( machine );
this.watchers.remove( node );
}
}
}
@@ -119,7 +119,7 @@ public class GridStorageCache implements IStorageGrid
final ICellContainer cc = (ICellContainer) machine;
this.inactiveCellProviders.add( cc );
this.getGrid().postEvent( new MENetworkCellArrayUpdate() );
cellUpdate( null );
if( node.isActive() )
{
@@ -170,7 +170,7 @@ public class GridStorageCache implements IStorageGrid
private CellChangeTracker addCellProvider( final ICellProvider cc, final CellChangeTracker tracker )
{
if( this.inactiveCellProviders.contains( cc ) )
if( this.inactiveCellProviders.contains( cc ) && !this.activeCellProviders.contains( cc ))
{
this.inactiveCellProviders.remove( cc );
this.activeCellProviders.add( cc );
@@ -248,8 +248,6 @@ public class GridStorageCache implements IStorageGrid
}
}
this.storageMonitors.forEach( ( channel, monitor ) -> monitor.forceUpdate() );
tracker.applyChanges();
}
@@ -281,6 +279,12 @@ public class GridStorageCache implements IStorageGrid
this.storageMonitors.get( chan ).postChange( true, (Iterable) input, src );
}
@Override
public void postCraftablesChanges( IStorageChannel<?> chan, Iterable<? extends IAEStack<?>> input, IActionSource src )
{
this.storageMonitors.get( chan ).updateCraftables( (Iterable) input, src );
}
@Override
public void registerCellProvider( final ICellProvider provider )
{
@@ -324,7 +328,10 @@ public class GridStorageCache implements IStorageGrid
public void applyChanges()
{
GridStorageCache.this.postChangesToNetwork( this.channel, this.up_or_down, this.list, this.src );
if( !this.list.isEmpty() )
{
GridStorageCache.this.postChangesToNetwork( this.channel, this.up_or_down, this.list, this.src );
}
}
}
+145 -98
View File
@@ -19,20 +19,10 @@
package appeng.me.cache;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Queues;
import appeng.api.AEApi;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable;
import appeng.api.networking.events.MENetworkStorageEvent;
@@ -41,15 +31,26 @@ import appeng.api.storage.IMEInventoryHandler;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.IMEMonitorHandlerReceiver;
import appeng.api.storage.IStorageChannel;
import appeng.api.storage.channels.IFluidStorageChannel;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEStack;
import appeng.api.storage.data.IItemList;
import appeng.me.storage.ItemWatcher;
import com.google.common.collect.Queues;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import java.util.*;
import java.util.Map.Entry;
public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
{
@Nonnull
private static final Deque<NetworkMonitor<?>> GLOBAL_DEPTH = Queues.newArrayDeque();
private static final Set<NetworkMonitor<?>> NESTED_MONITORS = new HashSet<>();
private static final HashMap<IActionSource, Set<NetworkMonitor<?>>> sourceSetHashMap = new HashMap<>();
protected static boolean nested = false;
protected boolean isNested = false;
@Nonnull
private final GridStorageCache myGridCache;
@@ -58,19 +59,21 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
@Nonnull
private final IItemList<T> cachedList;
@Nonnull
private final Map<IMEMonitorHandlerReceiver<T>, Object> listeners;
private final Object2ObjectMap<IMEMonitorHandlerReceiver<T>, Object> listeners;
private boolean sendEvent = false;
private boolean hasChanged = false;
private boolean forceUpdate = false;
@Nonnegative
private int localDepthSemaphore = 0;
private long gridItemCount;
private long gridFluidCount;
public NetworkMonitor( final GridStorageCache cache, final IStorageChannel<T> chan )
{
this.myGridCache = cache;
this.myChannel = chan;
this.cachedList = chan.createList();
this.listeners = new HashMap<>();
this.listeners = new Object2ObjectOpenHashMap<>();
}
@Override
@@ -88,21 +91,7 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
@Override
public T extractItems( final T request, final Actionable mode, final IActionSource src )
{
if( mode == Actionable.SIMULATE )
{
return this.getHandler().extractItems( request, mode, src );
}
this.localDepthSemaphore++;
final T leftover = this.getHandler().extractItems( request, mode, src );
this.localDepthSemaphore--;
if( this.localDepthSemaphore == 0 )
{
this.monitorDifference( request.copy(), leftover, true, src );
}
return leftover;
return this.getHandler().extractItems( request, mode, src );
}
@Override
@@ -135,38 +124,42 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
return this.getHandler().getSlot();
}
public long getGridCurrentCount()
{
if( myChannel == AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) )
{
return gridItemCount;
}
else if( myChannel == AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) )
{
return gridFluidCount;
}
return 0;
}
public void incGridCurrentCount( long count )
{
if( myChannel == AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) )
{
gridItemCount += count;
}
else if( myChannel == AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) )
{
gridFluidCount += count;
}
}
@Nonnull
@Override
public IItemList<T> getStorageList()
{
if( this.hasChanged )
{
this.hasChanged = false;
this.cachedList.resetStatus();
return this.getAvailableItems( this.cachedList );
}
return this.cachedList;
}
@Override
public T injectItems( final T input, final Actionable mode, final IActionSource src )
{
if( mode == Actionable.SIMULATE )
{
return this.getHandler().injectItems( input, mode, src );
}
this.localDepthSemaphore++;
final T leftover = this.getHandler().injectItems( input, mode, src );
this.localDepthSemaphore--;
if( this.localDepthSemaphore == 0 )
{
this.monitorDifference( input.copy(), leftover, false, src );
}
return leftover;
return this.getHandler().injectItems( input, mode, src );
}
@Override
@@ -198,36 +191,15 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
return this.listeners.entrySet().iterator();
}
private T monitorDifference( final IAEStack<T> original, final T leftOvers, final boolean extraction, final IActionSource src )
{
final T diff = original.copy();
if( extraction )
{
diff.setStackSize( leftOvers == null ? 0 : -leftOvers.getStackSize() );
}
else if( leftOvers != null )
{
diff.decStackSize( leftOvers.getStackSize() );
}
if( diff.getStackSize() != 0 )
{
this.postChangesToListeners( ImmutableList.of( diff ), src );
}
return leftOvers;
}
private void notifyListenersOfChange( final Iterable<T> diff, final IActionSource src )
{
this.hasChanged = true;
final Iterator<Entry<IMEMonitorHandlerReceiver<T>, Object>> i = this.getListeners();
while( i.hasNext() )
{
final Entry<IMEMonitorHandlerReceiver<T>, Object> o = i.next();
final IMEMonitorHandlerReceiver<T> receiver = o.getKey();
if( receiver.isValid( o.getValue() ) )
{
receiver.postChange( this, diff, src );
@@ -239,46 +211,60 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
}
}
private void postChangesToListeners( final Iterable<T> changes, final IActionSource src )
protected void updateCraftables( Iterable<T> input, IActionSource src )
{
this.postChange( true, changes, src );
for( final T changedItem : input )
{
if (changedItem.isCraftable()) {
this.cachedList.add( changedItem );
}
else
{
T i = this.cachedList.findPrecise( changedItem );
if (i != null)
i.setCraftable( false );
}
}
}
protected void postChange( final boolean add, final Iterable<T> changes, final IActionSource src )
{
if( this.localDepthSemaphore > 0 || GLOBAL_DEPTH.contains( this ) )
if( sourceSetHashMap.get( src ) != null && sourceSetHashMap.get( src ).contains( this ) )
{
NESTED_MONITORS.add( this );
nested = true;
return;
}
GLOBAL_DEPTH.push( this );
this.localDepthSemaphore++;
sourceSetHashMap.putIfAbsent( src, new HashSet<>() );
sourceSetHashMap.get( src ).add( this );
this.sendEvent = true;
this.notifyListenersOfChange( changes, src );
for( final T changedItem : changes )
for( final T change : changes )
{
T difference = changedItem;
if( !add && changedItem != null )
//T change = changed;
if( !add && change != null )
{
difference = changedItem.copy();
difference.setStackSize( -changedItem.getStackSize() );
//change = changed.copy();
change.setStackSize( -change.getStackSize() );
}
if( this.myGridCache.getInterestManager().containsKey( changedItem ) )
incGridCurrentCount( change.getStackSize() );
this.cachedList.addStorage( change );
if( this.myGridCache.getInterestManager().containsKey( change ) )
{
final Collection<ItemWatcher> list = this.myGridCache.getInterestManager().get( changedItem );
final Collection<ItemWatcher> list = this.myGridCache.getInterestManager().get( change );
if( !list.isEmpty() )
{
IAEStack<T> fullStack = this.getStorageList().findPrecise( changedItem );
IAEStack<T> fullStack = this.getStorageList().findPrecise( change );
if( fullStack == null )
{
fullStack = changedItem.copy();
fullStack = change.copy();
fullStack.setStackSize( 0 );
}
@@ -286,7 +272,7 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
for( final ItemWatcher iw : list )
{
iw.getHost().onStackChange( this.getStorageList(), fullStack, difference, src, this.getChannel() );
iw.getHost().onStackChange( this.getStorageList(), fullStack, change, src, this.getChannel() );
}
this.myGridCache.getInterestManager().disableTransactions();
@@ -294,21 +280,82 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
}
}
final NetworkMonitor<?> last = GLOBAL_DEPTH.pop();
this.localDepthSemaphore--;
this.notifyListenersOfChange( changes, src );
if( last != this )
sourceSetHashMap.get( src ).remove( this );
if( sourceSetHashMap.get( src ).isEmpty() )
{
throw new IllegalStateException( "Invalid Access to Networked Storage API detected." );
sourceSetHashMap.remove( src );
}
if( sourceSetHashMap.isEmpty() )
{
for( NetworkMonitor<?> nm : NESTED_MONITORS )
{
nm.setupForceUpdate();
}
nested = false;
NESTED_MONITORS.clear();
}
}
void setupForceUpdate()
{
if( nested != isNested )
{
isNested = nested;
forceUpdate();
}
}
void forceUpdate()
{
this.hasChanged = true;
forceUpdate = false;
this.cachedList.resetStatus();
this.getAvailableItems( this.cachedList );
long count = 0;
for( T stack : this.cachedList )
{
count += stack.getStackSize();
if( this.myGridCache.getInterestManager().containsKey( stack ) )
{
final Collection<ItemWatcher> list = this.myGridCache.getInterestManager().get( stack );
if( !list.isEmpty() )
{
IAEStack<T> fullStack = this.getStorageList().findPrecise( stack );
if( fullStack == null )
{
fullStack = stack.copy();
fullStack.setStackSize( 0 );
}
this.myGridCache.getInterestManager().enableTransactions();
for ( final ItemWatcher iw : list )
{
iw.getHost().onStackChange( this.getStorageList(), fullStack, stack, null, this.getChannel() );
}
this.myGridCache.getInterestManager().disableTransactions();
}
}
}
if( myChannel == AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) )
{
gridItemCount = count;
}
else if( myChannel == AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) )
{
gridFluidCount = count;
}
final Iterator<Entry<IMEMonitorHandlerReceiver<T>, Object>> i = this.getListeners();
while( i.hasNext() )
while ( i.hasNext() )
{
final Entry<IMEMonitorHandlerReceiver<T>, Object> o = i.next();
final IMEMonitorHandlerReceiver<T> receiver = o.getKey();
+56 -17
View File
@@ -19,7 +19,7 @@
package appeng.me.cache;
import java.util.HashMap;
import java.util.Collection;
import java.util.Random;
import com.google.common.collect.LinkedHashMultimap;
@@ -46,7 +46,7 @@ public class P2PCache implements IGridCache
private static final TunnelCollection<PartP2PTunnel> NULL_COLLECTION = new TunnelCollection<PartP2PTunnel>( null, null );
private final IGrid myGrid;
private final HashMap<Short, PartP2PTunnel> inputs = new HashMap<>();
private final Multimap<Short, PartP2PTunnel> inputs = LinkedHashMultimap.create();
private final Multimap<Short, PartP2PTunnel> outputs = LinkedHashMultimap.create();
private final Random frequencyGenerator;
@@ -110,10 +110,19 @@ public class P2PCache implements IGridCache
}
else
{
this.inputs.remove( t.getFrequency() );
this.inputs.remove( t.getFrequency(), t );
}
this.updateTunnel( t.getFrequency(), !t.isOutput(), false );
if( this.inputs.get( t.getFrequency() ).isEmpty() )
{
this.inputs.removeAll( t.getFrequency() );
}
if( this.outputs.get( t.getFrequency() ).isEmpty() )
{
this.outputs.removeAll( t.getFrequency() );
}
this.updateTunnel( t.getFrequency(), t.isOutput(), false );
}
}
@@ -142,7 +151,7 @@ public class P2PCache implements IGridCache
this.inputs.put( t.getFrequency(), t );
}
this.updateTunnel( t.getFrequency(), !t.isOutput(), false );
this.updateTunnel( t.getFrequency(), t.isOutput(), false );
}
}
@@ -164,6 +173,20 @@ public class P2PCache implements IGridCache
}
public void removeTunnel( final PartP2PTunnel t, short freq )
{
this.outputs.remove( freq, t );
this.inputs.remove( freq, t );
if( this.inputs.get( t.getFrequency() ).isEmpty() )
{
this.inputs.removeAll( t.getFrequency() );
}
if( this.outputs.get( t.getFrequency() ).isEmpty() )
{
this.outputs.removeAll( t.getFrequency() );
}
}
private void updateTunnel( final short freq, final boolean updateOutputs, final boolean configChange )
{
for( final PartP2PTunnel p : this.outputs.get( freq ) )
@@ -175,8 +198,7 @@ public class P2PCache implements IGridCache
p.onTunnelNetworkChange();
}
final PartP2PTunnel in = this.inputs.get( freq );
if( in != null )
for( final PartP2PTunnel in : this.inputs.get( freq ) )
{
if( configChange )
{
@@ -195,7 +217,7 @@ public class P2PCache implements IGridCache
if( this.inputs.containsValue( t ) )
{
this.inputs.remove( t.getFrequency() );
this.inputs.remove( t.getFrequency(), t );
}
t.setFrequency( newFrequency );
@@ -211,7 +233,6 @@ public class P2PCache implements IGridCache
// AELog.info( "update-" + (t.output ? "output: " : "input: ") + t.freq );
this.updateTunnel( t.getFrequency(), t.isOutput(), true );
this.updateTunnel( t.getFrequency(), !t.isOutput(), true );
}
public short newFrequency()
@@ -236,25 +257,43 @@ public class P2PCache implements IGridCache
public TunnelCollection<PartP2PTunnel> getOutputs( final short freq, final Class<? extends PartP2PTunnel> c )
{
final PartP2PTunnel in = this.inputs.get( freq );
Collection<PartP2PTunnel> in = this.inputs.get( freq );
if( in == null )
{
return NULL_COLLECTION;
}
final TunnelCollection<PartP2PTunnel> out = this.inputs.get( freq ).getCollection( this.outputs.get( freq ), c );
TunnelCollection<PartP2PTunnel> out;
for( PartP2PTunnel part : this.inputs.get( freq ) )
{
out = part.getCollection( this.outputs.get( freq ), c );
if( out != null )
{
return out;
}
}
return NULL_COLLECTION;
}
public TunnelCollection<PartP2PTunnel> getInputs( final short freq, final Class<? extends PartP2PTunnel> c )
{
Collection<PartP2PTunnel> out = this.outputs.get( freq );
if( out == null )
{
return NULL_COLLECTION;
}
return out;
}
public PartP2PTunnel getInput( final short freq )
{
return this.inputs.get( freq );
TunnelCollection<PartP2PTunnel> in;
for( PartP2PTunnel part : this.outputs.get( freq ) )
{
in = part.getCollection( this.inputs.get( freq ), c );
if( in != null )
{
return in;
}
}
return NULL_COLLECTION;
}
}
+1 -1
View File
@@ -314,7 +314,7 @@ public class PathGridCache implements IPathingGrid
int depth = 0;
for( final IGridNode nodes : this.requireChannels )
{
if( !this.semiOpen.contains( nodes ) )
if( !this.semiOpen.contains( (IPathItem) nodes ) )
{
final IGridBlock gb = nodes.getGridBlock();
final EnumSet<GridFlags> flags = gb.getFlags();
+43 -38
View File
@@ -19,9 +19,9 @@
package appeng.me.cache;
import java.util.HashMap;
import java.util.PriorityQueue;
import java.util.*;
import appeng.parts.automation.PartLevelEmitter;
import com.google.common.base.Preconditions;
import net.minecraft.crash.CrashReport;
@@ -46,7 +46,9 @@ public class TickManagerCache implements ITickManager
private final HashMap<IGridNode, TickTracker> alertable = new HashMap<>();
private final HashMap<IGridNode, TickTracker> sleeping = new HashMap<>();
private final HashMap<IGridNode, TickTracker> awake = new HashMap<>();
private final HashMap<IGridNode, TickTracker> laterTicker = new HashMap<>();
private final PriorityQueue<TickTracker> upcomingTicks = new PriorityQueue<>();
private long currentTick = 0;
public TickManagerCache( final IGrid g )
@@ -80,50 +82,52 @@ public class TickManagerCache implements ITickManager
public void onUpdateTick()
{
TickTracker tt = null;
try
{
this.currentTick++;
while( !this.upcomingTicks.isEmpty() )
while ( !this.upcomingTicks.isEmpty() )
{
tt = this.upcomingTicks.peek();
final int diff = (int) ( this.currentTick - tt.getLastTick() );
if( diff >= tt.getCurrentRate() )
// Stop once it reaches a TickTracker running at a later tick
if( tt.getNextTick() > this.currentTick )
{
// remove tt..
this.upcomingTicks.poll();
final TickRateModulation mod = tt.getGridTickable().tickingRequest( tt.getNode(), diff );
switch( mod )
{
case FASTER:
tt.setRate( tt.getCurrentRate() - 2 );
break;
case IDLE:
tt.setRate( tt.getRequest().maxTickRate );
break;
case SAME:
break;
case SLEEP:
this.sleepDevice( tt.getNode() );
break;
case SLOWER:
tt.setRate( tt.getCurrentRate() + 1 );
break;
case URGENT:
tt.setRate( 0 );
break;
default:
break;
}
if( this.awake.containsKey( tt.getNode() ) )
{
this.addToQueue( tt );
}
break;
}
else
this.upcomingTicks.poll();
final int diff = (int) ( this.currentTick - tt.getLastTick() );
final TickRateModulation mod = tt.getGridTickable().tickingRequest( tt.getNode(), diff );
switch ( mod )
{
return; // done!
case FASTER:
tt.setCurrentRate( tt.getCurrentRate() - 2 );
break;
case IDLE:
tt.setCurrentRate( tt.getRequest().maxTickRate );
break;
case SAME:
break;
case SLEEP:
this.sleepDevice( tt.getNode() );
break;
case SLOWER:
tt.setCurrentRate( tt.getCurrentRate() + 1 );
break;
case URGENT:
tt.setCurrentRate( 0 );
break;
default:
break;
}
if( this.awake.containsKey( tt.getNode() ) )
{
this.addToQueue( tt );
}
}
}
@@ -255,6 +259,7 @@ public class TickManagerCache implements ITickManager
final TickTracker gt = this.sleeping.get( node );
this.sleeping.remove( node );
this.awake.put( node, gt );
this.upcomingTicks.remove( gt );
this.addToQueue( gt );
return true;
+22 -21
View File
@@ -37,7 +37,6 @@ public class TickTracker implements Comparable<TickTracker>
private final TickingRequest request;
private final IGridTickable gt;
private final IGridNode node;
private final TickManagerCache host;
private final long LastFiveTicksTime = 0;
@@ -51,7 +50,6 @@ public class TickTracker implements Comparable<TickTracker>
this.node = node;
this.setCurrentRate( ( req.minTickRate + req.maxTickRate ) / 2 );
this.setLastTick( currentTick );
this.host = tickManagerCache;
}
public long getAvgNanos()
@@ -59,27 +57,25 @@ public class TickTracker implements Comparable<TickTracker>
return( this.LastFiveTicksTime / 5 );
}
public void setRate( final int rate )
{
this.setCurrentRate( rate );
if( this.getCurrentRate() < this.getRequest().minTickRate )
{
this.setCurrentRate( this.getRequest().minTickRate );
}
if( this.getCurrentRate() > this.getRequest().maxTickRate )
{
this.setCurrentRate( this.getRequest().maxTickRate );
}
}
@Override
public int compareTo( @Nonnull final TickTracker t )
{
final int nextTick = (int) ( ( this.getLastTick() - this.host.getCurrentTick() ) + this.getCurrentRate() );
final int ts_nextTick = (int) ( ( t.getLastTick() - this.host.getCurrentTick() ) + t.getCurrentRate() );
return nextTick - ts_nextTick;
int next = Long.compare( this.getNextTick(), t.getNextTick() );
if( next != 0 )
{
return next;
}
int last = Long.compare( this.getLastTick(), t.getLastTick() );
if( last != 0 )
{
return last;
}
return Integer.compare( this.getCurrentRate(), t.getCurrentRate() );
}
public void addEntityCrashInfo( final CrashReportCategory crashreportcategory )
@@ -111,7 +107,12 @@ public class TickTracker implements Comparable<TickTracker>
public void setCurrentRate( final int currentRate )
{
this.currentRate = currentRate;
this.currentRate = Math.min( this.getRequest().maxTickRate, Math.max( this.getRequest().minTickRate, currentRate ) );
}
public long getNextTick()
{
return this.lastTick + this.currentRate;
}
public long getLastTick()
@@ -19,14 +19,13 @@
package appeng.me.cluster.implementations;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import appeng.api.config.Upgrades;
import appeng.helpers.DualityInterface;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import net.minecraft.inventory.InventoryCrafting;
@@ -34,8 +33,6 @@ import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.fml.common.FMLCommonHandler;
import appeng.api.AEApi;
import appeng.api.config.Actionable;
@@ -93,6 +90,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
private final List<TileCraftingTile> storage = new ArrayList<>();
private final List<TileCraftingMonitorTile> status = new ArrayList<>();
private final HashMap<IMEMonitorHandlerReceiver<IAEItemStack>, Object> listeners = new HashMap<>();
private final Map<ICraftingPatternDetails, Queue<ICraftingMedium>> visitedMediums = new HashMap<>();
private ICraftingLink myLastLink;
private String myName = "";
private boolean isDestroyed = false;
@@ -238,8 +236,9 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
public IAEItemStack injectItems( final IAEItemStack input, final Actionable type, final IActionSource src )
{
if( !( input instanceof IAEItemStack ) )
{
// also stop accepting items when the job is complete, i.e. to prevent re-insertion when pushing out
// items during storeItems
if (input == null || isComplete) {
return input;
}
@@ -297,7 +296,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{
is.decStackSize( what.getStackSize() );
this.updateElapsedTime( what );
this.updateRemainingItemCount( what );
this.markDirty();
this.postCraftingStatusChange( what.copy().setStackSize( -what.getStackSize() ) );
@@ -436,6 +435,11 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
AELog.crafting( LOG_MARK_AS_COMPLETE, logStack );
}
// Waiting for can potentially contain items at this point, if the user has a 64xplank->64xbutton processing
// recipe for example, but only requested 1xbutton. We just ignore the rest since it will be dumped
// back into the network inventory regardless. For this to work it's important that injectItems in this CPU
// does not accept any further items if isComplete is true.
this.waitingFor.resetStatus();
this.remainingItemCount = 0;
this.startItemCount = 0;
this.lastTime = 0;
@@ -490,31 +494,62 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
return null;
}
private boolean canCraft( final ICraftingPatternDetails details, final IAEItemStack[] condensedInputs )
private boolean canCraft(final ICraftingPatternDetails details, final IAEItemStack[] condensedInputs)
{
for( IAEItemStack g : condensedInputs )
if( !details.isCraftable() )
{
if( details.isCraftable() )
// Processing patterns are relatively easy
for ( IAEItemStack input : condensedInputs )
{
boolean found = false;
final IAEItemStack ais = this.inventory.extractItems( input.copy(), Actionable.SIMULATE,
this.machineSrc );
for( IAEItemStack fuzz : this.inventory.getItemList().findFuzzy( g, FuzzyMode.IGNORE_ALL ) )
if( ais == null || ais.getStackSize() < input.getStackSize() )
{
fuzz = fuzz.copy();
fuzz.setStackSize( g.getStackSize() );
final IAEItemStack ais = this.inventory.extractItems( fuzz, Actionable.SIMULATE, this.machineSrc );
final ItemStack is = ais == null ? ItemStack.EMPTY : ais.createItemStack();
return false;
}
}
}
else if( details.canSubstitute() )
{
// When substitutions are allowed, we have to keep track of which items we've reserved
IAEItemStack[] inputs = details.getInputs();
Map<IAEItemStack, Integer> consumedCount = new HashMap<>();
for ( int i = 0; i < inputs.length; i++ )
{
List<IAEItemStack> substitutes = details.getSubstituteInputs( i );
if( substitutes.isEmpty() )
{
continue;
}
if( !is.isEmpty() && is.getCount() == g.getStackSize() )
boolean found = false;
for ( IAEItemStack substitute : substitutes )
{
for ( IAEItemStack fuzz : this.inventory.getItemList().findFuzzy( substitute, FuzzyMode.IGNORE_ALL ) )
{
found = true;
break;
int alreadyConsumed = consumedCount.getOrDefault( fuzz, 0 );
if( fuzz.getStackSize() - alreadyConsumed <= 0 )
{
continue; // Already fully consumed by a previous slot of this recipe
}
fuzz = fuzz.copy();
fuzz.setStackSize( 1 ); // We're iterating over non condensed inputs which means there's 1 of each needed
final IAEItemStack ais = this.inventory.extractItems( fuzz, Actionable.SIMULATE,
this.machineSrc );
if( ais != null && ais.getStackSize() > 0 )
{
// Mark 1 of the stack as consumed
consumedCount.merge( fuzz, 1, Integer::sum );
found = true;
break;
}
}
else if( !is.isEmpty() )
if( found )
{
g = g.copy();
g.decStackSize( is.getCount() );
break;
}
}
@@ -523,16 +558,40 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
return false;
}
}
else
{
final IAEItemStack ais = this.inventory.extractItems( g.copy(), Actionable.SIMULATE, this.machineSrc );
final ItemStack is = ais == null ? ItemStack.EMPTY : ais.createItemStack();
if( is.isEmpty() || is.getCount() < g.getStackSize() )
}
else
{
// When no substitutions can occur, we can simply check that all items are accounted since
// each type of item should only occur once
for ( IAEItemStack g : condensedInputs )
{
boolean found = false;
for ( IAEItemStack fuzz : this.inventory.getItemList().findFuzzy( g, FuzzyMode.IGNORE_ALL ) )
{
fuzz = fuzz.copy();
fuzz.setStackSize( g.getStackSize() );
final IAEItemStack ais = this.inventory.extractItems( fuzz, Actionable.SIMULATE, this.machineSrc );
if( ais != null && ais.getStackSize() >= g.getStackSize() )
{
found = true;
break;
}
else if( ais != null )
{
g = g.copy();
g.decStackSize( ais.getStackSize() );
}
}
if( !found )
{
return false;
}
}
}
return true;
@@ -648,14 +707,22 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{
InventoryCrafting ic = null;
for( final ICraftingMedium m : cc.getMediums( e.getKey() ) )
if (!visitedMediums.containsKey( details ) || visitedMediums.get( details ).isEmpty())
{
visitedMediums.put( details, new ArrayDeque<>( cc.getMediums( details ).stream().filter( Objects::nonNull ).collect( Collectors.toList()) ) );
}
while (!visitedMediums.get( details ).isEmpty())
{
ICraftingMedium m = visitedMediums.get( details ).poll();
if( e.getValue().value <= 0 )
{
continue;
}
if( !m.isBusy() )
if( m != null && !m.isBusy() )
{
if( ic == null )
{
@@ -679,71 +746,67 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
ic = new InventoryCrafting( new ContainerNull(), 3, 3 );
boolean found = false;
for( int x = 0; x < input.length; x++ )
{
if( input[x] != null )
{
for (int x = 0; x < input.length; x++) {
if (input[x] != null) {
found = false;
if( details.isCraftable() )
{
if (details.isCraftable()) {
final Collection<IAEItemStack> itemList;
if( details.canSubstitute() )
{
itemList = this.inventory.getItemList().findFuzzy( input[x], FuzzyMode.IGNORE_ALL );
}
else
{
itemList = new ArrayList<>( 1 );
if (details.canSubstitute()) {
final List<IAEItemStack> substitutes = details.getSubstituteInputs(x);
itemList = new ArrayList<>(substitutes.size());
final IAEItemStack item = this.inventory.getItemList().findPrecise( input[x] );
for (IAEItemStack stack : substitutes) {
itemList.addAll(this.inventory.getItemList().findFuzzy(stack,
FuzzyMode.IGNORE_ALL));
}
} else {
itemList = new ArrayList<>(1);
if( item != null )
{
itemList.add( item );
final IAEItemStack item = this.inventory.getItemList()
.findPrecise(input[x]);
if (item != null) {
itemList.add(item);
}
}
for( IAEItemStack fuzz : itemList )
{
for (IAEItemStack fuzz : itemList) {
fuzz = fuzz.copy();
fuzz.setStackSize( input[x].getStackSize() );
fuzz.setStackSize(input[x].getStackSize());
if( details.isValidItemForSlot( x, fuzz.createItemStack(), this.getWorld() ) )
{
final IAEItemStack ais = this.inventory.extractItems( fuzz, Actionable.MODULATE, this.machineSrc );
final ItemStack is = ais == null ? ItemStack.EMPTY : ais.createItemStack();
if (details.isValidItemForSlot(x, fuzz.createItemStack(),
this.getWorld())) {
final IAEItemStack ais = this.inventory.extractItems(fuzz,
Actionable.MODULATE, this.machineSrc);
final ItemStack is = ais == null ? ItemStack.EMPTY
: ais.createItemStack();
if( !is.isEmpty() )
{
this.postChange( AEItemStack.fromItemStack( is ), this.machineSrc );
ic.setInventorySlotContents( x, is );
if (!is.isEmpty()) {
this.postChange(AEItemStack.fromItemStack(is), this.machineSrc);
ic.setInventorySlotContents(x, is);
found = true;
break;
}
}
}
}
else
{
final IAEItemStack ais = this.inventory.extractItems( input[x].copy(), Actionable.MODULATE, this.machineSrc );
} else {
final IAEItemStack ais = this.inventory.extractItems(input[x].copy(),
Actionable.MODULATE, this.machineSrc);
final ItemStack is = ais == null ? ItemStack.EMPTY : ais.createItemStack();
if( !is.isEmpty() )
{
this.postChange( input[x], this.machineSrc );
ic.setInventorySlotContents( x, is );
if( is.getCount() == input[x].getStackSize() )
{
if (!is.isEmpty()) {
this.postChange(input[x], this.machineSrc);
ic.setInventorySlotContents(x, is);
if (is.getCount() == input[x].getStackSize()) {
found = true;
continue;
}
}
}
if( !found )
{
if (!found) {
break;
}
}
@@ -779,10 +842,6 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
if( details.isCraftable() )
{
FMLCommonHandler.instance()
.firePlayerCraftingEvent( Platform.getPlayer( (WorldServer) this.getWorld() ),
details.getOutput( ic, this.getWorld() ), ic );
for( int x = 0; x < ic.getSizeInventory(); x++ )
{
final ItemStack output = Platform.getContainerItem( ic.getStackInSlot( x ) );
@@ -831,6 +890,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
private void storeItems()
{
Preconditions.checkState(isComplete, "CPU should be complete to prevent re-insertion when dumping items");
final IGrid g = this.getGrid();
if( g == null )
@@ -841,23 +901,24 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
final IStorageGrid sg = g.getCache( IStorageGrid.class );
final IMEInventory<IAEItemStack> ii = sg.getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) );
for( IAEItemStack is : this.inventory.getItemList() )
IItemList<IAEItemStack> itemList = this.inventory.getItemList();
for( IAEItemStack is : itemList )
{
is = this.inventory.extractItems( is.copy(), Actionable.MODULATE, this.machineSrc );
this.postChange( is, this.machineSrc );
IAEItemStack remainder = ii.injectItems( is.copy(), Actionable.MODULATE, this.machineSrc );
if( is != null )
// The network was unable to receive all of the items, i.e. no or not enough storage space left
if( remainder != null )
{
this.postChange( is, this.machineSrc );
is = ii.injectItems( is, Actionable.MODULATE, this.machineSrc );
is.setStackSize( remainder.getStackSize() );
}
if( is != null )
else
{
this.inventory.injectItems( is, Actionable.MODULATE, this.machineSrc );
is.reset();
}
}
if( this.inventory.getItemList().isEmpty() )
if( itemList.isEmpty() )
{
this.inventory = new MECraftingInventory();
}
@@ -942,14 +1003,13 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
@Override
public boolean isBusy()
{
final Iterator<Entry<ICraftingPatternDetails, TaskProgress>> i = this.tasks.entrySet().iterator();
while( i.hasNext() )
this.tasks.entrySet().removeIf(
taskProgressEntry -> taskProgressEntry.getValue().value <= 0 );
if( !this.waitingFor.isEmpty() || !this.tasks.isEmpty() )
{
if( i.next().getValue().value <= 0 )
{
i.remove();
}
this.updateElapsedTime();
}
return !this.tasks.isEmpty() || !this.waitingFor.isEmpty();
@@ -1119,7 +1179,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{
for( final IAEItemStack ais : t.getKey().getCondensedOutputs() )
{
if( ais.equals( is ) )
if( ais.isSameType( is ) )
{
is.setStackSize( is.getStackSize() + ais.getStackSize() * t.getValue().value );
}
@@ -1341,12 +1401,16 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
this.remainingItemCount = itemCount;
}
private void updateElapsedTime( final IAEItemStack is )
private void updateRemainingItemCount( final IAEItemStack is )
{
this.remainingItemCount = this.getRemainingItemCount() - is.getStackSize();
}
private void updateElapsedTime()
{
final long nextStartTime = System.nanoTime();
this.elapsedTime = this.getElapsedTime() + nextStartTime - this.lastTime;
this.lastTime = nextStartTime;
this.remainingItemCount = this.getRemainingItemCount() - is.getStackSize();
}
public long getElapsedTime()
@@ -123,4 +123,4 @@ public class GenericInterestManager<T>
this.iw = watcher;
}
}
}
}
@@ -28,8 +28,6 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import com.google.common.collect.ImmutableList;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable;
import appeng.api.networking.security.IActionSource;
@@ -85,11 +83,7 @@ public class MEMonitorHandler<T extends IAEStack<T>> implements IMEMonitor<T>
@Override
public T injectItems( final T input, final Actionable mode, final IActionSource src )
{
if( mode == Actionable.SIMULATE )
{
return this.getHandler().injectItems( input, mode, src );
}
return this.monitorDifference( input.copy(), this.getHandler().injectItems( input, mode, src ), false, src );
return this.getHandler().injectItems( input, mode, src );
}
protected IMEInventoryHandler<T> getHandler()
@@ -97,28 +91,7 @@ public class MEMonitorHandler<T extends IAEStack<T>> implements IMEMonitor<T>
return this.internalHandler;
}
private T monitorDifference( final T original, final T leftOvers, final boolean extraction, final IActionSource src )
{
final T diff = original.copy();
if( extraction )
{
diff.setStackSize( leftOvers == null ? 0 : -leftOvers.getStackSize() );
}
else if( leftOvers != null )
{
diff.decStackSize( leftOvers.getStackSize() );
}
if( diff.getStackSize() != 0 )
{
this.postChangesToListeners( ImmutableList.of( diff ), src );
}
return leftOvers;
}
protected void postChangesToListeners( final Iterable<T> changes, final IActionSource src )
public void postChangesToListeners( final Iterable<T> changes, final IActionSource src )
{
this.notifyListenersOfChange( changes, src );
}
@@ -150,11 +123,7 @@ public class MEMonitorHandler<T extends IAEStack<T>> implements IMEMonitor<T>
@Override
public T extractItems( final T request, final Actionable mode, final IActionSource src )
{
if( mode == Actionable.SIMULATE )
{
return this.getHandler().extractItems( request, mode, src );
}
return this.monitorDifference( request.copy(), this.getHandler().extractItems( request, mode, src ), true, src );
return this.getHandler().extractItems( request, mode, src );
}
@Override
@@ -19,6 +19,7 @@
package appeng.me.helpers;
import java.util.Objects;
import java.util.Optional;
import net.minecraft.entity.player.EntityPlayer;
@@ -55,4 +56,24 @@ public class MachineSource implements IActionSource
return Optional.empty();
}
@Override
public boolean equals( Object o )
{
if( this == o )
{
return true;
}
if( o == null || getClass() != o.getClass() )
{
return false;
}
MachineSource that = (MachineSource) o;
return via.equals( that.via );
}
@Override
public int hashCode()
{
return Objects.hash( via );
}
}
@@ -151,7 +151,7 @@ public abstract class AbstractCellInventory<T extends IAEStack<T>> implements IC
}
// clean any old crusty stuff...
for( ; x < oldStoredItems && x < this.maxItemTypes; x++ )
for( ; x >= oldStoredItems && x < this.maxItemTypes; x++ )
{
this.tagCompound.removeTag( ITEM_SLOT_KEYS[x] );
this.tagCompound.removeTag( ITEM_SLOT_COUNT_KEYS[x] );

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