Compare commits

...

215 Commits

Author SHA1 Message Date
PrototypeTrousers 7d1c502b41 workss 2022-04-04 15:44:22 -03:00
PrototypeTrousers 63653c1833 added packets for missing items report 2022-04-04 03:55:51 -03:00
PrototypeTrousers 6cadfbdcdc 3 2022-04-01 19:30:18 -03:00
PrototypeTrousers d054c6ab91 2 2022-04-01 19:30:18 -03:00
PrototypeTrousers 234b1c5dc6 meh. crafting gets stuck if the output loops 2022-04-01 19:30:18 -03:00
PrototypeTrousers 8cc29734a2 positive loop support 2022-04-01 19:30:18 -03:00
PrototypeTrousers 1e9e8d2639 more checks if "gregtech" mod is loaded 2022-03-31 21:16:14 -03:00
PrototypeTrousers 19c6e2ff2d support for IC2 damageable items 2022-03-27 08:52:37 -03:00
PrototypeTrousers 4f25c1551b increase internal buffer of ME Chest
Fix item amount not refreshing when inserted/extracted
2022-03-27 08:10:02 -03:00
PrototypeTrousers 3b94e9420d fix NPE with ae2fc and blocking mode 2022-03-25 23:46:52 -03:00
PrototypeTrousers f30f334a23 move nonblocking call out of method used by ae2fc coremod 2022-03-24 23:25:28 -03:00
PrototypeTrousers 706e577dab Fix container item crafting (again)
avoid making some copies
fix crash without JEI
2022-03-16 00:52:38 -03:00
PrototypeTrousers ccc8486571 check if gregtech is loaded before checking for MetaTools 2022-03-12 22:36:22 -03:00
PrototypeTrousers 3e8440644e fix autocrafting with container items 2022-03-12 22:21:04 -03:00
PrototypeTrousers 50f4e08b64 Merge remote-tracking branch 'origin/AE2-Omnifactory' into AE2-Omnifactory 2022-03-12 17:27:17 -03:00
PrototypeTrousers cfa9fa2843 invalidate cached itemstack if its gonna be used in a real insertion 2022-03-12 17:14:37 -03:00
PrototypeTrousers 47f819e021 invalidate cached itemstack if its gonna be used in a real insertion 2022-03-12 11:03:04 -03:00
PrototypeTrousers 6d151bb890 GTCEu blocking mode fix 2022-03-11 23:11:52 -03:00
PrototypeTrousers 3305270a71 clean-up 2022-03-11 22:04:58 -03:00
PrototypeTrousers f824bfd2e1 small optimization 2022-03-10 21:35:18 -03:00
PrototypeTrousers 036f4e1c5b heavily tweaked auto-crafting 2022-03-09 23:14:02 -03:00
PrototypeTrousers 146d3f5628 fix fluid dupe 2022-03-06 08:24:29 -03:00
PrototypeTrousers 9c821cb015 cleaning 2022-03-05 23:29:20 -03:00
PrototypeTrousers 3a83c99b1f fix container items return properly 2022-03-05 11:15:32 -03:00
PrototypeTrousers 447c6debab account for interfaces priority affecting which items are extractable 2022-03-04 22:49:55 -03:00
PrototypeTrousers 50470ae3cf version 2022-03-04 21:44:58 -03:00
PrototypeTrousers 993be652c9 delay container item return when simulating crafting tree 2022-03-04 21:30:26 -03:00
PrototypeTrousers b3bfbd0b58 remove debugging log 2022-03-04 17:08:23 -03:00
PrototypeTrousers 49b3dc8b60 undo partially pattern cache rebuild optimization
enabled pattern substitution now can use substitute patterned items
2022-03-03 22:25:10 -03:00
PrototypeTrousers 71ffcfb839 JEI transfer handler OutOfBounds fix 2022-03-01 13:02:09 -03:00
PrototypeTrousers 73f76a6654 clean up 2022-02-28 23:30:52 -03:00
PrototypeTrousers 645de1d868 Merge branch 'craftingtree-tweaks' into AE2-Omnifactory 2022-02-28 23:17:21 -03:00
PrototypeTrousers 8f40478695 version 2022-02-28 23:16:53 -03:00
PrototypeTrousers 056fcc3818 switch to extractable instead of cached item list 2022-02-28 23:16:53 -03:00
PrototypeTrousers 0ed0eb9d5f better logging 2022-02-28 23:16:49 -03:00
PrototypeTrousers 3ddc846648 Merge branch 'craftingtree-tweaks' into AE2-Omnifactory 2022-02-28 23:06:11 -03:00
PrototypeTrousers f98f6ef852 misc cleaning 2022-02-28 22:57:35 -03:00
PrototypeTrousers 4192d721a0 only fire simulation if a player requested it 2022-02-28 21:25:33 -03:00
PrototypeTrousers a0f3ef9d86 cut crafting tree earlier if ingredients are available 2022-02-28 21:25:13 -03:00
PrototypeTrousers 6b29288de6 remove crafting penalties 2022-02-28 00:13:07 -03:00
PrototypeTrousers 285fc6314c small optimization to crafting tree 2022-02-27 23:04:29 -03:00
PrototypeTrousers 50fd83e96b adjust default blocking mode settings 2022-02-25 00:09:33 -03:00
PrototypeTrousers cc51138a6a blocking mode changes again
misc cleaning
2022-02-24 23:54:50 -03:00
PrototypeTrousers 918df0bf7f clean up 2022-02-22 23:55:52 -03:00
PrototypeTrousers c852199901 bump version 2022-02-22 22:55:44 -03:00
PrototypeTrousers fd95d3de47 fixed typo gtceu -> gteu 2022-02-22 22:37:28 -03:00
PrototypeTrousers c3dd6dabe1 fix blocking mode again... 2022-02-22 22:11:57 -03:00
PrototypeTrousers b0e81ac2d1 fix blocking mode somehow voiding items 2022-02-22 19:40:15 -03:00
PrototypeTrousers 30f4cdf545 attempt at pattern rebuild optimization 2022-02-22 00:02:17 -03:00
PrototypeTrousers ee9441474e tweak cache reset on interface config 2022-02-21 18:25:58 -03:00
PrototypeTrousers 8846202270 More itemstacks caching
Micro optimization on molecular assemblers
2022-02-21 15:11:16 -03:00
PrototypeTrousers 17a900ae9a actually return if a crafting job is running 2022-02-19 23:03:33 -03:00
PrototypeTrousers 66bc243b41 cache more itemstacks 2022-02-19 23:02:40 -03:00
PrototypeTrousers a2bda8f449 tile fluid textures on fluid interfaces properly 2022-02-17 20:15:29 -03:00
PrototypeTrousers a2c2a4df0f oops, add integrated circuit to default non blocking items 2022-02-15 19:33:56 -03:00
PrototypeTrousers b4e237244a fix interfaces with crafting cards attached to storage bus not working
add missing buttons to oredict storagebus
2022-02-14 17:15:51 -03:00
PrototypeTrousers b541ad8d18 misc cleaning
add lenses to non blocking list
2022-02-10 20:15:58 -03:00
PrototypeTrousers 64f29a7dba make it work 2022-02-10 17:59:03 -03:00
PrototypeTrousers 6d25b7ef3c reworked blocking mode. now items are configurable per mod 2022-02-09 22:15:44 -03:00
PrototypeTrousers c3a608ef59 fix export busses exporting items out of nowhere 2022-01-31 16:51:06 -03:00
PrototypeTrousers af1f5c34d2 fix npe when placing down an ore dict storage bus 2022-01-30 17:19:01 -03:00
PrototypeTrousers f5378e060e fix importing from storage drawers 2022-01-29 17:21:12 -03:00
PrototypeTrousers 47407acc42 backport of #5823 - try emptying interfaces first before handling crafting jobs 2022-01-29 17:03:15 -03:00
PrototypeTrousers d7f3428824 fix for infinite loop while loading 2022-01-24 13:19:31 -03:00
PrototypeTrousers 63e339b88b cache itemstacks more aggressively 2022-01-24 13:17:50 -03:00
PrototypeTrousers 98761809fd add the patterns inside the terminal to the drop list of the terminal 2022-01-23 23:08:47 -03:00
PrototypeTrousers 8cb013b686 versioning 2022-01-22 23:19:49 -03:00
PrototypeTrousers f2fe376982 Merge pull request #74 from Syrcan/GTEU-fix
GTEU input fix
2022-01-22 23:06:39 -03:00
Syrcan 603452de1f GTEU input fix 2022-01-22 10:11:23 +01:00
PrototypeTrousers 40bd96d21c tweak crafting job size again
null check
2022-01-21 18:12:18 -03:00
PrototypeTrousers a14d160a07 Reworked oredict storage bus
have a recipe now
expression matcher and validator from GTCEU by brachy84
2022-01-20 22:43:18 -03:00
PrototypeTrousers df28a5520f fix mod name
implement GTCEU Energy adapter
2022-01-20 20:02:26 -03:00
PrototypeTrousers 0d096944cc Merge branch 'gtceu-p2p' into AE2-Omnifactory 2022-01-20 17:48:07 -03:00
PrototypeTrousers 963d3414d8 update version
more of renaming mod
2022-01-20 17:46:07 -03:00
PrototypeTrousers 4414451f5e more gtceu p2p fixes 2022-01-20 17:05:21 -03:00
PrototypeTrousers e0ddb92b81 attune gtce p2p with cables 2022-01-20 13:28:08 -03:00
PrototypeTrousers 6f551ad67f wip gtceu p2p 2022-01-20 00:04:04 -03:00
PrototypeTrousers fd3349614d fix terminal crashing and not cleaning leftovers of larger recipe patterns 2022-01-11 11:23:40 -03:00
PrototypeTrousers 903f211044 fix crash while configuring fluid storage bus 2022-01-10 03:17:46 -03:00
PrototypeTrousers 78e1e26a11 Fix issues with the expanded pattern terminal and its patterns crafting 2022-01-05 21:36:49 -03:00
PrototypeTrousers 2a6de11597 update version 2022-01-04 17:08:55 -03:00
PrototypeTrousers cd2b53af85 Cherry-picked 5554ba903e74c2980b2e395c78555b40fc379e80
Be more lenient with extended block states being passed by other mods.
2022-01-04 17:01:55 -03:00
PrototypeTrousers 1c5565491a finish oredict storage bus 2022-01-03 13:16:27 -03:00
PrototypeTrousers 311cc5c6f6 more oredictbus work 2022-01-03 11:32:48 -03:00
PrototypeTrousers 41796449ed cache oredict filter list 2022-01-03 10:47:35 -03:00
PrototypeTrousers 9eef9d3840 partial implementation of oredict storage bus
missing proper GUI, text, item models, memorycard support.
logic works
2022-01-03 02:33:08 -03:00
PrototypeTrousers 13afa6908a implement expanded processing pattern terminal 2022-01-02 18:27:41 -03:00
PrototypeTrousers 103438f805 do full reset level emitter on stack update 2021-12-13 02:02:02 -03:00
PrototypeTrousers eaa01f7648 flip some boolean so craftables actually show up 2021-12-10 20:26:29 -03:00
PrototypeTrousers e81fb09599 when in off-hand, memory card wild paste as input 2021-12-10 14:02:56 -03:00
PrototypeTrousers 94d73aec7c wwww 2021-12-09 23:34:57 -03:00
PrototypeTrousers b51af43dba item/fluid count changes.. again 2021-12-07 21:10:04 -03:00
PrototypeTrousers 85dc8ae7c1 item costs/ghost fixes 2021-11-29 00:50:32 -03:00
PrototypeTrousers c34176f392 fix (?) item desync issues 2021-11-23 20:25:05 -03:00
PrototypeTrousers 76fe2175a0 moved p2p forge event to an upper class
add an extra update after the network has finished booting
2021-11-15 00:09:04 -03:00
PrototypeTrousers c5d33ed892 p2p fixes redton, light, items 2021-11-11 20:54:40 -03:00
PrototypeTrousers b423d99879 tweak crafting byte costs 2021-11-02 17:56:12 -03:00
PrototypeTrousers 81156b411d version 2021-11-02 15:34:45 -03:00
PrototypeTrousers 6be1660d41 Merge branch 'item-issues' into AE2-Omnifactory 2021-11-02 15:34:02 -03:00
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
192 changed files with 9810 additions and 4745 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)
+1 -1
View File
@@ -57,7 +57,7 @@ tasks.withType(JavaCompile) {
options.encoding = 'UTF-8' options.encoding = 'UTF-8'
} }
version = aeversion + "-" + aechannel + "-" + aebuild + " " + trousers version = aeversion + "-" + aechannel + "-" + aebuild + "-" + extended + "-" + extendedversion
group = aegroup group = aegroup
archivesBaseName = aebasename archivesBaseName = aebasename
+3 -5
View File
@@ -3,20 +3,18 @@ aechannel=stable
aebuild=7 aebuild=7
aegroup=appeng aegroup=appeng
aebasename=appliedenergistics2 aebasename=appliedenergistics2
trousers=omni-fixes-v21b extended=extended_life
extendedversion=v52b
######################################################### #########################################################
# Versions # # Versions #
######################################################### #########################################################
minecraft_version=1.12.2 minecraft_version=1.12.2
mcp_mappings=snapshot_20171003 mcp_mappings=snapshot_20171003
forge_version=14.23.5.2847 forge_version=14.23.5.2847
######################################################### #########################################################
# Installable # # Installable #
######################################################### #########################################################
hwyla_version=1.8.26-B41_1.12.2 hwyla_version=1.8.26-B41_1.12.2
######################################################### #########################################################
# Provided APIs # # Provided APIs #
######################################################### #########################################################
@@ -28,7 +26,7 @@ cofhcore_version=1.12.2-4.5.2.19
crafttweaker_version=4.1.8.9 crafttweaker_version=4.1.8.9
inventorytweaks_version=1.63 inventorytweaks_version=1.63
ctm_version=MC1.12.2-0.3.1.16 ctm_version=MC1.12.2-0.3.1.16
forestry_version=5.8.2.387
######################################################### #########################################################
# Deployment # # Deployment #
######################################################### #########################################################
+15 -18
View File
@@ -19,11 +19,6 @@
repositories { repositories {
mavenLocal() mavenLocal()
maven {
name = "storagedrawers"
url = "https://dl.bintray.com/jaquadro/dev/"
}
maven { maven {
name "Mobius" name "Mobius"
url "http://mobiusstrip.eu/maven" url "http://mobiusstrip.eu/maven"
@@ -36,7 +31,12 @@ repositories {
maven { maven {
name = "Tesla repo" name = "Tesla repo"
url "http://maven.mcmoddev.com" url "https://maven.mcmoddev.com"
}
maven {
name "Ellpeck"
url "https://maven.ellpeck.de"
} }
maven { maven {
@@ -59,12 +59,7 @@ repositories {
url "http://maven.k-4u.nl/" url "http://maven.k-4u.nl/"
} }
maven { // Hwyla maven { // CraftTweaker
name 'tehnut'
url "http://tehnut.info/maven"
}
maven { // CraftTweaker
name 'jared maven' name 'jared maven'
url "http://maven.blamejared.com/" url "http://maven.blamejared.com/"
} }
@@ -75,9 +70,9 @@ repositories {
//} //}
maven { maven {
name = "CurseForge" name = "CurseForge"
url = "https://minecraft.curseforge.com/api/maven/" url = "https://minecraft.curseforge.com/api/maven/"
} }
} }
configurations { configurations {
@@ -85,8 +80,7 @@ configurations {
} }
dependencies { dependencies {
compileOnly "gregtechce:gregtech:1.12.2:1.12.0.662" deobfCompile "gregtechce:gregtech:1.12.2:1.15.1.735"
// installable runtime dependencies // installable runtime dependencies
mods "mcp.mobius.waila:Hwyla:${hwyla_version}" mods "mcp.mobius.waila:Hwyla:${hwyla_version}"
mods "net.industrial-craft:industrialcraft-2:${ic2_version}:dev" mods "net.industrial-craft:industrialcraft-2:${ic2_version}:dev"
@@ -100,8 +94,11 @@ dependencies {
compileOnly "mcjty.theoneprobe:TheOneProbe-1.12:${top_version}:api" compileOnly "mcjty.theoneprobe:TheOneProbe-1.12:${top_version}:api"
compileOnly "cofh:CoFHCore:${cofhcore_version}:deobf" compileOnly "cofh:CoFHCore:${cofhcore_version}:deobf"
compileOnly "CraftTweaker2:CraftTweaker2-API:${crafttweaker_version}" compileOnly "CraftTweaker2:CraftTweaker2-API:${crafttweaker_version}"
compileOnly "inventory-tweaks:InventoryTweaks:${inventorytweaks_version}:api" compileOnly "inventory-tweaks:InventoryTweaks:${inventorytweaks_version}:api"
compileOnly "team.chisel.ctm:CTM:${ctm_version}" compileOnly "team.chisel.ctm:CTM:${ctm_version}"
compileOnly "de.ellpeck.actuallyadditions:ActuallyAdditions:1.12.2-r152.16:api"
deobfCompile "net.sengir.forestry:forestry_${minecraft_version}:$forestry_version"
// at runtime, use the full JEI jar // at runtime, use the full JEI jar
runtime "mezz.jei:jei_${minecraft_version}:${jei_version}" runtime "mezz.jei:jei_${minecraft_version}:${jei_version}"
@@ -28,7 +28,8 @@ public enum PowerUnits
{ {
AE( "gui.appliedenergistics2.units.appliedenergstics" ), // Native Units - AE Energy AE( "gui.appliedenergistics2.units.appliedenergstics" ), // Native Units - AE Energy
EU( "gui.appliedenergistics2.units.ic2" ), // IndustrialCraft 2 - Energy Units EU( "gui.appliedenergistics2.units.ic2" ), // IndustrialCraft 2 - Energy Units
RF( "gui.appliedenergistics2.units.rf" ); // RF - Redstone Flux RF( "gui.appliedenergistics2.units.rf" ), // RF - Redstone Flux
GTEU( "gui.appliedenergistics2.units.gteu" ); // RF - Redstone Flux
/** /**
* unlocalized name for the power unit. * unlocalized name for the power unit.
@@ -46,14 +47,13 @@ public enum PowerUnits
/** /**
* do power conversion using AE's conversion rates. * do power conversion using AE's conversion rates.
* * <p>
* Example: PowerUnits.EU.convertTo( PowerUnits.AE, 32 ); * Example: PowerUnits.EU.convertTo( PowerUnits.AE, 32 );
* * <p>
* will normally returns 64, as it will convert the EU, to AE with AE's power settings. * will normally returns 64, as it will convert the EU, to AE with AE's power settings.
* *
* @param target target power unit * @param target target power unit
* @param value value * @param value value
*
* @return value converted to target units, from this units. * @return value converted to target units, from this units.
*/ */
public double convertTo( final PowerUnits target, final double value ) public double convertTo( final PowerUnits target, final double value )
@@ -29,6 +29,7 @@ public enum TunnelType
ME, // Network Tunnel ME, // Network Tunnel
IC2_POWER, // EU Tunnel IC2_POWER, // EU Tunnel
FE_POWER, // Forge Energy tunnel FE_POWER, // Forge Energy tunnel
GTEU_POWER, // Forge Energy tunnel
REDSTONE, // Redstone Tunnel REDSTONE, // Redstone Tunnel
FLUID, // Fluid Tunnel FLUID, // Fluid Tunnel
ITEM, // Item Tunnel ITEM, // Item Tunnel
+2 -1
View File
@@ -46,7 +46,8 @@ public enum Upgrades
*/ */
FUZZY( 1 ), FUZZY( 1 ),
SPEED( 1 ), SPEED( 1 ),
INVERTER( 1 ); INVERTER( 1 ),
PATTERN_EXPANSION(1);
private final int tier; private final int tier;
private final Map<ItemStack, Integer> supportedMax = new HashMap<>(); private final Map<ItemStack, Integer> supportedMax = new HashMap<>();
@@ -89,6 +89,8 @@ public interface IMaterials
IItemDefinition cardCapacity(); IItemDefinition cardCapacity();
IItemDefinition cardPatternExpansion();
IItemDefinition cardFuzzy(); IItemDefinition cardFuzzy();
IItemDefinition cardInverter(); IItemDefinition cardInverter();
@@ -58,6 +58,8 @@ public interface IParts
IItemDefinition storageBus(); IItemDefinition storageBus();
IItemDefinition oreDictStorageBus();
IItemDefinition importBus(); IItemDefinition importBus();
IItemDefinition exportBus(); IItemDefinition exportBus();
@@ -86,6 +88,8 @@ public interface IParts
IItemDefinition p2PTunnelFE(); IItemDefinition p2PTunnelFE();
IItemDefinition p2PTunnelGTEU();
IItemDefinition p2PTunnelLight(); IItemDefinition p2PTunnelLight();
// IItemDefinition p2PTunnelOpenComputers(); // IItemDefinition p2PTunnelOpenComputers();
@@ -102,6 +106,8 @@ public interface IParts
IItemDefinition patternTerminal(); IItemDefinition patternTerminal();
IItemDefinition expandedProcessingPatternTerminal();
IItemDefinition craftingTerminal(); IItemDefinition craftingTerminal();
IItemDefinition terminal(); IItemDefinition terminal();
@@ -31,6 +31,9 @@ import net.minecraft.world.World;
import appeng.api.implementations.ICraftingPatternItem; import appeng.api.implementations.ICraftingPatternItem;
import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IAEItemStack;
import java.util.Collections;
import java.util.List;
/** /**
* do not implement provided by {@link ICraftingPatternItem} * do not implement provided by {@link ICraftingPatternItem}
@@ -84,6 +87,11 @@ public interface ICraftingPatternDetails
*/ */
boolean canSubstitute(); 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. * 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. * Called when a watched item changes amounts.
* *
* @param o changed item list
* @param fullStack old stack
* @param diffStack new stack * @param diffStack new stack
* @param src action source
* @param chan storage channel * @param chan storage channel
*/ */
void onStackChange( IItemList<?> o, IAEStack<?> fullStack, IAEStack<?> diffStack, IActionSource src, IStorageChannel<?> chan ); 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 * @param input injected items
*/ */
void postAlterationOfStoredItems( IStorageChannel<?> chan, Iterable<? extends IAEStack<?>> input, IActionSource src ); 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 * Used to add a cell provider to the storage system
@@ -112,4 +112,17 @@ public interface IAEItemStack extends IAEStack<IAEItemStack>
* @return definition stack * @return definition stack
*/ */
ItemStack getDefinition(); 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 );
ItemStack getCachedItemStack( long stackSize );
void setCachedItemStack( ItemStack is );
} }
@@ -56,7 +56,7 @@ public class BlockMolecularAssembler extends AEBaseTileBlock
@Override @Override
protected IProperty[] getAEStates() protected IProperty[] getAEStates()
{ {
return new IProperty[] { POWERED }; return new IProperty[]{POWERED};
} }
@Override @Override
@@ -108,4 +108,14 @@ public class BlockMolecularAssembler extends AEBaseTileBlock
return super.onBlockActivated( w, pos, state, p, hand, side, hitX, hitY, hitZ ); return super.onBlockActivated( w, pos, state, p, hand, side, hitX, hitY, hitZ );
} }
@Override
public void onNeighborChange( IBlockAccess world, BlockPos pos, BlockPos neighbor )
{
final TileMolecularAssembler tg = this.getTileEntity( world, pos );
if( tg != null )
{
tg.updateNeighbors( world, pos, neighbor );
}
}
} }
@@ -20,6 +20,7 @@ package appeng.capabilities;
import com.jaquadro.minecraft.storagedrawers.api.capabilities.IItemRepository; import com.jaquadro.minecraft.storagedrawers.api.capabilities.IItemRepository;
import gregtech.api.capability.IEnergyContainer;
import net.darkhax.tesla.api.ITeslaConsumer; import net.darkhax.tesla.api.ITeslaConsumer;
import net.darkhax.tesla.api.ITeslaHolder; import net.darkhax.tesla.api.ITeslaHolder;
import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTBase;
@@ -57,6 +58,8 @@ public final class Capabilities
public static Capability<IItemRepository> ITEM_REPOSITORY_CAPABILITY; public static Capability<IItemRepository> ITEM_REPOSITORY_CAPABILITY;
public static Capability<IEnergyContainer> GTCE_ENERGY;
/** /**
* Register AE2 provided capabilities. * Register AE2 provided capabilities.
*/ */
@@ -103,7 +106,19 @@ public final class Capabilities
} }
@CapabilityInject( IItemRepository.class ) @CapabilityInject( IItemRepository.class )
private static void capIItemRepositoryRegistered( Capability<IItemRepository> cap ) { ITEM_REPOSITORY_CAPABILITY = cap; } private static void capIItemRepositoryRegistered( Capability<IItemRepository> cap )
{
ITEM_REPOSITORY_CAPABILITY = cap;
}
@CapabilityInject( IEnergyContainer.class )
private static void capIEnergyContainerRegistered( Capability<IEnergyContainer> cap )
{
if( IntegrationRegistry.INSTANCE.isEnabled( IntegrationType.GTCE ) )
{
GTCE_ENERGY = cap;
}
}
// Create a storage implementation that does not do anything // Create a storage implementation that does not do anything
private static <T> Capability.IStorage<T> createNullStorage() private static <T> Capability.IStorage<T> createNullStorage()
+24 -37
View File
@@ -33,6 +33,7 @@ import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import appeng.container.slot.*; import appeng.container.slot.*;
import appeng.util.Platform;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
@@ -159,7 +160,7 @@ public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContain
final List<Slot> slots = this.getInventorySlots(); final List<Slot> slots = this.getInventorySlots();
final Iterator<Slot> i = slots.iterator(); final Iterator<Slot> i = slots.iterator();
while( i.hasNext() ) while ( i.hasNext() )
{ {
if( i.next() instanceof SlotME ) if( i.next() instanceof SlotME )
{ {
@@ -208,13 +209,17 @@ public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContain
} }
} }
GlStateManager.enableDepth(); GlStateManager.enableDepth();
bookmarkedJEIghostItem(mouseX,mouseY); if( Platform.isModLoaded( "jei" ) )
{
bookmarkedJEIghostItem( mouseX, mouseY );
}
GlStateManager.disableDepth(); GlStateManager.disableDepth();
} }
void bookmarkedJEIghostItem(final int mouseX, final int mouseY) { @Optional.Method( modid = "jei" )
void bookmarkedJEIghostItem( final int mouseX, final int mouseY )
if (!isJeiGhostItem) {
if( !isJeiGhostItem )
{ {
bookmarkedIngredient = runtime.getBookmarkOverlay().getIngredientUnderMouse(); bookmarkedIngredient = runtime.getBookmarkOverlay().getIngredientUnderMouse();
} }
@@ -248,7 +253,9 @@ public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContain
} }
} }
} }
private void drawTargets(int mouseX, int mouseY) {
private void drawTargets( int mouseX, int mouseY )
{
GlStateManager.disableLighting(); GlStateManager.disableLighting();
for( IGhostIngredientHandler.Target target : hoveredIngredientTargets ) for( IGhostIngredientHandler.Target target : hoveredIngredientTargets )
{ {
@@ -377,17 +384,13 @@ public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContain
final AppEngSlot aeSlot = (AppEngSlot) slot; final AppEngSlot aeSlot = (AppEngSlot) slot;
if( aeSlot.isSlotEnabled() ) if( aeSlot.isSlotEnabled() )
{ {
this.drawTexturedModalRect( ox + aeSlot.xPos - 1, oy + aeSlot.yPos - 1, optionalSlot.getSourceX() - 1, optionalSlot.getSourceY() - 1, this.drawTexturedModalRect( ox + aeSlot.xPos - 1, oy + aeSlot.yPos - 1, optionalSlot.getSourceX() - 1, optionalSlot.getSourceY() - 1, 18, 18 );
18,
18 );
} }
else else
{ {
GlStateManager.color( 1.0F, 1.0F, 1.0F, 0.4F ); GlStateManager.color( 1.0F, 1.0F, 1.0F, 0.4F );
GlStateManager.enableBlend(); GlStateManager.enableBlend();
this.drawTexturedModalRect( ox + aeSlot.xPos - 1, oy + aeSlot.yPos - 1, optionalSlot.getSourceX() - 1, optionalSlot.getSourceY() - 1, this.drawTexturedModalRect( ox + aeSlot.xPos - 1, oy + aeSlot.yPos - 1, optionalSlot.getSourceX() - 1, optionalSlot.getSourceY() - 1, 18, 18 );
18,
18 );
GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F ); GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F );
} }
} }
@@ -506,7 +509,7 @@ public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContain
{ {
final EntityPlayer player = Minecraft.getMinecraft().player; final EntityPlayer player = Minecraft.getMinecraft().player;
if( this.isJeiGhostItem && isDraggingJeiGhostItem) if( this.isJeiGhostItem && isDraggingJeiGhostItem )
{ {
for( IGhostIngredientHandler.Target target : hoveredIngredientTargets ) for( IGhostIngredientHandler.Target target : hoveredIngredientTargets )
{ {
@@ -759,7 +762,8 @@ public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContain
this.disableShiftClick = false; this.disableShiftClick = false;
} }
if (clickType == ClickType.PICKUP && isJeiGhostItem && !isDraggingJeiGhostItem) { if( clickType == ClickType.PICKUP && isJeiGhostItem && !isDraggingJeiGhostItem )
{
this.isDraggingJeiGhostItem = true; this.isDraggingJeiGhostItem = true;
return; return;
} }
@@ -879,7 +883,7 @@ public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContain
if( stack != ItemStack.EMPTY ) if( stack != ItemStack.EMPTY )
{ {
InventoryAction direction = wheel > 0 ? InventoryAction.PLACE_SINGLE : InventoryAction.PICKUP_SINGLE; InventoryAction direction = wheel > 0 ? InventoryAction.PLACE_SINGLE : InventoryAction.PICKUP_SINGLE;
final PacketInventoryAction p = new PacketInventoryAction( direction , slot.slotNumber , 0); final PacketInventoryAction p = new PacketInventoryAction( direction, slot.slotNumber, 0 );
NetworkHandler.instance().sendToServer( p ); NetworkHandler.instance().sendToServer( p );
} }
} }
@@ -1032,27 +1036,11 @@ public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContain
final float f1 = 0.00390625F; final float f1 = 0.00390625F;
final float f = 0.00390625F; final float f = 0.00390625F;
final float par6 = 16; final float par6 = 16;
vb.pos( par1 + 0, par2 + par6, this.zLevel ) vb.pos( par1 + 0, par2 + par6, this.zLevel ).tex( ( par3 + 0 ) * f, ( par4 + par6 ) * f1 ).color( 1.0f, 1.0f, 1.0f, aes.getOpacityOfIcon() ).endVertex();
.tex( ( par3 + 0 ) * f, ( par4 + par6 ) * f1 )
.color( 1.0f, 1.0f, 1.0f,
aes.getOpacityOfIcon() )
.endVertex();
final float par5 = 16; final float par5 = 16;
vb.pos( par1 + par5, par2 + par6, this.zLevel ) vb.pos( par1 + par5, par2 + par6, this.zLevel ).tex( ( par3 + par5 ) * f, ( par4 + par6 ) * f1 ).color( 1.0f, 1.0f, 1.0f, aes.getOpacityOfIcon() ).endVertex();
.tex( ( par3 + par5 ) * f, ( par4 + par6 ) * f1 ) vb.pos( par1 + par5, par2 + 0, this.zLevel ).tex( ( par3 + par5 ) * f, ( par4 + 0 ) * f1 ).color( 1.0f, 1.0f, 1.0f, aes.getOpacityOfIcon() ).endVertex();
.color( 1.0f, 1.0f, 1.0f, vb.pos( par1 + 0, par2 + 0, this.zLevel ).tex( ( par3 + 0 ) * f, ( par4 + 0 ) * f1 ).color( 1.0f, 1.0f, 1.0f, aes.getOpacityOfIcon() ).endVertex();
aes.getOpacityOfIcon() )
.endVertex();
vb.pos( par1 + par5, par2 + 0, this.zLevel )
.tex( ( par3 + par5 ) * f, ( par4 + 0 ) * f1 )
.color( 1.0f, 1.0f, 1.0f,
aes.getOpacityOfIcon() )
.endVertex();
vb.pos( par1 + 0, par2 + 0, this.zLevel )
.tex( ( par3 + 0 ) * f, ( par4 + 0 ) * f1 )
.color( 1.0f, 1.0f, 1.0f,
aes.getOpacityOfIcon() )
.endVertex();
tessellator.draw(); tessellator.draw();
} }
@@ -1066,8 +1054,7 @@ public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContain
{ {
if( ( (AppEngSlot) s ).getIsValid() == hasCalculatedValidness.NotAvailable ) if( ( (AppEngSlot) s ).getIsValid() == hasCalculatedValidness.NotAvailable )
{ {
boolean isValid = s.isItemValid( boolean isValid = s.isItemValid( is ) || s instanceof SlotOutput || s instanceof AppEngCraftingSlot || s instanceof SlotDisabled || s instanceof SlotInaccessible || s instanceof SlotFake || s instanceof SlotRestrictedInput || s instanceof SlotDisconnected;
is ) || s instanceof SlotOutput || s instanceof AppEngCraftingSlot || s instanceof SlotDisabled || s instanceof SlotInaccessible || s instanceof SlotFake || s instanceof SlotRestrictedInput || s instanceof SlotDisconnected;
if( isValid && s instanceof SlotRestrictedInput ) if( isValid && s instanceof SlotRestrictedInput )
{ {
try try
@@ -104,7 +104,7 @@ public class AEGuiHandler implements IAdvancedGuiHandler<AEBaseGui>, IGhostIngre
} }
if( doStart && GuiScreen.isShiftKeyDown() && Mouse.isButtonDown( 0 ) ) if( doStart && GuiScreen.isShiftKeyDown() && Mouse.isButtonDown( 0 ) )
{ {
if( gui instanceof GuiUpgradeable || gui instanceof GuiPatternTerm ) if( gui instanceof GuiUpgradeable || gui instanceof GuiPatternTerm || gui instanceof GuiExpandedProcessingPatternTerm )
{ {
IJEIGhostIngredients ghostGui = ( (IJEIGhostIngredients) gui ); IJEIGhostIngredients ghostGui = ( (IJEIGhostIngredients) gui );
for( Target<I> target : targets ) for( Target<I> target : targets )
@@ -21,6 +21,7 @@ package appeng.client.gui.implementations;
import java.io.IOException; import java.io.IOException;
import appeng.parts.reporting.PartExpandedProcessingPatternTerminal;
import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiButton;
import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@@ -123,6 +124,12 @@ public class GuiCraftAmount extends AEBaseGui
this.originalGui = GuiBridge.GUI_PATTERN_TERMINAL; this.originalGui = GuiBridge.GUI_PATTERN_TERMINAL;
} }
if( target instanceof PartExpandedProcessingPatternTerminal )
{
myIcon = parts.expandedProcessingPatternTerminal().maybeStack( 1 ).orElse( ItemStack.EMPTY );
this.originalGui = GuiBridge.GUI_EXPANDED_PROCESSING_PATTERN_TERMINAL;
}
if( this.originalGui != null && !myIcon.isEmpty() ) if( this.originalGui != null && !myIcon.isEmpty() )
{ {
this.buttonList.add( this.originalGuiBtn = new GuiTabButton( this.guiLeft + 154, this.guiTop, myIcon, myIcon.getDisplayName(), this.itemRender ) ); this.buttonList.add( this.originalGuiBtn = new GuiTabButton( this.guiLeft + 154, this.guiTop, myIcon, myIcon.getDisplayName(), this.itemRender ) );
@@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import appeng.parts.reporting.PartExpandedProcessingPatternTerminal;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import org.lwjgl.input.Mouse; import org.lwjgl.input.Mouse;
@@ -104,6 +105,11 @@ public class GuiCraftConfirm extends AEBaseGui
{ {
this.OriginalGui = GuiBridge.GUI_PATTERN_TERMINAL; this.OriginalGui = GuiBridge.GUI_PATTERN_TERMINAL;
} }
if( te instanceof PartExpandedProcessingPatternTerminal )
{
this.OriginalGui = GuiBridge.GUI_EXPANDED_PROCESSING_PATTERN_TERMINAL;
}
} }
boolean isAutoStart() boolean isAutoStart()
@@ -25,6 +25,7 @@ package appeng.client.gui.implementations;
import java.io.IOException; import java.io.IOException;
import appeng.parts.reporting.PartExpandedProcessingPatternTerminal;
import org.lwjgl.input.Mouse; import org.lwjgl.input.Mouse;
import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiButton;
@@ -95,6 +96,12 @@ public class GuiCraftingStatus extends GuiCraftingCPU
this.originalGui = GuiBridge.GUI_PATTERN_TERMINAL; this.originalGui = GuiBridge.GUI_PATTERN_TERMINAL;
} }
if( target instanceof PartExpandedProcessingPatternTerminal )
{
myIcon = parts.expandedProcessingPatternTerminal().maybeStack( 1 ).orElse( ItemStack.EMPTY );
this.originalGui = GuiBridge.GUI_EXPANDED_PROCESSING_PATTERN_TERMINAL;
}
} }
@Override @Override
@@ -0,0 +1,277 @@
package appeng.client.gui.implementations;
import appeng.api.config.ActionItems;
import appeng.api.config.ItemSubstitution;
import appeng.api.config.Settings;
import appeng.api.storage.ITerminalHost;
import appeng.client.gui.widgets.GuiImgButton;
import appeng.client.gui.widgets.GuiTabButton;
import appeng.container.implementations.ContainerExpandedProcessingPatternTerm;
import appeng.container.interfaces.IJEIGhostIngredients;
import appeng.container.slot.AppEngSlot;
import appeng.container.slot.SlotFake;
import appeng.core.AELog;
import appeng.core.localization.GuiText;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketInventoryAction;
import appeng.core.sync.packets.PacketValueConfig;
import appeng.helpers.InventoryAction;
import appeng.util.item.AEItemStack;
import mezz.jei.api.gui.IGhostIngredientHandler;
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 java.awt.Rectangle;
import java.io.IOException;
import java.util.*;
public class GuiExpandedProcessingPatternTerm extends GuiMEMonitorable implements IJEIGhostIngredients
{
private static final String BACKGROUND_EXPANDED_PROCESSING_MODE = "guis/pattern_processing_expanded.png";
private static final String SUBSITUTION_DISABLE = "0";
private static final String SUBSITUTION_ENABLE = "1";
private static final String CRAFTMODE_CRFTING = "1";
private static final String CRAFTMODE_PROCESSING = "0";
private GuiTabButton tabCraftButton;
private GuiTabButton tabProcessButton;
private GuiImgButton substitutionsEnabledBtn;
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<IGhostIngredientHandler.Target<?>, Object> mapTargetSlot = new HashMap<>();
public GuiExpandedProcessingPatternTerm( final InventoryPlayer inventoryPlayer, final ITerminalHost te )
{
super( inventoryPlayer, te, new ContainerExpandedProcessingPatternTerm( inventoryPlayer, te ) );
this.setReservedSpace( 81 );
}
@Override
protected void actionPerformed( final GuiButton btn )
{
super.actionPerformed( btn );
try
{
if( this.tabCraftButton == btn || this.tabProcessButton == btn )
{
NetworkHandler.instance().sendToServer( new PacketValueConfig( "PatternTerminal.CraftMode", this.tabProcessButton == btn ? CRAFTMODE_CRFTING : CRAFTMODE_PROCESSING ) );
}
if( this.encodeBtn == btn )
{
if( isShiftKeyDown() )
{
NetworkHandler.instance().sendToServer( new PacketValueConfig( "PatternTerminal.Encode", "2" ) );
}
else
{
NetworkHandler.instance().sendToServer( new PacketValueConfig( "PatternTerminal.Encode", "1" ) );
}
}
if( this.clearBtn == btn )
{
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().sendToServer( new PacketValueConfig( "PatternTerminal.Substitute", this.substitutionsEnabledBtn == btn ? SUBSITUTION_DISABLE : SUBSITUTION_ENABLE ) );
}
}
catch( final IOException e )
{
AELog.error( e );
}
}
@Override
public void initGui()
{
super.initGui();
this.tabCraftButton = new GuiTabButton( this.guiLeft + 173, this.guiTop + this.ySize - 177, new ItemStack( Blocks.CRAFTING_TABLE ), GuiText.CraftingPattern.getLocal(), this.itemRender );
this.buttonList.add( this.tabCraftButton );
this.tabProcessButton = new GuiTabButton( this.guiLeft + 173, this.guiTop + this.ySize - 177, new ItemStack( Blocks.FURNACE ), GuiText.ProcessingPattern.getLocal(), this.itemRender );
this.buttonList.add( this.tabProcessButton );
this.substitutionsEnabledBtn = new GuiImgButton( this.guiLeft + 84, this.guiTop + this.ySize - 163, Settings.ACTIONS, ItemSubstitution.ENABLED );
this.substitutionsEnabledBtn.setHalfSize( true );
this.buttonList.add( this.substitutionsEnabledBtn );
this.substitutionsDisabledBtn = new GuiImgButton( this.guiLeft + 84, this.guiTop + this.ySize - 163, Settings.ACTIONS, ItemSubstitution.DISABLED );
this.substitutionsDisabledBtn.setHalfSize( true );
this.buttonList.add( this.substitutionsDisabledBtn );
this.clearBtn = new GuiImgButton( this.guiLeft + 74, this.guiTop + this.ySize - 163, Settings.ACTIONS, ActionItems.CLOSE );
this.clearBtn.setHalfSize( true );
this.buttonList.add( this.clearBtn );
this.x3Btn = new GuiImgButton( this.guiLeft + 131, 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 + 131, 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 + 131, this.guiTop + this.ySize - 110, Settings.ACTIONS, ActionItems.INCREASE_BY_ONE );
this.plusOneBtn.setHalfSize( true );
this.buttonList.add( this.plusOneBtn );
this.divThreeBtn = new GuiImgButton( this.guiLeft + 87, 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 + 87, 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 + 87, this.guiTop + this.ySize - 110, 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 );
}
@Override
public void drawFG( final int offsetX, final int offsetY, final int mouseX, final int mouseY )
{
this.tabCraftButton.visible = false;
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 );
this.fontRenderer.drawString( GuiText.PatternTerminal.getLocal(), 8, this.ySize - 96 + 2 - this.getReservedSpace(), 4210752 );
}
@Override
protected String getBackground()
{
return BACKGROUND_EXPANDED_PROCESSING_MODE;
}
@Override
protected void repositionSlot( final AppEngSlot s )
{
final int offsetPlayerSide = s.isPlayerSide() ? 5 : 3;
s.yPos = s.getY() + this.ySize - 78 - offsetPlayerSide;
}
@Override
public List<IGhostIngredientHandler.Target<?>> getPhantomTargets( Object ingredient )
{
if( !( ingredient instanceof ItemStack ) )
{
return Collections.emptyList();
}
List<IGhostIngredientHandler.Target<?>> targets = new ArrayList<>();
for( Slot slot : this.inventorySlots.inventorySlots )
{
if( slot instanceof SlotFake )
{
ItemStack itemStack = (ItemStack) ingredient;
IGhostIngredientHandler.Target<Object> target = new IGhostIngredientHandler.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<IGhostIngredientHandler.Target<?>, Object> getFakeSlotTargetMap()
{
return mapTargetSlot;
}
}
@@ -50,7 +50,7 @@ public class GuiInterface extends GuiUpgradeable
public GuiInterface( final InventoryPlayer inventoryPlayer, final IInterfaceHost te ) public GuiInterface( final InventoryPlayer inventoryPlayer, final IInterfaceHost te )
{ {
super( new ContainerInterface( inventoryPlayer, te ) ); super( new ContainerInterface( inventoryPlayer, te ) );
this.ySize = 211; this.ySize = 256;
} }
@Override @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.BlockMode = new GuiImgButton( this.guiLeft - 18, this.guiTop + 8, Settings.BLOCK, YesNo.NO );
this.buttonList.add( this.BlockMode ); this.buttonList.add( this.BlockMode );
this.interfaceMode = new GuiToggleButton( this.guiLeft - 18, this.guiTop + 26, 84, 85, GuiText.InterfaceTerminal this.interfaceMode = new GuiToggleButton( this.guiLeft - 18, this.guiTop + 26, 84, 85, GuiText.InterfaceTerminal.getLocal(), GuiText.InterfaceTerminalHint.getLocal() );
.getLocal(), GuiText.InterfaceTerminalHint.getLocal() );
this.buttonList.add( this.interfaceMode ); 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.StoredItems.getLocal(), 8, 6 + 60 + 7, 4210752 );
this.fontRenderer.drawString( GuiText.Patterns.getLocal(), 8, 6 + 73 + 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 @Override
protected String getBackground() 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 @Override
@@ -117,4 +123,5 @@ public class GuiInterface extends GuiUpgradeable
NetworkHandler.instance().sendToServer( new PacketConfigButton( this.BlockMode.getSetting(), backwards ) ); NetworkHandler.instance().sendToServer( new PacketConfigButton( this.BlockMode.getSetting(), backwards ) );
} }
} }
} }
@@ -24,7 +24,13 @@ import java.util.*;
import appeng.api.config.ActionItems; import appeng.api.config.ActionItems;
import appeng.api.config.Settings; import appeng.api.config.Settings;
import appeng.api.config.Upgrades;
import appeng.client.gui.widgets.GuiImgButton; 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 appeng.util.BlockPosUtils;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
@@ -49,6 +55,7 @@ import appeng.util.Platform;
import net.minecraft.nbt.NBTUtil; import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextComponentString;
import net.minecraftforge.common.DimensionManager;
import org.lwjgl.input.Mouse; import org.lwjgl.input.Mouse;
@@ -67,6 +74,7 @@ public class GuiInterfaceTerminal extends AEBaseGui
private final HashMultimap<String, ClientDCInternalInv> byName = HashMultimap.create(); private final HashMultimap<String, ClientDCInternalInv> byName = HashMultimap.create();
private final HashMap<ClientDCInternalInv,BlockPos> blockPosHashMap = new HashMap<>(); private final HashMap<ClientDCInternalInv,BlockPos> blockPosHashMap = new HashMap<>();
private final HashMap<GuiButton,ClientDCInternalInv> guiButtonHashMap = 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<String> names = new ArrayList<>();
private final ArrayList<Object> lines = new ArrayList<>(); private final ArrayList<Object> lines = new ArrayList<>();
private final Set<Object> matchedStacks = new HashSet<>(); private final Set<Object> matchedStacks = new HashSet<>();
@@ -79,6 +87,7 @@ public class GuiInterfaceTerminal extends AEBaseGui
private PartInterfaceTerminal partInterfaceTerminal; private PartInterfaceTerminal partInterfaceTerminal;
private GuiButton guiButtonHide; private GuiButton guiButtonHide;
private GuiButton guiButtonNextAssembler; private GuiButton guiButtonNextAssembler;
private HashMap<ClientDCInternalInv,Integer> dimHashMap = new HashMap<>();
public GuiInterfaceTerminal( final InventoryPlayer inventoryPlayer, final PartInterfaceTerminal te ) public GuiInterfaceTerminal( final InventoryPlayer inventoryPlayer, final PartInterfaceTerminal te )
{ {
@@ -88,7 +97,7 @@ public class GuiInterfaceTerminal extends AEBaseGui
final GuiScrollbar scrollbar = new GuiScrollbar(); final GuiScrollbar scrollbar = new GuiScrollbar();
this.setScrollBar( scrollbar ); this.setScrollBar( scrollbar );
this.xSize = 208; this.xSize = 208;
this.ySize = 256; this.ySize = 255;
} }
@Override @Override
@@ -133,36 +142,43 @@ public class GuiInterfaceTerminal extends AEBaseGui
this.fontRenderer.drawString( this.getGuiDisplayName( GuiText.InterfaceTerminal.getLocal() ), 8, 6, 4210752 ); this.fontRenderer.drawString( this.getGuiDisplayName( GuiText.InterfaceTerminal.getLocal() ), 8, 6, 4210752 );
this.fontRenderer.drawString( GuiText.inventory.getLocal(), this.offsetX + 2, 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();
this.guiButtonNextAssembler = new GuiImgButton(guiLeft + 123, guiTop + 25,Settings.ACTIONS, ActionItems.FREE_MOLECULAR_SLOT_SHORTCUT); this.guiButtonNextAssembler = new GuiImgButton( guiLeft + 123, guiTop + 25, Settings.ACTIONS, ActionItems.FREE_MOLECULAR_SLOT_SHORTCUT );
this.buttonList.add( guiButtonNextAssembler ); this.buttonList.add( guiButtonNextAssembler );
guiButtonHide = new GuiImgButton( guiLeft + 141, guiTop + 25,Settings.ACTIONS, this.partInterfaceTerminal.onlyInterfacesWithFreeSlots ? guiButtonHide = new GuiImgButton( guiLeft + 141, guiTop + 25, Settings.ACTIONS, this.partInterfaceTerminal.onlyInterfacesWithFreeSlots ? ActionItems.TOGGLE_SHOW_FULL_INTERFACES_OFF : ActionItems.TOGGLE_SHOW_FULL_INTERFACES_ON );
ActionItems.TOGGLE_SHOW_FULL_INTERFACES_OFF :
ActionItems.TOGGLE_SHOW_FULL_INTERFACES_ON);
this.buttonList.add( guiButtonHide ); this.buttonList.add( guiButtonHide );
this.inventorySlots.inventorySlots.removeIf( slot -> slot instanceof SlotDisconnected ); this.inventorySlots.inventorySlots.removeIf( slot -> slot instanceof SlotDisconnected );
int offset = 51; int offset = 52;
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 && currentScroll + 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 ) if( lineObj instanceof ClientDCInternalInv )
{ {
final ClientDCInternalInv inv = (ClientDCInternalInv) lineObj; final ClientDCInternalInv inv = (ClientDCInternalInv) lineObj;
for( int z = 0; z < inv.getInventory().getSlots(); z++ )
{
this.inventorySlots.inventorySlots.add( new SlotDisconnected( inv, z, z * 18 + 22, 1 + offset ) );
if (this.matchedStacks.contains(inv.getInventory().getStackInSlot(z)))
drawRect( z * 18 + 22, 1 + offset, z * 18 + 22 + 16, 1 + offset + 16, 0x2A00FF00 );
}
GuiButton guiButton = new GuiImgButton(guiLeft + 4, guiTop + offset + 1, Settings.ACTIONS, ActionItems.HIGHLIGHT_INTERFACE); GuiButton guiButton = new GuiImgButton( guiLeft + 4, guiTop + offset, Settings.ACTIONS, ActionItems.HIGHLIGHT_INTERFACE );
guiButtonHashMap.put( guiButton , inv); guiButtonHashMap.put( guiButton, inv );
this.buttonList.add( guiButton ); this.buttonList.add( guiButton );
int extraLines = numUpgradesMap.get( inv );
for( int row = 0; row < 1 + extraLines && linesDraw < LINES_ON_PAGE ; ++row )
{
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 ) else if( lineObj instanceof String )
{ {
@@ -173,17 +189,17 @@ public class GuiInterfaceTerminal extends AEBaseGui
name = name + " (" + rows + ')'; 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 ); name = name.substring( 0, name.length() - 1 );
} }
this.fontRenderer.drawString( name, this.offsetX + 2, 5 + offset, 4210752 );
this.fontRenderer.drawString( name, this.offsetX + 2, 6 + 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" ); 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" ); else if( searchFieldOutputs.isMouseIn( mouseX, mouseY ) ) drawTooltip( Mouse.getEventX() * this.width / this.mc.displayWidth - offsetX, mouseY - guiTop, "Outputs OR names" );
} }
@@ -217,9 +233,21 @@ public class GuiInterfaceTerminal extends AEBaseGui
{ {
BlockPos blockPos = blockPosHashMap.get( guiButtonHashMap.get( this.selectedButton ) ); BlockPos blockPos = blockPosHashMap.get( guiButtonHashMap.get( this.selectedButton ) );
BlockPos blockPos2 = mc.player.getPosition(); BlockPos blockPos2 = mc.player.getPosition();
int dimension = mc.world.provider.getDimension(); int playerDim = mc.world.provider.getDimension();
hilightBlock( blockPos, System.currentTimeMillis() + 500 * BlockPosUtils.getDistance(blockPos, blockPos2), dimension ); int interfaceDim = dimHashMap.get( guiButtonHashMap.get( this.selectedButton ) );
mc.player.sendStatusMessage( new TextComponentString( "The interface is now highlighted at " + "X: " + blockPos.getX() + " Y: " + blockPos.getY() + " Z: " + blockPos.getZ() ), false ); 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(); mc.player.closeScreen();
} }
@@ -253,19 +281,28 @@ public class GuiInterfaceTerminal extends AEBaseGui
int offset = 51; int offset = 51;
final int ex = this.getScrollBar().getCurrentScroll(); final int ex = this.getScrollBar().getCurrentScroll();
int linesDraw = 0;
for( int x = 0; x < LINES_ON_PAGE && ex + x < this.lines.size(); x++ ) 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 ); final Object lineObj = this.lines.get( ex + x );
if( lineObj instanceof ClientDCInternalInv ) if( lineObj instanceof ClientDCInternalInv )
{ {
final ClientDCInternalInv inv = (ClientDCInternalInv) lineObj;
GlStateManager.color( 1, 1, 1, 1 ); GlStateManager.color( 1, 1, 1, 1 );
final int width = inv.getInventory().getSlots() * 18; final int width = 9 * 18;
this.drawTexturedModalRect( offsetX + 20, offsetY + offset, 20, 173, width, 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.searchFieldInputs != null ) if( this.searchFieldInputs != null )
@@ -325,6 +362,8 @@ public class GuiInterfaceTerminal extends AEBaseGui
final NBTTagCompound invData = in.getCompoundTag( key ); final NBTTagCompound invData = in.getCompoundTag( key );
final ClientDCInternalInv current = this.getById( id, invData.getLong( "sortBy" ), invData.getString( "un" ) ); final ClientDCInternalInv current = this.getById( id, invData.getLong( "sortBy" ), invData.getString( "un" ) );
blockPosHashMap.put( current, NBTUtil.getPosFromTag( invData.getCompoundTag( "pos" )) ); 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++ ) for( int x = 0; x < current.getInventory().getSlots(); x++ )
{ {
@@ -383,8 +422,12 @@ public class GuiInterfaceTerminal extends AEBaseGui
// Search if the current inventory holds a pattern containing the search term. // Search if the current inventory holds a pattern containing the search term.
if( !found ) if( !found )
{ {
int slot = 0;
for( final ItemStack itemStack : entry.getInventory() ) for( final ItemStack itemStack : entry.getInventory() )
{ {
if (slot > 8 + numUpgradesMap.get(entry) * 9) {
break;
}
if( !searchFieldInputs.isEmpty() && !searchFieldOutputs.isEmpty() ) { if( !searchFieldInputs.isEmpty() && !searchFieldOutputs.isEmpty() ) {
if (this.itemStackMatchesSearchTerm(itemStack, searchFieldInputs, 0) || this.itemStackMatchesSearchTerm(itemStack, searchFieldOutputs, 1)) { if (this.itemStackMatchesSearchTerm(itemStack, searchFieldInputs, 0) || this.itemStackMatchesSearchTerm(itemStack, searchFieldOutputs, 1)) {
found = true; found = true;
@@ -406,6 +449,7 @@ public class GuiInterfaceTerminal extends AEBaseGui
// If only Interfaces with empty slots should be shown, check that here // If only Interfaces with empty slots should be shown, check that here
if(itemStack.isEmpty()) if(itemStack.isEmpty())
interfaceHasFreeSlots = true; interfaceHasFreeSlots = true;
slot++;
} }
} }
// if found, filter skipped or machine name matching the search term, add it // if found, filter skipped or machine name matching the search term, add it
@@ -446,7 +490,7 @@ public class GuiInterfaceTerminal extends AEBaseGui
this.lines.addAll( clientInventories ); 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,int pass ) private boolean itemStackMatchesSearchTerm( final ItemStack itemStack, final String searchTerm,int pass )
@@ -536,7 +580,7 @@ public class GuiInterfaceTerminal extends AEBaseGui
if( o == null ) 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; this.refreshList = true;
} }
@@ -0,0 +1,179 @@
package appeng.client.gui.implementations;
import appeng.api.config.AccessRestriction;
import appeng.api.config.ActionItems;
import appeng.api.config.Settings;
import appeng.api.config.StorageFilter;
import appeng.client.gui.AEBaseGui;
import appeng.client.gui.widgets.GuiImgButton;
import appeng.client.gui.widgets.GuiTabButton;
import appeng.client.gui.widgets.MEGuiTextField;
import appeng.container.implementations.ContainerOreDictStorageBus;
import appeng.core.AELog;
import appeng.core.localization.GuiText;
import appeng.core.sync.GuiBridge;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketConfigButton;
import appeng.core.sync.packets.PacketSwitchGuis;
import appeng.core.sync.packets.PacketValueConfig;
import appeng.parts.misc.PartOreDicStorageBus;
import appeng.util.item.OreDictFilterMatcher;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.entity.player.InventoryPlayer;
import org.lwjgl.input.Mouse;
import java.io.IOException;
import java.util.regex.Pattern;
public class GuiOreDictStorageBus extends AEBaseGui
{
private final ContainerOreDictStorageBus container;
PartOreDicStorageBus part;
private GuiTabButton priority;
private GuiImgButton partition;
private GuiImgButton storageFilter;
private GuiImgButton rwMode;
private static final Pattern ORE_DICTIONARY_FILTER = Pattern.compile( "[(!]* *[0-9a-zA-Z*]* *\\)*( *[&|^]? *[(!]* *[0-9a-zA-Z*]* *\\)*)*" );
private MEGuiTextField searchFieldInputs;
public GuiOreDictStorageBus( final InventoryPlayer inventoryPlayer, final PartOreDicStorageBus te )
{
super( new ContainerOreDictStorageBus( inventoryPlayer, te ) );
this.container = (ContainerOreDictStorageBus) super.inventorySlots;
part = te;
this.ySize = 84;
}
@Override
public void initGui()
{
super.initGui();
this.searchFieldInputs = new MEGuiTextField( this.fontRenderer, this.guiLeft + 3, this.guiTop + 22, 170, 12 );
this.searchFieldInputs.setEnableBackgroundDrawing( false );
this.searchFieldInputs.setMaxStringLength( 512 );
this.searchFieldInputs.setTextColor( 0xFFFFFF );
this.searchFieldInputs.setVisible( true );
this.searchFieldInputs.setFocused( false );
this.searchFieldInputs.setValidator( str -> ORE_DICTIONARY_FILTER.matcher( str ).matches() );
this.buttonList.add( this.priority = new GuiTabButton( this.guiLeft + 154, this.guiTop, 2 + 4 * 16, GuiText.Priority.getLocal(), this.itemRender ) );
this.buttonList.add( this.partition = new GuiImgButton( this.guiLeft - 18, this.guiTop + 28, Settings.ACTIONS, ActionItems.WRENCH ) );
this.buttonList.add( this.rwMode = new GuiImgButton( this.guiLeft - 18, this.guiTop + 48, Settings.ACCESS, AccessRestriction.READ_WRITE ) );
this.buttonList.add( this.storageFilter = new GuiImgButton( this.guiLeft - 18, this.guiTop + 68, Settings.STORAGE_FILTER, StorageFilter.EXTRACTABLE_ONLY ) );
try
{
NetworkHandler.instance().sendToServer( new PacketValueConfig( "OreDictStorageBus.getRegex", "1" ) );
}
catch( IOException e )
{
e.printStackTrace();
}
}
public void fillRegex( String regex )
{
this.searchFieldInputs.setText( regex );
}
@Override
protected void actionPerformed( final GuiButton btn ) throws IOException
{
super.actionPerformed( btn );
final boolean backwards = Mouse.isButtonDown( 1 );
try
{
if( btn == this.priority )
{
NetworkHandler.instance().sendToServer( new PacketSwitchGuis( GuiBridge.GUI_PRIORITY ) );
}
else if( btn == this.partition )
{
NetworkHandler.instance().sendToServer( new PacketValueConfig( "StorageBus.Action", "Partition" ) );
}
else if( btn == this.rwMode )
{
NetworkHandler.instance().sendToServer( new PacketConfigButton( this.rwMode.getSetting(), backwards ) );
}
else if( btn == this.storageFilter )
{
NetworkHandler.instance().sendToServer( new PacketConfigButton( this.storageFilter.getSetting(), backwards ) );
}
}
catch( final IOException e )
{
AELog.debug( e );
}
}
@Override
protected void mouseClicked( final int xCoord, final int yCoord, final int btn ) throws IOException
{
boolean wasFocused = this.searchFieldInputs.isFocused();
this.searchFieldInputs.mouseClicked( xCoord, yCoord, btn );
if( btn == 1 && this.searchFieldInputs.isMouseIn( xCoord, yCoord ) )
{
this.searchFieldInputs.setText( "" );
}
if( !searchFieldInputs.isFocused() && wasFocused )
{
searchFieldInputs.setText( OreDictFilterMatcher.validateExp( searchFieldInputs.getText() ) );
NetworkHandler.instance().sendToServer( new PacketValueConfig( "OreDictStorageBus.save", searchFieldInputs.getText() ) );
}
super.mouseClicked( xCoord, yCoord, btn );
}
@Override
protected void keyTyped( final char character, final int key ) throws IOException
{
if( !this.checkHotbarKeys( key ) )
{
if( !this.searchFieldInputs.textboxKeyTyped( character, key ) )
{
super.keyTyped( character, key );
}
}
}
@Override
public void drawFG( int offsetX, int offsetY, int mouseX, int mouseY )
{
this.fontRenderer.drawString( this.getGuiDisplayName( GuiText.OreDictStorageBus.getLocal() ), 8, 6, 4210752 );
this.fontRenderer.drawString( this.searchFieldInputs.getText().length() + " / " + this.searchFieldInputs.getMaxStringLength(), 120, 36, 4210752 );
this.fontRenderer.drawString( "& = AND " + "| = OR", 8, 36, 4210752 );
this.fontRenderer.drawString( "^ = XOR " + "! = NOT", 8, 48, 4210752 );
this.fontRenderer.drawString( "() for priority " + "* for wildcard", 8, 60, 4210752 );
this.fontRenderer.drawString( "Ex.: *Redstone*&!dustRedstone", 8, 72, 4210752 );
if( this.storageFilter != null )
{
this.storageFilter.set( container.getStorageFilter() );
}
if( this.rwMode != null )
{
this.rwMode.set( container.getReadWriteMode() );
}
}
@Override
public void drawBG( int offsetX, int offsetY, int mouseX, int mouseY )
{
this.bindTexture( "guis/oredictstoragebus.png" );
this.drawTexturedModalRect( offsetX, offsetY, 0, 0, 175, 85 );
if( this.searchFieldInputs != null )
{
this.searchFieldInputs.drawTextBox();
}
}
}
@@ -270,12 +270,15 @@ public class GuiUpgradeable extends AEBaseGui implements IJEIGhostIngredients
@Override @Override
public Rectangle getArea() public Rectangle getArea()
{ {
if( slot instanceof SlotFake ) if( slot instanceof SlotFake && ( (SlotFake) slot ).isSlotEnabled() )
{
return new Rectangle( getGuiLeft() + ( (SlotFake) slot ).xPos, getGuiTop() + ( (SlotFake) slot ).yPos, 16, 16 ); return new Rectangle( getGuiLeft() + ( (SlotFake) slot ).xPos, getGuiTop() + ( (SlotFake) slot ).yPos, 16, 16 );
else }
else if( slot instanceof GuiFluidSlot && ( (GuiFluidSlot) slot ).isSlotEnabled() )
{ {
return new Rectangle( getGuiLeft() + ( (GuiFluidSlot) slot ).xPos(), getGuiTop() + ( (GuiFluidSlot) slot ).yPos(), 16, 16 ); return new Rectangle( getGuiLeft() + ( (GuiFluidSlot) slot ).xPos(), getGuiTop() + ( (GuiFluidSlot) slot ).yPos(), 16, 16 );
} }
return new Rectangle();
} }
@Override @Override
@@ -284,7 +287,7 @@ public class GuiUpgradeable extends AEBaseGui implements IJEIGhostIngredients
PacketInventoryAction p = null; PacketInventoryAction p = null;
try try
{ {
if( slot instanceof SlotFake ) if( slot instanceof SlotFake && ( (SlotFake) slot ).isSlotEnabled() )
{ {
if( finalItemStack.isEmpty() && finalFluidStack != null ) if( finalItemStack.isEmpty() && finalFluidStack != null )
{ {
@@ -10,9 +10,9 @@ import net.minecraft.item.ItemStack;
public abstract class GuiCustomSlot extends Gui implements ITooltip public abstract class GuiCustomSlot extends Gui implements ITooltip
{ {
private final int x; protected final int x;
private final int y; protected final int y;
private final int id; protected final int id;
public GuiCustomSlot( final int id, final int x, final int y ) public GuiCustomSlot( final int id, final int x, final int y )
{ {
@@ -87,6 +87,7 @@ public class GuiImgButton extends GuiButton implements ITooltip
this.registerApp( 16 * 10, Settings.POWER_UNITS, PowerUnits.AE, ButtonToolTips.PowerUnits, PowerUnits.AE.unlocalizedName ); this.registerApp( 16 * 10, Settings.POWER_UNITS, PowerUnits.AE, ButtonToolTips.PowerUnits, PowerUnits.AE.unlocalizedName );
this.registerApp( 16 * 10 + 1, Settings.POWER_UNITS, PowerUnits.EU, ButtonToolTips.PowerUnits, PowerUnits.EU.unlocalizedName ); this.registerApp( 16 * 10 + 1, Settings.POWER_UNITS, PowerUnits.EU, ButtonToolTips.PowerUnits, PowerUnits.EU.unlocalizedName );
this.registerApp( 16 * 10 + 4, Settings.POWER_UNITS, PowerUnits.RF, ButtonToolTips.PowerUnits, PowerUnits.RF.unlocalizedName ); this.registerApp( 16 * 10 + 4, Settings.POWER_UNITS, PowerUnits.RF, ButtonToolTips.PowerUnits, PowerUnits.RF.unlocalizedName );
this.registerApp( 16 * 10 + 1, Settings.POWER_UNITS, PowerUnits.GTEU, ButtonToolTips.PowerUnits, PowerUnits.EU.unlocalizedName );
this.registerApp( 3, Settings.REDSTONE_CONTROLLED, RedstoneMode.IGNORE, ButtonToolTips.RedstoneMode, ButtonToolTips.AlwaysActive ); this.registerApp( 3, Settings.REDSTONE_CONTROLLED, RedstoneMode.IGNORE, ButtonToolTips.RedstoneMode, ButtonToolTips.AlwaysActive );
this.registerApp( 0, Settings.REDSTONE_CONTROLLED, RedstoneMode.LOW_SIGNAL, ButtonToolTips.RedstoneMode, ButtonToolTips.ActiveWithoutSignal ); this.registerApp( 0, Settings.REDSTONE_CONTROLLED, RedstoneMode.LOW_SIGNAL, ButtonToolTips.RedstoneMode, ButtonToolTips.ActiveWithoutSignal );
@@ -108,15 +109,11 @@ public class GuiImgButton extends GuiButton implements ITooltip
this.registerApp( 16 * 2 + 3, Settings.SEARCH_MODE, SearchBoxMode.AUTOSEARCH, ButtonToolTips.SearchMode, ButtonToolTips.SearchMode_Auto ); this.registerApp( 16 * 2 + 3, Settings.SEARCH_MODE, SearchBoxMode.AUTOSEARCH, ButtonToolTips.SearchMode, ButtonToolTips.SearchMode_Auto );
this.registerApp( 16 * 2 + 4, Settings.SEARCH_MODE, SearchBoxMode.MANUAL_SEARCH, ButtonToolTips.SearchMode, ButtonToolTips.SearchMode_Standard ); this.registerApp( 16 * 2 + 4, Settings.SEARCH_MODE, SearchBoxMode.MANUAL_SEARCH, ButtonToolTips.SearchMode, ButtonToolTips.SearchMode_Standard );
this.registerApp( 16 * 2 + 5, Settings.SEARCH_MODE, SearchBoxMode.JEI_AUTOSEARCH, ButtonToolTips.SearchMode, ButtonToolTips.SearchMode_JEIAuto ); this.registerApp( 16 * 2 + 5, Settings.SEARCH_MODE, SearchBoxMode.JEI_AUTOSEARCH, ButtonToolTips.SearchMode, ButtonToolTips.SearchMode_JEIAuto );
this.registerApp( 16 * 2 + 6, Settings.SEARCH_MODE, SearchBoxMode.JEI_MANUAL_SEARCH, ButtonToolTips.SearchMode, this.registerApp( 16 * 2 + 6, Settings.SEARCH_MODE, SearchBoxMode.JEI_MANUAL_SEARCH, ButtonToolTips.SearchMode, ButtonToolTips.SearchMode_JEIStandard );
ButtonToolTips.SearchMode_JEIStandard );
this.registerApp( 16 * 2 + 7, Settings.SEARCH_MODE, SearchBoxMode.AUTOSEARCH_KEEP, ButtonToolTips.SearchMode, ButtonToolTips.SearchMode_AutoKeep ); this.registerApp( 16 * 2 + 7, Settings.SEARCH_MODE, SearchBoxMode.AUTOSEARCH_KEEP, ButtonToolTips.SearchMode, ButtonToolTips.SearchMode_AutoKeep );
this.registerApp( 16 * 2 + 8, Settings.SEARCH_MODE, SearchBoxMode.MANUAL_SEARCH_KEEP, ButtonToolTips.SearchMode, this.registerApp( 16 * 2 + 8, Settings.SEARCH_MODE, SearchBoxMode.MANUAL_SEARCH_KEEP, ButtonToolTips.SearchMode, ButtonToolTips.SearchMode_StandardKeep );
ButtonToolTips.SearchMode_StandardKeep ); this.registerApp( 16 * 2 + 9, Settings.SEARCH_MODE, SearchBoxMode.JEI_AUTOSEARCH_KEEP, ButtonToolTips.SearchMode, ButtonToolTips.SearchMode_JEIAutoKeep );
this.registerApp( 16 * 2 + 9, Settings.SEARCH_MODE, SearchBoxMode.JEI_AUTOSEARCH_KEEP, ButtonToolTips.SearchMode, this.registerApp( 16 * 2 + 10, Settings.SEARCH_MODE, SearchBoxMode.JEI_MANUAL_SEARCH_KEEP, ButtonToolTips.SearchMode, ButtonToolTips.SearchMode_JEIStandardKeep );
ButtonToolTips.SearchMode_JEIAutoKeep );
this.registerApp( 16 * 2 + 10, Settings.SEARCH_MODE, SearchBoxMode.JEI_MANUAL_SEARCH_KEEP, ButtonToolTips.SearchMode,
ButtonToolTips.SearchMode_JEIStandardKeep );
this.registerApp( 16 * 5 + 3, Settings.LEVEL_TYPE, LevelType.ENERGY_LEVEL, ButtonToolTips.LevelType, ButtonToolTips.LevelType_Energy ); this.registerApp( 16 * 5 + 3, Settings.LEVEL_TYPE, LevelType.ENERGY_LEVEL, ButtonToolTips.LevelType, ButtonToolTips.LevelType_Energy );
this.registerApp( 16 * 4 + 3, Settings.LEVEL_TYPE, LevelType.ITEM_LEVEL, ButtonToolTips.LevelType, ButtonToolTips.LevelType_Item ); this.registerApp( 16 * 4 + 3, Settings.LEVEL_TYPE, LevelType.ITEM_LEVEL, ButtonToolTips.LevelType, ButtonToolTips.LevelType_Item );
@@ -174,19 +171,15 @@ public class GuiImgButton extends GuiButton implements ITooltip
this.registerApp( 16 * 11 + 2, Settings.CRAFT_VIA_REDSTONE, YesNo.YES, ButtonToolTips.EmitterMode, ButtonToolTips.CraftViaRedstone ); this.registerApp( 16 * 11 + 2, Settings.CRAFT_VIA_REDSTONE, YesNo.YES, ButtonToolTips.EmitterMode, ButtonToolTips.CraftViaRedstone );
this.registerApp( 16 * 11 + 1, Settings.CRAFT_VIA_REDSTONE, YesNo.NO, ButtonToolTips.EmitterMode, ButtonToolTips.EmitWhenCrafting ); this.registerApp( 16 * 11 + 1, Settings.CRAFT_VIA_REDSTONE, YesNo.NO, ButtonToolTips.EmitterMode, ButtonToolTips.EmitWhenCrafting );
this.registerApp( 16 * 3 + 5, Settings.STORAGE_FILTER, StorageFilter.EXTRACTABLE_ONLY, ButtonToolTips.ReportInaccessibleItems, this.registerApp( 16 * 3 + 5, Settings.STORAGE_FILTER, StorageFilter.EXTRACTABLE_ONLY, ButtonToolTips.ReportInaccessibleItems, ButtonToolTips.ReportInaccessibleItemsNo );
ButtonToolTips.ReportInaccessibleItemsNo ); this.registerApp( 16 * 3 + 6, Settings.STORAGE_FILTER, StorageFilter.NONE, ButtonToolTips.ReportInaccessibleItems, ButtonToolTips.ReportInaccessibleItemsYes );
this.registerApp( 16 * 3 + 6, Settings.STORAGE_FILTER, StorageFilter.NONE, ButtonToolTips.ReportInaccessibleItems,
ButtonToolTips.ReportInaccessibleItemsYes );
this.registerApp( 16 * 14, Settings.PLACE_BLOCK, YesNo.YES, ButtonToolTips.BlockPlacement, ButtonToolTips.BlockPlacementYes ); this.registerApp( 16 * 14, Settings.PLACE_BLOCK, YesNo.YES, ButtonToolTips.BlockPlacement, ButtonToolTips.BlockPlacementYes );
this.registerApp( 16 * 14 + 1, Settings.PLACE_BLOCK, YesNo.NO, ButtonToolTips.BlockPlacement, ButtonToolTips.BlockPlacementNo ); this.registerApp( 16 * 14 + 1, Settings.PLACE_BLOCK, YesNo.NO, ButtonToolTips.BlockPlacement, ButtonToolTips.BlockPlacementNo );
this.registerApp( 16 * 15, Settings.SCHEDULING_MODE, SchedulingMode.DEFAULT, ButtonToolTips.SchedulingMode, ButtonToolTips.SchedulingModeDefault ); this.registerApp( 16 * 15, Settings.SCHEDULING_MODE, SchedulingMode.DEFAULT, ButtonToolTips.SchedulingMode, ButtonToolTips.SchedulingModeDefault );
this.registerApp( 16 * 15 + 1, Settings.SCHEDULING_MODE, SchedulingMode.ROUNDROBIN, ButtonToolTips.SchedulingMode, this.registerApp( 16 * 15 + 1, Settings.SCHEDULING_MODE, SchedulingMode.ROUNDROBIN, ButtonToolTips.SchedulingMode, ButtonToolTips.SchedulingModeRoundRobin );
ButtonToolTips.SchedulingModeRoundRobin ); this.registerApp( 16 * 15 + 2, Settings.SCHEDULING_MODE, SchedulingMode.RANDOM, ButtonToolTips.SchedulingMode, ButtonToolTips.SchedulingModeRandom );
this.registerApp( 16 * 15 + 2, Settings.SCHEDULING_MODE, SchedulingMode.RANDOM, ButtonToolTips.SchedulingMode,
ButtonToolTips.SchedulingModeRandom );
} }
} }
@@ -336,7 +329,7 @@ public class GuiImgButton extends GuiButton implements ITooltip
{ {
i = 0; i = 0;
} }
while( i + 30 < sb.length() && ( i = sb.lastIndexOf( " ", i + 30 ) ) != -1 ) while ( i + 30 < sb.length() && ( i = sb.lastIndexOf( " ", i + 30 ) ) != -1 )
{ {
sb.replace( i, i + 1, "\n" ); sb.replace( i, i + 1, "\n" );
} }
@@ -22,9 +22,10 @@ package appeng.client.render;
import appeng.api.storage.data.IAEFluidStack; import appeng.api.storage.data.IAEFluidStack;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.RenderItem; import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
@@ -32,6 +33,7 @@ import appeng.api.storage.data.IAEItemStack;
import appeng.util.IWideReadableNumberConverter; import appeng.util.IWideReadableNumberConverter;
import appeng.util.ReadableNumberConverter; import appeng.util.ReadableNumberConverter;
import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidStack;
import org.lwjgl.opengl.GL11;
/** /**
@@ -121,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. * Render an item in 2D and the given text below it.
* *
@@ -147,9 +192,9 @@ public class TesrRenderHelper
public static void renderFluid2dWithAmount( IAEFluidStack fluidStack, float scale, float spacing ) public static void renderFluid2dWithAmount( IAEFluidStack fluidStack, float scale, float spacing )
{ {
final ItemStack renderStack = fluidStack.asItemStackRepresentation(); final FluidStack renderStack = fluidStack.getFluidStack();
TesrRenderHelper.renderItem2d( renderStack, scale ); TesrRenderHelper.renderFluid2d( renderStack, scale );
final long stackSize = fluidStack.getStackSize() / 1000; final long stackSize = fluidStack.getStackSize() / 1000;
final String renderedStackSize = NUMBER_CONVERTER.toWideReadableForm( stackSize ) + "B"; final String renderedStackSize = NUMBER_CONVERTER.toWideReadableForm( stackSize ) + "B";
@@ -19,14 +19,9 @@
package appeng.client.render.model; package appeng.client.render.model;
import java.util.ArrayList; import appeng.block.storage.BlockDrive;
import java.util.List; import appeng.block.storage.DriveSlotState;
import java.util.Map; import appeng.block.storage.DriveSlotsState;
import javax.annotation.Nullable;
import javax.vecmath.Matrix4f;
import javax.vecmath.Vector3f;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.IBakedModel; import net.minecraft.client.renderer.block.model.IBakedModel;
@@ -37,9 +32,12 @@ import net.minecraft.util.EnumFacing;
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad; import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
import net.minecraftforge.common.property.IExtendedBlockState; import net.minecraftforge.common.property.IExtendedBlockState;
import appeng.block.storage.BlockDrive; import javax.annotation.Nullable;
import appeng.block.storage.DriveSlotState; import javax.vecmath.Matrix4f;
import appeng.block.storage.DriveSlotsState; import javax.vecmath.Vector3f;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class DriveBakedModel implements IBakedModel public class DriveBakedModel implements IBakedModel
@@ -57,13 +55,17 @@ public class DriveBakedModel implements IBakedModel
public List<BakedQuad> getQuads( @Nullable IBlockState state, @Nullable EnumFacing side, long rand ) public List<BakedQuad> getQuads( @Nullable IBlockState state, @Nullable EnumFacing side, long rand )
{ {
List<BakedQuad> result = new ArrayList<>(); List<BakedQuad> result = new ArrayList<>( this.bakedBase.getQuads( state, side, rand ) );
result.addAll( this.bakedBase.getQuads( state, side, rand ) );
if( side == null && state instanceof IExtendedBlockState ) if( side == null && state instanceof IExtendedBlockState )
{ {
IExtendedBlockState extState = (IExtendedBlockState) state; IExtendedBlockState extState = (IExtendedBlockState) state;
if (!extState.getUnlistedNames().contains( BlockDrive.SLOTS_STATE ))
{
return result;
}
DriveSlotsState slotsState = extState.getValue( BlockDrive.SLOTS_STATE ); DriveSlotsState slotsState = extState.getValue( BlockDrive.SLOTS_STATE );
for( int row = 0; row < 5; row++ ) for( int row = 0; row < 5; row++ )
@@ -26,6 +26,7 @@ import java.util.concurrent.Future;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import appeng.parts.reporting.PartExpandedProcessingPatternTerminal;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
@@ -149,6 +150,7 @@ public class ContainerCraftConfirm extends AEBaseContainer
if( ccr.getCpu() == c ) if( ccr.getCpu() == c )
{ {
found = true; found = true;
break;
} }
} }
@@ -345,11 +347,15 @@ public class ContainerCraftConfirm extends AEBaseContainer
originalGui = GuiBridge.GUI_PATTERN_TERMINAL; originalGui = GuiBridge.GUI_PATTERN_TERMINAL;
} }
if( ah instanceof PartExpandedProcessingPatternTerminal )
{
originalGui = GuiBridge.GUI_EXPANDED_PROCESSING_PATTERN_TERMINAL;
}
if( this.result != null && !this.isSimulation() ) if( this.result != null && !this.isSimulation() )
{ {
final ICraftingGrid cc = this.getGrid().getCache( ICraftingGrid.class ); final ICraftingGrid cc = this.getGrid().getCache( ICraftingGrid.class );
final ICraftingLink g = cc.submitJob( this.result, null, this.getSelectedCpu() == -1 ? null : this.cpus.get( this.getSelectedCpu() ).getCpu(), true, final ICraftingLink g = cc.submitJob( this.result, null, this.getSelectedCpu() == -1 ? null : this.cpus.get( this.getSelectedCpu() ).getCpu(), true, this.getActionSrc() );
this.getActionSrc() );
this.setAutoStart( false ); this.setAutoStart( false );
if( g != null && originalGui != null && this.getOpenContext() != null ) if( g != null && originalGui != null && this.getOpenContext() != null )
{ {
@@ -159,56 +159,58 @@ public class ContainerCraftingCPU extends AEBaseContainer implements IMEMonitorH
@Override @Override
public void detectAndSendChanges() 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 PacketMEInventoryUpdate a = new PacketMEInventoryUpdate( (byte) 0 );
final double remainingItems = this.getMonitor().getRemainingItemCount(); final PacketMEInventoryUpdate b = new PacketMEInventoryUpdate( (byte) 1 );
final double startItems = this.getMonitor().getStartItemCount(); final PacketMEInventoryUpdate c = new PacketMEInventoryUpdate( (byte) 2 );
final long eta = (long) ( elapsedTime / Math.max( 1d, ( startItems - remainingItems ) ) * remainingItems );
this.setEstimatedTime( eta );
}
final PacketMEInventoryUpdate a = new PacketMEInventoryUpdate( (byte) 0 ); for( final IAEItemStack out : this.list )
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 )
{ {
if( !a.isEmpty() ) a.appendItem( this.getMonitor().getItemStack( out, CraftingItemList.STORAGE ) );
{ b.appendItem( this.getMonitor().getItemStack( out, CraftingItemList.ACTIVE ) );
NetworkHandler.instance().sendTo( a, (EntityPlayerMP) g ); c.appendItem( this.getMonitor().getItemStack( out, CraftingItemList.PENDING ) );
} }
if( !b.isEmpty() ) this.list.resetStatus();
{
NetworkHandler.instance().sendTo( b, (EntityPlayerMP) g );
}
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 )
catch( final IOException e ) {
{ // :P
// :P }
} }
} }
super.detectAndSendChanges(); super.detectAndSendChanges();
@@ -0,0 +1,528 @@
package appeng.container.implementations;
import appeng.api.AEApi;
import appeng.api.definitions.IDefinitions;
import appeng.api.storage.ITerminalHost;
import appeng.container.slot.*;
import appeng.helpers.IContainerCraftingPacket;
import appeng.parts.reporting.PartExpandedProcessingPatternTerminal;
import appeng.util.Platform;
import appeng.util.inv.IAEAppEngInventory;
import appeng.util.inv.InvOperation;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.wrapper.PlayerInvWrapper;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import static appeng.helpers.PatternHelper.PROCESSING_INPUT_LIMIT;
import static appeng.helpers.PatternHelper.PROCESSING_OUTPUT_LIMIT;
public class ContainerExpandedProcessingPatternTerm extends ContainerMEMonitorable implements IAEAppEngInventory, IOptionalSlotHost, IContainerCraftingPacket
{
private final IItemHandler crafting;
private final SlotFakeCraftingMatrix[] gridSlots = new SlotFakeCraftingMatrix[PROCESSING_INPUT_LIMIT];
private final OptionalSlotFake[] outputSlots = new OptionalSlotFake[PROCESSING_OUTPUT_LIMIT];
private final SlotRestrictedInput patternSlotIN;
private final SlotRestrictedInput patternSlotOUT;
private final PartExpandedProcessingPatternTerminal expandedProcessingPatternTerminal;
public ContainerExpandedProcessingPatternTerm( InventoryPlayer ip, ITerminalHost monitorable )
{
super( ip, monitorable, false );
this.expandedProcessingPatternTerminal = (PartExpandedProcessingPatternTerminal) monitorable;
final IItemHandler patternInv = this.getExpandedPatternTerminal().getInventoryByName( "pattern" );
final IItemHandler output = this.getExpandedPatternTerminal().getInventoryByName( "output" );
this.crafting = this.getExpandedPatternTerminal().getInventoryByName( "crafting" );
for( int y = 0; y < 4; y++ )
{
for( int x = 0; x < 4; x++ )
{
this.addSlotToContainer( this.gridSlots[x + y * 4] = new SlotFakeCraftingMatrix( this.crafting, x + y * 4, 4 + x * 18, -85 + y * 18 ) );
}
}
for( int y = 0; y < 3; y++ )
{
for( int x = 0; x < 2; x++ )
{
this.addSlotToContainer( this.outputSlots[x + y * 2] = new SlotPatternOutputs( output, this, x + y * 2, 96 + x * 18, -76 + y * 18, 0, 0, 1 ) );
this.outputSlots[x + y * 2].setRenderDisabled( false );
this.outputSlots[x + y * 2].setIIcon( -1 );
}
}
this.addSlotToContainer( this.patternSlotIN = new SlotRestrictedInput( SlotRestrictedInput.PlacableItemType.BLANK_PATTERN, patternInv, 0, 147, -72 - 9, this.getInventoryPlayer() ) );
this.addSlotToContainer( this.patternSlotOUT = new SlotRestrictedInput( SlotRestrictedInput.PlacableItemType.ENCODED_PATTERN, patternInv, 1, 147, -72 + 34, this.getInventoryPlayer() ) );
this.patternSlotOUT.setStackLimit( 1 );
this.bindPlayerInventory( ip, 0, 0 );
}
@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.getExpandedPatternTerminal().getInventoryByName( "pattern" );
ItemStack remainder = patternInv.insertItem( 0, itemStack, false );
clickSlot.putStack( remainder );
}
}
return super.transferStackInSlot( p, idx );
}
@Override
public void saveChanges()
{
}
@Override
public void onChangeInventory( final IItemHandler inv, final int slot, final InvOperation mc, final ItemStack removedStack, final ItemStack newStack )
{
}
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();
final ItemStack[] in = this.getInputs();
final ItemStack[] out = this.getOutputs();
// if there is no input, this would be silly.
if( in == null || out == null )
{
return;
}
// first check the output slots, should either be null, or a pattern
if( !output.isEmpty() && !this.isPattern( output ) )
{
return;
} // if nothing is there we should snag a new pattern.
else if( output.isEmpty() )
{
output = this.patternSlotIN.getStack();
if( output.isEmpty() || !this.isPattern( output ) )
{
return; // no blanks.
}
// remove one, and clear the input slot.
output.setCount( output.getCount() - 1 );
if( output.getCount() == 0 )
{
this.patternSlotIN.putStack( ItemStack.EMPTY );
}
// add a new encoded pattern.
Optional<ItemStack> maybePattern = AEApi.instance().definitions().items().encodedPattern().maybeStack( 1 );
if( maybePattern.isPresent() )
{
output = maybePattern.get();
this.patternSlotOUT.putStack( output );
}
}
// encode the slot.
final NBTTagCompound encodedValue = new NBTTagCompound();
final NBTTagList tagIn = new NBTTagList();
final NBTTagList tagOut = new NBTTagList();
for( final ItemStack i : in )
{
tagIn.appendTag( this.createItemTag( i ) );
}
for( final ItemStack i : out )
{
tagOut.appendTag( this.createItemTag( i ) );
}
encodedValue.setTag( "in", tagIn );
encodedValue.setTag( "out", tagOut );
encodedValue.setBoolean( "crafting", false );
encodedValue.setBoolean( "substitute", false );
output.setTagCompound( encodedValue );
}
boolean isPattern( final ItemStack output )
{
if( output.isEmpty() )
{
return false;
}
final IDefinitions definitions = AEApi.instance().definitions();
boolean isPattern = definitions.items().encodedPattern().isSameAs( output );
isPattern |= definitions.materials().blankPattern().isSameAs( output );
return isPattern;
}
NBTBase createItemTag( final ItemStack i )
{
final NBTTagCompound c = new NBTTagCompound();
if( !i.isEmpty() )
{
i.writeToNBT( c );
}
return c;
}
@Override
public boolean isSlotEnabled( final int idx )
{
return true;
}
protected ItemStack[] getInputs()
{
final ItemStack[] input = new ItemStack[16];
boolean hasValue = false;
for( int x = 0; x < this.gridSlots.length; x++ )
{
input[x] = this.gridSlots[x].getStack();
if( !input[x].isEmpty() )
{
hasValue = true;
}
}
if( hasValue )
{
return input;
}
return null;
}
protected ItemStack[] getOutputs()
{
final List<ItemStack> list = new ArrayList<>( 3 );
boolean hasValue = false;
for( final OptionalSlotFake outputSlot : this.outputSlots )
{
final ItemStack out = outputSlot.getStack();
if( !out.isEmpty() && out.getCount() > 0 )
{
list.add( out );
hasValue = true;
}
}
if( hasValue )
{
return list.toArray( new ItemStack[0] );
}
return null;
}
public void clear()
{
for( final Slot s : this.gridSlots )
{
s.putStack( ItemStack.EMPTY );
}
for( final Slot s : this.outputSlots )
{
s.putStack( ItemStack.EMPTY );
}
this.detectAndSendChanges();
}
@Override
public IItemHandler getInventoryByName( final String name )
{
if( name.equals( "player" ) )
{
return new PlayerInvWrapper( this.getInventoryPlayer() );
}
return this.getExpandedPatternTerminal().getInventoryByName( name );
}
@Override
public boolean useRealItems()
{
return false;
}
public PartExpandedProcessingPatternTerminal getExpandedPatternTerminal()
{
return this.expandedProcessingPatternTerminal;
}
public void multiply( int multiple )
{
ItemStack[] input = new ItemStack[gridSlots.length];
boolean canMultiplyInputs = true;
boolean canMultiplyOutputs = true;
for( int x = 0; x < this.gridSlots.length; x++ )
{
input[x] = this.gridSlots[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.gridSlots )
{
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[gridSlots.length];
boolean canDivideInputs = true;
boolean canDivideOutputs = true;
for( int x = 0; x < this.gridSlots.length; x++ )
{
input[x] = this.gridSlots[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.gridSlots )
{
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[gridSlots.length];
boolean canIncreaseInputs = true;
boolean canIncreaseOutputs = true;
for( int x = 0; x < this.gridSlots.length; x++ )
{
input[x] = this.gridSlots[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.gridSlots )
{
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[gridSlots.length];
boolean canDecreaseInputs = true;
boolean canDecreaseOutputs = true;
for( int x = 0; x < this.gridSlots.length; x++ )
{
input[x] = this.gridSlots[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.gridSlots )
{
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[gridSlots.length];
boolean canGrowInputs = true;
boolean canGrowOutputs = true;
int maxInputStackGrowth = 0;
int maxOutputStackGrowth = 0;
for( int x = 0; x < this.gridSlots.length; x++ )
{
input[x] = this.gridSlots[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.gridSlots )
{
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 );
}
}
}
}
}
@@ -19,6 +19,9 @@
package appeng.container.implementations; package appeng.container.implementations;
import appeng.api.config.Upgrades;
import appeng.container.slot.*;
import appeng.util.Platform;
import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.entity.player.InventoryPlayer;
import appeng.api.config.SecurityPermissions; import appeng.api.config.SecurityPermissions;
@@ -26,14 +29,11 @@ import appeng.api.config.Settings;
import appeng.api.config.YesNo; import appeng.api.config.YesNo;
import appeng.api.util.IConfigManager; import appeng.api.util.IConfigManager;
import appeng.container.guisync.GuiSync; 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.DualityInterface;
import appeng.helpers.IInterfaceHost; import appeng.helpers.IInterfaceHost;
public class ContainerInterface extends ContainerUpgradeable public class ContainerInterface extends ContainerUpgradeable implements IOptionalSlotHost
{ {
private final DualityInterface myDuality; private final DualityInterface myDuality;
@@ -44,16 +44,22 @@ public class ContainerInterface extends ContainerUpgradeable
@GuiSync( 4 ) @GuiSync( 4 )
public YesNo iTermMode = YesNo.YES; public YesNo iTermMode = YesNo.YES;
@GuiSync( 7 )
public int patternExpansions = 0;
public ContainerInterface( final InventoryPlayer ip, final IInterfaceHost te ) public ContainerInterface( final InventoryPlayer ip, final IInterfaceHost te )
{ {
super( ip, te.getInterfaceDuality().getHost() ); super( ip, te.getInterfaceDuality().getHost() );
this.myDuality = te.getInterfaceDuality(); 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 for( int x = 0; x < 9; x++ )
.getPatterns(), x, 8 + 18 * x, 90 + 7, this.getInventoryPlayer() ).setStackLimit( 1 ) ); {
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++ ) for( int x = 0; x < DualityInterface.NUMBER_OF_CONFIG_SLOTS; x++ )
@@ -70,7 +76,7 @@ public class ContainerInterface extends ContainerUpgradeable
@Override @Override
protected int getHeight() protected int getHeight()
{ {
return 211; return 256;
} }
@Override @Override
@@ -82,16 +88,35 @@ public class ContainerInterface extends ContainerUpgradeable
@Override @Override
public int availableUpgrades() public int availableUpgrades()
{ {
return 1; return 4;
}
@Override
public boolean isSlotEnabled( final int idx )
{
return myDuality.getInstalledUpgrades(Upgrades.PATTERN_EXPANSION) >= idx;
} }
@Override @Override
public void detectAndSendChanges() public void detectAndSendChanges()
{ {
this.verifyPermissions( SecurityPermissions.BUILD, false ); this.verifyPermissions( SecurityPermissions.BUILD, false );
if (patternExpansions != getPatternUpgrades())
{
patternExpansions = getPatternUpgrades();
this.myDuality.dropExcessPatterns();
}
super.detectAndSendChanges(); 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 @Override
protected void loadSettingsFromHost( final IConfigManager cm ) protected void loadSettingsFromHost( final IConfigManager cm )
{ {
@@ -118,4 +143,9 @@ public class ContainerInterface extends ContainerUpgradeable
{ {
this.iTermMode = iTermMode; this.iTermMode = iTermMode;
} }
public int getPatternUpgrades()
{
return this.myDuality.getInstalledUpgrades( Upgrades.PATTERN_EXPANSION );
}
} }
@@ -24,6 +24,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import appeng.api.config.Upgrades;
import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@@ -403,7 +404,9 @@ public final class ContainerInterfaceTerminal extends AEBaseContainer
{ {
tag.setLong( "sortBy", inv.sortBy ); tag.setLong( "sortBy", inv.sortBy );
tag.setString( "un", inv.unlocalizedName ); tag.setString( "un", inv.unlocalizedName );
tag.setTag("pos", NBTUtil.createPosTag( inv.pos ) ); tag.setTag( "pos", NBTUtil.createPosTag( inv.pos ) );
tag.setInteger( "dim", inv.dim );
tag.setInteger( "numUpgrades", inv.numUpgrades );
} }
for( int x = 0; x < length; x++ ) for( int x = 0; x < length; x++ )
@@ -435,6 +438,8 @@ public final class ContainerInterfaceTerminal extends AEBaseContainer
private final IItemHandler client; private final IItemHandler client;
private final IItemHandler server; private final IItemHandler server;
private final BlockPos pos; private final BlockPos pos;
private final int dim;
private final int numUpgrades;
public InvTracker( final DualityInterface dual, final IItemHandler patterns, final String unlocalizedName ) public InvTracker( final DualityInterface dual, final IItemHandler patterns, final String unlocalizedName )
{ {
@@ -443,6 +448,8 @@ public final class ContainerInterfaceTerminal extends AEBaseContainer
this.unlocalizedName = unlocalizedName; this.unlocalizedName = unlocalizedName;
this.sortBy = dual.getSortValue(); this.sortBy = dual.getSortValue();
this.pos = dual.getLocation().getPos(); this.pos = dual.getLocation().getPos();
this.dim = dual.getLocation().getWorld().provider.getDimension();
this.numUpgrades = dual.getInstalledUpgrades( Upgrades.PATTERN_EXPANSION);
} }
} }
@@ -0,0 +1,140 @@
package appeng.container.implementations;
import appeng.api.AEApi;
import appeng.api.config.*;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.container.AEBaseContainer;
import appeng.container.guisync.GuiSync;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketValueConfig;
import appeng.parts.misc.PartOreDicStorageBus;
import appeng.util.Platform;
import appeng.util.item.AEItemStack;
import appeng.util.item.OreReference;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraftforge.oredict.OreDictionary;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class ContainerOreDictStorageBus extends AEBaseContainer
{
private final PartOreDicStorageBus part;
@GuiSync( 3 )
public AccessRestriction rwMode = AccessRestriction.READ_WRITE;
@GuiSync( 4 )
public StorageFilter storageFilter = StorageFilter.EXTRACTABLE_ONLY;
public ContainerOreDictStorageBus( final InventoryPlayer ip, final PartOreDicStorageBus anchor )
{
super( ip, anchor );
this.part = anchor;
this.bindPlayerInventory( ip, 14, 256 - /* height of player inventory */82 );
}
@Override
public void detectAndSendChanges()
{
this.verifyPermissions( SecurityPermissions.BUILD, false );
if( Platform.isServer() )
{
this.setReadWriteMode( (AccessRestriction) part.getConfigManager().getSetting( Settings.ACCESS ) );
this.setStorageFilter( (StorageFilter) part.getConfigManager().getSetting( Settings.STORAGE_FILTER ) );
}
super.detectAndSendChanges();
}
public void partition()
{
final IMEInventory<IAEItemStack> cellInv = this.part.getInternalHandler();
if( cellInv == null )
{
return;
}
Set<Integer> oreIDs = new HashSet<>();
for( IAEItemStack itemStack : cellInv.getAvailableItems( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList() ) )
{
OreReference ref = ( (AEItemStack) itemStack ).getOre().orElse( null );
if( ref != null )
{
oreIDs.addAll( ref.getOres() );
}
}
String oreMatch = "(";
String append = "";
for( Iterator<Integer> it = oreIDs.iterator(); it.hasNext(); )
{
int oreID = it.next();
if( it.hasNext() )
{
append = ")|(";
}
else
{
append = ")";
}
oreMatch = oreMatch.concat( OreDictionary.getOreName( oreID ) + append );
}
if( oreMatch.equals( "(" ) )
{
oreMatch = "";
}
part.saveOreMatch( oreMatch );
this.detectAndSendChanges();
}
public void saveOreMatch( String value )
{
part.saveOreMatch( value );
}
public void sendRegex()
{
try
{
NetworkHandler.instance().sendTo( new PacketValueConfig( "OreDictStorageBus.sendRegex", part.getOreExp() ), (EntityPlayerMP) getInventoryPlayer().player );
}
catch( IOException e )
{
e.printStackTrace();
}
}
public AccessRestriction getReadWriteMode()
{
return this.rwMode;
}
private void setReadWriteMode( final AccessRestriction rwMode )
{
this.rwMode = rwMode;
}
public StorageFilter getStorageFilter()
{
return this.storageFilter;
}
private void setStorageFilter( final StorageFilter storageFilter )
{
this.storageFilter = storageFilter;
}
}
@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import appeng.container.slot.*;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.entity.player.InventoryPlayer;
@@ -51,12 +52,6 @@ import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList; import appeng.api.storage.data.IItemList;
import appeng.container.ContainerNull; import appeng.container.ContainerNull;
import appeng.container.guisync.GuiSync; 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.core.sync.packets.PacketPatternSlot;
import appeng.helpers.IContainerCraftingPacket; import appeng.helpers.IContainerCraftingPacket;
import appeng.items.storage.ItemViewCell; import appeng.items.storage.ItemViewCell;
@@ -132,6 +127,28 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA
this.updateOrderOfOutputSlots(); 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() private void updateOrderOfOutputSlots()
{ {
if( !this.isCraftingMode() ) if( !this.isCraftingMode() )
@@ -161,7 +178,7 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA
this.getAndUpdateOutput(); this.getAndUpdateOutput();
} }
private ItemStack getAndUpdateOutput() protected ItemStack getAndUpdateOutput()
{ {
final World world = this.getPlayerInv().player.world; final World world = this.getPlayerInv().player.world;
final InventoryCrafting ic = new InventoryCrafting( this, 3, 3 ); final InventoryCrafting ic = new InventoryCrafting( this, 3, 3 );
@@ -488,7 +505,7 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA
} }
} }
private ItemStack[] getInputs() protected ItemStack[] getInputs()
{ {
final ItemStack[] input = new ItemStack[9]; final ItemStack[] input = new ItemStack[9];
boolean hasValue = false; boolean hasValue = false;
@@ -510,7 +527,7 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA
return null; return null;
} }
private ItemStack[] getOutputs() protected ItemStack[] getOutputs()
{ {
if( this.isCraftingMode() ) if( this.isCraftingMode() )
{ {
@@ -518,7 +535,7 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA
if( !out.isEmpty() && out.getCount() > 0 ) if( !out.isEmpty() && out.getCount() > 0 )
{ {
return new ItemStack[] { out }; return new ItemStack[]{out};
} }
} }
else else
@@ -546,7 +563,7 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA
return null; return null;
} }
private boolean isPattern( final ItemStack output ) boolean isPattern( final ItemStack output )
{ {
if( output.isEmpty() ) if( output.isEmpty() )
{ {
@@ -561,7 +578,7 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA
return isPattern; return isPattern;
} }
private NBTBase createItemTag( final ItemStack i ) NBTBase createItemTag( final ItemStack i )
{ {
final NBTTagCompound c = new NBTTagCompound(); final NBTTagCompound c = new NBTTagCompound();
@@ -807,7 +824,7 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA
return this.patternTerminal; return this.patternTerminal;
} }
private boolean isSubstitute() boolean isSubstitute()
{ {
return this.substitute; return this.substitute;
} }
@@ -157,7 +157,7 @@ public class AppEngSlot extends Slot
{ {
if( this.isSlotEnabled() ) 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; return false;
} }
+88 -53
View File
@@ -20,11 +20,7 @@ package appeng.core;
import java.io.File; import java.io.File;
import java.util.Arrays; import java.util.*;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
@@ -64,13 +60,67 @@ public final class AEConfig extends Configuration implements IConfigurableObject
private static AEConfig instance; private static AEConfig instance;
// Default Grindstone ores // Default Grindstone ores
private static final String[] ORES_VANILLA = { "Obsidian", "Ender", "EnderPearl", "Coal", "Iron", "Gold", "Charcoal", "NetherQuartz" }; private static final String[] ORES_VANILLA = {
private static final String[] ORES_AE = { "CertusQuartz", "Wheat", "Fluix" }; "Obsidian", "Ender", "EnderPearl", "Coal", "Iron", "Gold",
private static final String[] ORES_COMMON = { "Copper", "Tin", "Silver", "Lead", "Bronze" }; "Charcoal", "NetherQuartz"
private static final String[] ORES_MISC = { "Brass", "Platinum", "Nickel", "Invar", "Aluminium", "Electrum", "Osmium", "Zinc" }; };
private static final String[] ORES_AE = {"CertusQuartz", "Wheat", "Fluix"};
private static final String[] ORES_COMMON = {
"Copper", "Tin", "Silver", "Lead", "Bronze"
};
private static final String[] ORES_MISC = {
"Brass", "Platinum", "Nickel", "Invar", "Aluminium", "Electrum",
"Osmium", "Zinc"
};
private String[] nonBlockingItems = {
"[gregtech|actuallyadditions]", "gregtech:circuit.integrated",
"gregtech:shape.mold.plate", "gregtech:shape.mold.gear",
"gregtech:shape.mold.credit", "gregtech:shape.mold.bottle",
"gregtech:shape.mold.ingot", "gregtech:shape.mold.ball",
"gregtech:shape.mold.block", "gregtech:shape.mold.nugget",
"gregtech:shape.mold.cylinder", "gregtech:shape.mold.anvil",
"gregtech:shape.mold.name", "gregtech:shape.mold.gear.small",
"gregtech:shape.mold.rotor", "gregtech:shape.extruder.plate",
"gregtech:shape.extruder.rod", "gregtech:shape.extruder.bolt",
"gregtech:shape.extruder.ring", "gregtech:shape.extruder.cell",
"gregtech:shape.extruder.ingot", "gregtech:shape.extruder.wire",
"gregtech:shape.extruder.pipe.tiny",
"gregtech:shape.extruder.pipe.small",
"gregtech:shape.extruder.pipe.medium",
"gregtech:shape.extruder.pipe.normal",
"gregtech:shape.extruder.pipe.large",
"gregtech:shape.extruder.pipe.huge",
"gregtech:shape.extruder.block", "gregtech:shape.extruder.sword",
"gregtech:shape.extruder.pickaxe", "gregtech:shape.extruder.shovel",
"gregtech:shape.extruder.axe", "gregtech:shape.extruder.hoe",
"gregtech:shape.extruder.hammer", "gregtech:shape.extruder.file",
"gregtech:shape.extruder.saw", "gregtech:shape.extruder.gear",
"gregtech:shape.extruder.bottle", "gregtech:shape.extruder.foil",
"gregtech:shape.extruder.gear_small",
"gregtech:shape.extruder.rod_long", "gregtech:shape.extruder.rotor",
"gregtech:glass_lens.white", "gregtech:glass_lens.orange",
"gregtech:glass_lens.magenta", "gregtech:glass_lens.light_blue",
"gregtech:glass_lens.yellow", "gregtech:glass_lens.lime",
"gregtech:glass_lens.pink", "gregtech:glass_lens.gray",
"gregtech:glass_lens.light_gray", "gregtech:glass_lens.cyan",
"gregtech:glass_lens.purple", "gregtech:glass_lens.blue",
"gregtech:glass_lens.brown", "gregtech:glass_lens.green",
"gregtech:glass_lens.red", "gregtech:glass_lens.black",
"contenttweaker:smallgearextrudershape",
"contenttweaker:creativeportabletankmold", "ore:lensAlmandine",
"ore:lensBlueTopaz", "ore:lensDiamond", "ore:lensEmerald",
"ore:lensGreenSapphire", "ore:lensRutile", "ore:lensRuby",
"ore:lensSapphire", "ore:lensTopaz", "ore:lensJasper",
"ore:lensGlass", "ore:lensOlivine", "ore:lensOpal",
"ore:lensAmethyst", "ore:lensLapis", "ore:lensEnderPearl",
"ore:lensEnderEye", "ore:lensGarnetRed", "ore:lensGarnetYellow",
"ore:lensVinteum", "ore:lensNetherStar",
};
// Default Energy Conversion Rates // Default Energy Conversion Rates
private static final double DEFAULT_IC2_EXCHANGE = 2.0; private static final double DEFAULT_IC2_EXCHANGE = 2.0;
private static final double DEFAULT_GTEU_EXCHANGE = 2.0;
private static final double DEFAULT_RF_EXCHANGE = 0.5; private static final double DEFAULT_RF_EXCHANGE = 0.5;
private final IConfigManager settings = new ConfigManager( this ); private final IConfigManager settings = new ConfigManager( this );
@@ -90,10 +140,10 @@ public final class AEConfig extends Configuration implements IConfigurableObject
private PowerUnits selectedPowerUnit = PowerUnits.AE; private PowerUnits selectedPowerUnit = PowerUnits.AE;
// GUI Buttons // GUI Buttons
private final int[] craftByStacks = { 1, 10, 100, 1000 }; private final int[] craftByStacks = {1, 10, 100, 1000};
private final int[] priorityByStacks = { 1, 10, 100, 1000 }; private final int[] priorityByStacks = {1, 10, 100, 1000};
private final int[] levelByStacks = { 1, 10, 100, 1000 }; private final int[] levelByStacks = {1, 10, 100, 1000};
private final int[] levelByMillibuckets = { 10, 100, 1000, 10000 }; private final int[] levelByMillibuckets = {10, 100, 1000, 10000};
// Spatial IO/Dimension // Spatial IO/Dimension
private int storageProviderID = -1; private int storageProviderID = -1;
@@ -125,7 +175,7 @@ public final class AEConfig extends Configuration implements IConfigurableObject
private int minMeteoriteDistanceSq = this.minMeteoriteDistance * this.minMeteoriteDistance; private int minMeteoriteDistanceSq = this.minMeteoriteDistance * this.minMeteoriteDistance;
private double meteoriteClusterChance = 0.1; private double meteoriteClusterChance = 0.1;
private int meteoriteMaximumSpawnHeight = 180; private int meteoriteMaximumSpawnHeight = 180;
private int[] meteoriteDimensionWhitelist = { 0 }; private int[] meteoriteDimensionWhitelist = {0};
// Wireless // Wireless
private double wirelessBaseCost = 8; private double wirelessBaseCost = 8;
@@ -148,6 +198,7 @@ public final class AEConfig extends Configuration implements IConfigurableObject
PowerUnits.EU.conversionRatio = this.get( "PowerRatios", "IC2", DEFAULT_IC2_EXCHANGE ).getDouble( DEFAULT_IC2_EXCHANGE ); PowerUnits.EU.conversionRatio = this.get( "PowerRatios", "IC2", DEFAULT_IC2_EXCHANGE ).getDouble( DEFAULT_IC2_EXCHANGE );
PowerUnits.RF.conversionRatio = this.get( "PowerRatios", "ForgeEnergy", DEFAULT_RF_EXCHANGE ).getDouble( DEFAULT_RF_EXCHANGE ); PowerUnits.RF.conversionRatio = this.get( "PowerRatios", "ForgeEnergy", DEFAULT_RF_EXCHANGE ).getDouble( DEFAULT_RF_EXCHANGE );
PowerUnits.GTEU.conversionRatio = this.get( "PowerRatios", "GTEU", DEFAULT_GTEU_EXCHANGE ).getDouble( DEFAULT_GTEU_EXCHANGE );
final double usageEffective = this.get( "PowerRatios", "UsageMultiplier", 1.0 ).getDouble( 1.0 ); final double usageEffective = this.get( "PowerRatios", "UsageMultiplier", 1.0 ).getDouble( 1.0 );
PowerMultiplier.CONFIG.multiplier = Math.max( 0.01, usageEffective ); PowerMultiplier.CONFIG.multiplier = Math.max( 0.01, usageEffective );
@@ -155,32 +206,24 @@ public final class AEConfig extends Configuration implements IConfigurableObject
CondenserOutput.MATTER_BALLS.requiredPower = this.get( "Condenser", "MatterBalls", 256 ).getInt( 256 ); CondenserOutput.MATTER_BALLS.requiredPower = this.get( "Condenser", "MatterBalls", 256 ).getInt( 256 );
CondenserOutput.SINGULARITY.requiredPower = this.get( "Condenser", "Singularity", 256000 ).getInt( 256000 ); CondenserOutput.SINGULARITY.requiredPower = this.get( "Condenser", "Singularity", 256000 ).getInt( 256000 );
this.removeCrashingItemsOnLoad = this.get( "general", "removeCrashingItemsOnLoad", false, this.removeCrashingItemsOnLoad = this.get( "general", "removeCrashingItemsOnLoad", false, "Will auto-remove items that crash when being loaded from storage. This will destroy those items instead of crashing the game!" ).getBoolean();
"Will auto-remove items that crash when being loaded from storage. This will destroy those items instead of crashing the game!" ).getBoolean();
this.setCategoryComment( "GrindStone", this.setCategoryComment( "BlockingMode", "Map of items to not block when blockingmode is enabled.\n[modid]\nmodid:item:metadata(optional,default:0)\nSupports more than one modid, so you can block different things between, for example, gregtech or enderio" );
"Creates recipe of the following pattern automatically: '1 oreTYPE => 2 dustTYPE' and '(1 ingotTYPE or 1 crystalTYPE or 1 gemTYPE) => 1 dustTYPE'" ); this.nonBlockingItems = this.get( "BlockingMode", "nonBlockingItems", nonBlockingItems, "NonBlockingItems" ).getStringList();
this.grinderOres = this.get( "GrindStone", "grinderOres", this.grinderOres, "The list of types to handle. Specify without a prefix like ore or dust." )
.getStringList(); this.setCategoryComment( "GrindStone", "Creates recipe of the following pattern automatically: '1 oreTYPE => 2 dustTYPE' and '(1 ingotTYPE or 1 crystalTYPE or 1 gemTYPE) => 1 dustTYPE'" );
this.grinderBlackList = Sets.newHashSet( this.grinderOres = this.get( "GrindStone", "grinderOres", this.grinderOres, "The list of types to handle. Specify without a prefix like ore or dust." ).getStringList();
this.get( "GrindStone", "blacklist", new String[] {}, "Blacklists the exact oredict name from being handled by any recipe." ) this.grinderBlackList = Sets.newHashSet( this.get( "GrindStone", "blacklist", new String[]{}, "Blacklists the exact oredict name from being handled by any recipe." ).getStringList() );
.getStringList() ); this.oreDoublePercentage = this.get( "GrindStone", "oreDoublePercentage", this.oreDoublePercentage, "Chance to actually get an output with stacksize > 1." ).getDouble( this.oreDoublePercentage );
this.oreDoublePercentage = this
.get( "GrindStone", "oreDoublePercentage", this.oreDoublePercentage, "Chance to actually get an output with stacksize > 1." )
.getDouble( this.oreDoublePercentage );
this.settings.registerSetting( Settings.SEARCH_TOOLTIPS, YesNo.YES ); this.settings.registerSetting( Settings.SEARCH_TOOLTIPS, YesNo.YES );
this.settings.registerSetting( Settings.TERMINAL_STYLE, TerminalStyle.TALL ); this.settings.registerSetting( Settings.TERMINAL_STYLE, TerminalStyle.TALL );
this.settings.registerSetting( Settings.SEARCH_MODE, SearchBoxMode.AUTOSEARCH ); this.settings.registerSetting( Settings.SEARCH_MODE, SearchBoxMode.AUTOSEARCH );
this.spawnChargedChance = (float) ( 1.0 - this.get( "worldGen", "spawnChargedChance", 1.0 - this.spawnChargedChance ) this.spawnChargedChance = (float) ( 1.0 - this.get( "worldGen", "spawnChargedChance", 1.0 - this.spawnChargedChance ).getDouble( 1.0 - this.spawnChargedChance ) );
.getDouble(
1.0 - this.spawnChargedChance ) );
this.minMeteoriteDistance = this.get( "worldGen", "minMeteoriteDistance", this.minMeteoriteDistance ).getInt( this.minMeteoriteDistance ); this.minMeteoriteDistance = this.get( "worldGen", "minMeteoriteDistance", this.minMeteoriteDistance ).getInt( this.minMeteoriteDistance );
this.meteoriteClusterChance = this.get( "worldGen", "meteoriteClusterChance", this.meteoriteClusterChance ).getDouble( this.meteoriteClusterChance ); this.meteoriteClusterChance = this.get( "worldGen", "meteoriteClusterChance", this.meteoriteClusterChance ).getDouble( this.meteoriteClusterChance );
this.meteoriteMaximumSpawnHeight = this.get( "worldGen", "meteoriteMaximumSpawnHeight", this.meteoriteMaximumSpawnHeight ) this.meteoriteMaximumSpawnHeight = this.get( "worldGen", "meteoriteMaximumSpawnHeight", this.meteoriteMaximumSpawnHeight ).getInt( this.meteoriteMaximumSpawnHeight );
.getInt(
this.meteoriteMaximumSpawnHeight );
this.meteoriteDimensionWhitelist = this.get( "worldGen", "meteoriteDimensionWhitelist", this.meteoriteDimensionWhitelist ).getIntList(); this.meteoriteDimensionWhitelist = this.get( "worldGen", "meteoriteDimensionWhitelist", this.meteoriteDimensionWhitelist ).getIntList();
this.quartzOresPerCluster = this.get( "worldGen", "quartzOresPerCluster", this.quartzOresPerCluster ).getInt( this.quartzOresPerCluster ); this.quartzOresPerCluster = this.get( "worldGen", "quartzOresPerCluster", this.quartzOresPerCluster ).getInt( this.quartzOresPerCluster );
@@ -188,23 +231,16 @@ public final class AEConfig extends Configuration implements IConfigurableObject
this.minMeteoriteDistanceSq = this.minMeteoriteDistance * this.minMeteoriteDistance; this.minMeteoriteDistanceSq = this.minMeteoriteDistance * this.minMeteoriteDistance;
this.addCustomCategoryComment( "wireless", this.addCustomCategoryComment( "wireless", "Range= wirelessBaseRange + wirelessBoosterRangeMultiplier * Math.pow( boosters, wirelessBoosterExp )\nPowerDrain= wirelessBaseCost + wirelessCostMultiplier * Math.pow( boosters, 1 + boosters / wirelessHighWirelessCount )" );
"Range= wirelessBaseRange + wirelessBoosterRangeMultiplier * Math.pow( boosters, wirelessBoosterExp )\nPowerDrain= wirelessBaseCost + wirelessCostMultiplier * Math.pow( boosters, 1 + boosters / wirelessHighWirelessCount )" );
this.wirelessBaseCost = this.get( "wireless", "wirelessBaseCost", this.wirelessBaseCost ).getDouble( this.wirelessBaseCost ); this.wirelessBaseCost = this.get( "wireless", "wirelessBaseCost", this.wirelessBaseCost ).getDouble( this.wirelessBaseCost );
this.wirelessCostMultiplier = this.get( "wireless", "wirelessCostMultiplier", this.wirelessCostMultiplier ).getDouble( this.wirelessCostMultiplier ); this.wirelessCostMultiplier = this.get( "wireless", "wirelessCostMultiplier", this.wirelessCostMultiplier ).getDouble( this.wirelessCostMultiplier );
this.wirelessBaseRange = this.get( "wireless", "wirelessBaseRange", this.wirelessBaseRange ).getDouble( this.wirelessBaseRange ); this.wirelessBaseRange = this.get( "wireless", "wirelessBaseRange", this.wirelessBaseRange ).getDouble( this.wirelessBaseRange );
this.wirelessBoosterRangeMultiplier = this.get( "wireless", "wirelessBoosterRangeMultiplier", this.wirelessBoosterRangeMultiplier ) this.wirelessBoosterRangeMultiplier = this.get( "wireless", "wirelessBoosterRangeMultiplier", this.wirelessBoosterRangeMultiplier ).getDouble( this.wirelessBoosterRangeMultiplier );
.getDouble(
this.wirelessBoosterRangeMultiplier );
this.wirelessBoosterExp = this.get( "wireless", "wirelessBoosterExp", this.wirelessBoosterExp ).getDouble( this.wirelessBoosterExp ); this.wirelessBoosterExp = this.get( "wireless", "wirelessBoosterExp", this.wirelessBoosterExp ).getDouble( this.wirelessBoosterExp );
this.wirelessTerminalDrainMultiplier = this.get( "wireless", "wirelessTerminalDrainMultiplier", this.wirelessTerminalDrainMultiplier ) this.wirelessTerminalDrainMultiplier = this.get( "wireless", "wirelessTerminalDrainMultiplier", this.wirelessTerminalDrainMultiplier ).getDouble( this.wirelessTerminalDrainMultiplier );
.getDouble(
this.wirelessTerminalDrainMultiplier );
this.formationPlaneEntityLimit = this.get( "automation", "formationPlaneEntityLimit", this.formationPlaneEntityLimit ) this.formationPlaneEntityLimit = this.get( "automation", "formationPlaneEntityLimit", this.formationPlaneEntityLimit ).getInt( this.formationPlaneEntityLimit );
.getInt(
this.formationPlaneEntityLimit );
this.wirelessTerminalBattery = this.get( "battery", "wirelessTerminal", this.wirelessTerminalBattery ).getInt( this.wirelessTerminalBattery ); this.wirelessTerminalBattery = this.get( "battery", "wirelessTerminal", this.wirelessTerminalBattery ).getInt( this.wirelessTerminalBattery );
this.chargedStaffBattery = this.get( "battery", "chargedStaff", this.chargedStaffBattery ).getInt( this.chargedStaffBattery ); this.chargedStaffBattery = this.get( "battery", "chargedStaff", this.chargedStaffBattery ).getInt( this.chargedStaffBattery );
@@ -245,8 +281,7 @@ public final class AEConfig extends Configuration implements IConfigurableObject
try try
{ {
this.selectedPowerUnit = PowerUnits.valueOf( this.selectedPowerUnit = PowerUnits.valueOf( this.get( "Client", "PowerUnit", this.selectedPowerUnit.name(), this.getListComment( this.selectedPowerUnit ) ).getString() );
this.get( "Client", "PowerUnit", this.selectedPowerUnit.name(), this.getListComment( this.selectedPowerUnit ) ).getString() );
} }
catch( final Throwable t ) catch( final Throwable t )
{ {
@@ -262,17 +297,13 @@ public final class AEConfig extends Configuration implements IConfigurableObject
{ {
this.storageProviderID = this.get( "spatialio", "storageProviderID", this.storageProviderID ).getInt( this.storageProviderID ); this.storageProviderID = this.get( "spatialio", "storageProviderID", this.storageProviderID ).getInt( this.storageProviderID );
this.storageDimensionID = this.get( "spatialio", "storageDimensionID", this.storageDimensionID ).getInt( this.storageDimensionID ); this.storageDimensionID = this.get( "spatialio", "storageDimensionID", this.storageDimensionID ).getInt( this.storageDimensionID );
this.spatialPowerMultiplier = this.get( "spatialio", "spatialPowerMultiplier", this.spatialPowerMultiplier ) this.spatialPowerMultiplier = this.get( "spatialio", "spatialPowerMultiplier", this.spatialPowerMultiplier ).getDouble( this.spatialPowerMultiplier );
.getDouble(
this.spatialPowerMultiplier );
this.spatialPowerExponent = this.get( "spatialio", "spatialPowerExponent", this.spatialPowerExponent ).getDouble( this.spatialPowerExponent ); this.spatialPowerExponent = this.get( "spatialio", "spatialPowerExponent", this.spatialPowerExponent ).getDouble( this.spatialPowerExponent );
} }
if( this.isFeatureEnabled( AEFeature.CRAFTING_CPU ) ) if( this.isFeatureEnabled( AEFeature.CRAFTING_CPU ) )
{ {
this.craftingCalculationTimePerTick = this.get( "craftingCPU", "craftingCalculationTimePerTick", this.craftingCalculationTimePerTick ) this.craftingCalculationTimePerTick = this.get( "craftingCPU", "craftingCalculationTimePerTick", this.craftingCalculationTimePerTick ).getInt( this.craftingCalculationTimePerTick );
.getInt(
this.craftingCalculationTimePerTick );
} }
this.updatable = true; this.updatable = true;
@@ -446,8 +477,7 @@ public final class AEConfig extends Configuration implements IConfigurableObject
return true; return true;
} }
this.setCategoryComment( "OreCamouflage", this.setCategoryComment( "OreCamouflage", "AE2 Automatically uses alternative ores present in your instance of MC to blend better with its surroundings, if you prefer you can disable this selectively using these flags; Its important to note, that some if these items even if enabled may not be craftable in game because other items are overriding their recipes." );
"AE2 Automatically uses alternative ores present in your instance of MC to blend better with its surroundings, if you prefer you can disable this selectively using these flags; Its important to note, that some if these items even if enabled may not be craftable in game because other items are overriding their recipes." );
final Property p = this.get( "OreCamouflage", mt.name(), true ); final Property p = this.get( "OreCamouflage", mt.name(), true );
p.setComment( "OreDictionary Names: " + mt.getOreName() ); p.setComment( "OreDictionary Names: " + mt.getOreName() );
@@ -715,6 +745,11 @@ public final class AEConfig extends Configuration implements IConfigurableObject
return this.quartzOresClusterAmount; return this.quartzOresClusterAmount;
} }
public String[] getNonBlockingItems()
{
return nonBlockingItems;
}
public int getChargedChange() public int getChargedChange()
{ {
return this.chargedChange; return this.chargedChange;
+4 -2
View File
@@ -25,6 +25,7 @@ import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import appeng.helpers.NonBlockingItems;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
@@ -183,8 +184,7 @@ public final class AppEng
AELog.info( "Pre Initialization ( ended after " + watch.elapsed( TimeUnit.MILLISECONDS ) + "ms )" ); AELog.info( "Pre Initialization ( ended after " + watch.elapsed( TimeUnit.MILLISECONDS ) + "ms )" );
// Instantiate all Plugins // Instantiate all Plugins
List<Object> injectables = Lists.newArrayList( List<Object> injectables = Lists.newArrayList( AEApi.instance() );
AEApi.instance() );
new PluginLoader().loadPlugins( injectables, event.getAsmData() ); new PluginLoader().loadPlugins( injectables, event.getAsmData() );
} }
@@ -239,6 +239,8 @@ public final class AppEng
AppEng.proxy.postInit(); AppEng.proxy.postInit();
AEConfig.instance().save(); AEConfig.instance().save();
NonBlockingItems.INSTANCE.init();
NetworkRegistry.INSTANCE.registerGuiHandler( this, GuiBridge.GUI_Handler ); NetworkRegistry.INSTANCE.registerGuiHandler( this, GuiBridge.GUI_Handler );
NetworkHandler.init( "AE2" ); NetworkHandler.init( "AE2" );
@@ -363,6 +363,8 @@ final class Registration
// Interface // Interface
Upgrades.CRAFTING.registerItem( parts.iface(), 1 ); Upgrades.CRAFTING.registerItem( parts.iface(), 1 );
Upgrades.CRAFTING.registerItem( blocks.iface(), 1 ); Upgrades.CRAFTING.registerItem( blocks.iface(), 1 );
Upgrades.PATTERN_EXPANSION.registerItem( parts.iface(), 3 );
Upgrades.PATTERN_EXPANSION.registerItem( blocks.iface(), 3 );
// IO Port! // IO Port!
Upgrades.SPEED.registerItem( blocks.iOPort(), 3 ); Upgrades.SPEED.registerItem( blocks.iOPort(), 3 );
@@ -175,7 +175,7 @@ public class ApiStorage implements IStorageHelper
@Override @Override
public int transferFactor() public int transferFactor()
{ {
return 125; return 1000;
} }
@Override @Override
@@ -86,6 +86,7 @@ public final class ApiMaterials implements IMaterials
private final IItemDefinition cardRedstone; private final IItemDefinition cardRedstone;
private final IItemDefinition cardSpeed; private final IItemDefinition cardSpeed;
private final IItemDefinition cardCapacity; private final IItemDefinition cardCapacity;
private final IItemDefinition cardPatternExpansion;
private final IItemDefinition cardFuzzy; private final IItemDefinition cardFuzzy;
private final IItemDefinition cardInverter; private final IItemDefinition cardInverter;
private final IItemDefinition cardCrafting; 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.cardRedstone = new DamagedItemDefinition( "material.card.redstone", materials.createMaterial( MaterialType.CARD_REDSTONE ) );
this.cardSpeed = new DamagedItemDefinition( "material.card.acceleration", materials.createMaterial( MaterialType.CARD_SPEED ) ); 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.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.cardFuzzy = new DamagedItemDefinition( "material.card.fuzzy", materials.createMaterial( MaterialType.CARD_FUZZY ) );
this.cardInverter = new DamagedItemDefinition( "material.card.inverter", materials.createMaterial( MaterialType.CARD_INVERTER ) ); this.cardInverter = new DamagedItemDefinition( "material.card.inverter", materials.createMaterial( MaterialType.CARD_INVERTER ) );
this.cardCrafting = new DamagedItemDefinition( "material.card.crafting", materials.createMaterial( MaterialType.CARD_CRAFTING ) ); 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; return this.cardCapacity;
} }
@Override
public IItemDefinition cardPatternExpansion(){ return this.cardPatternExpansion;}
@Override @Override
public IItemDefinition cardFuzzy() public IItemDefinition cardFuzzy()
{ {
@@ -52,6 +52,7 @@ public final class ApiParts implements IParts
private final IItemDefinition toggleBus; private final IItemDefinition toggleBus;
private final IItemDefinition invertedToggleBus; private final IItemDefinition invertedToggleBus;
private final IItemDefinition storageBus; private final IItemDefinition storageBus;
private final IItemDefinition oreDictStorageBus;
private final IItemDefinition importBus; private final IItemDefinition importBus;
private final IItemDefinition exportBus; private final IItemDefinition exportBus;
private final IItemDefinition iface; private final IItemDefinition iface;
@@ -69,6 +70,7 @@ public final class ApiParts implements IParts
private final IItemDefinition p2PTunnelFluids; private final IItemDefinition p2PTunnelFluids;
private final IItemDefinition p2PTunnelEU; private final IItemDefinition p2PTunnelEU;
private final IItemDefinition p2PTunnelFE; private final IItemDefinition p2PTunnelFE;
private final IItemDefinition p2PTunnelGTEU;
private final IItemDefinition p2PTunnelLight; private final IItemDefinition p2PTunnelLight;
// private final IItemDefinition p2PTunnelOpenComputers; // private final IItemDefinition p2PTunnelOpenComputers;
private final IItemDefinition cableAnchor; private final IItemDefinition cableAnchor;
@@ -77,6 +79,7 @@ public final class ApiParts implements IParts
private final IItemDefinition darkMonitor; private final IItemDefinition darkMonitor;
private final IItemDefinition interfaceTerminal; private final IItemDefinition interfaceTerminal;
private final IItemDefinition patternTerminal; private final IItemDefinition patternTerminal;
private final IItemDefinition expandedProcessingPatternTerminal;
private final IItemDefinition craftingTerminal; private final IItemDefinition craftingTerminal;
private final IItemDefinition terminal; private final IItemDefinition terminal;
private final IItemDefinition storageMonitor; private final IItemDefinition storageMonitor;
@@ -89,9 +92,7 @@ public final class ApiParts implements IParts
public ApiParts( FeatureFactory registry, PartModels partModels ) public ApiParts( FeatureFactory registry, PartModels partModels )
{ {
final ItemPart itemPart = new ItemPart(); final ItemPart itemPart = new ItemPart();
registry.item( "part", () -> itemPart ) registry.item( "part", () -> itemPart ).rendering( new ItemPartRendering( partModels, itemPart ) ).build();
.rendering( new ItemPartRendering( partModels, itemPart ) )
.build();
// Register all part models // Register all part models
for( PartType partType : PartType.values() ) for( PartType partType : PartType.values() )
@@ -112,6 +113,7 @@ public final class ApiParts implements IParts
this.toggleBus = new DamagedItemDefinition( "part.toggle_bus", itemPart.createPart( PartType.TOGGLE_BUS ) ); this.toggleBus = new DamagedItemDefinition( "part.toggle_bus", itemPart.createPart( PartType.TOGGLE_BUS ) );
this.invertedToggleBus = new DamagedItemDefinition( "part.toggle_bus.inverted", itemPart.createPart( PartType.INVERTED_TOGGLE_BUS ) ); this.invertedToggleBus = new DamagedItemDefinition( "part.toggle_bus.inverted", itemPart.createPart( PartType.INVERTED_TOGGLE_BUS ) );
this.storageBus = new DamagedItemDefinition( "part.bus.storage", itemPart.createPart( PartType.STORAGE_BUS ) ); this.storageBus = new DamagedItemDefinition( "part.bus.storage", itemPart.createPart( PartType.STORAGE_BUS ) );
this.oreDictStorageBus = new DamagedItemDefinition( "part.bus.oredict_storage", itemPart.createPart( PartType.OREDICT_STORAGE_BUS ) );
this.importBus = new DamagedItemDefinition( "part.bus.import", itemPart.createPart( PartType.IMPORT_BUS ) ); this.importBus = new DamagedItemDefinition( "part.bus.import", itemPart.createPart( PartType.IMPORT_BUS ) );
this.exportBus = new DamagedItemDefinition( "part.bus.export", itemPart.createPart( PartType.EXPORT_BUS ) ); this.exportBus = new DamagedItemDefinition( "part.bus.export", itemPart.createPart( PartType.EXPORT_BUS ) );
this.iface = new DamagedItemDefinition( "part.interface", itemPart.createPart( PartType.INTERFACE ) ); this.iface = new DamagedItemDefinition( "part.interface", itemPart.createPart( PartType.INTERFACE ) );
@@ -119,8 +121,7 @@ public final class ApiParts implements IParts
this.levelEmitter = new DamagedItemDefinition( "part.level_emitter", itemPart.createPart( PartType.LEVEL_EMITTER ) ); this.levelEmitter = new DamagedItemDefinition( "part.level_emitter", itemPart.createPart( PartType.LEVEL_EMITTER ) );
this.fluidLevelEmitter = new DamagedItemDefinition( "part.fluid_level_emitter", itemPart.createPart( PartType.FLUID_LEVEL_EMITTER ) ); this.fluidLevelEmitter = new DamagedItemDefinition( "part.fluid_level_emitter", itemPart.createPart( PartType.FLUID_LEVEL_EMITTER ) );
this.annihilationPlane = new DamagedItemDefinition( "part.plane.annihilation", itemPart.createPart( PartType.ANNIHILATION_PLANE ) ); this.annihilationPlane = new DamagedItemDefinition( "part.plane.annihilation", itemPart.createPart( PartType.ANNIHILATION_PLANE ) );
this.identityAnnihilationPlane = new DamagedItemDefinition( "part.plane.annihiliation.identity", itemPart this.identityAnnihilationPlane = new DamagedItemDefinition( "part.plane.annihiliation.identity", itemPart.createPart( PartType.IDENTITY_ANNIHILATION_PLANE ) );
.createPart( PartType.IDENTITY_ANNIHILATION_PLANE ) );
this.fluidAnnihilationPlane = new DamagedItemDefinition( "part.plane.fluid_annihilation", itemPart.createPart( PartType.FLUID_ANNIHILATION_PLANE ) ); this.fluidAnnihilationPlane = new DamagedItemDefinition( "part.plane.fluid_annihilation", itemPart.createPart( PartType.FLUID_ANNIHILATION_PLANE ) );
this.formationPlane = new DamagedItemDefinition( "part.plane.formation", itemPart.createPart( PartType.FORMATION_PLANE ) ); this.formationPlane = new DamagedItemDefinition( "part.plane.formation", itemPart.createPart( PartType.FORMATION_PLANE ) );
this.fluidFormationPlane = new DamagedItemDefinition( "part.plane.fluid_formation", itemPart.createPart( PartType.FLUID_FORMATION_PLANE ) ); this.fluidFormationPlane = new DamagedItemDefinition( "part.plane.fluid_formation", itemPart.createPart( PartType.FLUID_FORMATION_PLANE ) );
@@ -130,6 +131,7 @@ public final class ApiParts implements IParts
this.p2PTunnelFluids = new DamagedItemDefinition( "part.tunnel.fluid", itemPart.createPart( PartType.P2P_TUNNEL_FLUIDS ) ); this.p2PTunnelFluids = new DamagedItemDefinition( "part.tunnel.fluid", itemPart.createPart( PartType.P2P_TUNNEL_FLUIDS ) );
this.p2PTunnelEU = new DamagedItemDefinition( "part.tunnel.eu", itemPart.createPart( PartType.P2P_TUNNEL_IC2 ) ); this.p2PTunnelEU = new DamagedItemDefinition( "part.tunnel.eu", itemPart.createPart( PartType.P2P_TUNNEL_IC2 ) );
this.p2PTunnelFE = new DamagedItemDefinition( "part.tunnel.fe", itemPart.createPart( PartType.P2P_TUNNEL_FE ) ); this.p2PTunnelFE = new DamagedItemDefinition( "part.tunnel.fe", itemPart.createPart( PartType.P2P_TUNNEL_FE ) );
this.p2PTunnelGTEU = new DamagedItemDefinition( "part.tunnel.gteu", itemPart.createPart( PartType.P2P_TUNNEL_GTEU ) );
this.p2PTunnelLight = new DamagedItemDefinition( "part.tunnel.light", itemPart.createPart( PartType.P2P_TUNNEL_LIGHT ) ); this.p2PTunnelLight = new DamagedItemDefinition( "part.tunnel.light", itemPart.createPart( PartType.P2P_TUNNEL_LIGHT ) );
// this.p2PTunnelOpenComputers = new DamagedItemDefinition( itemMultiPart.createPart( // this.p2PTunnelOpenComputers = new DamagedItemDefinition( itemMultiPart.createPart(
// PartType.P2PTunnelOpenComputers ) ); // PartType.P2PTunnelOpenComputers ) );
@@ -139,6 +141,7 @@ public final class ApiParts implements IParts
this.darkMonitor = new DamagedItemDefinition( "part.monitor.dark", itemPart.createPart( PartType.DARK_MONITOR ) ); this.darkMonitor = new DamagedItemDefinition( "part.monitor.dark", itemPart.createPart( PartType.DARK_MONITOR ) );
this.interfaceTerminal = new DamagedItemDefinition( "part.terminal.interface", itemPart.createPart( PartType.INTERFACE_TERMINAL ) ); this.interfaceTerminal = new DamagedItemDefinition( "part.terminal.interface", itemPart.createPart( PartType.INTERFACE_TERMINAL ) );
this.patternTerminal = new DamagedItemDefinition( "part.terminal.pattern", itemPart.createPart( PartType.PATTERN_TERMINAL ) ); this.patternTerminal = new DamagedItemDefinition( "part.terminal.pattern", itemPart.createPart( PartType.PATTERN_TERMINAL ) );
this.expandedProcessingPatternTerminal = new DamagedItemDefinition( "part.terminal.expanded_processing_pattern", itemPart.createPart( PartType.EXPANDED_PROCESSING_PATTERN_TERMINAL ) );
this.craftingTerminal = new DamagedItemDefinition( "part.terminal.crafting", itemPart.createPart( PartType.CRAFTING_TERMINAL ) ); this.craftingTerminal = new DamagedItemDefinition( "part.terminal.crafting", itemPart.createPart( PartType.CRAFTING_TERMINAL ) );
this.terminal = new DamagedItemDefinition( "part.terminal", itemPart.createPart( PartType.TERMINAL ) ); this.terminal = new DamagedItemDefinition( "part.terminal", itemPart.createPart( PartType.TERMINAL ) );
this.storageMonitor = new DamagedItemDefinition( "part.monitor.storage", itemPart.createPart( PartType.STORAGE_MONITOR ) ); this.storageMonitor = new DamagedItemDefinition( "part.monitor.storage", itemPart.createPart( PartType.STORAGE_MONITOR ) );
@@ -245,6 +248,12 @@ public final class ApiParts implements IParts
return this.storageBus; return this.storageBus;
} }
@Override
public IItemDefinition oreDictStorageBus()
{
return this.oreDictStorageBus;
}
@Override @Override
public IItemDefinition importBus() public IItemDefinition importBus()
{ {
@@ -329,6 +338,11 @@ public final class ApiParts implements IParts
return this.p2PTunnelFE; return this.p2PTunnelFE;
} }
public IItemDefinition p2PTunnelGTEU()
{
return this.p2PTunnelGTEU;
}
@Override @Override
public IItemDefinition p2PTunnelLight() public IItemDefinition p2PTunnelLight()
{ {
@@ -379,6 +393,12 @@ public final class ApiParts implements IParts
return this.patternTerminal; return this.patternTerminal;
} }
@Override
public IItemDefinition expandedProcessingPatternTerminal()
{
return this.expandedProcessingPatternTerminal;
}
@Override @Override
public IItemDefinition craftingTerminal() public IItemDefinition craftingTerminal()
{ {
@@ -25,13 +25,13 @@ public enum AEFeature
// is just flat out required by tons of // is just flat out required by tons of
// important stuff. // important stuff.
CORE( "Core", null ) CORE( "Core", null )
{ {
@Override @Override
public boolean isVisible() public boolean isVisible()
{ {
return false; return false;
} }
}, },
CERTUS_QUARTZ_WORLD_GEN( "CertusQuartzWorldGen", Constants.CATEGORY_WORLD ), CERTUS_QUARTZ_WORLD_GEN( "CertusQuartzWorldGen", Constants.CATEGORY_WORLD ),
METEORITE_WORLD_GEN( "MeteoriteWorldGen", Constants.CATEGORY_WORLD ), METEORITE_WORLD_GEN( "MeteoriteWorldGen", Constants.CATEGORY_WORLD ),
@@ -126,6 +126,7 @@ public enum AEFeature
P2P_TUNNEL_REDSTONE( "P2PTunnelRedstone", Constants.CATEGORY_P2P_TUNNELS ), P2P_TUNNEL_REDSTONE( "P2PTunnelRedstone", Constants.CATEGORY_P2P_TUNNELS ),
P2P_TUNNEL_EU( "P2PTunnelEU", Constants.CATEGORY_P2P_TUNNELS ), P2P_TUNNEL_EU( "P2PTunnelEU", Constants.CATEGORY_P2P_TUNNELS ),
P2P_TUNNEL_FE( "P2PTunnelFE", Constants.CATEGORY_P2P_TUNNELS ), P2P_TUNNEL_FE( "P2PTunnelFE", Constants.CATEGORY_P2P_TUNNELS ),
P2P_TUNNEL_GTEU( "P2PTunnelGTEU", Constants.CATEGORY_P2P_TUNNELS ),
P2P_TUNNEL_FLUIDS( "P2PTunnelFluids", Constants.CATEGORY_P2P_TUNNELS ), P2P_TUNNEL_FLUIDS( "P2PTunnelFluids", Constants.CATEGORY_P2P_TUNNELS ),
P2P_TUNNEL_LIGHT( "P2PTunnelLight", Constants.CATEGORY_P2P_TUNNELS ), P2P_TUNNEL_LIGHT( "P2PTunnelLight", Constants.CATEGORY_P2P_TUNNELS ),
P2P_TUNNEL_OPEN_COMPUTERS( "P2PTunnelOpenComputers", Constants.CATEGORY_P2P_TUNNELS ), P2P_TUNNEL_OPEN_COMPUTERS( "P2PTunnelOpenComputers", Constants.CATEGORY_P2P_TUNNELS ),
@@ -163,7 +164,6 @@ public enum AEFeature
MOLECULAR_ASSEMBLER( "MolecularAssembler", Constants.CATEGORY_CRAFTING_FEATURES ), MOLECULAR_ASSEMBLER( "MolecularAssembler", Constants.CATEGORY_CRAFTING_FEATURES ),
PATTERNS( "Patterns", Constants.CATEGORY_CRAFTING_FEATURES ), PATTERNS( "Patterns", Constants.CATEGORY_CRAFTING_FEATURES ),
CRAFTING_CPU( "CraftingCPU", Constants.CATEGORY_CRAFTING_FEATURES ), CRAFTING_CPU( "CraftingCPU", Constants.CATEGORY_CRAFTING_FEATURES ),
CRAFTING_MANAGER_FALLBACK( "CraftingManagerFallback", Constants.CATEGORY_CRAFTING_FEATURES, "Use CraftingManager to find an alternative recipe, after a pattern rejected an ingredient. Should be enabled to avoid issues, but can have a minor performance impact." ),
BASIC_CARDS( "BasicCards", Constants.CATEGORY_UPGRADES ), BASIC_CARDS( "BasicCards", Constants.CATEGORY_UPGRADES ),
ADVANCED_CARDS( "AdvancedCards", Constants.CATEGORY_UPGRADES ), ADVANCED_CARDS( "AdvancedCards", Constants.CATEGORY_UPGRADES ),
@@ -19,13 +19,14 @@
package appeng.core.features.registries; package appeng.core.features.registries;
import java.util.HashMap; import java.util.*;
import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import appeng.core.AELog;
import appeng.util.item.OreHelper;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.init.Items; import net.minecraft.init.Items;
import net.minecraft.item.Item; import net.minecraft.item.Item;
@@ -67,6 +68,25 @@ public final class P2PTunnelRegistry implements IP2PTunnelRegistry
this.addNewAttunement( new ItemStack( Blocks.TORCH ), TunnelType.LIGHT ); this.addNewAttunement( new ItemStack( Blocks.TORCH ), TunnelType.LIGHT );
this.addNewAttunement( new ItemStack( Blocks.GLOWSTONE ), TunnelType.LIGHT ); this.addNewAttunement( new ItemStack( Blocks.GLOWSTONE ), TunnelType.LIGHT );
List<String> gtceOreDict = new ArrayList<>();
gtceOreDict.add( "wireGtHex" );
gtceOreDict.add( "wireGtOctal" );
gtceOreDict.add( "wireGtQuadruple" );
gtceOreDict.add( "wireGtDouble" );
gtceOreDict.add( "wireGtSingle" );
gtceOreDict.add( "cableGtHex" );
gtceOreDict.add( "cableGtOctal" );
gtceOreDict.add( "cableGtQuadruple" );
gtceOreDict.add( "cableGtDouble" );
gtceOreDict.add( "cableGtSingle" );
for( String oreDict : gtceOreDict )
{
Arrays.stream( OreDictionary.getOreNames() ).filter( oreName -> oreName.startsWith( oreDict ) ).forEach( oreName -> {
OreHelper.INSTANCE.getCachedOres( oreName ).forEach( stack -> this.addNewAttunement( stack, TunnelType.GTEU_POWER ) );
} );
}
/** /**
* Forge energy tunnel items * Forge energy tunnel items
*/ */
@@ -127,12 +147,12 @@ public final class P2PTunnelRegistry implements IP2PTunnelRegistry
this.addNewAttunement( this.getModItem( "enderio", "itemitemconduit", OreDictionary.WILDCARD_VALUE ), TunnelType.ITEM ); this.addNewAttunement( this.getModItem( "enderio", "itemitemconduit", OreDictionary.WILDCARD_VALUE ), TunnelType.ITEM );
this.addNewAttunement( this.getModItem( "thermaldynamics", "duct_32", 0 ), TunnelType.ITEM ); // itemduct this.addNewAttunement( this.getModItem( "thermaldynamics", "duct_32", 0 ), TunnelType.ITEM ); // itemduct
this.addNewAttunement( this.getModItem( "thermaldynamics", "duct_32", 1 ), TunnelType.ITEM ); // itemduct this.addNewAttunement( this.getModItem( "thermaldynamics", "duct_32", 1 ), TunnelType.ITEM ); // itemduct
// (opaque) // (opaque)
this.addNewAttunement( this.getModItem( "thermaldynamics", "duct_32", 2 ), TunnelType.ITEM ); // impulse this.addNewAttunement( this.getModItem( "thermaldynamics", "duct_32", 2 ), TunnelType.ITEM ); // impulse
// itemduct // itemduct
this.addNewAttunement( this.getModItem( "thermaldynamics", "duct_32", 3 ), TunnelType.ITEM ); // impulse this.addNewAttunement( this.getModItem( "thermaldynamics", "duct_32", 3 ), TunnelType.ITEM ); // impulse
// itemduct // itemduct
// (opaque) // (opaque)
/** /**
* attune based on lots of random item related stuff * attune based on lots of random item related stuff
@@ -148,12 +168,12 @@ public final class P2PTunnelRegistry implements IP2PTunnelRegistry
this.addNewAttunement( this.getModItem( "enderio", "itemliquidconduit", OreDictionary.WILDCARD_VALUE ), TunnelType.FLUID ); this.addNewAttunement( this.getModItem( "enderio", "itemliquidconduit", OreDictionary.WILDCARD_VALUE ), TunnelType.FLUID );
this.addNewAttunement( this.getModItem( "thermaldynamics", "duct_16", 0 ), TunnelType.FLUID ); // fluiduct this.addNewAttunement( this.getModItem( "thermaldynamics", "duct_16", 0 ), TunnelType.FLUID ); // fluiduct
this.addNewAttunement( this.getModItem( "thermaldynamics", "duct_16", 1 ), TunnelType.FLUID ); // fluiduct this.addNewAttunement( this.getModItem( "thermaldynamics", "duct_16", 1 ), TunnelType.FLUID ); // fluiduct
// (opaque) // (opaque)
this.addNewAttunement( this.getModItem( "thermaldynamics", "duct_16", 2 ), TunnelType.FLUID ); // fluiduct this.addNewAttunement( this.getModItem( "thermaldynamics", "duct_16", 2 ), TunnelType.FLUID ); // fluiduct
// hardened // hardened
this.addNewAttunement( this.getModItem( "thermaldynamics", "duct_16", 3 ), TunnelType.FLUID ); // fluiduct this.addNewAttunement( this.getModItem( "thermaldynamics", "duct_16", 3 ), TunnelType.FLUID ); // fluiduct
// hardened // hardened
// (opaque) // (opaque)
for( final AEColor c : AEColor.values() ) for( final AEColor c : AEColor.values() )
{ {
@@ -70,6 +70,7 @@ public enum GuiText
EnergyDrain, EnergyDrain,
StorageBus, StorageBus,
OreDictStorageBus,
StorageBusFluids, StorageBusFluids,
Priority, Priority,
Security, Security,
@@ -98,6 +99,7 @@ public enum GuiText
OCTunnel, OCTunnel,
LightTunnel, LightTunnel,
FETunnel, FETunnel,
GTEUTunnel,
PressureTunnel, PressureTunnel,
// spatial // spatial
@@ -31,8 +31,10 @@ public enum WailaText
DeviceMissingChannel, DeviceMissingChannel,
P2PUnlinked, P2PUnlinked,
P2PInputOneOutput, P2P_INPUT_ONE_OUTPUT,
P2PInputManyOutputs, P2P_INPUT_MANY_OUTPUTS,
P2P_OUTPUT_ONE_INPUT,
P2P_OUTPUT_MANY_INPUTS,
P2POutput, P2POutput,
Locked, Locked,
@@ -24,34 +24,9 @@ import java.lang.reflect.InvocationTargetException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import appeng.core.sync.packets.*;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import appeng.core.sync.packets.PacketAssemblerAnimation;
import appeng.core.sync.packets.PacketClick;
import appeng.core.sync.packets.PacketCompassRequest;
import appeng.core.sync.packets.PacketCompassResponse;
import appeng.core.sync.packets.PacketCompressedNBT;
import appeng.core.sync.packets.PacketConfigButton;
import appeng.core.sync.packets.PacketCraftRequest;
import appeng.core.sync.packets.PacketFluidSlot;
import appeng.core.sync.packets.PacketInventoryAction;
import appeng.core.sync.packets.PacketJEIRecipe;
import appeng.core.sync.packets.PacketLightning;
import appeng.core.sync.packets.PacketMEFluidInventoryUpdate;
import appeng.core.sync.packets.PacketMEInventoryUpdate;
import appeng.core.sync.packets.PacketMatterCannon;
import appeng.core.sync.packets.PacketMockExplosion;
import appeng.core.sync.packets.PacketPaintedEntity;
import appeng.core.sync.packets.PacketPartPlacement;
import appeng.core.sync.packets.PacketPatternSlot;
import appeng.core.sync.packets.PacketProgressBar;
import appeng.core.sync.packets.PacketSwapSlots;
import appeng.core.sync.packets.PacketSwitchGuis;
import appeng.core.sync.packets.PacketTargetFluidStack;
import appeng.core.sync.packets.PacketTargetItemStack;
import appeng.core.sync.packets.PacketTransitionEffect;
import appeng.core.sync.packets.PacketValueConfig;
public class AppEngPacketHandlerBase public class AppEngPacketHandlerBase
{ {
@@ -107,7 +82,10 @@ public class AppEngPacketHandlerBase
PACKET_PAINTED_ENTITY( PacketPaintedEntity.class ), PACKET_PAINTED_ENTITY( PacketPaintedEntity.class ),
PACKET_FLUID_TANK( PacketFluidSlot.class ); PACKET_FLUID_TANK( PacketFluidSlot.class ),
PACKET_INFORM_PLAYER( PacketInformPlayer.class );
private final Class<? extends AppEngPacket> packetClass; private final Class<? extends AppEngPacket> packetClass;
private final Constructor<? extends AppEngPacket> packetConstructor; private final Constructor<? extends AppEngPacket> packetConstructor;
+7 -33
View File
@@ -21,6 +21,9 @@ package appeng.core.sync;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import appeng.container.implementations.*;
import appeng.parts.misc.PartOreDicStorageBus;
import appeng.parts.reporting.PartExpandedProcessingPatternTerminal;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@@ -53,39 +56,6 @@ import appeng.client.gui.GuiNull;
import appeng.container.AEBaseContainer; import appeng.container.AEBaseContainer;
import appeng.container.ContainerNull; import appeng.container.ContainerNull;
import appeng.container.ContainerOpenContext; import appeng.container.ContainerOpenContext;
import appeng.container.implementations.ContainerCellWorkbench;
import appeng.container.implementations.ContainerChest;
import appeng.container.implementations.ContainerCondenser;
import appeng.container.implementations.ContainerCraftAmount;
import appeng.container.implementations.ContainerCraftConfirm;
import appeng.container.implementations.ContainerCraftingCPU;
import appeng.container.implementations.ContainerCraftingStatus;
import appeng.container.implementations.ContainerCraftingTerm;
import appeng.container.implementations.ContainerDrive;
import appeng.container.implementations.ContainerFormationPlane;
import appeng.container.implementations.ContainerGrinder;
import appeng.container.implementations.ContainerIOPort;
import appeng.container.implementations.ContainerInscriber;
import appeng.container.implementations.ContainerInterface;
import appeng.container.implementations.ContainerInterfaceTerminal;
import appeng.container.implementations.ContainerLevelEmitter;
import appeng.container.implementations.ContainerMAC;
import appeng.container.implementations.ContainerMEMonitorable;
import appeng.container.implementations.ContainerMEPortableCell;
import appeng.container.implementations.ContainerNetworkStatus;
import appeng.container.implementations.ContainerNetworkTool;
import appeng.container.implementations.ContainerPatternTerm;
import appeng.container.implementations.ContainerPriority;
import appeng.container.implementations.ContainerQNB;
import appeng.container.implementations.ContainerQuartzKnife;
import appeng.container.implementations.ContainerSecurityStation;
import appeng.container.implementations.ContainerSkyChest;
import appeng.container.implementations.ContainerSpatialIOPort;
import appeng.container.implementations.ContainerStorageBus;
import appeng.container.implementations.ContainerUpgradeable;
import appeng.container.implementations.ContainerVibrationChamber;
import appeng.container.implementations.ContainerWireless;
import appeng.container.implementations.ContainerWirelessTerm;
import appeng.fluids.container.ContainerFluidFormationPlane; import appeng.fluids.container.ContainerFluidFormationPlane;
import appeng.fluids.container.ContainerFluidIO; import appeng.fluids.container.ContainerFluidIO;
import appeng.fluids.container.ContainerFluidInterface; import appeng.fluids.container.ContainerFluidInterface;
@@ -171,6 +141,8 @@ public enum GuiBridge implements IGuiHandler
GUI_STORAGEBUS( ContainerStorageBus.class, PartStorageBus.class, GuiHostType.WORLD, SecurityPermissions.BUILD ), GUI_STORAGEBUS( ContainerStorageBus.class, PartStorageBus.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_OREDICTSTORAGEBUS( ContainerOreDictStorageBus.class, PartOreDicStorageBus.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_STORAGEBUS_FLUID( ContainerFluidStorageBus.class, PartFluidStorageBus.class, GuiHostType.WORLD, SecurityPermissions.BUILD ), GUI_STORAGEBUS_FLUID( ContainerFluidStorageBus.class, PartFluidStorageBus.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_FORMATION_PLANE( ContainerFormationPlane.class, PartFormationPlane.class, GuiHostType.WORLD, SecurityPermissions.BUILD ), GUI_FORMATION_PLANE( ContainerFormationPlane.class, PartFormationPlane.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
@@ -185,6 +157,8 @@ public enum GuiBridge implements IGuiHandler
GUI_PATTERN_TERMINAL( ContainerPatternTerm.class, PartPatternTerminal.class, GuiHostType.WORLD, SecurityPermissions.CRAFT ), GUI_PATTERN_TERMINAL( ContainerPatternTerm.class, PartPatternTerminal.class, GuiHostType.WORLD, SecurityPermissions.CRAFT ),
GUI_EXPANDED_PROCESSING_PATTERN_TERMINAL( ContainerExpandedProcessingPatternTerm.class, PartExpandedProcessingPatternTerminal.class, GuiHostType.WORLD, SecurityPermissions.CRAFT ),
GUI_FLUID_TERMINAL( ContainerFluidTerminal.class, ITerminalHost.class, GuiHostType.WORLD, SecurityPermissions.BUILD ), GUI_FLUID_TERMINAL( ContainerFluidTerminal.class, ITerminalHost.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
// extends (Container/Gui) + Bus // extends (Container/Gui) + Bus
@@ -0,0 +1,89 @@
package appeng.core.sync.packets;
import appeng.api.storage.data.IAEItemStack;
import appeng.core.AppEng;
import appeng.core.sync.AppEngPacket;
import appeng.core.sync.network.INetworkInfo;
import appeng.util.item.AEItemStack;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.text.TextComponentString;
import java.io.IOException;
public class PacketInformPlayer extends AppEngPacket
{
private IAEItemStack actualItem = null;
private IAEItemStack reportedItem = null;
private final InfoType type;
public PacketInformPlayer( ByteBuf stream ) throws IOException
{
this.type = InfoType.values()[stream.readInt()];
if( type == InfoType.PARTIAL_ITEM_EXTRACTION )
{
this.reportedItem = AEItemStack.fromPacket( stream );
this.actualItem = AEItemStack.fromPacket( stream );
}
else if( type == InfoType.NO_ITEMS_EXTRACTED )
{
this.reportedItem = AEItemStack.fromPacket( stream );
}
}
public PacketInformPlayer( final IAEItemStack iaeItemStack ) throws IOException
{
this( iaeItemStack, null );
}
public PacketInformPlayer( IAEItemStack extra, IAEItemStack result ) throws IOException
{
this.reportedItem = extra;
this.actualItem = result;
if( actualItem == null )
{
this.type = InfoType.NO_ITEMS_EXTRACTED;
}
else
{
this.type = InfoType.PARTIAL_ITEM_EXTRACTION;
}
final ByteBuf data = Unpooled.buffer();
data.writeInt( this.getPacketID() );
data.writeInt( type.ordinal() );
reportedItem.writeToPacket( data );
if( actualItem != null )
{
actualItem.writeToPacket( data );
}
this.configureWrite( data );
}
@Override
public void clientPacketData( final INetworkInfo network, final AppEngPacket packet, final EntityPlayer player )
{
TextComponentString msg = null;
if( this.type == InfoType.PARTIAL_ITEM_EXTRACTION )
{
AppEng.proxy.getPlayers().get( 0 ).sendStatusMessage( new TextComponentString( "System reported " + reportedItem.getStackSize() + " " + reportedItem.getItem().getItemStackDisplayName( reportedItem.getDefinition() ) + " available but could only extract" + actualItem.getStackSize() ), false );
}
else if( this.type == InfoType.NO_ITEMS_EXTRACTED )
{
AppEng.proxy.getPlayers().get( 0 ).sendStatusMessage( new TextComponentString( "System reported " + reportedItem.getStackSize() + " " + reportedItem.getItem().getItemStackDisplayName( reportedItem.getDefinition() ) + " available but could not extract anything" ), false );
}
}
public enum InfoType
{
PARTIAL_ITEM_EXTRACTION,
NO_ITEMS_EXTRACTED
}
}
@@ -20,6 +20,7 @@ package appeng.core.sync.packets;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import appeng.api.storage.data.IAEFluidStack; import appeng.api.storage.data.IAEFluidStack;
import appeng.container.slot.IJEITargetSlot; import appeng.container.slot.IJEITargetSlot;
@@ -191,7 +192,20 @@ public class PacketInventoryAction extends AppEngPacket
} }
else if( this.action == InventoryAction.PLACE_JEI_GHOST_ITEM ) else if( this.action == InventoryAction.PLACE_JEI_GHOST_ITEM )
{ {
if( sender.openContainer.inventorySlots.get( this.slot ) instanceof SlotFake ) 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 if( this.slot < sender.openContainer.inventorySlots.size() && sender.openContainer.inventorySlots.get( this.slot ) instanceof SlotFake )
{ {
if( this.slotItem != null ) if( this.slotItem != null )
{ {
@@ -216,18 +230,6 @@ public class PacketInventoryAction extends AppEngPacket
AELog.debug( e ); AELog.debug( e );
} }
} }
if( sender.openContainer instanceof ContainerFluidConfigurable )
{
if( this.slotItem != null )
{
IAEFluidStack aefs = AEFluidStack.fromNBT( this.slotItem.getDefinition().getTagCompound() );
if( aefs != null )
{
( (ContainerFluidConfigurable) sender.openContainer ).getFluidConfigInventory().setFluidInSlot( this.slot, aefs );
}
}
}
} }
else else
{ {
@@ -23,11 +23,12 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.List;
import appeng.api.config.FuzzyMode; import appeng.api.config.FuzzyMode;
import appeng.api.storage.data.IItemList; import appeng.container.implementations.ContainerExpandedProcessingPatternTerm;
import appeng.container.implementations.ContainerPatternTerm; import appeng.container.implementations.ContainerPatternTerm;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
@@ -39,6 +40,7 @@ import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagList;
import net.minecraftforge.fml.common.Optional;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import appeng.api.AEApi; import appeng.api.AEApi;
@@ -68,8 +70,9 @@ import appeng.util.prioritylist.IPartitionList;
public class PacketJEIRecipe extends AppEngPacket public class PacketJEIRecipe extends AppEngPacket
{ {
private ItemStack[][] recipe; private List<ItemStack[]> recipe;
private ItemStack[] output; private List<ItemStack> output;
static ItemStack[] emptyArray = {ItemStack.EMPTY};
// automatic. // automatic.
@@ -80,28 +83,35 @@ public class PacketJEIRecipe extends AppEngPacket
final NBTTagCompound comp = CompressedStreamTools.readCompressed( bytes ); final NBTTagCompound comp = CompressedStreamTools.readCompressed( bytes );
if( comp != null ) if( comp != null )
{ {
this.recipe = new ItemStack[9][]; this.recipe = new ArrayList<>();
for( int x = 0; x < this.recipe.length; x++ )
for( int x = 0; x < comp.getKeySet().size(); x++ )
{ {
final NBTTagList list = comp.getTagList( "#" + x, 10 ); if( comp.hasKey( "#" + x ) )
if( list.tagCount() > 0 )
{ {
this.recipe[x] = new ItemStack[list.tagCount()]; final NBTTagList list = comp.getTagList( "#" + x, 10 );
for( int y = 0; y < list.tagCount(); y++ ) if( list.tagCount() > 0 )
{ {
this.recipe[x][y] = new ItemStack( list.getCompoundTagAt( y ) ); this.recipe.add( new ItemStack[list.tagCount()] );
for( int y = 0; y < list.tagCount(); y++ )
{
this.recipe.get( x )[y] = new ItemStack( list.getCompoundTagAt( y ) );
}
}
else
{
this.recipe.add( emptyArray );
} }
} }
} }
if ( comp.hasKey("outputs") ) {
final NBTTagList outputList = comp.getTagList("outputs", 10); if( comp.hasKey( "outputs" ) )
this.output = new ItemStack[3]; {
for( int x = 0; x < this.output.length; x++ ) final NBTTagList outputList = comp.getTagList( "outputs", 10 );
this.output = new ArrayList<>();
for( int z = 0; z < outputList.tagCount(); z++ )
{ {
if( outputList.tagCount() > 0 ) this.output.add( new ItemStack( outputList.getCompoundTagAt( z ) ) );
{
this.output[x] = new ItemStack(outputList.getCompoundTagAt( x ));
}
} }
} }
} }
@@ -165,15 +175,23 @@ public class PacketJEIRecipe extends AppEngPacket
{ {
ItemStack currentItem = craftMatrix.getStackInSlot( x ); ItemStack currentItem = craftMatrix.getStackInSlot( x );
if( x >= this.recipe.size() )
{
currentItem = ItemStack.EMPTY;
}
// prepare slots // prepare slots
if( !currentItem.isEmpty() ) if( !currentItem.isEmpty() )
{ {
// already the correct item? // already the correct item?
ItemStack newItem = this.canUseInSlot( x, currentItem ); ItemStack newItem = this.canUseInSlot( x, currentItem );
if ( !cct.useRealItems() && this.recipe[x] != null ) { if( !cct.useRealItems() && this.recipe.get( x ) != null )
if (this.recipe[x].length > 0 ) {
currentItem.setCount( recipe[x][0].getCount() ); if( this.recipe.get( x ).length > 0 )
{
currentItem.setCount( recipe.get( x )[0].getCount() );
}
} }
// put away old item // put away old item
@@ -192,12 +210,12 @@ public class PacketJEIRecipe extends AppEngPacket
} }
} }
if( currentItem.isEmpty() && this.recipe[x] != null ) if( currentItem.isEmpty() && recipe.size() > x && recipe.get( x ) != null )
{ {
// for each variant // for each variant
for( int y = 0; y < this.recipe[x].length && currentItem.isEmpty(); y++ ) for( int y = 0; y < this.recipe.get( x ).length && currentItem.isEmpty(); y++ )
{ {
final IAEItemStack request = AEItemStack.fromItemStack( this.recipe[x][y] ); final IAEItemStack request = AEItemStack.fromItemStack( this.recipe.get( x )[y] );
if( request != null ) if( request != null )
{ {
// try ae // try ae
@@ -211,23 +229,21 @@ public class PacketJEIRecipe extends AppEngPacket
out = Platform.poweredExtraction( energy, storage, request, cct.getActionSource() ); out = Platform.poweredExtraction( energy, storage, request, cct.getActionSource() );
if( out == null ) if( out == null )
{ {
Collection<IAEItemStack> outList = inv.getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ).getStorageList().findFuzzy( request, FuzzyMode.IGNORE_ALL ); if( request.getItem().isDamageable() || Platform.isGTDamageableItem( request.getItem() ) )
IAEItemStack mostDamaged = null;
for( IAEItemStack is : outList )
{ {
if( !is.isCraftable() && is.getItem().isDamageable() ) Collection<IAEItemStack> outList = inv.getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ).getStorageList().findFuzzy( request, FuzzyMode.IGNORE_ALL );
for( IAEItemStack is : outList )
{ {
if( mostDamaged == null || mostDamaged.getItemDamage() < is.getItemDamage() ) if( is.getDefinition().getMetadata() == request.getDefinition().getMetadata() )
{ {
mostDamaged = is; out = Platform.poweredExtraction( energy, storage, is.copy().setStackSize( 1 ), cct.getActionSource() );
}
if( out != null )
{
break;
} }
} }
} }
if( mostDamaged != null )
{
mostDamaged.setStackSize( 1 );
out = Platform.poweredExtraction( energy, storage, mostDamaged, cct.getActionSource() );
}
} }
} }
else else
@@ -246,7 +262,10 @@ public class PacketJEIRecipe extends AppEngPacket
if( out != null ) if( out != null )
{ {
out.setStackSize( recipe[x][y].getCount() ); if( !cct.useRealItems() )
{
out.setStackSize( recipe.get( x )[y].getCount() );
}
currentItem = out.createItemStack(); currentItem = out.createItemStack();
} }
} }
@@ -258,20 +277,20 @@ public class PacketJEIRecipe extends AppEngPacket
if( cct.useRealItems() ) if( cct.useRealItems() )
{ {
currentItem = ad.removeSimilarItems(1, this.recipe[x][y],FuzzyMode.IGNORE_ALL, null ); currentItem = ad.removeSimilarItems( 1, this.recipe.get( x )[y], FuzzyMode.IGNORE_ALL, null );
} }
else else
{ {
currentItem = ad.simulateSimilarRemove(recipe[x][y].getCount(), this.recipe[x][y],FuzzyMode.IGNORE_ALL, null ); currentItem = ad.simulateSimilarRemove( recipe.get( x )[y].getCount(), this.recipe.get( x )[y], FuzzyMode.IGNORE_ALL, null );
} }
} }
} }
} }
if (!cct.useRealItems()) if( !cct.useRealItems() )
{ {
if( currentItem.isEmpty() && this.recipe[x] != null ) if( currentItem.isEmpty() && recipe.size() > x && this.recipe.get( x ) != null )
{ {
currentItem = this.recipe[x][0].copy(); currentItem = this.recipe.get( x )[0].copy();
} }
} }
} }
@@ -280,28 +299,35 @@ public class PacketJEIRecipe extends AppEngPacket
con.onCraftMatrixChanged( new WrapperInvItemHandler( craftMatrix ) ); con.onCraftMatrixChanged( new WrapperInvItemHandler( craftMatrix ) );
if( this.output != null && con instanceof ContainerPatternTerm && !( (ContainerPatternTerm) con ).isCraftingMode() ) if( this.output != null && ( ( con instanceof ContainerPatternTerm && !( (ContainerPatternTerm) con ).isCraftingMode() ) || con instanceof ContainerExpandedProcessingPatternTerm ) )
{ {
IItemHandler outputSlots = cct.getInventoryByName( "output" ); IItemHandler outputSlots = cct.getInventoryByName( "output" );
for( int i = 0; i < this.output.length; ++i ) for( int i = 0; i < outputSlots.getSlots(); ++i )
{ {
ItemHandlerUtil.setStackInSlot( outputSlots, i, this.output[i] ); ItemHandlerUtil.setStackInSlot( outputSlots, i, ItemStack.EMPTY );
}
for( int i = 0; i < this.output.size() && i < outputSlots.getSlots(); ++i )
{
if( this.output.get( i ) == null || this.output.get( i ) == ItemStack.EMPTY )
{
continue;
}
ItemHandlerUtil.setStackInSlot( outputSlots, i, this.output.get( i ) );
} }
} }
} }
} }
/** /**
*
* @param slot * @param slot
* @param is itemstack * @param is itemstack
* @return is if it can be used, else EMPTY * @return is if it can be used, else EMPTY
*/ */
private ItemStack canUseInSlot( int slot, ItemStack is ) private ItemStack canUseInSlot( int slot, ItemStack is )
{ {
if( this.recipe[slot] != null ) if( this.recipe.get( slot ) != null )
{ {
for( ItemStack option : this.recipe[slot] ) for( ItemStack option : this.recipe.get( slot ) )
{ {
if( ItemStack.areItemStacksEqual( is, option ) ) if( ItemStack.areItemStacksEqual( is, option ) )
{ {
@@ -19,6 +19,7 @@
package appeng.core.sync.packets; package appeng.core.sync.packets;
import appeng.fluids.container.ContainerFluidInterface;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
@@ -90,5 +91,9 @@ public class PacketTargetFluidStack extends AppEngPacket
{ {
( (ContainerFluidTerminal) player.openContainer ).setTargetStack( this.stack ); ( (ContainerFluidTerminal) player.openContainer ).setTargetStack( this.stack );
} }
else if( player.openContainer instanceof ContainerFluidInterface )
{
( (ContainerFluidInterface) player.openContainer ).setTargetStack( this.stack );
}
} }
} }
@@ -24,6 +24,8 @@ import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import appeng.client.gui.implementations.GuiOreDictStorageBus;
import appeng.container.implementations.*;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
@@ -40,17 +42,6 @@ import appeng.api.util.IConfigManager;
import appeng.api.util.IConfigurableObject; import appeng.api.util.IConfigurableObject;
import appeng.client.gui.implementations.GuiCraftingCPU; import appeng.client.gui.implementations.GuiCraftingCPU;
import appeng.container.AEBaseContainer; import appeng.container.AEBaseContainer;
import appeng.container.implementations.ContainerCellWorkbench;
import appeng.container.implementations.ContainerCraftConfirm;
import appeng.container.implementations.ContainerCraftingCPU;
import appeng.container.implementations.ContainerCraftingStatus;
import appeng.container.implementations.ContainerLevelEmitter;
import appeng.container.implementations.ContainerNetworkTool;
import appeng.container.implementations.ContainerPatternTerm;
import appeng.container.implementations.ContainerPriority;
import appeng.container.implementations.ContainerQuartzKnife;
import appeng.container.implementations.ContainerSecurityStation;
import appeng.container.implementations.ContainerStorageBus;
import appeng.core.sync.AppEngPacket; import appeng.core.sync.AppEngPacket;
import appeng.core.sync.network.INetworkInfo; import appeng.core.sync.network.INetworkInfo;
import appeng.fluids.container.ContainerFluidLevelEmitter; import appeng.fluids.container.ContainerFluidLevelEmitter;
@@ -166,58 +157,109 @@ public class PacketValueConfig extends AppEngPacket
final ContainerFluidLevelEmitter lvc = (ContainerFluidLevelEmitter) c; final ContainerFluidLevelEmitter lvc = (ContainerFluidLevelEmitter) c;
lvc.setLevel( Long.parseLong( this.Value ), player ); lvc.setLevel( Long.parseLong( this.Value ), player );
} }
else if( this.Name.startsWith( "PatternTerminal." ) && c instanceof ContainerPatternTerm ) else if( this.Name.startsWith( "PatternTerminal." ) )
{ {
final ContainerPatternTerm cpt = (ContainerPatternTerm) c; if( c instanceof ContainerPatternTerm )
if( this.Name.equals( "PatternTerminal.CraftMode" ) )
{ {
cpt.getPatternTerminal().setCraftingRecipe( this.Value.equals( "1" ) ); final ContainerPatternTerm cpt = (ContainerPatternTerm) c;
} if( this.Name.equals( "PatternTerminal.CraftMode" ) )
else if( this.Name.equals( "PatternTerminal.Encode" ) )
{
if (this.Value.equals( "2" )) {
cpt.encodeAndMoveToInventory();
}
else
{ {
cpt.encode(); cpt.getPatternTerminal().setCraftingRecipe( this.Value.equals( "1" ) );
}
else if( this.Name.equals( "PatternTerminal.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" ) );
} }
} }
else if( this.Name.equals( "PatternTerminal.Clear" ) ) else if( c instanceof ContainerExpandedProcessingPatternTerm )
{ {
cpt.clear(); final ContainerExpandedProcessingPatternTerm cept = (ContainerExpandedProcessingPatternTerm) c;
} if( this.Name.equals( "PatternTerminal.Encode" ) )
else if( this.Name.equals( "PatternTerminal.MultiplyByTwo" ) ) {
{ if( this.Value.equals( "2" ) )
cpt.multiply(2); {
} cept.encodeAndMoveToInventory();
else if( this.Name.equals( "PatternTerminal.MultiplyByThree" ) ) }
{ else
cpt.multiply(3); {
} cept.encode();
else if( this.Name.equals( "PatternTerminal.DivideByTwo" ) ) }
{ }
cpt.divide(2); else if( this.Name.equals( "PatternTerminal.Clear" ) )
} {
else if( this.Name.equals( "PatternTerminal.DivideByThree" ) ) cept.clear();
{ }
cpt.divide(3); else if( this.Name.equals( "PatternTerminal.MultiplyByTwo" ) )
} {
else if( this.Name.equals( "PatternTerminal.IncreaseByOne" ) ) cept.multiply( 2 );
{ }
cpt.increase(1); else if( this.Name.equals( "PatternTerminal.MultiplyByThree" ) )
} {
else if( this.Name.equals( "PatternTerminal.DecreaseByOne" ) ) cept.multiply( 3 );
{ }
cpt.decrease(1); else if( this.Name.equals( "PatternTerminal.DivideByTwo" ) )
} {
else if( this.Name.equals( "PatternTerminal.MaximizeCount" ) ) cept.divide( 2 );
{ }
cpt.maximizeCount(); else if( this.Name.equals( "PatternTerminal.DivideByThree" ) )
} {
else if( this.Name.equals( "PatternTerminal.Substitute" ) ) cept.divide( 3 );
{ }
cpt.getPatternTerminal().setSubstitution( this.Value.equals( "1" ) ); else if( this.Name.equals( "PatternTerminal.IncreaseByOne" ) )
{
cept.increase( 1 );
}
else if( this.Name.equals( "PatternTerminal.DecreaseByOne" ) )
{
cept.decrease( 1 );
}
else if( this.Name.equals( "PatternTerminal.MaximizeCount" ) )
{
cept.maximizeCount();
}
} }
} }
else if( this.Name.startsWith( "StorageBus." ) ) else if( this.Name.startsWith( "StorageBus." ) )
@@ -234,6 +276,11 @@ public class PacketValueConfig extends AppEngPacket
{ {
( (ContainerFluidStorageBus) c ).partition(); ( (ContainerFluidStorageBus) c ).partition();
} }
else if( c instanceof ContainerOreDictStorageBus )
{
( (ContainerOreDictStorageBus) c ).partition();
( (ContainerOreDictStorageBus) c ).sendRegex();
}
} }
else if( this.Value.equals( "Clear" ) ) else if( this.Value.equals( "Clear" ) )
{ {
@@ -248,6 +295,20 @@ public class PacketValueConfig extends AppEngPacket
} }
} }
} }
else if( this.Name.startsWith( "OreDictStorageBus" ) )
{
if( c instanceof ContainerOreDictStorageBus )
{
if( this.Name.equals( "OreDictStorageBus.save" ) )
{
( (ContainerOreDictStorageBus) c ).saveOreMatch( this.Value );
}
if( this.Name.equals( "OreDictStorageBus.getRegex" ) )
{
( (ContainerOreDictStorageBus) c ).sendRegex();
}
}
}
else if( this.Name.startsWith( "CellWorkbench." ) && c instanceof ContainerCellWorkbench ) else if( this.Name.startsWith( "CellWorkbench." ) && c instanceof ContainerCellWorkbench )
{ {
final ContainerCellWorkbench ccw = (ContainerCellWorkbench) c; final ContainerCellWorkbench ccw = (ContainerCellWorkbench) c;
@@ -324,6 +385,14 @@ public class PacketValueConfig extends AppEngPacket
( (GuiCraftingCPU) gs ).clearItems(); ( (GuiCraftingCPU) gs ).clearItems();
} }
} }
else if( this.Name.equals( "OreDictStorageBus.sendRegex" ) )
{
final GuiScreen gs = Minecraft.getMinecraft().currentScreen;
if( gs instanceof GuiOreDictStorageBus )
{
( (GuiOreDictStorageBus) gs ).fillRegex( this.Value );
}
}
else if( c instanceof IConfigurableObject ) else if( c instanceof IConfigurableObject )
{ {
final IConfigManager cm = ( (IConfigurableObject) c ).getConfigManager(); final IConfigManager cm = ( (IConfigurableObject) c ).getConfigManager();
+139 -54
View File
@@ -19,15 +19,6 @@
package appeng.crafting; package appeng.crafting;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
import com.google.common.base.Stopwatch;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import appeng.api.AEApi; import appeng.api.AEApi;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
import appeng.api.networking.IGrid; import appeng.api.networking.IGrid;
@@ -36,7 +27,6 @@ import appeng.api.networking.IGridNode;
import appeng.api.networking.crafting.ICraftingCallback; import appeng.api.networking.crafting.ICraftingCallback;
import appeng.api.networking.crafting.ICraftingGrid; import appeng.api.networking.crafting.ICraftingGrid;
import appeng.api.networking.crafting.ICraftingJob; import appeng.api.networking.crafting.ICraftingJob;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.networking.security.IActionHost; import appeng.api.networking.security.IActionHost;
import appeng.api.networking.security.IActionSource; import appeng.api.networking.security.IActionSource;
import appeng.api.networking.storage.IStorageGrid; import appeng.api.networking.storage.IStorageGrid;
@@ -46,52 +36,64 @@ import appeng.api.storage.data.IItemList;
import appeng.api.util.DimensionalCoord; import appeng.api.util.DimensionalCoord;
import appeng.core.AELog; import appeng.core.AELog;
import appeng.hooks.TickHandler; import appeng.hooks.TickHandler;
import appeng.me.cache.GridStorageCache;
import com.google.common.base.Stopwatch;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.world.World;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
public class CraftingJob implements Runnable, ICraftingJob public class CraftingJob implements Runnable, ICraftingJob
{ {
private static final String LOG_CRAFTING_JOB = "CraftingJob (%s) issued by %s requesting [%s] using %s bytes took %s ms"; private static final String LOG_CRAFTING_JOB = "CraftingJob (%s) issued by %s requesting [%s] using %s bytes took %s us";
private static final String LOG_MACHINE_SOURCE_DETAILS = "Machine[object=%s, %s]"; private static final String LOG_MACHINE_SOURCE_DETAILS = "Machine[object=%s, %s]";
private final MECraftingInventory original; private final MECraftingInventory original;
private final World world; private final World world;
private final IItemList<IAEItemStack> crafting = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); private final IItemList<IAEItemStack> crafting = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList();
private final IItemList<IAEItemStack> missing = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); private final IItemList<IAEItemStack> missing = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList();
private final IItemList<IAEItemStack> neededForLoop = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList();
private final Object2ObjectOpenHashMap<CraftingTreeNode, IAEItemStack> reserved = new Object2ObjectOpenHashMap<>();
private final HashMap<String, TwoIntegers> opsAndMultiplier = new HashMap<>(); private final HashMap<String, TwoIntegers> opsAndMultiplier = new HashMap<>();
private final Object monitor = new Object(); private final Object monitor = new Object();
private CraftingTreeNode tree; private final Stopwatch tickSpreadingWatch = Stopwatch.createUnstarted();
private final Stopwatch craftingTreeWatch = Stopwatch.createUnstarted();
private final IAEItemStack output; private final IAEItemStack output;
private final IActionSource actionSrc;
private final ICraftingCallback callback;
private CraftingTreeNode tree;
private boolean simulate = false; private boolean simulate = false;
private MECraftingInventory availableCheck; private MECraftingInventory availableCheck;
private long bytes = 0; private long bytes = 0;
private final IActionSource actionSrc; private boolean running = false;
private final ICraftingCallback callback;
private boolean done = false; private boolean done = false;
private int time;
private World wrapWorld( final World w ) private int incTime;
{
return w;
}
public CraftingJob( final World w, final IGrid grid, final IActionSource actionSrc, final IAEItemStack what, final ICraftingCallback callback ) public CraftingJob( final World w, final IGrid grid, final IActionSource actionSrc, final IAEItemStack what, final ICraftingCallback callback )
{ {
this.world = this.wrapWorld( w ); this.world = w;
this.output = what.copy(); this.output = what.copy();
this.actionSrc = actionSrc; this.actionSrc = actionSrc;
this.callback = callback; this.callback = callback;
final ICraftingGrid cc = grid.getCache( ICraftingGrid.class );
final IStorageGrid sg = grid.getCache( IStorageGrid.class );
this.original = new MECraftingInventory( sg
.getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ), actionSrc, false, false, false );
ICraftingGrid cc = grid.getCache( ICraftingGrid.class );
final GridStorageCache sg = grid.getCache( IStorageGrid.class );
this.original = sg.getExtractableList( actionSrc );
this.availableCheck = new MECraftingInventory( this.original, false, false, false );
this.setTree( this.getCraftingTree( cc, what ) ); this.setTree( this.getCraftingTree( cc, what ) );
this.availableCheck = null; this.availableCheck = null;
} }
private CraftingTreeNode getCraftingTree( final ICraftingGrid cc, final IAEItemStack what ) private CraftingTreeNode getCraftingTree( final ICraftingGrid cc, final IAEItemStack what )
{ {
return new CraftingTreeNode( cc, this, what, null, -1, 0 ); return new CraftingTreeNode( cc, this, what, what.getStackSize(), null, -1 );
} }
void refund( final IAEItemStack o ) void refund( final IAEItemStack o )
@@ -104,12 +106,12 @@ public class CraftingJob implements Runnable, ICraftingJob
return this.availableCheck.extractItems( available, Actionable.MODULATE, this.actionSrc ); return this.availableCheck.extractItems( available, Actionable.MODULATE, this.actionSrc );
} }
public void writeToNBT( final NBTTagCompound out ) IAEItemStack checkAvailable( final IAEItemStack available )
{ {
return this.availableCheck.extractItems( available, Actionable.SIMULATE, this.actionSrc );
} }
void addTask( IAEItemStack what, final long crafts, final ICraftingPatternDetails details, final int depth ) void addTask( IAEItemStack what, final long crafts )
{ {
if( crafts > 0 ) if( crafts > 0 )
{ {
@@ -125,6 +127,22 @@ public class CraftingJob implements Runnable, ICraftingJob
this.missing.add( what ); this.missing.add( what );
} }
public void reserve( CraftingTreeNode node, IAEItemStack stack )
{
this.checkUse( stack );
reserved.put( node, stack );
}
public IItemList<IAEItemStack> getNeededForLoop()
{
return neededForLoop;
}
public Object2ObjectOpenHashMap<CraftingTreeNode, IAEItemStack> getReserved()
{
return reserved;
}
@Override @Override
public void run() public void run()
{ {
@@ -133,14 +151,17 @@ public class CraftingJob implements Runnable, ICraftingJob
try try
{ {
TickHandler.INSTANCE.registerCraftingSimulation( this.world, this ); TickHandler.INSTANCE.registerCraftingSimulation( this.world, this );
this.handlePausing();
final Stopwatch timer = Stopwatch.createStarted();
final MECraftingInventory craftingInventory = new MECraftingInventory( this.original, true, false, true ); final MECraftingInventory craftingInventory = new MECraftingInventory( this.original, true, false, true );
craftingInventory.ignore( this.output );
this.availableCheck = new MECraftingInventory( this.original, false, false, false ); this.availableCheck = new MECraftingInventory( this.original, false, false, false );
this.reserved.values().forEach( availableCheck::reserve );
this.reserved.values().forEach( craftingInventory::reserve );
craftingTreeWatch.start();
this.getTree().request( craftingInventory, this.output.getStackSize(), this.actionSrc ); this.getTree().request( craftingInventory, this.output.getStackSize(), this.actionSrc );
craftingTreeWatch.stop();
this.getTree().dive( this ); this.getTree().dive( this );
for( final String s : this.opsAndMultiplier.keySet() ) for( final String s : this.opsAndMultiplier.keySet() )
@@ -149,9 +170,14 @@ public class CraftingJob implements Runnable, ICraftingJob
AELog.crafting( s + " * " + ti.times + " = " + ( ti.perOp * ti.times ) ); AELog.crafting( s + " * " + ti.times + " = " + ( ti.perOp * ti.times ) );
} }
this.logCraftingJob( "real", timer ); if( actionSrc.player().isPresent() )
// if ( mode == Actionable.MODULATE ) {
// craftingInventory.moveItemsToStorage( storage ); this.logCraftingJob( "simulated, success", craftingTreeWatch );
}
else
{
this.logCraftingJob( "real, success", craftingTreeWatch );
}
} }
catch( final CraftBranchFailure e ) catch( final CraftBranchFailure e )
{ {
@@ -159,23 +185,32 @@ public class CraftingJob implements Runnable, ICraftingJob
try try
{ {
final Stopwatch timer = Stopwatch.createStarted(); if( actionSrc.player().isPresent() )
final MECraftingInventory craftingInventory = new MECraftingInventory( this.original, true, false, true );
craftingInventory.ignore( this.output );
this.availableCheck = new MECraftingInventory( this.original, false, false, false );
this.getTree().setSimulate();
this.getTree().request( craftingInventory, this.output.getStackSize(), this.actionSrc );
this.getTree().dive( this );
for( final String s : this.opsAndMultiplier.keySet() )
{ {
final TwoIntegers ti = this.opsAndMultiplier.get( s ); final MECraftingInventory craftingInventory = new MECraftingInventory( this.original, true, false, true );
AELog.crafting( s + " * " + ti.times + " = " + ( ti.perOp * ti.times ) ); this.getTree().setSimulate();
}
this.logCraftingJob( "simulate", timer ); this.availableCheck = new MECraftingInventory( this.original, false, false, false );
this.reserved.values().forEach( availableCheck::reserve );
this.reserved.values().forEach( craftingInventory::reserve );
craftingTreeWatch.reset().start();
this.getTree().request( craftingInventory, this.output.getStackSize(), this.actionSrc );
craftingTreeWatch.stop();
this.getTree().dive( this );
for( final String s : this.opsAndMultiplier.keySet() )
{
final TwoIntegers ti = this.opsAndMultiplier.get( s );
AELog.crafting( s + " * " + ti.times + " = " + ( ti.perOp * ti.times ) );
}
this.logCraftingJob( "simulated, failed", craftingTreeWatch );
}
else
{
this.logCraftingJob( "real, failed", craftingTreeWatch );
}
} }
catch( final CraftBranchFailure e1 ) catch( final CraftBranchFailure e1 )
{ {
@@ -214,6 +249,43 @@ public class CraftingJob implements Runnable, ICraftingJob
this.finish(); this.finish();
} }
void handlePausing() throws InterruptedException
{
if( !this.actionSrc.player().isPresent() && this.incTime > 100 )
{
this.incTime = 0;
synchronized ( this.monitor )
{
if( this.tickSpreadingWatch.elapsed( TimeUnit.MICROSECONDS ) > this.time )
{
this.running = false;
this.craftingTreeWatch.stop();
this.tickSpreadingWatch.stop();
this.monitor.notify();
}
if( !this.running )
{
AELog.craftingDebug( "crafting job will now sleep" );
while ( !this.running )
{
this.monitor.wait();
}
AELog.craftingDebug( "crafting job now active" );
}
}
}
if( Thread.interrupted() )
{
throw new InterruptedException();
}
this.incTime++;
}
private void finish() private void finish()
{ {
if( this.callback != null ) if( this.callback != null )
@@ -223,8 +295,9 @@ public class CraftingJob implements Runnable, ICraftingJob
this.availableCheck = null; this.availableCheck = null;
synchronized( this.monitor ) synchronized ( this.monitor )
{ {
this.running = false;
this.done = true; this.done = true;
this.monitor.notify(); this.monitor.notify();
} }
@@ -270,13 +343,25 @@ public class CraftingJob implements Runnable, ICraftingJob
/** /**
* @return true if this needs more simulation * @return true if this needs more simulation
*/ */
public boolean simulateFor() public boolean simulateFor( final int milli )
{ {
synchronized( this.monitor ) { this.time = milli;
if ( this.done ) {
synchronized ( this.monitor )
{
if( this.done )
{
return false; return false;
} }
if( !this.actionSrc.player().isPresent() )
{
this.tickSpreadingWatch.reset();
this.tickSpreadingWatch.start();
this.monitor.notify();
}
this.running = true;
} }
return true; return true;
} }
@@ -300,7 +385,7 @@ public class CraftingJob implements Runnable, ICraftingJob
if( AELog.isCraftingLogEnabled() ) if( AELog.isCraftingLogEnabled() )
{ {
final String itemToOutput = this.output.toString(); final String itemToOutput = this.output.toString();
final long elapsedTime = timer.elapsed( TimeUnit.MILLISECONDS ); final long elapsedTime = timer.elapsed( TimeUnit.MICROSECONDS );
final String actionSource; final String actionSource;
if( this.actionSrc.player().isPresent() ) if( this.actionSrc.player().isPresent() )
@@ -19,14 +19,6 @@
package appeng.crafting; package appeng.crafting;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.google.common.collect.Lists;
import net.minecraft.world.World;
import appeng.api.AEApi; import appeng.api.AEApi;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
import appeng.api.config.FuzzyMode; import appeng.api.config.FuzzyMode;
@@ -36,9 +28,22 @@ import appeng.api.networking.security.IActionSource;
import appeng.api.storage.channels.IItemStorageChannel; import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList; import appeng.api.storage.data.IItemList;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketInformPlayer;
import appeng.me.cluster.implementations.CraftingCPUCluster; import appeng.me.cluster.implementations.CraftingCPUCluster;
import appeng.util.Platform;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.Optional;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
@Optional.Interface( iface = "gregtech.api.items.IToolItem", modid = "gregtech" )
public class CraftingTreeNode public class CraftingTreeNode
{ {
@@ -53,22 +58,20 @@ public class CraftingTreeNode
private final IAEItemStack what; private final IAEItemStack what;
// what are the crafting patterns for this? // what are the crafting patterns for this?
private final ArrayList<CraftingTreeProcess> nodes = new ArrayList<>(); private final ArrayList<CraftingTreeProcess> nodes = new ArrayList<>();
private final boolean canEmit;
private CraftingTreeNode loopHead;
private int bytes = 0; private int bytes = 0;
private boolean canEmit = false;
private long missing = 0; private long missing = 0;
private long howManyEmitted = 0; private long howManyEmitted = 0;
private boolean exhausted = false; private boolean exhausted = false;
private boolean sim; public CraftingTreeNode( final ICraftingGrid cc, final CraftingJob job, final IAEItemStack wat, long amount, final CraftingTreeProcess par, final int slot )
public CraftingTreeNode( final ICraftingGrid cc, final CraftingJob job, final IAEItemStack wat, final CraftingTreeProcess par, final int slot, final int depth )
{ {
this.what = wat; this.what = wat;
this.parent = par; this.parent = par;
this.slot = slot; this.slot = slot;
this.world = job.getWorld(); this.world = job.getWorld();
this.job = job; this.job = job;
this.sim = false;
this.canEmit = cc.canEmitFor( this.what ); this.canEmit = cc.canEmitFor( this.what );
@@ -80,78 +83,136 @@ public class CraftingTreeNode
for( final ICraftingPatternDetails details : cc.getCraftingFor( this.what, this.parent == null ? null : this.parent.details, slot, this.world ) )// in for( final ICraftingPatternDetails details : cc.getCraftingFor( this.what, this.parent == null ? null : this.parent.details, slot, this.world ) )// in
// order. // order.
{ {
if( this.parent == null || this.parent.notRecursive( details ) ) int times = 1;
for( IAEItemStack o : details.getCondensedOutputs() )
{ {
this.nodes.add( new CraftingTreeProcess( cc, job, details, this, depth + 1 ) ); if( what.equals( o ) )
{
times = (int) ( amount / o.getStackSize() + ( amount % o.getStackSize() != 0 ? 1 : 0 ) );
}
}
if( this.parent == null )
{
this.nodes.add( new CraftingTreeProcess( cc, job, details, times, this ) );
continue;
}
if( details == parent.details )
{
continue;
}
CraftingTreeNode recursive = recursiveNode( this );
if( recursive == null )
{
this.nodes.add( new CraftingTreeProcess( cc, job, details, times, this ) );
}
else
{
reserveForNode();
} }
} }
} }
boolean notRecursive( final ICraftingPatternDetails details ) void reserveForNode()
{ {
IAEItemStack[] o = details.getCondensedOutputs(); if( this.equals( loopHead ) )
for( final IAEItemStack i : o )
{ {
if( i.equals( this.what ) ) return;
{
return false;
}
} }
IAEItemStack available = job.checkAvailable( this.what );
o = details.getCondensedInputs(); if( available != null && available.getStackSize() >= this.what.getStackSize() )
for( final IAEItemStack i : o )
{ {
if( i.equals( this.what ) ) this.job.reserve( this, this.what.copy() );
{
return false;
}
} }
else
if( this.parent == null )
{ {
return true; parent.reserveForNode();
} }
return this.parent.notRecursive( details );
} }
IAEItemStack request( final MECraftingInventory inv, long l, final IActionSource src ) throws CraftBranchFailure, InterruptedException IAEItemStack request( final MECraftingInventory inv, long l, final IActionSource src ) throws CraftBranchFailure, InterruptedException
{ {
this.job.handlePausing();
if( this.canEmit )
{
final IAEItemStack wat = this.what.copy();
wat.setStackSize( l );
this.howManyEmitted = wat.getStackSize();
this.bytes += wat.getStackSize();
return wat;
}
final IItemList<IAEItemStack> inventoryList = inv.getItemList();
IAEItemStack reserved = job.getReserved().get( this );
final List<IAEItemStack> thingsUsed = new ArrayList<>(); final List<IAEItemStack> thingsUsed = new ArrayList<>();
this.what.setStackSize( l ); this.what.setStackSize( l );
if( this.getSlot() >= 0 && this.parent != null && this.parent.details.isCraftable() ) if( this.getSlot() >= 0 && this.parent != null && this.parent.details.isCraftable() )
{ {
final Collection<IAEItemStack> itemList; Collection<IAEItemStack> itemList = new HashSet<>();
final IItemList<IAEItemStack> inventoryList = inv.getItemList();
if( this.parent.details.canSubstitute() ) if( this.what.getItem().isDamageable() || Platform.isGTDamageableItem( this.what.getItem() ) )
{ {
itemList = inventoryList.findFuzzy( this.what, FuzzyMode.IGNORE_ALL ); itemList.addAll( inventoryList.findFuzzy( this.what, FuzzyMode.IGNORE_ALL ) );
if( this.parent.details.canSubstitute() )
{
for( IAEItemStack is : inventoryList )
{
if( is.fuzzyComparison( this.what, FuzzyMode.IGNORE_ALL ) )
{
itemList.add( is );
}
}
}
} }
else else
{ {
itemList = Lists.newArrayList();
final IAEItemStack item = inventoryList.findPrecise( this.what ); final IAEItemStack item = inventoryList.findPrecise( this.what );
if( item != null ) if( item != null )
{ {
itemList.add( item ); itemList.add( item );
} }
if( this.parent.details.canSubstitute() )
{
for( IAEItemStack s : parent.details.getSubstituteInputs( this.slot ) )
{
if( s != null )
{
for( IAEItemStack ss : inventoryList.findFuzzy( s, FuzzyMode.IGNORE_ALL ) )
{
if( ss != null )
{
itemList.add( ss );
}
}
}
}
}
} }
for( IAEItemStack fuzz : itemList ) for( IAEItemStack fuzz : itemList )
{ {
if( this.parent.details.isValidItemForSlot( this.getSlot(), fuzz.copy().setStackSize( 1 ).createItemStack(), this.world ) ) if( this.parent.details.isValidItemForSlot( this.getSlot(), fuzz.getDefinition(), this.world ) )
{ {
fuzz = fuzz.copy(); fuzz = fuzz.copy();
fuzz.setStackSize( l ); fuzz.setStackSize( l );
final IAEItemStack available = inv.extractItems( fuzz, Actionable.MODULATE, src ); final IAEItemStack available;
if( reserved != null )
{
available = reserved;
}
else
{
available = inv.extractItems( fuzz, Actionable.MODULATE, src );
}
if( available != null ) if( available != null )
{ {
@@ -164,6 +225,11 @@ public class CraftingTreeNode
thingsUsed.add( is.copy() ); thingsUsed.add( is.copy() );
this.used.add( is ); this.used.add( is );
} }
else if( reserved != null )
{
thingsUsed.add( reserved.copy() );
this.used.add( reserved );
}
} }
this.bytes += available.getStackSize(); this.bytes += available.getStackSize();
@@ -179,7 +245,20 @@ public class CraftingTreeNode
} }
else else
{ {
final IAEItemStack available = inv.extractItems( this.what, Actionable.MODULATE, src ); final IAEItemStack available;
if( parent == null && this.what.equals( job.getOutput() ) )
{
available = null;
}
else if( reserved != null )
{
available = reserved;
}
else
{
available = inv.extractItems( this.what, Actionable.MODULATE, src );
}
if( available != null ) if( available != null )
{ {
@@ -192,6 +271,11 @@ public class CraftingTreeNode
thingsUsed.add( is.copy() ); thingsUsed.add( is.copy() );
this.used.add( is ); this.used.add( is );
} }
else if( reserved != null )
{
thingsUsed.add( reserved.copy() );
this.used.add( reserved );
}
} }
this.bytes += available.getStackSize(); this.bytes += available.getStackSize();
@@ -204,31 +288,19 @@ public class CraftingTreeNode
} }
} }
if( this.canEmit )
{
final IAEItemStack wat = this.what.copy();
wat.setStackSize( l );
this.howManyEmitted = wat.getStackSize();
this.bytes += wat.getStackSize();
return wat;
}
this.exhausted = true; this.exhausted = true;
if( this.nodes.size() == 1 ) if( this.nodes.size() == 1 )
{ {
final CraftingTreeProcess pro = this.nodes.get( 0 ); final CraftingTreeProcess pro = this.nodes.get( 0 );
while( pro.possible && l > 0 ) while ( pro.possible && l > 0 )
{ {
final IAEItemStack madeWhat = pro.getAmountCrafted( this.what ); final IAEItemStack madeWhat = pro.getAmountCrafted( this.what );
pro.request( inv, pro.getTimes( l, madeWhat.getStackSize() ), src ); pro.request( inv, pro.getTimes( l, madeWhat.getStackSize() ), src );
madeWhat.setStackSize( l ); madeWhat.setStackSize( l );
final IAEItemStack available = inv.extractItems( madeWhat, Actionable.MODULATE, src ); final IAEItemStack available = inv.extractItems( madeWhat, Actionable.MODULATE, src );
if( available != null ) if( available != null )
@@ -253,10 +325,12 @@ public class CraftingTreeNode
{ {
try try
{ {
while( pro.possible && l > 0 ) while ( pro.possible && l > 0 )
{ {
final MECraftingInventory subInv = new MECraftingInventory( inv, true, true, true ); final MECraftingInventory subInv = new MECraftingInventory( inv, true, true, true );
pro.request( subInv, 1, src ); final IAEItemStack madeWhat = pro.getAmountCrafted( this.what );
pro.request( subInv, pro.getTimes( l, madeWhat.getStackSize() ), src );
this.what.setStackSize( l ); this.what.setStackSize( l );
final IAEItemStack available = subInv.extractItems( this.what, Actionable.MODULATE, src ); final IAEItemStack available = subInv.extractItems( this.what, Actionable.MODULATE, src );
@@ -289,10 +363,10 @@ public class CraftingTreeNode
} }
} }
if( this.sim ) if( job.isSimulation() )
{ {
this.missing += l;
this.bytes += l; this.bytes += l;
this.missing += l;
final IAEItemStack rv = this.what.copy(); final IAEItemStack rv = this.what.copy();
rv.setStackSize( l ); rv.setStackSize( l );
return rv; return rv;
@@ -308,6 +382,26 @@ public class CraftingTreeNode
throw new CraftBranchFailure( this.what, l ); throw new CraftBranchFailure( this.what, l );
} }
CraftingTreeNode recursiveNode( CraftingTreeNode node )
{
if( this.parent == null )
{
return null;
}
if( node != this )
{
if( node.what.equals( this.what ) )
{
if( node.what.getStackSize() == this.what.getStackSize() )
{
loopHead = this;
return node;
}
}
}
return this.parent.notRecursive( node );
}
void dive( final CraftingJob job ) void dive( final CraftingJob job )
{ {
if( this.missing > 0 ) if( this.missing > 0 )
@@ -316,7 +410,7 @@ public class CraftingTreeNode
} }
// missing = 0; // missing = 0;
job.addBytes( 8 + this.bytes ); job.addBytes( this.bytes );
for( final CraftingTreeProcess pro : this.nodes ) for( final CraftingTreeProcess pro : this.nodes )
{ {
@@ -333,7 +427,6 @@ public class CraftingTreeNode
void setSimulate() void setSimulate()
{ {
this.sim = true;
this.missing = 0; this.missing = 0;
this.bytes = 0; this.bytes = 0;
this.used.resetStatus(); this.used.resetStatus();
@@ -353,6 +446,24 @@ public class CraftingTreeNode
if( ex == null || ex.getStackSize() != i.getStackSize() ) if( ex == null || ex.getStackSize() != i.getStackSize() )
{ {
if( src.player().isPresent() )
{
try
{
if( ex == null )
{
NetworkHandler.instance().sendTo( new PacketInformPlayer( i ), (EntityPlayerMP) src.player().get() );
}
else
{
NetworkHandler.instance().sendTo( new PacketInformPlayer( ex, i ), (EntityPlayerMP) src.player().get() );
}
}
catch( IOException e )
{
e.printStackTrace();
}
}
throw new CraftBranchFailure( i, i.getStackSize() ); throw new CraftBranchFailure( i, i.getStackSize() );
} }
@@ -19,241 +19,208 @@
package appeng.crafting; package appeng.crafting;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
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; import appeng.api.config.Actionable;
import appeng.api.config.FuzzyMode;
import appeng.api.networking.crafting.ICraftingGrid; import appeng.api.networking.crafting.ICraftingGrid;
import appeng.api.networking.crafting.ICraftingPatternDetails; import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.networking.security.IActionSource; import appeng.api.networking.security.IActionSource;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList; import appeng.api.storage.data.IItemList;
import appeng.container.ContainerNull;
import appeng.me.cluster.implementations.CraftingCPUCluster; import appeng.me.cluster.implementations.CraftingCPUCluster;
import appeng.util.Platform; import appeng.util.Platform;
import appeng.util.item.AEItemStack;
import com.google.common.collect.ImmutableCollection;
import it.unimi.dsi.fastutil.objects.Object2LongArrayMap;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
public class CraftingTreeProcess public class CraftingTreeProcess
{ {
private final CraftingTreeNode parent;
final ICraftingPatternDetails details; final ICraftingPatternDetails details;
private final CraftingTreeNode parent;
private final CraftingJob job; private final CraftingJob job;
private final Map<CraftingTreeNode, Long> nodes = new HashMap<>(); private final Object2LongArrayMap<CraftingTreeNode> nodes = new Object2LongArrayMap<>();
private final int depth;
boolean possible = true; boolean possible = true;
private World world;
private long crafts = 0; private long crafts = 0;
private boolean containerItems;
private boolean limitQty;
private boolean fullSimulation;
private long bytes = 0; private long bytes = 0;
private boolean hasContainerItem = false;
public CraftingTreeProcess( final ICraftingGrid cc, final CraftingJob job, final ICraftingPatternDetails details, final CraftingTreeNode craftingTreeNode, final int depth ) public CraftingTreeProcess( final ICraftingGrid cc, final CraftingJob job, final ICraftingPatternDetails details, int times, final CraftingTreeNode craftingTreeNode )
{ {
this.parent = craftingTreeNode; this.parent = craftingTreeNode;
this.details = details; this.details = details;
this.job = job; this.job = job;
this.depth = depth; World world = job.getWorld();
final World world = job.getWorld();
if( details.isCraftable() ) final IAEItemStack[] list = details.getInputs();
// this is minor different then below, this slot uses the pattern, but kinda fudges it.
for( IAEItemStack part : details.getCondensedInputs() )
{ {
final IAEItemStack[] list = details.getInputs(); if( part == null )
final InventoryCrafting ic = new InventoryCrafting( new ContainerNull(), 3, 3 );
final IAEItemStack[] is = details.getInputs();
for( int x = 0; x < ic.getSizeInventory(); x++ )
{ {
ic.setInventorySlotContents( x, is[x] == null ? ItemStack.EMPTY : is[x].createItemStack() ); continue;
} }
for( int x = 0; x < list.length; x++ )
for( int x = 0; x < ic.getSizeInventory(); x++ )
{ {
final ItemStack g = ic.getStackInSlot( x ); final IAEItemStack comparePart = list[x];
if( !g.isEmpty() && g.getCount() > 1 ) if( part.equals( comparePart ) )
{ {
this.fullSimulation = true; boolean isPartContainer = false;
} if( part.getItem().hasContainerItem( part.getDefinition() ) )
}
for( final IAEItemStack part : details.getCondensedInputs() )
{
final ItemStack g = part.createItemStack();
boolean isAnInput = false;
for( final IAEItemStack a : details.getCondensedOutputs() )
{
if( !g.isEmpty() && a != null && a.equals( g ) )
{ {
isAnInput = true; part = list[x];
isPartContainer = true;
this.hasContainerItem = true;
} }
}
if( isAnInput ) long wantedSize = isPartContainer ? part.getStackSize() : part.getStackSize() * times;
{
this.limitQty = true;
}
if( g.getItem().hasContainerItem( g ) ) if( details.canSubstitute() && cc.getCraftingFor( part, details, x, world ).isEmpty() )
{
this.limitQty = this.containerItems = true;
}
}
final boolean complicated = false;
if( this.containerItems || complicated )
{
for( int x = 0; x < list.length; x++ )
{
final IAEItemStack part = list[x];
if( part != null )
{ {
this.nodes.put( new CraftingTreeNode( cc, job, part.copy(), this, x, depth + 1 ), part.getStackSize() ); for( IAEItemStack subs : details.getSubstituteInputs( x ) )
}
}
}
else
{
// this is minor different then below, this slot uses the pattern, but kinda fudges it.
for( final IAEItemStack part : details.getCondensedInputs() )
{
for( int x = 0; x < list.length; x++ )
{
final IAEItemStack comparePart = list[x];
if( part != null && part.equals( comparePart ) )
{ {
// use the first slot... if( subs.fuzzyComparison( part, FuzzyMode.IGNORE_ALL ) )
this.nodes.put( new CraftingTreeNode( cc, job, part.copy(), this, x, depth + 1 ), part.getStackSize() ); {
break; this.nodes.put( new CraftingTreeNode( cc, job, subs.copy(), wantedSize, this, x ), part.getStackSize() / times );
wantedSize = 0;
break;
}
}
//try to order the crafting of a substitute
ICraftingPatternDetails prioritizedPattern = null;
IAEItemStack prioritizedIAE = null;
for( IAEItemStack subs : details.getSubstituteInputs( x ) )
{
if( subs.equals( part ) )
{
continue;
}
ImmutableCollection<ICraftingPatternDetails> detailCollection = cc.getCraftingFor( subs, details, x, world );
for( ICraftingPatternDetails sp : detailCollection )
{
if( prioritizedPattern == null )
{
prioritizedPattern = sp;
prioritizedIAE = subs;
}
else
{
if( sp.getPriority() > prioritizedPattern.getPriority() )
{
prioritizedPattern = sp;
}
}
}
if( prioritizedIAE != null )
{
this.nodes.put( new CraftingTreeNode( cc, job, prioritizedIAE.copy(), wantedSize, this, x ), part.getStackSize() / times );
wantedSize = 0;
break;
}
} }
} }
} if( wantedSize > 0 )
}
}
else
{
for( final IAEItemStack part : details.getCondensedInputs() )
{
final ItemStack g = part.createItemStack();
boolean isAnInput = false;
for( final IAEItemStack a : details.getCondensedOutputs() )
{
if( !g.isEmpty() && a != null && a.equals( g ) )
{ {
isAnInput = true; part = part.copy().setStackSize( wantedSize );
// use the first slot...
this.nodes.put( new CraftingTreeNode( cc, job, part.copy(), wantedSize, this, x ), part.getStackSize() / times );
wantedSize = 0;
}
if( !isPartContainer && wantedSize == 0 )
{
break;
} }
} }
if( isAnInput )
{
this.limitQty = true;
}
}
for( final IAEItemStack part : details.getCondensedInputs() )
{
this.nodes.put( new CraftingTreeNode( cc, job, part.copy(), this, -1, depth + 1 ), part.getStackSize() );
} }
} }
} }
boolean notRecursive( final ICraftingPatternDetails details ) CraftingTreeNode notRecursive( CraftingTreeNode node )
{ {
return this.parent == null || this.parent.notRecursive( details ); if( parent == null )
{
return null;
}
return this.parent.recursiveNode( node );
} }
long getTimes( final long remaining, final long stackSize ) long getTimes( final long remaining, final long stackSize )
{ {
if( this.limitQty || this.fullSimulation ) if( hasContainerItem )
{ {
return 1; return 1;
} }
return ( remaining / stackSize ) + ( remaining % stackSize != 0 ? 1 : 0 ); return ( remaining / stackSize ) + ( remaining % stackSize != 0 ? 1 : 0 );
} }
void request( final MECraftingInventory inv, final long i, final IActionSource src ) throws CraftBranchFailure, InterruptedException void request( final MECraftingInventory inv, final long amountOfTimes, final IActionSource src ) throws CraftBranchFailure, InterruptedException
{ {
this.job.handlePausing();
List<IAEItemStack> containerItems = null;
if( this.fullSimulation ) // request and remove inputs...
for( final Entry<CraftingTreeNode, Long> entry : this.nodes.object2LongEntrySet() )
{ {
final InventoryCrafting ic = new InventoryCrafting( new ContainerNull(), 3, 3 ); final IAEItemStack stack = entry.getKey().request( inv, details.isCraftable() && hasContainerItem ? 1 : entry.getValue() * amountOfTimes, src );
for( final Entry<CraftingTreeNode, Long> entry : this.nodes.entrySet() ) if( stack.equals( job.getOutput() ) )
{ {
final IAEItemStack item = entry.getKey().getStack( entry.getValue() ); job.getNeededForLoop().add( stack.copy() );
final IAEItemStack stack = entry.getKey().request( inv, item.getStackSize(), src );
ic.setInventorySlotContents( entry.getKey().getSlot(), stack.createItemStack() );
} }
for( int x = 0; x < ic.getSizeInventory(); x++ ) if( details.isCraftable() && stack.getItem().hasContainerItem( stack.getDefinition() ) )
{ {
ItemStack is = ic.getStackInSlot( x ); final ItemStack is = Platform.getContainerItem( stack.createItemStack() );
is = Platform.getContainerItem( is ); final IAEItemStack o = AEItemStack.fromItemStack( is );
final IAEItemStack o = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createStack( is );
if( o != null ) if( o != null )
{ {
this.bytes++; if( containerItems == null )
inv.injectItems( o, Actionable.MODULATE, src );
}
}
}
else
{
// request and remove inputs...
for( final Entry<CraftingTreeNode, Long> entry : this.nodes.entrySet() )
{
final IAEItemStack item = entry.getKey().getStack( entry.getValue() );
final IAEItemStack stack = entry.getKey().request( inv, item.getStackSize() * i, src );
if( this.containerItems )
{
final ItemStack is = Platform.getContainerItem( stack.createItemStack() );
final IAEItemStack o = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createStack( is );
if( o != null )
{ {
this.bytes++; containerItems = new ArrayList<>();
inv.injectItems( o, Actionable.MODULATE, src ); }
this.bytes++;
o.setCachedItemStack( is );
containerItems.add( o );
}
if( containerItems != null )
{
for( IAEItemStack i : containerItems )
{
inv.injectItems( i, Actionable.MODULATE, src );
} }
} }
} }
} }
// assume its possible. // assume its possible.
// add crafting results.. // add crafting results..
for( final IAEItemStack out : this.details.getCondensedOutputs() ) for( final IAEItemStack out : this.details.getCondensedOutputs() )
{ {
final IAEItemStack o = out.copy(); final IAEItemStack o = out.copy();
o.setStackSize( o.getStackSize() * i ); o.setStackSize( o.getStackSize() * amountOfTimes );
inv.injectItems( o, Actionable.MODULATE, src ); inv.injectItems( o, Actionable.MODULATE, src );
} }
this.crafts += amountOfTimes;
this.crafts += i;
} }
void dive( final CraftingJob job ) void dive( final CraftingJob job )
{ {
job.addTask( this.getAmountCrafted( this.parent.getStack( 1 ) ), this.crafts, this.details, this.depth ); job.addTask( this.getAmountCrafted( this.parent.getStack( 1 ) ), this.crafts );
for( final CraftingTreeNode pro : this.nodes.keySet() ) for( final Entry<CraftingTreeNode, Long> entry : this.nodes.object2LongEntrySet() )
{ {
pro.dive( job ); entry.getKey().dive( job );
} }
job.addBytes( 8 + this.crafts + this.bytes ); job.addBytes( this.crafts * 8 + this.bytes );
} }
IAEItemStack getAmountCrafted( IAEItemStack what2 ) IAEItemStack getAmountCrafted( IAEItemStack what2 )
@@ -287,9 +254,9 @@ public class CraftingTreeProcess
this.crafts = 0; this.crafts = 0;
this.bytes = 0; this.bytes = 0;
for( final CraftingTreeNode pro : this.nodes.keySet() ) for( final Entry<CraftingTreeNode, Long> entry : this.nodes.object2LongEntrySet() )
{ {
pro.setSimulate(); entry.getKey().setSimulate();
} }
} }
@@ -297,9 +264,9 @@ public class CraftingTreeProcess
{ {
craftingCPUCluster.addCrafting( this.details, this.crafts ); craftingCPUCluster.addCrafting( this.details, this.crafts );
for( final CraftingTreeNode pro : this.nodes.keySet() ) for( final Entry<CraftingTreeNode, Long> entry : this.nodes.object2LongEntrySet() )
{ {
pro.setJob( storage, craftingCPUCluster, src ); entry.getKey().setJob( storage, craftingCPUCluster, src );
} }
} }
@@ -312,9 +279,14 @@ public class CraftingTreeProcess
plan.addRequestable( i ); plan.addRequestable( i );
} }
for( final CraftingTreeNode pro : this.nodes.keySet() ) for( final Entry<CraftingTreeNode, Long> entry : this.nodes.object2LongEntrySet() )
{ {
pro.getPlan( plan ); entry.getKey().getPlan( plan );
} }
} }
public void reserveForNode()
{
parent.reserveForNode();
}
} }
@@ -28,7 +28,13 @@ import appeng.api.storage.IStorageChannel;
import appeng.api.storage.channels.IItemStorageChannel; import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList; import appeng.api.storage.data.IItemList;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketInformPlayer;
import appeng.util.inv.ItemListIgnoreCrafting; import appeng.util.inv.ItemListIgnoreCrafting;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.text.TextComponentString;
import java.io.IOException;
public class MECraftingInventory implements IMEInventory<IAEItemStack> public class MECraftingInventory implements IMEInventory<IAEItemStack>
@@ -95,8 +101,7 @@ public class MECraftingInventory implements IMEInventory<IAEItemStack>
this.injectedCache = null; this.injectedCache = null;
} }
this.localCache = this.target this.localCache = this.target.getAvailableItems( new ItemListIgnoreCrafting<>( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList() ) );
.getAvailableItems( new ItemListIgnoreCrafting<>( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList() ) );
this.par = parent; this.par = parent;
} }
@@ -307,8 +312,25 @@ public class MECraftingInventory implements IMEInventory<IAEItemStack>
if( result == null || result.getStackSize() != extra.getStackSize() ) if( result == null || result.getStackSize() != extra.getStackSize() )
{ {
if( src.player().isPresent() )
{
try
{
if( result == null )
{
NetworkHandler.instance().sendTo( new PacketInformPlayer( extra ), (EntityPlayerMP) src.player().get() );
}
else
{
NetworkHandler.instance().sendTo( new PacketInformPlayer( extra, result ), (EntityPlayerMP) src.player().get() );
}
}
catch( IOException e )
{
e.printStackTrace();
}
}
failed = true; failed = true;
break;
} }
} }
} }
@@ -339,11 +361,6 @@ public class MECraftingInventory implements IMEInventory<IAEItemStack>
return true; return true;
} }
private void addMissing( final IAEItemStack extra )
{
this.missingCache.add( extra );
}
void ignore( final IAEItemStack what ) void ignore( final IAEItemStack what )
{ {
final IAEItemStack list = this.localCache.findPrecise( what ); final IAEItemStack list = this.localCache.findPrecise( what );
@@ -352,4 +369,18 @@ public class MECraftingInventory implements IMEInventory<IAEItemStack>
list.setStackSize( 0 ); list.setStackSize( 0 );
} }
} }
void reserve( final IAEItemStack what )
{
final IAEItemStack list = this.localCache.findPrecise( what );
if( list != null )
{
list.decStackSize( what.getStackSize() );
}
}
private void addMissing( final IAEItemStack extra )
{
this.missingCache.add( extra );
}
} }
@@ -21,6 +21,9 @@ package appeng.fluids.client.gui;
import java.io.IOException; 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.client.gui.GuiButton;
import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.entity.player.InventoryPlayer;
@@ -38,11 +41,12 @@ import appeng.fluids.helper.IFluidInterfaceHost;
import appeng.fluids.util.IAEFluidTank; 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; public final static int ID_BUTTON_TANK = 222;
private final IFluidInterfaceHost host; private final IFluidInterfaceHost host;
private final ContainerFluidInterface container;
private GuiTabButton priority; private GuiTabButton priority;
public GuiFluidInterface( final InventoryPlayer ip, final IFluidInterfaceHost te ) public GuiFluidInterface( final InventoryPlayer ip, final IFluidInterfaceHost te )
@@ -50,6 +54,8 @@ public class GuiFluidInterface extends GuiUpgradeable
super( new ContainerFluidInterface( ip, te ) ); super( new ContainerFluidInterface( ip, te ) );
this.ySize = 231; this.ySize = 231;
this.host = te; this.host = te;
( this.container = (ContainerFluidInterface) this.inventorySlots ).setGui( this );
} }
@Override @Override
@@ -62,9 +68,7 @@ public class GuiFluidInterface extends GuiUpgradeable
for( int i = 0; i < DualityFluidInterface.NUMBER_OF_TANKS; ++i ) 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 this.guiSlots.add( new GuiFluidTank( fluidTank, i, DualityFluidInterface.NUMBER_OF_TANKS + i, 36 + 18 * i, 57, 16, 64 ) );
.getGuiTop() + 53, 16, 68 );
this.buttonList.add( guiTank );
this.guiSlots.add( new GuiFluidSlot( configFluids, i, i, 35 + 18 * i, 35 ) ); 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 @Override
protected boolean drawUpgrades() protected boolean drawUpgrades()
{ {
return false; return false;
} }
@Override
public void updateSetting( IConfigManager manager, Enum settingName, Enum newValue )
{
}
} }
@@ -19,42 +19,50 @@
package appeng.fluids.client.gui.widgets; 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.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.fml.relauncher.SideOnly;
import appeng.api.storage.data.IAEFluidStack; import appeng.api.storage.data.IAEFluidStack;
import appeng.api.util.AEColor;
import appeng.client.gui.widgets.ITooltip; import appeng.client.gui.widgets.ITooltip;
import appeng.fluids.util.IAEFluidTank; import appeng.fluids.util.IAEFluidTank;
@SideOnly( Side.CLIENT ) @SideOnly( Side.CLIENT )
public class GuiFluidTank extends GuiButton implements ITooltip public class GuiFluidTank extends GuiCustomSlot implements ITooltip
{ {
private final IAEFluidTank tank; private final IAEFluidTank tank;
private final int slot; 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 ) 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.tank = tank;
this.slot = slot; this.slot = slot;
this.width = w;
this.height = h;
} }
@Override @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.disableBlend();
GlStateManager.disableLighting(); 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 ); final IAEFluidStack fluid = this.tank.getFluidInSlot( this.slot );
if( fluid != null && fluid.getStackSize() > 0 ) if( fluid != null && fluid.getStackSize() > 0 )
@@ -72,14 +80,13 @@ public class GuiFluidTank extends GuiButton implements ITooltip
int iconHeightRemainder = scaledHeight % 16; int iconHeightRemainder = scaledHeight % 16;
if( iconHeightRemainder > 0 ) 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, 16, iconHeightRemainder );
} }
for( int i = 0; i < scaledHeight / 16; i++ ) for( int i = 0; i < scaledHeight / 16; 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, 16, 16 );
} }
} }
} }
} }
@@ -100,19 +107,19 @@ public class GuiFluidTank extends GuiButton implements ITooltip
@Override @Override
public int xPos() public int xPos()
{ {
return this.x - 2; return this.x - 1;
} }
@Override @Override
public int yPos() public int yPos()
{ {
return this.y - 2; return this.y - 4;
} }
@Override @Override
public int getWidth() public int getWidth()
{ {
return this.width + 4; return this.width;
} }
@Override @Override
@@ -127,4 +134,24 @@ public class GuiFluidTank extends GuiButton implements ITooltip
return true; 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; package appeng.fluids.container;
import javax.annotation.Nonnull;
import java.util.Collections; import java.util.Collections;
import java.util.Map; 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.entity.player.InventoryPlayer;
import net.minecraft.inventory.IContainerListener; import net.minecraft.inventory.IContainerListener;
@@ -33,12 +41,19 @@ import appeng.fluids.helper.FluidSyncHelper;
import appeng.fluids.helper.IFluidInterfaceHost; import appeng.fluids.helper.IFluidInterfaceHost;
import appeng.fluids.util.IAEFluidTank; import appeng.fluids.util.IAEFluidTank;
import appeng.util.Platform; 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 DualityFluidInterface myDuality;
private final FluidSyncHelper tankSync; 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 ) public ContainerFluidInterface( final InventoryPlayer ip, final IFluidInterfaceHost te )
{ {
@@ -60,6 +75,15 @@ public class ContainerFluidInterface extends ContainerFluidConfigurable
return this.myDuality.getConfig(); 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 @Override
public void detectAndSendChanges() public void detectAndSendChanges()
{ {
@@ -97,6 +121,126 @@ public class ContainerFluidInterface extends ContainerFluidConfigurable
this.tankSync.readPacket( fluids ); 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 @Override
protected boolean supportCapacity() protected boolean supportCapacity()
{ {
@@ -24,6 +24,9 @@ import java.nio.BufferOverflowException;
import javax.annotation.Nonnull; 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.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.entity.player.InventoryPlayer;
@@ -70,6 +73,7 @@ import appeng.me.helpers.ChannelPowerSrc;
import appeng.util.ConfigManager; import appeng.util.ConfigManager;
import appeng.util.IConfigManagerHost; import appeng.util.IConfigManagerHost;
import appeng.util.Platform; 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 || notInserted.getStackSize() == 0 )
{
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 @Override
public void doAction( EntityPlayerMP player, InventoryAction action, int slot, long id ) 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(); final ItemStack held = player.inventory.getItemStack();
if( held.getCount() != 1 ) ItemStack heldCopy = held.copy();
{ heldCopy.setCount( 1 );
// only support stacksize 1 for now IFluidHandlerItem fh = FluidUtil.getFluidHandler( heldCopy );
return;
}
final IFluidHandlerItem fh = FluidUtil.getFluidHandler( held );
if( fh == null ) if( fh == null )
{ {
// only fluid handlers items // only fluid handlers items
@@ -372,84 +455,122 @@ public class ContainerFluidTerminal extends AEBaseContainer implements IConfigMa
// Check how much we can store in the item // Check how much we can store in the item
stack.setStackSize( Integer.MAX_VALUE ); stack.setStackSize( Integer.MAX_VALUE );
int amountAllowed = fh.fill( stack.getFluidStack(), false ); int amountAllowed = fh.fill( stack.getFluidStack(), false );
stack.setStackSize( amountAllowed ); int heldAmount = held.getCount();
for( int i = 0; i < heldAmount; i++ )
// 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 )
{ {
return; ItemStack copiedFluidContainer = held.copy();
} copiedFluidContainer.setCount( 1 );
fh = FluidUtil.getFluidHandler( copiedFluidContainer );
// How much could fit into the container // Check if we can pull out of the system
final int canFill = fh.fill( canPull.getFluidStack(), false ); final IAEFluidStack canPull = Platform.poweredExtraction( this.getPowerSource(), this.monitor, stack.setStackSize( amountAllowed ), this.getActionSource(), Actionable.SIMULATE );
if( canFill == 0 ) if( canPull == null || canPull.getStackSize() < 1 )
{
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 )
{ {
return; 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 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 ); else if( action == InventoryAction.EMPTY_ITEM )
extract.amount = drained.amount; {
int heldAmount = held.getCount();
final IAEFluidStack notInserted = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ), for( int i = 0; i < heldAmount; i++ )
this.getActionSource() );
if( notInserted != null && notInserted.getStackSize() > 0 )
{ {
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 ); this.updateHeld( player );
} }
} }
@@ -91,12 +91,10 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
private int isWorking = -1; private int isWorking = -1;
private int priority; private int priority;
private final MEMonitorPassThrough<IAEItemStack> items = new MEMonitorPassThrough<>( new NullInventory<IAEItemStack>(), AEApi.instance() private final MEMonitorPassThrough<IAEItemStack> items = new MEMonitorPassThrough<>( new NullInventory<IAEItemStack>(), AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) );
.storage() private final MEMonitorPassThrough<IAEFluidStack> fluids = new MEMonitorPassThrough<>( new NullInventory<IAEFluidStack>(), AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) );
.getStorageChannel( IItemStorageChannel.class ) ); private boolean resetConfigCache = true;
private final MEMonitorPassThrough<IAEFluidStack> fluids = new MEMonitorPassThrough<>( new NullInventory<IAEFluidStack>(), AEApi.instance() private IMEMonitor<IAEFluidStack> configCachedHandler;
.storage()
.getStorageChannel( IFluidStorageChannel.class ) );
public DualityFluidInterface( final AENetworkProxy networkProxy, final IFluidInterfaceHost ih ) public DualityFluidInterface( final AENetworkProxy networkProxy, final IFluidInterfaceHost ih )
{ {
@@ -119,15 +117,7 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
public IUpgradeableHost getHost() public IUpgradeableHost getHost()
{ {
if( this.iHost instanceof IUpgradeableHost ) return this.iHost;
{
return this.iHost;
}
if( this.iHost instanceof IUpgradeableHost )
{
return this.iHost;
}
return null;
} }
@Override @Override
@@ -146,7 +136,12 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
{ {
if( this.hasConfig() ) 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; return (IMEMonitor<T>) this.fluids;
@@ -383,7 +378,7 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
{ {
changed = true; 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 ); final IAEFluidStack acquired = Platform.poweredExtraction( src, dest, work, this.interfaceRequestSource );
if( acquired != null ) if( acquired != null )
@@ -450,7 +445,13 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
if( inventory == this.config ) if( inventory == this.config )
{ {
boolean cfg = hasConfig();
this.readConfig(); this.readConfig();
if( cfg != hasConfig )
{
resetConfigCache = true;
this.notifyNeighbors();
}
} }
else if( inventory == this.tanks ) else if( inventory == this.tanks )
{ {
@@ -555,7 +556,6 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
InterfaceInventory( final DualityFluidInterface tileInterface ) InterfaceInventory( final DualityFluidInterface tileInterface )
{ {
super( tileInterface.tanks ); super( tileInterface.tanks );
this.setActionSource( new MachineSource( tileInterface.iHost ) );
} }
@Override @Override
@@ -19,16 +19,15 @@
package appeng.fluids.parts; package appeng.fluids.parts;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Settings; import appeng.api.config.Settings;
import appeng.api.config.StorageFilter; import appeng.api.config.StorageFilter;
import appeng.parts.misc.PartStorageBus; 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.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidTankProperties; import net.minecraftforge.fluids.capability.IFluidTankProperties;
@@ -45,7 +44,6 @@ import appeng.api.storage.channels.IFluidStorageChannel;
import appeng.api.storage.data.IAEFluidStack; import appeng.api.storage.data.IAEFluidStack;
import appeng.api.storage.data.IItemList; import appeng.api.storage.data.IItemList;
import appeng.fluids.util.AEFluidStack; import appeng.fluids.util.AEFluidStack;
import appeng.me.GridAccessException;
import appeng.me.helpers.IGridProxyable; import appeng.me.helpers.IGridProxyable;
import appeng.me.storage.ITickingMonitor; import appeng.me.storage.ITickingMonitor;
@@ -65,17 +63,20 @@ public class FluidHandlerAdapter implements IMEInventory<IAEFluidStack>, IBaseMo
private final IGridProxyable proxyable; private final IGridProxyable proxyable;
private final FluidHandlerAdapter.InventoryCache cache; private final FluidHandlerAdapter.InventoryCache cache;
private StorageFilter mode; private StorageFilter mode;
private AccessRestriction access;
FluidHandlerAdapter( IFluidHandler fluidHandler, IGridProxyable proxy ) FluidHandlerAdapter( IFluidHandler fluidHandler, IGridProxyable proxy )
{ {
this.fluidHandler = fluidHandler; this.fluidHandler = fluidHandler;
this.proxyable = proxy; this.proxyable = proxy;
if( this.proxyable instanceof PartStorageBus ) if( this.proxyable instanceof PartFluidStorageBus )
{ {
PartStorageBus partStorageBus = (PartStorageBus) this.proxyable; PartFluidStorageBus partFluidStorageBus = (PartFluidStorageBus) this.proxyable;
this.mode = ( (StorageFilter) partStorageBus.getConfigManager().getSetting( Settings.STORAGE_FILTER ) ); 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 = new FluidHandlerAdapter.InventoryCache( this.fluidHandler, this.mode );
this.cache.update();
} }
@Override @Override
@@ -94,11 +95,14 @@ public class FluidHandlerAdapter implements IMEInventory<IAEFluidStack>, IBaseMo
if( type == Actionable.MODULATE ) if( type == Actionable.MODULATE )
{ {
IAEFluidStack added = input.copy().setStackSize( input.getStackSize() - remaining );
this.cache.currentlyCached.add( added );
this.postDifference( Collections.singletonList( added ) );
try try
{ {
this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() ); this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() );
} }
catch( GridAccessException ignore ) catch( GridAccessException ex )
{ {
// meh // meh
} }
@@ -123,25 +127,32 @@ public class FluidHandlerAdapter implements IMEInventory<IAEFluidStack>, IBaseMo
return null; return null;
} }
IAEFluidStack gatheredAEFluidstack = AEFluidStack.fromFluidStack( gathered );
if( mode == Actionable.MODULATE ) 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 try
{ {
this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() ); this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() );
} }
catch( GridAccessException ignore ) catch( GridAccessException ex )
{ {
// meh // meh
} }
} }
return AEFluidStack.fromFluidStack( gathered ); return gatheredAEFluidstack;
} }
@Override @Override
public TickRateModulation onTick() public TickRateModulation onTick()
{ {
List<IAEFluidStack> changes = this.cache.update(); List<IAEFluidStack> changes = this.cache.update();
if( !changes.isEmpty() ) if( !changes.isEmpty() && access.hasPermission( AccessRestriction.READ ) )
{ {
this.postDifference( changes ); this.postDifference( changes );
return TickRateModulation.URGENT; return TickRateModulation.URGENT;
@@ -202,9 +213,9 @@ public class FluidHandlerAdapter implements IMEInventory<IAEFluidStack>, IBaseMo
private static class InventoryCache private static class InventoryCache
{ {
private IAEFluidStack[] cachedAeStacks = new IAEFluidStack[0];
private final IFluidHandler fluidHandler; private final IFluidHandler fluidHandler;
private final StorageFilter mode; private final StorageFilter mode;
IItemList<IAEFluidStack> currentlyCached = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList();
public InventoryCache( IFluidHandler fluidHandler, StorageFilter mode ) public InventoryCache( IFluidHandler fluidHandler, StorageFilter mode )
{ {
@@ -216,102 +227,46 @@ public class FluidHandlerAdapter implements IMEInventory<IAEFluidStack>, IBaseMo
{ {
final List<IAEFluidStack> changes = new ArrayList<>(); final List<IAEFluidStack> changes = new ArrayList<>();
final IFluidTankProperties[] tankProperties = this.fluidHandler.getTankProperties(); final IFluidTankProperties[] tankProperties = this.fluidHandler.getTankProperties();
final int slots = tankProperties.length;
// Make room for new slots IItemList<IAEFluidStack> currentlyOnStorage = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList();
if( slots > this.cachedAeStacks.length )
{
this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, slots );
}
for( int slot = 0; slot < slots; slot++ ) for( IFluidTankProperties tankProperty : tankProperties )
{ {
// Save the old stuff if( this.mode == StorageFilter.EXTRACTABLE_ONLY && this.fluidHandler.drain( 1, false ) == null )
final IAEFluidStack oldAEFS = this.cachedAeStacks[slot];
FluidStack newFS = tankProperties[slot].getContents();
if( this.mode == StorageFilter.EXTRACTABLE_ONLY && newFS != null )
{ {
if( this.fluidHandler.drain( 1, false ) == null ) continue;
{
newFS = null;
}
} }
this.handlePossibleSlotChanges( slot, oldAEFS, newFS, changes ); currentlyOnStorage.add( AEFluidStack.fromFluidStack( tankProperty.getContents() ) );
} }
// Handle cases where the number of slots actually is lower now than before for ( final IAEFluidStack is : currentlyCached )
if( slots < this.cachedAeStacks.length )
{ {
for( int slot = slots; slot < this.cachedAeStacks.length; slot++ ) is.setStackSize( -is.getStackSize() );
{
final IAEFluidStack aeStack = this.cachedAeStacks[slot];
if( aeStack != null )
{
final IAEFluidStack a = aeStack.copy();
a.setStackSize( -a.getStackSize() );
changes.add( a );
}
}
this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, slots );
} }
for ( final IAEFluidStack is : currentlyOnStorage )
{
currentlyCached.add( is );
}
for ( final IAEFluidStack is : currentlyCached )
{
if( is.getStackSize() != 0 )
{
changes.add( is );
}
}
currentlyCached = currentlyOnStorage;
return changes; return changes;
} }
public IItemList<IAEFluidStack> getAvailableItems( IItemList<IAEFluidStack> out ) public IItemList<IAEFluidStack> getAvailableItems( IItemList<IAEFluidStack> out )
{ {
Arrays.stream( this.cachedAeStacks ).forEach( out::add ); currentlyCached.iterator().forEachRemaining( out::add );
return out; 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] );
}
}
} }
} }
@@ -178,8 +178,9 @@ public class PartFluidFormationPlane extends PartAbstractFormationPlane<IAEFluid
this.stateChanged(); this.stateChanged();
} }
@Override
@MENetworkEventSubscribe @MENetworkEventSubscribe
public void updateChannels( final MENetworkChannelsChanged changedChannels ) public void chanRender( final MENetworkChannelsChanged changedChannels )
{ {
this.stateChanged(); this.stateChanged();
} }
@@ -204,7 +205,7 @@ public class PartFluidFormationPlane extends PartAbstractFormationPlane<IAEFluid
@Override @Override
public List<IMEInventoryHandler> getCellArray( final IStorageChannel channel ) 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 ); final List<IMEInventoryHandler> handler = new ArrayList<>( 1 );
handler.add( this.myHandler ); handler.add( this.myHandler );
@@ -90,14 +90,16 @@ public class PartFluidInterface extends PartBasicState implements IGridTickable,
return this.duality; return this.duality;
} }
@Override
@MENetworkEventSubscribe @MENetworkEventSubscribe
public void stateChange( final MENetworkChannelsChanged c ) public void chanRender( final MENetworkChannelsChanged c )
{ {
this.duality.notifyNeighbors(); this.duality.notifyNeighbors();
} }
@Override
@MENetworkEventSubscribe @MENetworkEventSubscribe
public void stateChange( final MENetworkPowerStatusChange c ) public void powerRender( final MENetworkPowerStatusChange c )
{ {
this.duality.notifyNeighbors(); this.duality.notifyNeighbors();
} }
@@ -4,7 +4,9 @@ package appeng.fluids.parts;
import java.util.Random; import java.util.Random;
import appeng.api.storage.data.IItemList;
import appeng.fluids.helper.IConfigurableFluidInventory; import appeng.fluids.helper.IConfigurableFluidInventory;
import appeng.me.cache.NetworkMonitor;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
@@ -34,7 +36,6 @@ import appeng.api.storage.IStorageChannel;
import appeng.api.storage.channels.IFluidStorageChannel; import appeng.api.storage.channels.IFluidStorageChannel;
import appeng.api.storage.data.IAEFluidStack; import appeng.api.storage.data.IAEFluidStack;
import appeng.api.storage.data.IAEStack; import appeng.api.storage.data.IAEStack;
import appeng.api.storage.data.IItemList;
import appeng.api.util.AECableType; import appeng.api.util.AECableType;
import appeng.api.util.AEPartLocation; import appeng.api.util.AEPartLocation;
import appeng.api.util.IConfigManager; import appeng.api.util.IConfigManager;
@@ -127,15 +128,25 @@ public class PartFluidLevelEmitter extends PartUpgradeable implements IStackWatc
this.configureWatchers(); this.configureWatchers();
} }
@Override
@MENetworkEventSubscribe @MENetworkEventSubscribe
public void channelChanged( final MENetworkChannelsChanged c ) public void powerRender( final MENetworkPowerStatusChange powerEvent )
{ {
if (this.getProxy().isActive())
{
onListUpdate();
}
this.updateState(); this.updateState();
} }
@Override
@MENetworkEventSubscribe @MENetworkEventSubscribe
public void powerChanged( final MENetworkPowerStatusChange c ) public void chanRender( final MENetworkChannelsChanged c )
{ {
if (this.getProxy().isActive())
{
onListUpdate();
}
this.updateState(); this.updateState();
} }
@@ -247,10 +258,9 @@ public class PartFluidLevelEmitter extends PartUpgradeable implements IStackWatc
if( myStack == null ) if( myStack == null )
{ {
this.lastReportedValue = 0; if( monitor instanceof NetworkMonitor )
for( final IAEFluidStack st : monitor.getStorageList() )
{ {
this.lastReportedValue += st.getStackSize(); this.lastReportedValue = ( (NetworkMonitor<IAEFluidStack>) monitor ).getGridCurrentCount();
} }
} }
else else
File diff suppressed because it is too large Load Diff
+265 -200
View File
@@ -19,38 +19,6 @@
package appeng.helpers; package appeng.helpers;
import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import appeng.integration.modules.gregtech.GTCEInventoryAdaptor;
import appeng.util.*;
import appeng.util.inv.*;
import com.google.common.collect.ImmutableSet;
import gregtech.api.block.machines.BlockMachine;
import gregtech.api.metatileentity.MetaTileEntity;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Items;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
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;
import appeng.api.AEApi; import appeng.api.AEApi;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
import appeng.api.config.Settings; import appeng.api.config.Settings;
@@ -74,11 +42,7 @@ import appeng.api.networking.ticking.IGridTickable;
import appeng.api.networking.ticking.TickRateModulation; import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.networking.ticking.TickingRequest; import appeng.api.networking.ticking.TickingRequest;
import appeng.api.parts.IPart; import appeng.api.parts.IPart;
import appeng.api.storage.IMEInventory; import appeng.api.storage.*;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.IStorageChannel;
import appeng.api.storage.IStorageMonitorable;
import appeng.api.storage.IStorageMonitorableAccessor;
import appeng.api.storage.channels.IFluidStorageChannel; import appeng.api.storage.channels.IFluidStorageChannel;
import appeng.api.storage.channels.IItemStorageChannel; import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEFluidStack; import appeng.api.storage.data.IAEFluidStack;
@@ -100,7 +64,39 @@ import appeng.parts.automation.StackUpgradeInventory;
import appeng.parts.automation.UpgradeInventory; import appeng.parts.automation.UpgradeInventory;
import appeng.tile.inventory.AppEngInternalAEInventory; import appeng.tile.inventory.AppEngInternalAEInventory;
import appeng.tile.inventory.AppEngInternalInventory; 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.*;
import appeng.util.item.AEItemStack; import appeng.util.item.AEItemStack;
import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.Ints;
import de.ellpeck.actuallyadditions.api.tile.IPhantomTile;
import gregtech.api.block.machines.BlockMachine;
import gregtech.api.metatileentity.MetaTileEntity;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Items;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
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;
import javax.annotation.Nullable;
import java.util.*;
import static gregtech.api.block.machines.BlockMachine.getMetaTileEntity; import static gregtech.api.block.machines.BlockMachine.getMetaTileEntity;
@@ -109,10 +105,10 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
{ {
public static final int NUMBER_OF_STORAGE_SLOTS = 9; public static final int NUMBER_OF_STORAGE_SLOTS = 9;
public static final int NUMBER_OF_CONFIG_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 static final Collection<Block> BAD_BLOCKS = new HashSet<>( 100 );
private final IAEItemStack[] requireWork = { null, null, null, null, null, null, null, null, null }; private final IAEItemStack[] requireWork = {null, null, null, null, null, null, null, null, null};
private final MultiCraftingTracker craftingTracker; private final MultiCraftingTracker craftingTracker;
private final AENetworkProxy gridProxy; private final AENetworkProxy gridProxy;
private final IInterfaceHost iHost; private final IInterfaceHost iHost;
@@ -122,30 +118,27 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
private final AppEngInternalAEInventory config = new AppEngInternalAEInventory( this, NUMBER_OF_CONFIG_SLOTS ); private final AppEngInternalAEInventory config = new AppEngInternalAEInventory( this, NUMBER_OF_CONFIG_SLOTS );
private final AppEngInternalInventory storage = new AppEngInternalInventory( this, NUMBER_OF_STORAGE_SLOTS ); private final AppEngInternalInventory storage = new AppEngInternalInventory( this, NUMBER_OF_STORAGE_SLOTS );
private final AppEngInternalInventory patterns = new AppEngInternalInventory( this, NUMBER_OF_PATTERN_SLOTS ); private final AppEngInternalInventory patterns = new AppEngInternalInventory( this, NUMBER_OF_PATTERN_SLOTS );
private final MEMonitorPassThrough<IAEItemStack> items = new MEMonitorPassThrough<>( new NullInventory<IAEItemStack>(), AEApi.instance() private final MEMonitorPassThrough<IAEItemStack> items = new MEMonitorPassThrough<>( new NullInventory<IAEItemStack>(), AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) );
.storage() private final MEMonitorPassThrough<IAEFluidStack> fluids = new MEMonitorPassThrough<>( new NullInventory<IAEFluidStack>(), AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) );
.getStorageChannel( IItemStorageChannel.class ) );
private final MEMonitorPassThrough<IAEFluidStack> fluids = new MEMonitorPassThrough<>( new NullInventory<IAEFluidStack>(), AEApi.instance()
.storage()
.getStorageChannel( IFluidStorageChannel.class ) );
private final UpgradeInventory upgrades; private final UpgradeInventory upgrades;
private final Accessor accessor = new Accessor();
private boolean hasConfig = false; private boolean hasConfig = false;
private int priority; private int priority;
private List<ICraftingPatternDetails> craftingList = null; private List<ICraftingPatternDetails> craftingList = null;
private List<ItemStack> waitingToSend = null; private List<ItemStack> waitingToSend = null;
private IMEInventory<IAEItemStack> destination; private IMEInventory<IAEItemStack> destination;
private int isWorking = -1; private int isWorking = -1;
private final Accessor accessor = new Accessor();
private EnumSet<EnumFacing> visitedFaces = EnumSet.noneOf( EnumFacing.class ); private EnumSet<EnumFacing> visitedFaces = EnumSet.noneOf( EnumFacing.class );
private EnumMap<EnumFacing,List<ItemStack>> waitingToSendFacing = new EnumMap<>(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 ) public DualityInterface( final AENetworkProxy networkProxy, final IInterfaceHost ih )
{ {
this.gridProxy = networkProxy; this.gridProxy = networkProxy;
this.gridProxy.setFlags( GridFlags.REQUIRE_CHANNEL ); 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.BLOCK, YesNo.NO );
this.cm.registerSetting( Settings.INTERFACE_TERMINAL, YesNo.YES ); this.cm.registerSetting( Settings.INTERFACE_TERMINAL, YesNo.YES );
@@ -160,6 +153,11 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
this.interfaceRequestSource = new InterfaceRequestSource( this.iHost ); this.interfaceRequestSource = new InterfaceRequestSource( this.iHost );
} }
private static boolean invIsCustomBlocking( BlockingInventoryAdaptor inv )
{
return ( inv.containsBlockingItems() );
}
@Override @Override
public void saveChanges() public void saveChanges()
{ {
@@ -173,10 +171,15 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
{ {
return; return;
} }
if( inv == this.config && ( !removed.isEmpty() || !added.isEmpty() ) )
if( inv == this.config )
{ {
boolean cfg = hasConfig();
this.readConfig(); this.readConfig();
if( cfg != hasConfig )
{
resetConfigCache = true;
this.notifyNeighbors();
}
} }
else if( inv == this.patterns && ( !removed.isEmpty() || !added.isEmpty() ) ) else if( inv == this.patterns && ( !removed.isEmpty() || !added.isEmpty() ) )
{ {
@@ -235,12 +238,12 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
NBTTagCompound sidedWaitList = new NBTTagCompound(); NBTTagCompound sidedWaitList = new NBTTagCompound();
if (this.waitingToSendFacing != null) if( this.waitingToSendFacing != null )
{ {
for( EnumFacing s : this.iHost.getTargets() ) for( EnumFacing s : this.iHost.getTargets() )
{ {
NBTTagList waitingListSided = new NBTTagList(); NBTTagList waitingListSided = new NBTTagList();
if (this.waitingToSendFacing.containsKey( s )) if( this.waitingToSendFacing.containsKey( s ) )
{ {
for( final ItemStack is : this.waitingToSendFacing.get( s ) ) for( final ItemStack is : this.waitingToSendFacing.get( s ) )
{ {
@@ -273,10 +276,12 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
} }
this.waitingToSendFacing = null; this.waitingToSendFacing = null;
final NBTTagCompound waitingListSided = data.getCompoundTag("sidedWaitList"); final NBTTagCompound waitingListSided = data.getCompoundTag( "sidedWaitList" );
for (EnumFacing s : EnumFacing.values()) for( EnumFacing s : EnumFacing.values() )
if (waitingListSided.hasKey( s.name() )) { {
if( waitingListSided.hasKey( s.name() ) )
{
NBTTagList w = waitingListSided.getTagList( s.name(), 10 ); NBTTagList w = waitingListSided.getTagList( s.name(), 10 );
for( int x = 0; x < w.tagCount(); x++ ) for( int x = 0; x < w.tagCount(); x++ )
{ {
@@ -284,14 +289,32 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
if( c != null ) if( c != null )
{ {
final ItemStack is = new ItemStack( c ); final ItemStack is = new ItemStack( c );
this.addToSendListFacing( is , EnumFacing.getFront( s.getIndex() ) ); this.addToSendListFacing( is, EnumFacing.getFront( s.getIndex() ) );
} }
} }
} }
}
this.craftingTracker.readFromNBT( data ); 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.upgrades.readFromNBT( data, "upgrades" );
this.config.readFromNBT( data, "config" ); 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.patterns.readFromNBT( data, "patterns" );
this.storage.readFromNBT( data, "storage" ); this.storage.readFromNBT( data, "storage" );
this.priority = data.getInteger( "priority" ); this.priority = data.getInteger( "priority" );
@@ -330,8 +353,9 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
{ {
return; return;
} }
if (this.waitingToSendFacing == null){ if( this.waitingToSendFacing == null )
this.waitingToSendFacing = new EnumMap<>(EnumFacing.class); {
this.waitingToSendFacing = new EnumMap<>( EnumFacing.class );
} }
this.waitingToSendFacing.computeIfAbsent( f, k -> new ArrayList<>() ); this.waitingToSendFacing.computeIfAbsent( f, k -> new ArrayList<>() );
@@ -388,25 +412,25 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
// :P // :P
} }
} }
this.notifyNeighbors(); this.notifyNeighbors();
} }
private void updateCraftingList() private void updateCraftingList()
{ {
final Boolean[] accountedFor = { false, false, false, false, false, false, false, false, false }; // 9... final Boolean[] accountedFor = new Boolean[this.patterns.getSlots()];
Arrays.fill( accountedFor, false );
assert ( accountedFor.length == this.patterns.getSlots() );
if( !this.gridProxy.isReady() ) if( !this.gridProxy.isReady() )
{ {
return; return;
} }
boolean removed = false;
if( this.craftingList != null ) if( this.craftingList != null )
{ {
final Iterator<ICraftingPatternDetails> i = this.craftingList.iterator(); final Iterator<ICraftingPatternDetails> i = this.craftingList.iterator();
while( i.hasNext() ) while ( i.hasNext() )
{ {
final ICraftingPatternDetails details = i.next(); final ICraftingPatternDetails details = i.next();
boolean found = false; boolean found = false;
@@ -422,41 +446,49 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
if( !found ) if( !found )
{ {
removed = true;
i.remove(); i.remove();
} }
} }
} }
boolean newPattern = false;
for( int x = 0; x < accountedFor.length; x++ ) for( int x = 0; x < accountedFor.length; x++ )
{ {
if( !accountedFor[x] ) if( !accountedFor[x] )
{ {
newPattern = true;
this.addToCraftingList( this.patterns.getStackInSlot( x ) ); this.addToCraftingList( this.patterns.getStackInSlot( x ) );
} }
} }
try try
{ {
this.gridProxy.getGrid().postEvent( new MENetworkCraftingPatternChange( this, this.gridProxy.getNode() ) ); this.gridProxy.getGrid().postEvent( new MENetworkCraftingPatternChange( this, this.gridProxy.getNode() ) );
} }
catch( final GridAccessException e ) catch( GridAccessException e )
{ {
// :P e.printStackTrace();
} }
} }
private boolean hasWorkToDo() { private boolean hasWorkToDo()
{
if (hasItemsToSend()){ if( hasItemsToSend() )
{
return true; return true;
} }
if(hasItemsToSendFacing()){ if( hasItemsToSendFacing() )
{
return true; return true;
} }
for (final IAEItemStack requiredWork : this.requireWork) { for( final IAEItemStack requiredWork : this.requireWork )
if (requiredWork != null) { {
if( requiredWork != null )
{
return true; return true;
} }
} }
@@ -567,7 +599,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
private boolean hasItemsToSendFacing() private boolean hasItemsToSendFacing()
{ {
if (waitingToSendFacing != null) if( waitingToSendFacing != null )
{ {
for( EnumFacing enumFacing : waitingToSendFacing.keySet() ) for( EnumFacing enumFacing : waitingToSendFacing.keySet() )
{ {
@@ -580,11 +612,37 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
return false; 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 @Override
public boolean canInsert( final ItemStack stack ) public boolean canInsert( final ItemStack stack )
{ {
final IAEItemStack out = this.destination.injectItems( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createStack( stack ), final IAEItemStack out = this.destination.injectItems( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createStack( stack ), Actionable.SIMULATE, null );
Actionable.SIMULATE, null );
if( out == null ) if( out == null )
{ {
return true; return true;
@@ -658,7 +716,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
this.pushItemsOut( this.iHost.getTargets() ); this.pushItemsOut( this.iHost.getTargets() );
} }
if (hasItemsToSendFacing()) if( hasItemsToSendFacing() )
{ {
for( EnumFacing enumFacing : waitingToSendFacing.keySet() ) for( EnumFacing enumFacing : waitingToSendFacing.keySet() )
{ {
@@ -681,7 +739,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
final World w = tile.getWorld(); final World w = tile.getWorld();
final Iterator<ItemStack> i = this.waitingToSend.iterator(); final Iterator<ItemStack> i = this.waitingToSend.iterator();
while( i.hasNext() ) while ( i.hasNext() )
{ {
ItemStack whatToSend = i.next(); ItemStack whatToSend = i.next();
@@ -728,8 +786,8 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
private void pushItemsOut( final EnumFacing s ) private void pushItemsOut( final EnumFacing s )
{ {
if (!this.waitingToSendFacing.containsKey(s) || if( !this.waitingToSendFacing.containsKey( s ) || ( this.waitingToSendFacing.containsKey( s ) && this.waitingToSendFacing.get( s ).isEmpty() ) )
(this.waitingToSendFacing.containsKey(s) && this.waitingToSendFacing.get( s ).isEmpty())) { {
return; return;
} }
@@ -742,17 +800,18 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
return; return;
} }
final InventoryAdaptor ad = InventoryAdaptor.getAdaptor( te, s.getOpposite() );
final Iterator<ItemStack> i = this.waitingToSendFacing.get( s ).iterator(); final Iterator<ItemStack> i = this.waitingToSendFacing.get( s ).iterator();
while ( i.hasNext() ) while ( i.hasNext() )
{ {
ItemStack whatToSend = i.next(); ItemStack whatToSend = i.next();
final InventoryAdaptor ad = InventoryAdaptor.getAdaptor( te, s.getOpposite() );
if( ad != null ) if( ad != null )
{ {
final ItemStack result = ad.addItems( whatToSend ); final ItemStack result = ad.addItems( whatToSend );
if( !result.isEmpty() ) if( !result.isEmpty() )
{ {
whatToSend.setCount( whatToSend.getCount() - ( whatToSend.getCount() - result.getCount() ) ); whatToSend.setCount( result.getCount() );
} }
else else
{ {
@@ -793,35 +852,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
this.destination = this.gridProxy.getStorage().getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ); this.destination = this.gridProxy.getStorage().getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) );
final IEnergySource src = this.gridProxy.getEnergy(); final IEnergySource src = this.gridProxy.getEnergy();
if( this.craftingTracker.isBusy( x ) ) if( itemStack.getStackSize() < 0 )
{
changed = this.handleCrafting( x, adaptor, itemStack ) || changed;
}
else if( itemStack.getStackSize() > 0 )
{
// make sure strange things didn't happen...
if( !adaptor.simulateAdd( itemStack.createItemStack() ).isEmpty() )
{
changed = true;
throw new GridAccessException();
}
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
{
changed = this.handleCrafting( x, adaptor, itemStack ) || changed;
}
}
else if( itemStack.getStackSize() < 0 )
{ {
IAEItemStack toStore = itemStack.copy(); IAEItemStack toStore = itemStack.copy();
toStore.setStackSize( -toStore.getStackSize() ); toStore.setStackSize( -toStore.getStackSize() );
@@ -859,6 +890,51 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
} }
} }
} }
if( this.craftingTracker.isBusy( x ) )
{
changed = this.handleCrafting( x, adaptor, itemStack ) || changed;
}
else if( itemStack.getStackSize() > 0 )
{
// make sure strange things didn't happen...
ItemStack inputStack = itemStack.getCachedItemStack( itemStack.getStackSize() );
ItemStack remaining = adaptor.simulateAdd( inputStack );
if( !remaining.isEmpty() )
{
itemStack.setCachedItemStack( remaining );
changed = true;
throw new GridAccessException();
}
IAEItemStack storedStack = this.gridProxy.getStorage().getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ).getStorageList().findPrecise( itemStack );
if( storedStack != null )
{
final IAEItemStack acquired = Platform.poweredExtraction( src, this.destination, itemStack, this.interfaceRequestSource );
if( acquired != null )
{
changed = true;
inputStack.setCount( Ints.saturatedCast( acquired.getStackSize() ) );
final ItemStack issue = adaptor.addItems( inputStack );
if( !issue.isEmpty() )
{
throw new IllegalStateException( "bad attempt at managing inventory. ( addItems )" );
}
}
else if( storedStack.isCraftable() )
{
itemStack.setCachedItemStack( inputStack );
changed = this.handleCrafting( x, adaptor, itemStack ) || changed;
}
if( acquired == null )
{
itemStack.setCachedItemStack( inputStack );
}
}
}
// else wtf? // else wtf?
} }
catch( final GridAccessException e ) catch( final GridAccessException e )
@@ -886,8 +962,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
{ {
if( this.getInstalledUpgrades( Upgrades.CRAFTING ) > 0 && itemStack != null ) if( this.getInstalledUpgrades( Upgrades.CRAFTING ) > 0 && itemStack != null )
{ {
return this.craftingTracker.handleCrafting( x, itemStack.getStackSize(), itemStack, d, this.iHost.getTileEntity().getWorld(), return this.craftingTracker.handleCrafting( x, itemStack.getStackSize(), itemStack, d, this.iHost.getTileEntity().getWorld(), this.gridProxy.getGrid(), this.gridProxy.getCrafting(), this.mySource );
this.gridProxy.getGrid(), this.gridProxy.getCrafting(), this.mySource );
} }
} }
catch( final GridAccessException e ) catch( final GridAccessException e )
@@ -921,7 +996,12 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
{ {
if( this.hasConfig() ) 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; return (IMEMonitor<T>) this.items;
@@ -1022,12 +1102,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
private boolean invIsBlocked( InventoryAdaptor inv ) private boolean invIsBlocked( InventoryAdaptor inv )
{ {
return (inv.containsItems()); return ( inv.containsItems() );
}
private static boolean invIsBlockedGTCE( GTCEInventoryAdaptor inv )
{
return ( !inv.canRemoveAllExceptCircuits() );
} }
@Override @Override
@@ -1079,29 +1154,44 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
} }
} }
final InventoryAdaptor ad = InventoryAdaptor.getAdaptor( te, s.getOpposite() ); InventoryAdaptor ad = InventoryAdaptor.getAdaptor( te, s.getOpposite() );
if( ad != null ) if( ad != null )
{ {
boolean isDrawer = te.getBlockType().getRegistryName().getResourceDomain().equals( "storagedrawers" );
if( this.isBlocking() ) if( this.isBlocking() )
{ {
if( te.getBlockType().getRegistryName().getResourceDomain().equals( "gregtech" ) ) IPhantomTile phantomTE;
if( Loader.isModLoaded( "actuallyadditions" ) && te instanceof IPhantomTile )
{ {
GTad = GTCEInventoryAdaptor.getAdaptor( te, s.getOpposite() ); phantomTE = ( (IPhantomTile) te );
if( invIsBlockedGTCE( GTad ) ) if( phantomTE.hasBoundPosition() )
{
TileEntity phantom = w.getTileEntity( phantomTE.getBoundPosition() );
if( NonBlockingItems.INSTANCE.getMap().containsKey( w.getBlockState( phantomTE.getBoundPosition() ).getBlock().getRegistryName().getResourceDomain() ) )
{
if( isCustomInvBlocking( phantom, s ) )
{
visitedFaces.remove( s );
continue;
}
}
}
}
else if( NonBlockingItems.INSTANCE.getMap().containsKey( w.getBlockState( tile.getPos().offset( s ) ).getBlock().getRegistryName().getResourceDomain() ) )
{
if( isCustomInvBlocking( te, s ) )
{ {
visitedFaces.remove( s ); visitedFaces.remove( s );
continue; continue;
} }
} }
else if ( invIsBlocked( ad ) ) else if( invIsBlocked( ad ) )
{ {
visitedFaces.remove( s ); visitedFaces.remove( s );
continue; continue;
} }
} }
if( this.acceptsItems( ad, patternDetails, isDrawer ) ) if( this.acceptsItems( ad, table ) )
{ {
visitedFaces.remove( s ); visitedFaces.remove( s );
for( int x = 0; x < table.getSizeInventory(); x++ ) for( int x = 0; x < table.getSizeInventory(); x++ )
@@ -1142,23 +1232,42 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
for( final EnumFacing s : possibleDirections ) for( final EnumFacing s : possibleDirections )
{ {
final TileEntity te = w.getTileEntity( tile.getPos().offset( s ) ); final TileEntity te = w.getTileEntity( tile.getPos().offset( s ) );
IPhantomTile phantomTE;
final InventoryAdaptor ad = InventoryAdaptor.getAdaptor( te, s.getOpposite() ); final InventoryAdaptor ad = InventoryAdaptor.getAdaptor( te, s.getOpposite() );
if( ad != null ) if( ad != null )
{ {
if( te.getBlockType().getRegistryName().getResourceDomain().equals( "gregtech" ) ) if( Loader.isModLoaded( "actuallyadditions" ) && Loader.isModLoaded( "gregtech" ) && te instanceof IPhantomTile )
{ {
GTad = GTCEInventoryAdaptor.getAdaptor( te, s.getOpposite() ); phantomTE = ( (IPhantomTile) te );
if( !invIsBlockedGTCE( GTad ) ) if( phantomTE.hasBoundPosition() )
{
TileEntity phantom = w.getTileEntity( phantomTE.getBoundPosition() );
if( NonBlockingItems.INSTANCE.getMap().containsKey( w.getBlockState( phantomTE.getBoundPosition() ).getBlock().getRegistryName().getResourceDomain() ) )
{
if( !isCustomInvBlocking( phantom, s ) )
{
allAreBusy = false;
break;
}
}
}
}
else if( NonBlockingItems.INSTANCE.getMap().containsKey( w.getBlockState( tile.getPos().offset( s ) ).getBlock().getRegistryName().getResourceDomain() ) )
{
if( !isCustomInvBlocking( te, s ) )
{ {
allAreBusy = false; allAreBusy = false;
break; break;
} }
} }
else if( !invIsBlocked( ad ) ) else
{ {
allAreBusy = false; if( !invIsBlocked( ad ) )
break; {
allAreBusy = false;
break;
}
} }
} }
} }
@@ -1167,6 +1276,12 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
return busy; return busy;
} }
boolean isCustomInvBlocking( TileEntity te, EnumFacing s )
{
BlockingInventoryAdaptor blockingInventoryAdaptor = BlockingInventoryAdaptor.getAdaptor( te, s.getOpposite() );
return invIsCustomBlocking( blockingInventoryAdaptor );
}
private boolean sameGrid( final IGrid grid ) throws GridAccessException private boolean sameGrid( final IGrid grid ) throws GridAccessException
{ {
return grid == this.gridProxy.getGrid(); return grid == this.gridProxy.getGrid();
@@ -1177,75 +1292,23 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
return this.cm.getSetting( Settings.BLOCK ) == YesNo.YES; return this.cm.getSetting( Settings.BLOCK ) == YesNo.YES;
} }
private boolean acceptsItems( final InventoryAdaptor ad, final ICraftingPatternDetails patternDetails, boolean isDrawer ) private boolean acceptsItems( final InventoryAdaptor ad, final InventoryCrafting table )
{ {
List<ItemStack> patternedStacks = Arrays.stream( patternDetails.getCondensedInputs() ).map( IAEItemStack::createItemStack ).collect( Collectors.toList() ); for( int x = 0; x < table.getSizeInventory(); x++ )
List<ItemSlot> copiedItemSlots = new ArrayList<>();
if( patternedStacks.size() == 1 )
{ {
return ad.simulateAdd( patternedStacks.get( 0 ) ).isEmpty(); final ItemStack is = table.getStackInSlot( x );
} if( is.isEmpty() )
else
{
for ( ItemSlot itemSlot : ad )
{ {
//skip storage drawers slot 0 to avoid voiding items due to broken itemhandler implementation continue;
if( isDrawer && itemSlot.getSlot() == 0 ){
continue;
}
//some inventory may expose their special slots ( for upgrades, etc )
//if its empty AND we cant fit any of the items in the recipes, skip it.
ItemStack stackInSlot = itemSlot.getItemStack();
for ( IAEItemStack aeItemStack : patternDetails.getCondensedInputs() )
{
if( stackInSlot.isEmpty() )
{
if( itemSlot.simulateInsertItem( aeItemStack.getDefinition() ).isEmpty() )
{
copiedItemSlots.add( itemSlot.copy() );
break;
}
}
// copy partially filled slots for merging logic
else if( stackInSlot.getCount() < Math.min( itemSlot.getSlotLimit(), stackInSlot.getMaxStackSize() ) )
{
if( aeItemStack.isSameType( stackInSlot ) )
{
copiedItemSlots.add( itemSlot.copy() );
break;
}
}
}
} }
// start merging in order of slots, left to right. if( !ad.simulateAdd( is ).isEmpty() )
for ( ItemSlot copiedItemSlot : copiedItemSlots )
{ {
Iterator<ItemStack> patStackIterator = patternedStacks.iterator(); return false;
while ( patStackIterator.hasNext() )
{
ItemStack patStack = patStackIterator.next();
ItemStack remainder = copiedItemSlot.simulateInsertItem( patStack );
if( !remainder.isEmpty() )
{
patStack.setCount( patStack.getCount() - ( patStack.getCount() - remainder.getCount() ) );
}
else //entire stack got injected
{
patStackIterator.remove();
break;
}
}
// if we merged EVERYTHING successfully , return true.
if( patternedStacks.size() == 0 )
{
return true;
}
} }
return false;
} }
return true;
} }
@Override @Override
@@ -1276,13 +1339,13 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
if( this.waitingToSendFacing != null ) if( this.waitingToSendFacing != null )
{ {
for (List<ItemStack> itemList : waitingToSendFacing.values()) for( List<ItemStack> itemList : waitingToSendFacing.values() )
{ {
for (final ItemStack is : itemList) for( final ItemStack is : itemList )
{ {
if (!is.isEmpty()) if( !is.isEmpty() )
{ {
drops.add(is); drops.add( is );
} }
} }
} }
@@ -1412,9 +1475,9 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
final Block directedBlock = directedBlockState.getBlock(); final Block directedBlock = directedBlockState.getBlock();
ItemStack what = new ItemStack( directedBlock, 1, directedBlock.getMetaFromState( directedBlockState ) ); ItemStack what = new ItemStack( directedBlock, 1, directedBlock.getMetaFromState( directedBlockState ) );
if ( Loader.isModLoaded("gregtech") && directedBlock instanceof BlockMachine ) if( Loader.isModLoaded( "gregtech" ) && directedBlock instanceof BlockMachine )
{ {
MetaTileEntity metaTileEntity = getMetaTileEntity(hostWorld, targ); MetaTileEntity metaTileEntity = getMetaTileEntity( hostWorld, targ );
return metaTileEntity.getMetaFullName(); return metaTileEntity.getMetaFullName();
} }
@@ -1530,6 +1593,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
} }
private class InterfaceRequestContext implements Comparable<Integer> private class InterfaceRequestContext implements Comparable<Integer>
{ {
@@ -1540,13 +1604,13 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
} }
} }
private class InterfaceInventory extends MEMonitorIInventory private class InterfaceInventory extends MEMonitorIInventory
{ {
public InterfaceInventory( final DualityInterface tileInterface ) public InterfaceInventory( final DualityInterface tileInterface )
{ {
super( new AdaptorItemHandler( tileInterface.storage ) ); super( new AdaptorItemHandler( tileInterface.storage ) );
this.setActionSource( new MachineSource( DualityInterface.this.iHost ) );
} }
@Override @Override
@@ -1578,6 +1642,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
} }
} }
private class Accessor implements IStorageMonitorableAccessor private class Accessor implements IStorageMonitorableAccessor
{ {
@@ -62,6 +62,7 @@ public class HighlighterHandler
tessellator.draw(); tessellator.draw();
GlStateManager.enableTexture2D(); GlStateManager.enableTexture2D();
GlStateManager.enableDepth();
GlStateManager.popMatrix(); GlStateManager.popMatrix();
} }
@@ -24,6 +24,7 @@ import java.util.concurrent.Future;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World; import net.minecraft.world.World;
@@ -83,57 +84,70 @@ public class MultiCraftingTracker
public boolean handleCrafting( final int x, final long itemToCraft, final IAEItemStack ais, final InventoryAdaptor d, final World w, final IGrid g, final ICraftingGrid cg, final IActionSource mySrc ) public boolean handleCrafting( final int x, final long itemToCraft, final IAEItemStack ais, final InventoryAdaptor d, final World w, final IGrid g, final ICraftingGrid cg, final IActionSource mySrc )
{ {
if( ais != null && d.simulateAdd( ais.createItemStack() ).isEmpty() ) if( ais != null )
{ {
final Future<ICraftingJob> craftingJob = this.getJob( x ); ItemStack inputStack = ais.getCachedItemStack( ais.getStackSize() );
if( this.getLink( x ) != null ) ItemStack remaining = d.simulateAdd( inputStack );
{
return false;
}
else if( craftingJob != null )
{
try if( remaining.isEmpty() )
{
ais.setCachedItemStack( inputStack );
final Future<ICraftingJob> craftingJob = this.getJob( x );
if( this.getLink( x ) != null )
{ {
ICraftingJob job = null; return false;
if( craftingJob.isDone() ) }
else if( craftingJob != null )
{
try
{ {
job = craftingJob.get(); ICraftingJob job = null;
} if( craftingJob.isDone() )
if( job != null )
{
final ICraftingLink link = cg.submitJob( job, this.owner, null, false, mySrc );
this.setJob( x, null );
if( link != null )
{ {
this.setLink( x, link ); job = craftingJob.get();
}
return true; if( job != null )
{
final ICraftingLink link = cg.submitJob( job, this.owner, null, false, mySrc );
this.setJob( x, null );
if( link != null )
{
this.setLink( x, link );
return true;
}
} }
} }
catch( final InterruptedException e )
{
// :P
}
catch( final ExecutionException e )
{
// :P
}
} }
catch( final InterruptedException e ) else
{ {
// :P if( this.getLink( x ) == null )
} {
catch( final ExecutionException e ) final IAEItemStack aisC = ais.copy();
{ aisC.setStackSize( itemToCraft );
// :P
this.setJob( x, cg.beginCraftingJob( w, g, mySrc, aisC, null ) );
}
} }
} }
else else
{ {
if( this.getLink( x ) == null ) ais.setCachedItemStack( remaining );
{
final IAEItemStack aisC = ais.copy();
aisC.setStackSize( itemToCraft );
this.setJob( x, cg.beginCraftingJob( w, g, mySrc, aisC, null ) );
}
} }
} }
return false; return false;
@@ -0,0 +1,133 @@
package appeng.helpers;
import appeng.core.AEConfig;
import appeng.core.AELog;
import appeng.util.Platform;
import gregtech.api.items.metaitem.MetaItem;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.objects.*;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.oredict.OreDictionary;
import java.util.*;
public class NonBlockingItems
{
public static Map<String, Object2ObjectOpenHashMap<Item, IntSet>> NON_BLOCKING_MAP = new HashMap<>();
public static NonBlockingItems INSTANCE = new NonBlockingItems();
private NonBlockingItems()
{
String[] strings = AEConfig.instance().getNonBlockingItems();
String[] modids = new String[0];
if( strings.length > 0 )
{
for( String s : strings )
{
if( s.startsWith( "[" ) && s.endsWith( "]" ) )
{
modids = s.substring( 1, s.length() - 1 ).split( "\\|" );
}
else
{
for( String modid : modids )
{
if( !Loader.isModLoaded( modid ) )
{
continue;
}
NON_BLOCKING_MAP.putIfAbsent( modid, new Object2ObjectOpenHashMap<>() );
String[] ModItemMeta = s.split( ":" );
if( ModItemMeta.length < 2 || ModItemMeta.length > 3 )
{
AELog.error( "Invalid non blocking item entry: " + s );
continue;
}
if( ModItemMeta[0].equals( "gregtech" ) && Platform.isModLoaded( "gregtech" ) )
{
boolean found = false;
for( MetaItem<?> metaItem : MetaItem.getMetaItems() )
{
MetaItem<?>.MetaValueItem metaItem2 = metaItem.getItem( ModItemMeta[1] );
if( metaItem.getItem( ModItemMeta[1] ) != null )
{
found = true;
ItemStack itemStack = metaItem2.getStackForm();
NON_BLOCKING_MAP.get( modid ).putIfAbsent( itemStack.getItem(), new IntOpenHashSet() );
NON_BLOCKING_MAP.get( modid ).computeIfPresent( itemStack.getItem(), ( item, intSet ) ->
{
intSet.add( itemStack.getItemDamage() );
return intSet;
} );
}
else
{
ItemStack itemStack = GameRegistry.makeItemStack( ModItemMeta[0] + ":" + ModItemMeta[1], ModItemMeta.length == 3 ? Integer.parseInt( ModItemMeta[2] ) : 0, 1, null );
if( !itemStack.isEmpty() )
{
NON_BLOCKING_MAP.get( modid ).putIfAbsent( itemStack.getItem(), new IntOpenHashSet() );
NON_BLOCKING_MAP.get( modid ).computeIfPresent( itemStack.getItem(), ( item, intSet ) ->
{
intSet.add( itemStack.getItemDamage() );
return intSet;
} );
}
}
}
if( !found )
{
AELog.error( "Item not found on nonBlocking config: " + s );
}
}
else if( ModItemMeta[0].equals( "ore" ) )
{
OreDictionary.getOres( ModItemMeta[1] ).forEach( itemStack ->
{
NON_BLOCKING_MAP.get( modid ).putIfAbsent( itemStack.getItem(), new IntOpenHashSet() );
NON_BLOCKING_MAP.get( modid ).computeIfPresent( itemStack.getItem(), ( item, intSet ) ->
{
intSet.add( itemStack.getItemDamage() );
return intSet;
} );
} );
}
else
{
ItemStack itemStack = GameRegistry.makeItemStack( ModItemMeta[0] + ":" + ModItemMeta[1], ModItemMeta.length == 3 ? Integer.parseInt( ModItemMeta[2] ) : 0, 1, null );
if( !itemStack.isEmpty() )
{
NON_BLOCKING_MAP.get( modid ).putIfAbsent( itemStack.getItem(), new IntOpenHashSet() );
NON_BLOCKING_MAP.get( modid ).computeIfPresent( itemStack.getItem(), ( item, intSet ) ->
{
intSet.add( itemStack.getItemDamage() );
return intSet;
} );
}
else
{
AELog.error( "Item not found on nonBlocking config: " + s );
}
}
}
}
}
}
}
public Map<String, Object2ObjectOpenHashMap<Item, IntSet>> getMap()
{
return NON_BLOCKING_MAP;
}
public void init()
{
}
}
+145 -53
View File
@@ -19,21 +19,17 @@
package appeng.helpers; package appeng.helpers;
import java.util.ArrayList; import java.util.*;
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 net.minecraft.inventory.InventoryCrafting; import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager; import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.NonNullList;
import net.minecraft.world.World; import net.minecraft.world.World;
import appeng.api.AEApi; import appeng.api.AEApi;
@@ -41,25 +37,33 @@ import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.storage.channels.IItemStorageChannel; import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IAEItemStack;
import appeng.container.ContainerNull; import appeng.container.ContainerNull;
import appeng.core.AEConfig;
import appeng.core.AELog;
import appeng.core.features.AEFeature;
import appeng.util.Platform; import appeng.util.Platform;
import appeng.util.item.AEItemStack; import appeng.util.item.AEItemStack;
import net.minecraftforge.common.crafting.IShapedRecipe;
import net.minecraftforge.fml.common.Optional;
public class PatternHelper implements ICraftingPatternDetails, Comparable<PatternHelper> public class PatternHelper implements ICraftingPatternDetails, Comparable<PatternHelper>
{ {
private static final int CRAFTING_GRID_DIMENSION = 3;
private static final int CRAFTING_INPUT_LIMIT = CRAFTING_GRID_DIMENSION * CRAFTING_GRID_DIMENSION;
public static final int PROCESSING_INPUT_HEIGHT = 4;
public static final int PROCESSING_INPUT_WIDTH = 4;
public static final int PROCESSING_INPUT_LIMIT = PROCESSING_INPUT_HEIGHT * PROCESSING_INPUT_WIDTH;
private static final int CRAFTING_OUTPUT_LIMIT = 1;
public static final int PROCESSING_OUTPUT_LIMIT = 6;
private final ItemStack patternItem; private final ItemStack patternItem;
private final InventoryCrafting crafting = new InventoryCrafting( new ContainerNull(), 3, 3 ); private final InventoryCrafting crafting;
private final InventoryCrafting testFrame = new InventoryCrafting( new ContainerNull(), 3, 3 ); private final InventoryCrafting testFrame;
private final ItemStack correctOutput; private final ItemStack correctOutput;
private final IRecipe standardRecipe; private final IRecipe standardRecipe;
private final IAEItemStack[] condensedInputs; private final IAEItemStack[] condensedInputs;
private final IAEItemStack[] condensedOutputs; private final IAEItemStack[] condensedOutputs;
private final IAEItemStack[] inputs; private final IAEItemStack[] inputs;
private final IAEItemStack[] outputs; private final IAEItemStack[] outputs;
private final Map<Integer, List<IAEItemStack>> substituteInputs;
private final boolean isCrafting; private final boolean isCrafting;
private final boolean canSubstitute; private final boolean canSubstitute;
private final Set<TestLookup> failCache = new HashSet<>(); private final Set<TestLookup> failCache = new HashSet<>();
@@ -80,6 +84,9 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
final NBTTagList outTag = encodedValue.getTagList( "out", 10 ); final NBTTagList outTag = encodedValue.getTagList( "out", 10 );
this.isCrafting = encodedValue.getBoolean( "crafting" ); this.isCrafting = encodedValue.getBoolean( "crafting" );
crafting = new InventoryCrafting( new ContainerNull(), isCrafting ? 3 : 4, isCrafting ? 3 : 4 );
testFrame = new InventoryCrafting( new ContainerNull(), isCrafting ? 3 : 4, isCrafting ? 3 : 4 );
this.canSubstitute = this.isCrafting && encodedValue.getBoolean( "substitute" ); this.canSubstitute = this.isCrafting && encodedValue.getBoolean( "substitute" );
this.patternItem = is; this.patternItem = is;
this.pattern = AEItemStack.fromItemStack( is ); this.pattern = AEItemStack.fromItemStack( is );
@@ -143,9 +150,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[isCrafting ? CRAFTING_INPUT_LIMIT : PROCESSING_INPUT_LIMIT] );
this.inputs = in.toArray( new IAEItemStack[in.size()] ); this.outputs = out.toArray( new IAEItemStack[outputLength] );
this.substituteInputs = new HashMap<>( CRAFTING_INPUT_LIMIT );
final Map<IAEItemStack, IAEItemStack> tmpOutputs = new HashMap<>(); final Map<IAEItemStack, IAEItemStack> tmpOutputs = new HashMap<>();
@@ -239,7 +248,7 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
final TestStatus result = this.getStatus( slotIndex, i ); final TestStatus result = this.getStatus( slotIndex, i );
switch( result ) switch ( result )
{ {
case ACCEPT: case ACCEPT:
return true; return true;
@@ -257,6 +266,16 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
this.testFrame.setInventorySlotContents( slotIndex, i ); this.testFrame.setInventorySlotContents( slotIndex, i );
// If we cannot substitute, the items must match exactly
if( ( !( i.getItem().isDamageable() || Platform.isGTDamageableItem( i.getItem() ) ) && !canSubstitute ) && slotIndex < inputs.length )
{
if( !inputs[slotIndex].isSameType( i ) )
{
this.markItemAs( slotIndex, i, TestStatus.DECLINE );
return false;
}
}
if( this.standardRecipe.matches( this.testFrame, w ) ) if( this.standardRecipe.matches( this.testFrame, w ) )
{ {
final ItemStack testOutput = this.standardRecipe.getCraftingResult( this.testFrame ); final ItemStack testOutput = this.standardRecipe.getCraftingResult( this.testFrame );
@@ -268,25 +287,6 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
return true; 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 ); this.markItemAs( slotIndex, i, TestStatus.DECLINE );
return false; return false;
@@ -328,6 +328,114 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
return this.canSubstitute; 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 @Override
public ItemStack getOutput( final InventoryCrafting craftingInv, final World w ) public ItemStack getOutput( final InventoryCrafting craftingInv, final World w )
{ {
@@ -406,24 +514,6 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
return this.pattern.hashCode(); 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 @Override
public boolean equals( final Object obj ) public boolean equals( final Object obj )
{ {
@@ -447,7 +537,9 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
private enum TestStatus private enum TestStatus
{ {
ACCEPT, DECLINE, TEST ACCEPT,
DECLINE,
TEST
} }
private static final class TestLookup private static final class TestLookup
+10 -18
View File
@@ -187,20 +187,16 @@ public class TickHandler
if( ev.type == Type.WORLD && ev.phase == Phase.END ) if( ev.type == Type.WORLD && ev.phase == Phase.END )
{ {
final WorldTickEvent wte = (WorldTickEvent) ev; final WorldTickEvent wte = (WorldTickEvent) ev;
synchronized( this.craftingJobs ) synchronized ( this.craftingJobs )
{ {
final Collection<CraftingJob> jobSet = this.craftingJobs.get( wte.world ); final Collection<CraftingJob> jobSet = this.craftingJobs.get( wte.world );
if( !jobSet.isEmpty() ) if( !jobSet.isEmpty() )
{ {
final Iterator<CraftingJob> i = jobSet.iterator(); final int jobSize = jobSet.size();
while( i.hasNext() ) final int microSecondsPerTick = AEConfig.instance().getCraftingCalculationTimePerTick() * 1000;
{ final int simTime = Math.max( 1, microSecondsPerTick / jobSize );
final CraftingJob cj = i.next();
if( !cj.simulateFor() ) jobSet.removeIf( cj -> !cj.simulateFor( simTime ) );
{
i.remove();
}
}
} }
} }
} }
@@ -211,7 +207,7 @@ public class TickHandler
this.tickColors( this.srvPlayerColors ); this.tickColors( this.srvPlayerColors );
// ready tiles. // ready tiles.
final HandlerRep repo = this.getRepo(); final HandlerRep repo = this.getRepo();
while( !repo.tiles.isEmpty() ) while ( !repo.tiles.isEmpty() )
{ {
final AEBaseTile bt = repo.tiles.poll(); final AEBaseTile bt = repo.tiles.poll();
if( !bt.isInvalid() ) if( !bt.isInvalid() )
@@ -243,7 +239,7 @@ public class TickHandler
private void tickColors( final HashMap<Integer, PlayerColor> playerSet ) private void tickColors( final HashMap<Integer, PlayerColor> playerSet )
{ {
final Iterator<PlayerColor> i = playerSet.values().iterator(); final Iterator<PlayerColor> i = playerSet.values().iterator();
while( i.hasNext() ) while ( i.hasNext() )
{ {
final PlayerColor pc = i.next(); final PlayerColor pc = i.next();
if( pc.ticksLeft <= 0 ) if( pc.ticksLeft <= 0 )
@@ -264,7 +260,7 @@ public class TickHandler
final Stopwatch sw = Stopwatch.createStarted(); final Stopwatch sw = Stopwatch.createStarted();
IWorldCallable<?> c = null; IWorldCallable<?> c = null;
while( ( c = queue.poll() ) != null ) while ( ( c = queue.poll() ) != null )
{ {
try try
{ {
@@ -280,15 +276,11 @@ public class TickHandler
AELog.debug( e ); AELog.debug( e );
} }
} }
// long time = sw.elapsed( TimeUnit.MILLISECONDS );
// if ( time > 0 )
// AELog.info( "processQueue Time: " + time + "ms" );
} }
public void registerCraftingSimulation( final World world, final CraftingJob craftingJob ) public void registerCraftingSimulation( final World world, final CraftingJob craftingJob )
{ {
synchronized( this.craftingJobs ) synchronized ( this.craftingJobs )
{ {
this.craftingJobs.put( world, craftingJob ); this.craftingJobs.put( world, craftingJob );
} }
@@ -30,35 +30,37 @@ import appeng.integration.modules.waila.WailaModule;
public enum IntegrationType public enum IntegrationType
{ {
IC2( IntegrationSide.BOTH, "Industrial Craft 2", "ic2" ) IC2( IntegrationSide.BOTH, "Industrial Craft 2", "ic2" )
{ {
@Override @Override
public IIntegrationModule createInstance() public IIntegrationModule createInstance()
{ {
return Integrations.setIc2( new IC2Module() ); return Integrations.setIc2( new IC2Module() );
} }
}, },
GTCE( IntegrationSide.BOTH, "GregTech", "gregtech" ),
RC( IntegrationSide.BOTH, "Railcraft", "railcraft" ), RC( IntegrationSide.BOTH, "Railcraft", "railcraft" ),
MFR( IntegrationSide.BOTH, "Mine Factory Reloaded", "minefactoryreloaded" ), MFR( IntegrationSide.BOTH, "Mine Factory Reloaded", "minefactoryreloaded" ),
Waila( IntegrationSide.BOTH, "Waila", "waila" ) Waila( IntegrationSide.BOTH, "Waila", "waila" )
{ {
@Override @Override
public IIntegrationModule createInstance() public IIntegrationModule createInstance()
{ {
return new WailaModule(); return new WailaModule();
} }
}, },
InvTweaks( IntegrationSide.CLIENT, "Inventory Tweaks", "inventorytweaks" ) InvTweaks( IntegrationSide.CLIENT, "Inventory Tweaks", "inventorytweaks" )
{ {
@Override @Override
public IIntegrationModule createInstance() public IIntegrationModule createInstance()
{ {
return Integrations.setInvTweaks( new InventoryTweaksModule() ); return Integrations.setInvTweaks( new InventoryTweaksModule() );
} }
}, },
JEI( IntegrationSide.CLIENT, "Just Enough Items", "jei" ) JEI( IntegrationSide.CLIENT, "Just Enough Items", "jei" )
{ {
@@ -1,26 +0,0 @@
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();
}
@@ -1,58 +0,0 @@
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 );
}
}
@@ -26,6 +26,7 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import appeng.client.gui.AEGuiHandler; import appeng.client.gui.AEGuiHandler;
import appeng.container.implementations.ContainerExpandedProcessingPatternTerm;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
@@ -90,16 +91,13 @@ public class JEIPlugin implements IModPlugin
this.registerDescriptions( definitions, registry ); this.registerDescriptions( definitions, registry );
// Allow recipe transfer from JEI to crafting and pattern terminal // Allow recipe transfer from JEI to crafting and pattern terminal
registry.getRecipeTransferRegistry() registry.getRecipeTransferRegistry().addRecipeTransferHandler( new RecipeTransferHandler<>( ContainerCraftingTerm.class ), VanillaRecipeCategoryUid.CRAFTING );
.addRecipeTransferHandler( new RecipeTransferHandler<>( ContainerCraftingTerm.class ), registry.getRecipeTransferRegistry().addRecipeTransferHandler( new RecipeTransferHandler<>( ContainerPatternTerm.class ), Constants.UNIVERSAL_RECIPE_TRANSFER_UID );
VanillaRecipeCategoryUid.CRAFTING ); registry.getRecipeTransferRegistry().addRecipeTransferHandler( new RecipeTransferHandler<>( ContainerExpandedProcessingPatternTerm.class ), Constants.UNIVERSAL_RECIPE_TRANSFER_UID );
registry.getRecipeTransferRegistry()
.addRecipeTransferHandler( new RecipeTransferHandler<>( ContainerPatternTerm.class ),
Constants.UNIVERSAL_RECIPE_TRANSFER_UID );
aeGuiHandler = new AEGuiHandler(); aeGuiHandler = new AEGuiHandler();
registry.addAdvancedGuiHandlers(aeGuiHandler); registry.addAdvancedGuiHandlers( aeGuiHandler );
registry.addGhostIngredientHandler( aeGuiHandler.getGuiContainerClass(), aeGuiHandler); registry.addGhostIngredientHandler( aeGuiHandler.getGuiContainerClass(), aeGuiHandler );
} }
private void registerDescriptions( IDefinitions definitions, IModRegistry registry ) private void registerDescriptions( IDefinitions definitions, IModRegistry registry )
@@ -27,6 +27,7 @@ import java.util.Map;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import appeng.container.implementations.ContainerPatternTerm; import appeng.container.implementations.ContainerPatternTerm;
import appeng.core.sync.packets.PacketValueConfig;
import mezz.jei.api.recipe.VanillaRecipeCategoryUid; import mezz.jei.api.recipe.VanillaRecipeCategoryUid;
import mezz.jei.transfer.RecipeTransferErrorInternal; import mezz.jei.transfer.RecipeTransferErrorInternal;
import mezz.jei.transfer.RecipeTransferErrorTooltip; import mezz.jei.transfer.RecipeTransferErrorTooltip;
@@ -73,24 +74,7 @@ class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandl
{ {
final String recipeType = recipeLayout.getRecipeCategory().getUid(); final String recipeType = recipeLayout.getRecipeCategory().getUid();
if (!recipeType.equals( VanillaRecipeCategoryUid.INFORMATION) && !recipeType.equals(VanillaRecipeCategoryUid.FUEL)) if (recipeType.equals( VanillaRecipeCategoryUid.INFORMATION) || recipeType.equals(VanillaRecipeCategoryUid.FUEL))
{
if( container instanceof ContainerPatternTerm )
{
if( !( (ContainerPatternTerm) container ).isCraftingMode() )
{
if( recipeType.equals( VanillaRecipeCategoryUid.CRAFTING ) )
{
return new RecipeTransferErrorTooltip( I18n.format( "gui.appliedenergistics2.CraftingPattern" ) );
}
}
else if( !recipeType.equals( VanillaRecipeCategoryUid.CRAFTING ) )
{
return new RecipeTransferErrorTooltip( I18n.format( "gui.appliedenergistics2.ProcessingPattern" ) );
}
}
}
else
{ {
return RecipeTransferErrorInternal.INSTANCE; return RecipeTransferErrorInternal.INSTANCE;
} }
@@ -100,6 +84,30 @@ class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandl
return null; 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(); Map<Integer, ? extends IGuiIngredient<ItemStack>> ingredients = recipeLayout.getItemStacks().getGuiIngredients();
final NBTTagCompound recipe = new NBTTagCompound(); final NBTTagCompound recipe = new NBTTagCompound();
@@ -139,8 +147,12 @@ class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandl
} }
// prefer pure crystals. // prefer pure crystals.
for( ItemStack stack : ingredient.getAllIngredients() ) for ( ItemStack stack : ingredient.getAllIngredients() )
{ {
if( stack == null )
{
continue;
}
if( Platform.isRecipePrioritized( stack ) ) if( Platform.isRecipePrioritized( stack ) )
{ {
list.add( 0, stack ); list.add( 0, stack );
@@ -151,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(); final NBTTagCompound tag = new NBTTagCompound();
is.writeToNBT( tag ); is.writeToNBT( tag );
@@ -35,6 +35,8 @@ public enum TheOneProbeText
P2P_UNLINKED, P2P_UNLINKED,
P2P_INPUT_ONE_OUTPUT, P2P_INPUT_ONE_OUTPUT,
P2P_INPUT_MANY_OUTPUTS, P2P_INPUT_MANY_OUTPUTS,
P2P_OUTPUT_ONE_INPUT,
P2P_OUTPUT_MANY_INPUTS,
P2P_OUTPUT, P2P_OUTPUT,
P2P_FREQUENCY, P2P_FREQUENCY,
@@ -57,11 +57,11 @@ public class P2PStateInfoProvider implements IPartProbInfoProvider
// The default state // The default state
int state = STATE_UNLINKED; int state = STATE_UNLINKED;
int outputCount = 0; int outputCount = getOutputCount( tunnel );
int inputCount = getInputCount( tunnel );
if( !tunnel.isOutput() ) if( !tunnel.isOutput() )
{ {
outputCount = getOutputCount( tunnel );
if( outputCount > 0 ) if( outputCount > 0 )
{ {
// Only set it to INPUT if we know there are any outputs // Only set it to INPUT if we know there are any outputs
@@ -70,8 +70,7 @@ public class P2PStateInfoProvider implements IPartProbInfoProvider
} }
else else
{ {
final PartP2PTunnel input = tunnel.getInput(); if( inputCount > 0 )
if( input != null )
{ {
state = STATE_OUTPUT; state = STATE_OUTPUT;
} }
@@ -83,7 +82,7 @@ public class P2PStateInfoProvider implements IPartProbInfoProvider
probeInfo.text( TheOneProbeText.P2P_UNLINKED.getLocal() ); probeInfo.text( TheOneProbeText.P2P_UNLINKED.getLocal() );
break; break;
case STATE_OUTPUT: case STATE_OUTPUT:
probeInfo.text( TheOneProbeText.P2P_OUTPUT.getLocal() ); probeInfo.text( getInputText( inputCount ) );
break; break;
case STATE_INPUT: case STATE_INPUT:
probeInfo.text( getOutputText( outputCount ) ); 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 ) private static String getOutputText( int outputs )
{ {
if( outputs <= 1 ) 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 java.util.List;
import appeng.integration.modules.theoneprobe.TheOneProbeText;
import com.google.common.collect.Iterators; import com.google.common.collect.Iterators;
import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.player.EntityPlayerMP;
@@ -117,11 +118,11 @@ public final class P2PStateWailaDataProvider extends BasePartWailaDataProvider
// The default state // The default state
int state = STATE_UNLINKED; int state = STATE_UNLINKED;
int outputCount = 0; int outputCount = getOutputCount( tunnel );
int inputCount = getInputCount( tunnel );
if( !tunnel.isOutput() ) if( !tunnel.isOutput() )
{ {
outputCount = getOutputCount( tunnel );
if( outputCount > 0 ) if( outputCount > 0 )
{ {
// Only set it to INPUT if we know there are any outputs // Only set it to INPUT if we know there are any outputs
@@ -130,8 +131,7 @@ public final class P2PStateWailaDataProvider extends BasePartWailaDataProvider
} }
else else
{ {
PartP2PTunnel input = tunnel.getInput(); if( inputCount > 0 )
if( input != null )
{ {
state = STATE_OUTPUT; 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 ) private static String getOutputText( int outputs )
{ {
if( outputs <= 1 ) if( outputs <= 1 )
{ {
return WailaText.P2PInputOneOutput.getLocal(); return WailaText.P2P_INPUT_ONE_OUTPUT.getLocal();
} }
else 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; package appeng.items.contents;
import appeng.api.networking.security.IActionSource;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
@@ -42,6 +43,8 @@ import appeng.me.helpers.MEMonitorHandler;
import appeng.util.ConfigManager; import appeng.util.ConfigManager;
import appeng.util.Platform; import appeng.util.Platform;
import java.util.Collections;
public class PortableCellViewer extends MEMonitorHandler<IAEItemStack> implements IPortableCell, IInventorySlotAware 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 ) ); 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 @Override
public <T extends IAEStack<T>> IMEMonitor<T> getInventory( IStorageChannel<T> channel ) 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; return Upgrades.INVERTER;
case CARD_CRAFTING: case CARD_CRAFTING:
return Upgrades.CRAFTING; return Upgrades.CRAFTING;
case CARD_PATTERN_EXPANSION:
return Upgrades.PATTERN_EXPANSION;
default: default:
return null; return null;
} }
@@ -118,7 +118,10 @@ public enum MaterialType
FLUID_CELL1K_PART( 54, "material_fluid_cell1k_part", EnumSet.of( AEFeature.STORAGE_CELLS ) ), 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_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_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 Set<AEFeature> features;
private final ModelResourceLocation model; private final ModelResourceLocation model;
+149 -185
View File
@@ -28,6 +28,9 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import appeng.parts.misc.*;
import appeng.parts.p2p.*;
import appeng.parts.reporting.*;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.client.renderer.block.model.ModelResourceLocation;
@@ -57,33 +60,12 @@ import appeng.parts.automation.PartFormationPlane;
import appeng.parts.automation.PartIdentityAnnihilationPlane; import appeng.parts.automation.PartIdentityAnnihilationPlane;
import appeng.parts.automation.PartImportBus; import appeng.parts.automation.PartImportBus;
import appeng.parts.automation.PartLevelEmitter; import appeng.parts.automation.PartLevelEmitter;
import appeng.parts.misc.PartCableAnchor;
import appeng.parts.misc.PartInterface;
import appeng.parts.misc.PartInvertedToggleBus;
import appeng.parts.misc.PartStorageBus;
import appeng.parts.misc.PartToggleBus;
import appeng.parts.networking.PartCableCovered; import appeng.parts.networking.PartCableCovered;
import appeng.parts.networking.PartCableGlass; import appeng.parts.networking.PartCableGlass;
import appeng.parts.networking.PartCableSmart; import appeng.parts.networking.PartCableSmart;
import appeng.parts.networking.PartDenseCableCovered; import appeng.parts.networking.PartDenseCableCovered;
import appeng.parts.networking.PartDenseCableSmart; import appeng.parts.networking.PartDenseCableSmart;
import appeng.parts.networking.PartQuartzFiber; import appeng.parts.networking.PartQuartzFiber;
import appeng.parts.p2p.PartP2PFEPower;
import appeng.parts.p2p.PartP2PFluids;
import appeng.parts.p2p.PartP2PIC2Power;
import appeng.parts.p2p.PartP2PItems;
import appeng.parts.p2p.PartP2PLight;
import appeng.parts.p2p.PartP2PRedstone;
import appeng.parts.p2p.PartP2PTunnelME;
import appeng.parts.reporting.PartConversionMonitor;
import appeng.parts.reporting.PartCraftingTerminal;
import appeng.parts.reporting.PartDarkPanel;
import appeng.parts.reporting.PartInterfaceTerminal;
import appeng.parts.reporting.PartPanel;
import appeng.parts.reporting.PartPatternTerminal;
import appeng.parts.reporting.PartSemiDarkPanel;
import appeng.parts.reporting.PartStorageMonitor;
import appeng.parts.reporting.PartTerminal;
import appeng.util.Platform; import appeng.util.Platform;
@@ -92,96 +74,84 @@ public enum PartType
INVALID_TYPE( -1, "invalid", EnumSet.of( AEFeature.CORE ), EnumSet.noneOf( IntegrationType.class ), null ), INVALID_TYPE( -1, "invalid", EnumSet.of( AEFeature.CORE ), EnumSet.noneOf( IntegrationType.class ), null ),
CABLE_GLASS( 0, "cable_glass", EnumSet.of( AEFeature.GLASS_CABLES ), EnumSet.noneOf( IntegrationType.class ), PartCableGlass.class ) CABLE_GLASS( 0, "cable_glass", EnumSet.of( AEFeature.GLASS_CABLES ), EnumSet.noneOf( IntegrationType.class ), PartCableGlass.class )
{ {
@Override @Override
public boolean isCable() public boolean isCable()
{ {
return true; return true;
} }
@Override @Override
@SideOnly( Side.CLIENT ) @SideOnly( Side.CLIENT )
protected List<ModelResourceLocation> createItemModels( String baseName ) protected List<ModelResourceLocation> createItemModels( String baseName )
{ {
return Arrays.stream( AEColor.values() ) return Arrays.stream( AEColor.values() ).map( color -> modelFromBaseName( baseName + "_" + color.name().toLowerCase() ) ).collect( Collectors.toList() );
.map( color -> modelFromBaseName( baseName + "_" + color.name().toLowerCase() ) ) }
.collect( Collectors.toList() ); },
}
},
CABLE_COVERED( 20, "cable_covered", EnumSet.of( AEFeature.COVERED_CABLES ), EnumSet.noneOf( IntegrationType.class ), PartCableCovered.class ) CABLE_COVERED( 20, "cable_covered", EnumSet.of( AEFeature.COVERED_CABLES ), EnumSet.noneOf( IntegrationType.class ), PartCableCovered.class )
{ {
@Override @Override
public boolean isCable() public boolean isCable()
{ {
return true; return true;
} }
@Override @Override
@SideOnly( Side.CLIENT ) @SideOnly( Side.CLIENT )
protected List<ModelResourceLocation> createItemModels( String baseName ) protected List<ModelResourceLocation> createItemModels( String baseName )
{ {
return Arrays.stream( AEColor.values() ) return Arrays.stream( AEColor.values() ).map( color -> modelFromBaseName( baseName + "_" + color.name().toLowerCase() ) ).collect( Collectors.toList() );
.map( color -> modelFromBaseName( baseName + "_" + color.name().toLowerCase() ) ) }
.collect( Collectors.toList() ); },
}
},
CABLE_SMART( 40, "cable_smart", EnumSet.of( AEFeature.CHANNELS, AEFeature.SMART_CABLES ), EnumSet.noneOf( IntegrationType.class ), PartCableSmart.class ) CABLE_SMART( 40, "cable_smart", EnumSet.of( AEFeature.CHANNELS, AEFeature.SMART_CABLES ), EnumSet.noneOf( IntegrationType.class ), PartCableSmart.class )
{ {
@Override @Override
public boolean isCable() public boolean isCable()
{ {
return true; return true;
} }
@Override @Override
@SideOnly( Side.CLIENT ) @SideOnly( Side.CLIENT )
protected List<ModelResourceLocation> createItemModels( String baseName ) protected List<ModelResourceLocation> createItemModels( String baseName )
{ {
return Arrays.stream( AEColor.values() ) return Arrays.stream( AEColor.values() ).map( color -> modelFromBaseName( baseName + "_" + color.name().toLowerCase() ) ).collect( Collectors.toList() );
.map( color -> modelFromBaseName( baseName + "_" + color.name().toLowerCase() ) ) }
.collect( Collectors.toList() ); },
}
},
CABLE_DENSE_SMART( 60, "cable_dense_smart", EnumSet.of( AEFeature.CHANNELS, AEFeature.DENSE_CABLES ), EnumSet CABLE_DENSE_SMART( 60, "cable_dense_smart", EnumSet.of( AEFeature.CHANNELS, AEFeature.DENSE_CABLES ), EnumSet.noneOf( IntegrationType.class ), PartDenseCableSmart.class )
.noneOf( IntegrationType.class ), PartDenseCableSmart.class ) {
{ @Override
@Override public boolean isCable()
public boolean isCable() {
{ return true;
return true; }
}
@Override @Override
@SideOnly( Side.CLIENT ) @SideOnly( Side.CLIENT )
protected List<ModelResourceLocation> createItemModels( String baseName ) protected List<ModelResourceLocation> createItemModels( String baseName )
{ {
return Arrays.stream( AEColor.values() ) return Arrays.stream( AEColor.values() ).map( color -> modelFromBaseName( baseName + "_" + color.name().toLowerCase() ) ).collect( Collectors.toList() );
.map( color -> modelFromBaseName( baseName + "_" + color.name().toLowerCase() ) ) }
.collect( Collectors.toList() ); },
}
},
CABLE_DENSE_COVERED( 500, "cable_dense_covered", EnumSet.of( AEFeature.CHANNELS, AEFeature.DENSE_CABLES ), EnumSet CABLE_DENSE_COVERED( 500, "cable_dense_covered", EnumSet.of( AEFeature.CHANNELS, AEFeature.DENSE_CABLES ), EnumSet.noneOf( IntegrationType.class ), PartDenseCableCovered.class )
.noneOf( IntegrationType.class ), PartDenseCableCovered.class ) {
{ @Override
@Override public boolean isCable()
public boolean isCable() {
{ return true;
return true; }
}
@Override @Override
@SideOnly( Side.CLIENT ) @SideOnly( Side.CLIENT )
protected List<ModelResourceLocation> createItemModels( String baseName ) protected List<ModelResourceLocation> createItemModels( String baseName )
{ {
return Arrays.stream( AEColor.values() ) return Arrays.stream( AEColor.values() ).map( color -> modelFromBaseName( baseName + "_" + color.name().toLowerCase() ) ).collect( Collectors.toList() );
.map( color -> modelFromBaseName( baseName + "_" + color.name().toLowerCase() ) ) }
.collect( Collectors.toList() ); },
}
},
TOGGLE_BUS( 80, "toggle_bus", EnumSet.of( AEFeature.TOGGLE_BUS ), EnumSet.noneOf( IntegrationType.class ), PartToggleBus.class ), TOGGLE_BUS( 80, "toggle_bus", EnumSet.of( AEFeature.TOGGLE_BUS ), EnumSet.noneOf( IntegrationType.class ), PartToggleBus.class ),
@@ -193,14 +163,13 @@ public enum PartType
MONITOR( 160, "monitor", EnumSet.of( AEFeature.PANELS ), EnumSet.noneOf( IntegrationType.class ), PartPanel.class, "itemIlluminatedPanel" ), MONITOR( 160, "monitor", EnumSet.of( AEFeature.PANELS ), EnumSet.noneOf( IntegrationType.class ), PartPanel.class, "itemIlluminatedPanel" ),
SEMI_DARK_MONITOR( 180, "semi_dark_monitor", EnumSet.of( AEFeature.PANELS ), EnumSet SEMI_DARK_MONITOR( 180, "semi_dark_monitor", EnumSet.of( AEFeature.PANELS ), EnumSet.noneOf( IntegrationType.class ), PartSemiDarkPanel.class, "itemIlluminatedPanel" ),
.noneOf( IntegrationType.class ), PartSemiDarkPanel.class, "itemIlluminatedPanel" ),
DARK_MONITOR( 200, "dark_monitor", EnumSet.of( AEFeature.PANELS ), EnumSet.noneOf( IntegrationType.class ), PartDarkPanel.class, "itemIlluminatedPanel" ), DARK_MONITOR( 200, "dark_monitor", EnumSet.of( AEFeature.PANELS ), EnumSet.noneOf( IntegrationType.class ), PartDarkPanel.class, "itemIlluminatedPanel" ),
STORAGE_BUS( 220, "storage_bus", EnumSet.of( AEFeature.STORAGE_BUS ), EnumSet.noneOf( IntegrationType.class ), PartStorageBus.class ), STORAGE_BUS( 220, "storage_bus", EnumSet.of( AEFeature.STORAGE_BUS ), EnumSet.noneOf( IntegrationType.class ), PartStorageBus.class ),
FLUID_STORAGE_BUS( 221, "fluid_storage_bus", EnumSet.of( AEFeature.FLUID_STORAGE_BUS ), EnumSet FLUID_STORAGE_BUS( 221, "fluid_storage_bus", EnumSet.of( AEFeature.FLUID_STORAGE_BUS ), EnumSet.noneOf( IntegrationType.class ), PartFluidStorageBus.class ),
.noneOf( IntegrationType.class ), PartFluidStorageBus.class ), OREDICT_STORAGE_BUS( 222, "oredict_storage_bus", EnumSet.of( AEFeature.STORAGE_BUS ), EnumSet.noneOf( IntegrationType.class ), PartOreDicStorageBus.class ),
IMPORT_BUS( 240, "import_bus", EnumSet.of( AEFeature.IMPORT_BUS ), EnumSet.noneOf( IntegrationType.class ), PartImportBus.class ), IMPORT_BUS( 240, "import_bus", EnumSet.of( AEFeature.IMPORT_BUS ), EnumSet.noneOf( IntegrationType.class ), PartImportBus.class ),
@@ -211,113 +180,109 @@ public enum PartType
FLUID_EXPORT_BUS( 261, "fluid_export_bus", EnumSet.of( AEFeature.FLUID_EXPORT_BUS ), EnumSet.noneOf( IntegrationType.class ), PartFluidExportBus.class ), FLUID_EXPORT_BUS( 261, "fluid_export_bus", EnumSet.of( AEFeature.FLUID_EXPORT_BUS ), EnumSet.noneOf( IntegrationType.class ), PartFluidExportBus.class ),
LEVEL_EMITTER( 280, "level_emitter", EnumSet.of( AEFeature.LEVEL_EMITTER ), EnumSet.noneOf( IntegrationType.class ), PartLevelEmitter.class ), LEVEL_EMITTER( 280, "level_emitter", EnumSet.of( AEFeature.LEVEL_EMITTER ), EnumSet.noneOf( IntegrationType.class ), PartLevelEmitter.class ),
FLUID_LEVEL_EMITTER( 281, "fluid_level_emitter", EnumSet.of( AEFeature.FLUID_LEVEL_EMITTER ), EnumSet FLUID_LEVEL_EMITTER( 281, "fluid_level_emitter", EnumSet.of( AEFeature.FLUID_LEVEL_EMITTER ), EnumSet.noneOf( IntegrationType.class ), PartFluidLevelEmitter.class ),
.noneOf( IntegrationType.class ), PartFluidLevelEmitter.class ),
ANNIHILATION_PLANE( 300, "annihilation_plane", EnumSet.of( AEFeature.ANNIHILATION_PLANE ), EnumSet ANNIHILATION_PLANE( 300, "annihilation_plane", EnumSet.of( AEFeature.ANNIHILATION_PLANE ), EnumSet.noneOf( IntegrationType.class ), PartAnnihilationPlane.class ),
.noneOf( IntegrationType.class ), PartAnnihilationPlane.class ),
IDENTITY_ANNIHILATION_PLANE( 301, "identity_annihilation_plane", EnumSet.of( AEFeature.ANNIHILATION_PLANE, AEFeature.IDENTITY_ANNIHILATION_PLANE ), EnumSet IDENTITY_ANNIHILATION_PLANE( 301, "identity_annihilation_plane", EnumSet.of( AEFeature.ANNIHILATION_PLANE, AEFeature.IDENTITY_ANNIHILATION_PLANE ), EnumSet.noneOf( IntegrationType.class ), PartIdentityAnnihilationPlane.class ),
.noneOf( IntegrationType.class ), PartIdentityAnnihilationPlane.class ),
FLUID_ANNIHILATION_PLANE( 302, "fluid_annihilation_plane", EnumSet.of( AEFeature.FLUID_ANNIHILATION_PLANE ), EnumSet FLUID_ANNIHILATION_PLANE( 302, "fluid_annihilation_plane", EnumSet.of( AEFeature.FLUID_ANNIHILATION_PLANE ), EnumSet.noneOf( IntegrationType.class ), PartFluidAnnihilationPlane.class ),
.noneOf( IntegrationType.class ), PartFluidAnnihilationPlane.class ),
FORMATION_PLANE( 320, "formation_plane", EnumSet.of( AEFeature.FORMATION_PLANE ), EnumSet.noneOf( IntegrationType.class ), PartFormationPlane.class ), FORMATION_PLANE( 320, "formation_plane", EnumSet.of( AEFeature.FORMATION_PLANE ), EnumSet.noneOf( IntegrationType.class ), PartFormationPlane.class ),
FLUID_FORMATION_PLANE( 321, "fluid_formation_plane", EnumSet.of( AEFeature.FLUID_FORMATION_PLANE ), EnumSet FLUID_FORMATION_PLANE( 321, "fluid_formation_plane", EnumSet.of( AEFeature.FLUID_FORMATION_PLANE ), EnumSet.noneOf( IntegrationType.class ), PartFluidFormationPlane.class ),
.noneOf( IntegrationType.class ), PartFluidFormationPlane.class ),
PATTERN_TERMINAL( 340, "pattern_terminal", EnumSet.of( AEFeature.PATTERNS ), EnumSet.noneOf( IntegrationType.class ), PartPatternTerminal.class ), PATTERN_TERMINAL( 340, "pattern_terminal", EnumSet.of( AEFeature.PATTERNS ), EnumSet.noneOf( IntegrationType.class ), PartPatternTerminal.class ),
CRAFTING_TERMINAL( 360, "crafting_terminal", EnumSet.of( AEFeature.CRAFTING_TERMINAL ), EnumSet EXPANDED_PROCESSING_PATTERN_TERMINAL( 341, "expanded_processing_pattern_terminal", EnumSet.of( AEFeature.PATTERNS ), EnumSet.noneOf( IntegrationType.class ), PartExpandedProcessingPatternTerminal.class ),
.noneOf( IntegrationType.class ), PartCraftingTerminal.class ),
CRAFTING_TERMINAL( 360, "crafting_terminal", EnumSet.of( AEFeature.CRAFTING_TERMINAL ), EnumSet.noneOf( IntegrationType.class ), PartCraftingTerminal.class ),
TERMINAL( 380, "terminal", EnumSet.of( AEFeature.TERMINAL ), EnumSet.noneOf( IntegrationType.class ), PartTerminal.class ), TERMINAL( 380, "terminal", EnumSet.of( AEFeature.TERMINAL ), EnumSet.noneOf( IntegrationType.class ), PartTerminal.class ),
STORAGE_MONITOR( 400, "storage_monitor", EnumSet.of( AEFeature.STORAGE_MONITOR ), EnumSet.noneOf( IntegrationType.class ), PartStorageMonitor.class ), STORAGE_MONITOR( 400, "storage_monitor", EnumSet.of( AEFeature.STORAGE_MONITOR ), EnumSet.noneOf( IntegrationType.class ), PartStorageMonitor.class ),
CONVERSION_MONITOR( 420, "conversion_monitor", EnumSet.of( AEFeature.PART_CONVERSION_MONITOR ), EnumSet CONVERSION_MONITOR( 420, "conversion_monitor", EnumSet.of( AEFeature.PART_CONVERSION_MONITOR ), EnumSet.noneOf( IntegrationType.class ), PartConversionMonitor.class ),
.noneOf( IntegrationType.class ), PartConversionMonitor.class ),
INTERFACE( 440, "interface", EnumSet.of( AEFeature.INTERFACE ), EnumSet.noneOf( IntegrationType.class ), PartInterface.class ), INTERFACE( 440, "interface", EnumSet.of( AEFeature.INTERFACE ), EnumSet.noneOf( IntegrationType.class ), PartInterface.class ),
FLUID_INTERFACE( 441, "fluid_interface", EnumSet.of( AEFeature.FLUID_INTERFACE ), EnumSet.noneOf( IntegrationType.class ), PartFluidInterface.class ), FLUID_INTERFACE( 441, "fluid_interface", EnumSet.of( AEFeature.FLUID_INTERFACE ), EnumSet.noneOf( IntegrationType.class ), PartFluidInterface.class ),
P2P_TUNNEL_ME( 460, "p2p_tunnel_me", EnumSet.of( AEFeature.P2P_TUNNEL, AEFeature.P2P_TUNNEL_ME ), EnumSet P2P_TUNNEL_ME( 460, "p2p_tunnel_me", EnumSet.of( AEFeature.P2P_TUNNEL, AEFeature.P2P_TUNNEL_ME ), EnumSet.noneOf( IntegrationType.class ), PartP2PTunnelME.class, GuiText.METunnel )
.noneOf( IntegrationType.class ), PartP2PTunnelME.class, GuiText.METunnel ) {
{ @Override
@Override String getUnlocalizedName()
String getUnlocalizedName() {
{ return "p2p_tunnel";
return "p2p_tunnel"; }
} },
},
P2P_TUNNEL_REDSTONE( 461, "p2p_tunnel_redstone", EnumSet.of( AEFeature.P2P_TUNNEL, AEFeature.P2P_TUNNEL_REDSTONE ), EnumSet P2P_TUNNEL_REDSTONE( 461, "p2p_tunnel_redstone", EnumSet.of( AEFeature.P2P_TUNNEL, AEFeature.P2P_TUNNEL_REDSTONE ), EnumSet.noneOf( IntegrationType.class ), PartP2PRedstone.class, GuiText.RedstoneTunnel )
.noneOf( IntegrationType.class ), PartP2PRedstone.class, GuiText.RedstoneTunnel ) {
{ @Override
@Override String getUnlocalizedName()
String getUnlocalizedName() {
{ return "p2p_tunnel";
return "p2p_tunnel"; }
} },
},
P2P_TUNNEL_ITEMS( 462, "p2p_tunnel_items", EnumSet.of( AEFeature.P2P_TUNNEL, AEFeature.P2P_TUNNEL_ITEMS ), EnumSet P2P_TUNNEL_ITEMS( 462, "p2p_tunnel_items", EnumSet.of( AEFeature.P2P_TUNNEL, AEFeature.P2P_TUNNEL_ITEMS ), EnumSet.noneOf( IntegrationType.class ), PartP2PItems.class, GuiText.ItemTunnel )
.noneOf( IntegrationType.class ), PartP2PItems.class, GuiText.ItemTunnel ) {
{ @Override
@Override String getUnlocalizedName()
String getUnlocalizedName() {
{ return "p2p_tunnel";
return "p2p_tunnel"; }
} },
},
P2P_TUNNEL_FLUIDS( 463, "p2p_tunnel_fluids", EnumSet.of( AEFeature.P2P_TUNNEL, AEFeature.P2P_TUNNEL_FLUIDS ), EnumSet P2P_TUNNEL_FLUIDS( 463, "p2p_tunnel_fluids", EnumSet.of( AEFeature.P2P_TUNNEL, AEFeature.P2P_TUNNEL_FLUIDS ), EnumSet.noneOf( IntegrationType.class ), PartP2PFluids.class, GuiText.FluidTunnel )
.noneOf( IntegrationType.class ), PartP2PFluids.class, GuiText.FluidTunnel ) {
{ @Override
@Override String getUnlocalizedName()
String getUnlocalizedName() {
{ return "p2p_tunnel";
return "p2p_tunnel"; }
} },
},
P2P_TUNNEL_IC2( 465, "p2p_tunnel_ic2", EnumSet.of( AEFeature.P2P_TUNNEL, AEFeature.P2P_TUNNEL_EU ), EnumSet P2P_TUNNEL_IC2( 465, "p2p_tunnel_ic2", EnumSet.of( AEFeature.P2P_TUNNEL, AEFeature.P2P_TUNNEL_EU ), EnumSet.of( IntegrationType.IC2 ), PartP2PIC2Power.class, GuiText.EUTunnel )
.of( IntegrationType.IC2 ), PartP2PIC2Power.class, GuiText.EUTunnel ) {
{ @Override
@Override String getUnlocalizedName()
String getUnlocalizedName() {
{ return "p2p_tunnel";
return "p2p_tunnel"; }
} },
},
P2P_TUNNEL_LIGHT( 467, "p2p_tunnel_light", EnumSet.of( AEFeature.P2P_TUNNEL, AEFeature.P2P_TUNNEL_LIGHT ), EnumSet P2P_TUNNEL_LIGHT( 467, "p2p_tunnel_light", EnumSet.of( AEFeature.P2P_TUNNEL, AEFeature.P2P_TUNNEL_LIGHT ), EnumSet.noneOf( IntegrationType.class ), PartP2PLight.class, GuiText.LightTunnel )
.noneOf( IntegrationType.class ), PartP2PLight.class, GuiText.LightTunnel ) {
{ @Override
@Override String getUnlocalizedName()
String getUnlocalizedName() {
{ return "p2p_tunnel";
return "p2p_tunnel"; }
} },
},
P2P_TUNNEL_FE( 469, "p2p_tunnel_fe", EnumSet.of( AEFeature.P2P_TUNNEL, AEFeature.P2P_TUNNEL_FE ), EnumSet P2P_TUNNEL_FE( 469, "p2p_tunnel_fe", EnumSet.of( AEFeature.P2P_TUNNEL, AEFeature.P2P_TUNNEL_FE ), EnumSet.noneOf( IntegrationType.class ), PartP2PFEPower.class, GuiText.FETunnel )
.noneOf( IntegrationType.class ), PartP2PFEPower.class, GuiText.FETunnel ) {
{ @Override
@Override String getUnlocalizedName()
String getUnlocalizedName() {
{ return "p2p_tunnel";
return "p2p_tunnel"; }
} },
},
P2P_TUNNEL_GTEU( 470, "p2p_tunnel_gteu", EnumSet.of( AEFeature.P2P_TUNNEL, AEFeature.P2P_TUNNEL_GTEU ), EnumSet.of( IntegrationType.GTCE ), PartP2PGTCEPower.class, GuiText.GTEUTunnel )
{
@Override
String getUnlocalizedName()
{
return "p2p_tunnel";
}
},
// P2PTunnelOpenComputers( 468, EnumSet.of( AEFeature.P2PTunnel, AEFeature.P2PTunnelOpenComputers ), EnumSet.of( // P2PTunnelOpenComputers( 468, EnumSet.of( AEFeature.P2PTunnel, AEFeature.P2PTunnelOpenComputers ), EnumSet.of(
// IntegrationType.OpenComputers ), PartP2POpenComputers.class, GuiText.OCTunnel ), // IntegrationType.OpenComputers ), PartP2POpenComputers.class, GuiText.OCTunnel ),
INTERFACE_TERMINAL( 480, "interface_terminal", EnumSet.of( AEFeature.INTERFACE_TERMINAL ), EnumSet INTERFACE_TERMINAL( 480, "interface_terminal", EnumSet.of( AEFeature.INTERFACE_TERMINAL ), EnumSet.noneOf( IntegrationType.class ), PartInterfaceTerminal.class ),
.noneOf( IntegrationType.class ), PartInterfaceTerminal.class ),
FLUID_TERMINAL( 520, "fluid_terminal", EnumSet.of( AEFeature.FLUID_TERMINAL ), EnumSet.noneOf( IntegrationType.class ), PartFluidTerminal.class ); FLUID_TERMINAL( 520, "fluid_terminal", EnumSet.of( AEFeature.FLUID_TERMINAL ), EnumSet.noneOf( IntegrationType.class ), PartFluidTerminal.class );
@@ -358,8 +323,7 @@ public enum PartType
this.oreName = oreDict; this.oreName = oreDict;
// The part is enabled if all features + integrations it needs are enabled // The part is enabled if all features + integrations it needs are enabled
this.enabled = features.stream().allMatch( AEConfig.instance()::isFeatureEnabled ) && integrations.stream() this.enabled = features.stream().allMatch( AEConfig.instance()::isFeatureEnabled ) && integrations.stream().allMatch( IntegrationRegistry.INSTANCE::isEnabled );
.allMatch( IntegrationRegistry.INSTANCE::isEnabled );
if( this.enabled ) if( this.enabled )
{ {
@@ -403,7 +403,7 @@ public class ToolMatterCannon extends AEBasePoweredItem implements IStorageCell<
} }
else if( pos.entityHit.attackEntityFrom( dmgSrc, dmg ) ) else if( pos.entityHit.attackEntityFrom( dmgSrc, dmg ) )
{ {
hasDestroyed = true; hasDestroyed = pos.entityHit.isEntityAlive();
} }
} }
else if( pos.typeOfHit == RayTraceResult.Type.BLOCK ) else if( pos.typeOfHit == RayTraceResult.Type.BLOCK )
+1 -7
View File
@@ -19,12 +19,8 @@
package appeng.me; package appeng.me;
import java.util.Collection; import java.util.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
import appeng.api.AEApi; import appeng.api.AEApi;
import appeng.api.networking.IGrid; import appeng.api.networking.IGrid;
@@ -220,9 +216,7 @@ public class Grid implements IGrid
@Override @Override
public MENetworkEvent postEvent( final MENetworkEvent ev ) public MENetworkEvent postEvent( final MENetworkEvent ev )
{ {
CraftingGridCache.pauseRebuilds();
final MENetworkEvent ret = this.eventBus.postEvent( this, ev ); final MENetworkEvent ret = this.eventBus.postEvent( this, ev );
CraftingGridCache.unpauseRebuilds();
return ret; return ret;
} }
+17 -13
View File
@@ -59,12 +59,13 @@ import appeng.me.cache.CraftingGridCache;
import appeng.me.pathfinding.IPathItem; import appeng.me.pathfinding.IPathItem;
import appeng.util.IWorldCallable; import appeng.util.IWorldCallable;
import appeng.util.ReadOnlyCollection; import appeng.util.ReadOnlyCollection;
import net.minecraftforge.common.util.Constants;
public class GridNode implements IGridNode, IPathItem public class GridNode implements IGridNode, IPathItem
{ {
private static final MENetworkChannelsChanged EVENT = new MENetworkChannelsChanged(); private static final MENetworkChannelsChanged EVENT = new MENetworkChannelsChanged();
private static final int[] CHANNEL_COUNT = { 0, 8, 32 }; private static final int[] CHANNEL_COUNT = {0, 8, 32};
private final List<IGridConnection> connections = new ArrayList<>(); private final List<IGridConnection> connections = new ArrayList<>();
private final IGridBlock gridProxy; private final IGridBlock gridProxy;
@@ -165,8 +166,6 @@ public class GridNode implements IGridNode, IPathItem
{ {
final Object tracker = new Object(); final Object tracker = new Object();
CraftingGridCache.pauseRebuilds();
Deque<GridNode> nextRun = new ArrayDeque<>(); Deque<GridNode> nextRun = new ArrayDeque<>();
nextRun.add( this ); nextRun.add( this );
@@ -177,9 +176,9 @@ public class GridNode implements IGridNode, IPathItem
final Deque<IGridConnection> nextConn = new ArrayDeque<>(); final Deque<IGridConnection> nextConn = new ArrayDeque<>();
final IGridConnectionVisitor gcv = (IGridConnectionVisitor) g; final IGridConnectionVisitor gcv = (IGridConnectionVisitor) g;
while( !nextRun.isEmpty() ) while ( !nextRun.isEmpty() )
{ {
while( !nextConn.isEmpty() ) while ( !nextConn.isEmpty() )
{ {
gcv.visitConnection( nextConn.poll() ); gcv.visitConnection( nextConn.poll() );
} }
@@ -195,7 +194,7 @@ public class GridNode implements IGridNode, IPathItem
} }
else else
{ {
while( !nextRun.isEmpty() ) while ( !nextRun.isEmpty() )
{ {
final Iterable<GridNode> thisRun = nextRun; final Iterable<GridNode> thisRun = nextRun;
nextRun = new ArrayDeque<>(); nextRun = new ArrayDeque<>();
@@ -206,7 +205,6 @@ public class GridNode implements IGridNode, IPathItem
} }
} }
} }
CraftingGridCache.unpauseRebuilds();
} }
@Override @Override
@@ -268,7 +266,7 @@ public class GridNode implements IGridNode, IPathItem
@Override @Override
public void destroy() public void destroy()
{ {
while( !this.connections.isEmpty() ) while ( !this.connections.isEmpty() )
{ {
// not part of this network for real anymore. // not part of this network for real anymore.
if( this.connections.size() == 1 ) if( this.connections.size() == 1 )
@@ -333,7 +331,11 @@ public class GridNode implements IGridNode, IPathItem
@Override @Override
public void loadFromNBT( final String name, final NBTTagCompound nodeData ) public void loadFromNBT( final String name, final NBTTagCompound nodeData )
{ {
if( this.myGrid == null ) if( this.myGrid != null )
{
throw new IllegalStateException( "Loading data after part of a grid, this is invalid." );
}
if( nodeData.hasKey( name, 10 ) )
{ {
final NBTTagCompound node = nodeData.getCompoundTag( name ); final NBTTagCompound node = nodeData.getCompoundTag( name );
this.playerID = node.getInteger( "p" ); this.playerID = node.getInteger( "p" );
@@ -345,7 +347,9 @@ public class GridNode implements IGridNode, IPathItem
} }
else else
{ {
throw new IllegalStateException( "Loading data after part of a grid, this is invalid." ); this.playerID = -1; // Unknown owner
setLastSecurityKey( -1 );
setGridStorage( null );
} }
} }
@@ -371,7 +375,7 @@ public class GridNode implements IGridNode, IPathItem
@Override @Override
public boolean meetsChannelRequirements() public boolean meetsChannelRequirements()
{ {
return( !this.gridProxy.getFlags().contains( GridFlags.REQUIRE_CHANNEL ) || this.getUsedChannels() > 0 ); return ( !this.gridProxy.getFlags().contains( GridFlags.REQUIRE_CHANNEL ) || this.getUsedChannels() > 0 );
} }
@Override @Override
@@ -633,10 +637,10 @@ public class GridNode implements IGridNode, IPathItem
this.usedChannels = 0; this.usedChannels = 0;
} }
final int idx = this.connections.indexOf( fast ); final int idx = this.connections.indexOf( (IGridConnection) fast );
if( idx > 0 ) if( idx > 0 )
{ {
this.connections.remove( fast ); this.connections.remove( (IGridConnection) fast );
this.connections.add( 0, (IGridConnection) fast ); this.connections.add( 0, (IGridConnection) fast );
} }
} }
+82 -66
View File
@@ -30,7 +30,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; 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.ImmutableSet;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import it.unimi.dsi.fastutil.objects.*;
import net.minecraft.world.World; import net.minecraft.world.World;
import appeng.api.AEApi; import appeng.api.AEApi;
@@ -105,17 +105,17 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
private final Set<ICraftingProvider> craftingProviders = new HashSet<>(); private final Set<ICraftingProvider> craftingProviders = new HashSet<>();
private final Map<IGridNode, ICraftingWatcher> craftingWatchers = new HashMap<>(); private final Map<IGridNode, ICraftingWatcher> craftingWatchers = new HashMap<>();
private final IGrid grid; private final IGrid grid;
private final Map<ICraftingPatternDetails, List<ICraftingMedium>> craftingMethods = new HashMap<>(); private final Object2ObjectMap<ICraftingPatternDetails, List<ICraftingMedium>> craftingMethods = new Object2ObjectOpenHashMap<>();
private final Map<IAEItemStack, ImmutableList<ICraftingPatternDetails>> craftableItems = new HashMap<>(); private final Object2ObjectMap<IAEItemStack, ImmutableList<ICraftingPatternDetails>> craftableItems = new Object2ObjectOpenHashMap<>();
private final Set<IAEItemStack> emitableItems = new HashSet<>(); private final Set<IAEItemStack> emitableItems = new HashSet<>();
private final Map<String, CraftingLinkNexus> craftingLinks = new HashMap<>(); private final Map<String, CraftingLinkNexus> craftingLinks = new HashMap<>();
private final Multimap<IAEStack, CraftingWatcher> interests = HashMultimap.create(); private final Multimap<IAEStack, CraftingWatcher> interests = HashMultimap.create();
private final GenericInterestManager<CraftingWatcher> interestManager = new GenericInterestManager<>( this.interests ); private final GenericInterestManager<CraftingWatcher> interestManager = new GenericInterestManager<>( this.interests );
private IStorageGrid storageGrid; private IStorageGrid storageGrid;
private IEnergyGrid energyGrid; private IEnergyGrid energyGrid;
int i;
private boolean updateList = false; private boolean updateList = false;
private static int pauseRebuilds = 0; private boolean updatePatterns = false;
private static Set<CraftingGridCache> rebuildNeeded = new HashSet<>();
public CraftingGridCache( final IGrid grid ) public CraftingGridCache( final IGrid grid )
{ {
@@ -140,8 +140,14 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
this.updateCPUClusters(); this.updateCPUClusters();
} }
if( updatePatterns )
{
this.recalculateCraftingPatterns();
this.updatePatterns = false;
}
final Iterator<CraftingLinkNexus> craftingLinkIterator = this.craftingLinks.values().iterator(); final Iterator<CraftingLinkNexus> craftingLinkIterator = this.craftingLinks.values().iterator();
while( craftingLinkIterator.hasNext() ) while ( craftingLinkIterator.hasNext() )
{ {
if( craftingLinkIterator.next().isDead( this.grid, this ) ) if( craftingLinkIterator.next().isDead( this.grid, this ) )
{ {
@@ -160,11 +166,11 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
{ {
if( machine instanceof ICraftingWatcherHost ) if( machine instanceof ICraftingWatcherHost )
{ {
final ICraftingWatcher craftingWatcher = this.craftingWatchers.get( machine ); final ICraftingWatcher craftingWatcher = this.craftingWatchers.get( gridNode );
if( craftingWatcher != null ) if( craftingWatcher != null )
{ {
craftingWatcher.reset(); craftingWatcher.reset();
this.craftingWatchers.remove( machine ); this.craftingWatchers.remove( gridNode );
} }
} }
@@ -187,7 +193,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
if( machine instanceof ICraftingProvider ) if( machine instanceof ICraftingProvider )
{ {
this.craftingProviders.remove( machine ); this.craftingProviders.remove( machine );
this.updatePatterns(); this.updatePatterns = true;
} }
} }
@@ -221,7 +227,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
if( machine instanceof ICraftingProvider ) if( machine instanceof ICraftingProvider )
{ {
this.craftingProviders.add( (ICraftingProvider) machine ); this.craftingProviders.add( (ICraftingProvider) machine );
this.updatePatterns(); this.updatePatterns = true;
} }
} }
@@ -242,52 +248,28 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
// nothing! // 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() private void updatePatterns()
{ {
// coalesce change events during a grid traversal to a single rebuild this.updatePatterns = true;
if (pauseRebuilds != 0) }
{
rebuildNeeded.add(this);
return;
}
final Map<IAEItemStack, ImmutableList<ICraftingPatternDetails>> oldItems = this.craftableItems; private void recalculateCraftingPatterns()
{
final Object2ObjectMap<IAEItemStack, ImmutableList<ICraftingPatternDetails>> oldItems = new Object2ObjectOpenHashMap<>( this.craftableItems );
final Set<IAEItemStack> oldEmitableItems = new HashSet<>( this.emitableItems );
// erase list. // erase list.
this.craftingMethods.clear(); this.craftingMethods.clear();
this.craftableItems.clear(); this.craftableItems.clear();
this.emitableItems.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.. // re-create list..
for( final ICraftingProvider provider : this.craftingProviders ) for( final ICraftingProvider provider : this.craftingProviders )
{ {
provider.provideCrafting( this ); provider.provideCrafting( this );
} }
final Map<IAEItemStack, Set<ICraftingPatternDetails>> tmpCraft = new HashMap<>(); final Object2ObjectMap<IAEItemStack, ObjectSet<ICraftingPatternDetails>> tmpCraft = new Object2ObjectOpenHashMap<>();
// new craftables! // new craftables!
for( final ICraftingPatternDetails details : this.craftingMethods.keySet() ) for( final ICraftingPatternDetails details : this.craftingMethods.keySet() )
@@ -298,11 +280,11 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
out.reset(); out.reset();
out.setCraftable( true ); out.setCraftable( true );
Set<ICraftingPatternDetails> methods = tmpCraft.get( out ); ObjectSet<ICraftingPatternDetails> methods = tmpCraft.get( out );
if( methods == null ) if( methods == null )
{ {
tmpCraft.put( out, methods = new TreeSet<>( COMPARATOR ) ); tmpCraft.put( out, methods = new ObjectRBTreeSet<>( COMPARATOR ) );
} }
methods.add( details ); methods.add( details );
@@ -310,13 +292,60 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
} }
// make them immutable // 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.craftableItems.put( e.getKey(), ImmutableList.copyOf( e.getValue() ) );
} }
this.storageGrid.postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ), this.craftableItems.keySet(), List<IAEItemStack> craftablesChanged = new ArrayList<>();
new BaseActionSource() );
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.add( changedStack );
}
}
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.add( changedStack );
}
}
for( final IAEItemStack st : oldEmitableItems )
{
if( !emitableItems.contains( st ) )
{
IAEItemStack changedStack = st.copy();
changedStack.reset();
changedStack.setCraftable( false );
craftablesChanged.add( changedStack );
}
}
for( final IAEItemStack st : this.emitableItems )
{
if( !oldEmitableItems.contains( st ) )
{
IAEItemStack changedStack = st.copy();
changedStack.reset();
changedStack.setCraftable( true );
craftablesChanged.add( changedStack );
}
}
this.storageGrid.postCraftablesChanges( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ), craftablesChanged, new BaseActionSource() );
} }
private void updateCPUClusters() private void updateCPUClusters()
@@ -494,22 +523,6 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
if( res == null ) if( res == null )
{ {
if( details != null && details.isCraftable() )
{
for( final IAEItemStack ais : this.craftableItems.keySet() )
{
if( ais.getItem() == whatToCraft.getItem() && ( !ais.getItem().getHasSubtypes() || ais.getItemDamage() == whatToCraft.getItemDamage() ) )
{
// TODO: check if OK
// TODO: this is slightly hacky, but fine as long as we only deal with itemstacks
if( details.isValidItemForSlot( slotIndex, ais.asItemStackRepresentation(), world ) )
{
return this.craftableItems.get( ais );
}
}
}
}
return ImmutableSet.of(); return ImmutableSet.of();
} }
@@ -555,8 +568,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
} }
} }
Collections.sort( validCpusClusters, ( firstCluster, nextCluster ) -> Collections.sort( validCpusClusters, ( firstCluster, nextCluster ) -> {
{
if( prioritizePower ) if( prioritizePower )
{ {
final int comparison1 = Long.compare( nextCluster.getCoProcessors(), firstCluster.getCoProcessors() ); final int comparison1 = Long.compare( nextCluster.getCoProcessors(), firstCluster.getCoProcessors() );
@@ -635,7 +647,11 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
public boolean hasCpu( final ICraftingCPU cpu ) 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() public GenericInterestManager<CraftingWatcher> getInterestManager()
@@ -665,7 +681,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
private void findNext() private void findNext()
{ {
while( this.iterator.hasNext() && this.cpuCluster == null ) while ( this.iterator.hasNext() && this.cpuCluster == null )
{ {
this.cpuCluster = this.iterator.next(); this.cpuCluster = this.iterator.next();
if( !this.cpuCluster.isActive() || this.cpuCluster.isDestroyed() ) if( !this.cpuCluster.isActive() || this.cpuCluster.isDestroyed() )
+177 -41
View File
@@ -30,6 +30,7 @@ import java.util.PriorityQueue;
import java.util.Queue; import java.util.Queue;
import java.util.Set; import java.util.Set;
import com.google.common.base.Preconditions;
import com.google.common.collect.HashMultiset; import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset; import com.google.common.collect.Multiset;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
@@ -63,12 +64,10 @@ import appeng.me.energy.EnergyWatcher;
public class EnergyGridCache implements IEnergyGrid public class EnergyGridCache implements IEnergyGrid
{ {
private static final double MAX_BUFFER_STORAGE = 200; private static final double MAX_BUFFER_STORAGE = 800;
private static final Comparator<IEnergyGridProvider> COMPARATOR_HIGHEST_AMOUNT_STORED_FIRST = ( o1, o2 ) -> Double.compare( o2.getProviderStoredEnergy(), private static final Comparator<IEnergyGridProvider> COMPARATOR_HIGHEST_AMOUNT_STORED_FIRST = ( o1, o2 ) -> Double.compare( o2.getProviderStoredEnergy(), o1.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 percent1 = ( o1.getProviderStoredEnergy() + 1 ) / ( o1.getProviderMaxEnergy() + 1 );
final double percent2 = ( o2.getProviderStoredEnergy() + 1 ) / ( o2.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(); 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 double averageLength = 40.0;
private final Set<IAEPowerStorage> providers = new LinkedHashSet<>(); 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<>(); 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 Multiset<IEnergyGridProvider> energyGridProviders = HashMultiset.create();
private final IGrid myGrid; private final IGrid myGrid;
private final HashMap<IGridNode, IEnergyWatcher> watchers = new HashMap<>(); private final HashMap<IGridNode, IEnergyWatcher> watchers = new HashMap<>();
@@ -110,6 +124,10 @@ public class EnergyGridCache implements IEnergyGrid
private double lastStoredPower = -1; private double lastStoredPower = -1;
private final GridPowerStorage localStorage = new GridPowerStorage(); 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 ) public EnergyGridCache( final IGrid g )
{ {
@@ -143,20 +161,33 @@ public class EnergyGridCache implements IEnergyGrid
{ {
if( ev.storage.isAEPublicPowerStorage() ) 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; else
case REQUEST_POWER:
if( ev.storage.getPowerFlow() != AccessRestriction.READ )
{ {
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 else
@@ -301,19 +332,56 @@ public class EnergyGridCache implements IEnergyGrid
{ {
double extractedPower = 0; double extractedPower = 0;
this.providers.addAll( providersToAdd );
providersToAdd.clear();
providers.removeIf( providerToRemove::contains );
this.providerToRemove.clear();
final Iterator<IAEPowerStorage> it = this.providers.iterator(); final Iterator<IAEPowerStorage> it = this.providers.iterator();
while( extractedPower < amt && it.hasNext() ) ongoingExtractOperation = true;
boolean ls = false;
try
{ {
final IAEPowerStorage node = it.next(); while ( extractedPower < amt && it.hasNext() )
final double req = amt - extractedPower;
final double newPower = node.extractAEPower( req, mode, PowerMultiplier.ONE );
extractedPower += newPower;
if( newPower < req && mode == Actionable.MODULATE )
{ {
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; final double originalAmount = amt;
this.requesters.addAll( requesterToAdd );
requesterToAdd.clear();
requesters.removeIf( requesterToRemove::contains );
this.requesterToRemove.clear();
final Iterator<IAEPowerStorage> it = this.requesters.iterator(); final Iterator<IAEPowerStorage> it = this.requesters.iterator();
while( amt > 0 && it.hasNext() ) ongoingInjectOperation = true;
try
{ {
final IAEPowerStorage node = it.next(); while ( amt > 0 && it.hasNext() )
amt = node.injectAEPower( amt, mode );
if( amt > 0 && mode == Actionable.MODULATE )
{ {
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 ); final double overflow = Math.max( 0.0, amt );
@@ -367,7 +455,7 @@ public class EnergyGridCache implements IEnergyGrid
double required = 0; double required = 0;
final Iterator<IAEPowerStorage> it = this.requesters.iterator(); final Iterator<IAEPowerStorage> it = this.requesters.iterator();
while( required < maxRequired && it.hasNext() ) while ( required < maxRequired && it.hasNext() )
{ {
final IAEPowerStorage node = it.next(); final IAEPowerStorage node = it.next();
if( node.getPowerFlow() != AccessRestriction.READ ) if( node.getPowerFlow() != AccessRestriction.READ )
@@ -428,11 +516,7 @@ public class EnergyGridCache implements IEnergyGrid
@Override @Override
public double getStoredPower() public double getStoredPower()
{ {
if( this.availableTicksSinceUpdate > 90 ) this.refreshPower();
{
this.refreshPower();
}
return Math.max( 0.0, this.globalAvailablePower ); return Math.max( 0.0, this.globalAvailablePower );
} }
@@ -505,9 +589,22 @@ public class EnergyGridCache implements IEnergyGrid
this.globalMaxPower -= ps.getAEMaxPower(); this.globalMaxPower -= ps.getAEMaxPower();
this.globalAvailablePower -= ps.getAECurrentPower(); this.globalAvailablePower -= ps.getAECurrentPower();
} }
if( !ongoingExtractOperation )
this.providers.remove( ps ); {
this.requesters.remove( ps ); 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 @Override
public void addNode( final IGridNode node, final IGridHost machine ) 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 ) if( current > 0 && ps.getPowerFlow() != AccessRestriction.WRITE )
{ {
this.globalAvailablePower += current; this.globalAvailablePower += current;
this.providers.add( ps ); if( !ongoingExtractOperation )
{
addProvider( ps );
}
else
{
this.providersToAdd.add( ps );
}
} }
if( current < max && ps.getPowerFlow() != AccessRestriction.READ ) 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
} }
} }
} }
} }
+59 -20
View File
@@ -19,13 +19,12 @@
package appeng.me.cache; package appeng.me.cache;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.crafting.MECraftingInventory;
import appeng.helpers.IInterfaceHost;
import appeng.helpers.IPriorityHost;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
import com.google.common.collect.SetMultimap; import com.google.common.collect.SetMultimap;
@@ -55,6 +54,8 @@ import appeng.me.helpers.GenericInterestManager;
import appeng.me.helpers.MachineSource; import appeng.me.helpers.MachineSource;
import appeng.me.storage.ItemWatcher; import appeng.me.storage.ItemWatcher;
import appeng.me.storage.NetworkInventoryHandler; import appeng.me.storage.NetworkInventoryHandler;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class GridStorageCache implements IStorageGrid public class GridStorageCache implements IStorageGrid
@@ -66,8 +67,11 @@ public class GridStorageCache implements IStorageGrid
private final SetMultimap<IAEStack, ItemWatcher> interests = HashMultimap.create(); private final SetMultimap<IAEStack, ItemWatcher> interests = HashMultimap.create();
private final GenericInterestManager<ItemWatcher> interestManager = new GenericInterestManager<>( this.interests ); private final GenericInterestManager<ItemWatcher> interestManager = new GenericInterestManager<>( this.interests );
private final HashMap<IGridNode, IStackWatcher> watchers = new HashMap<>(); private final HashMap<IGridNode, IStackWatcher> watchers = new HashMap<>();
private Map<IStorageChannel<? extends IAEStack>, NetworkInventoryHandler<?>> storageNetworks; private final Map<IStorageChannel<? extends IAEStack>, NetworkInventoryHandler<?>> storageNetworks;
private Map<IStorageChannel<? extends IAEStack>, NetworkMonitor<?>> storageMonitors; private final Map<IStorageChannel<? extends IAEStack>, NetworkMonitor<?>> storageMonitors;
private MECraftingInventory localCache = null;
private final Int2ObjectMap<MECraftingInventory> extractableItemPriorityMap = new Int2ObjectOpenHashMap<>();
private int localDepth;
public GridStorageCache( final IGrid g ) public GridStorageCache( final IGrid g )
{ {
@@ -81,6 +85,8 @@ public class GridStorageCache implements IStorageGrid
@Override @Override
public void onUpdateTick() public void onUpdateTick()
{ {
this.localCache = null;
this.extractableItemPriorityMap.clear();
this.storageMonitors.forEach( ( channel, monitor ) -> monitor.onTick() ); this.storageMonitors.forEach( ( channel, monitor ) -> monitor.onTick() );
} }
@@ -94,19 +100,19 @@ public class GridStorageCache implements IStorageGrid
this.removeCellProvider( cc, tracker ); this.removeCellProvider( cc, tracker );
this.inactiveCellProviders.remove( cc ); this.inactiveCellProviders.remove( cc );
this.getGrid().postEvent( new MENetworkCellArrayUpdate() ); cellUpdate( null );
tracker.applyChanges(); tracker.applyChanges();
} }
if( machine instanceof IStackWatcherHost ) if( machine instanceof IStackWatcherHost )
{ {
final IStackWatcher myWatcher = this.watchers.get( machine ); final IStackWatcher myWatcher = this.watchers.get( node );
if( myWatcher != null ) if( myWatcher != null )
{ {
myWatcher.reset(); myWatcher.reset();
this.watchers.remove( machine ); this.watchers.remove( node );
} }
} }
} }
@@ -119,7 +125,7 @@ public class GridStorageCache implements IStorageGrid
final ICellContainer cc = (ICellContainer) machine; final ICellContainer cc = (ICellContainer) machine;
this.inactiveCellProviders.add( cc ); this.inactiveCellProviders.add( cc );
this.getGrid().postEvent( new MENetworkCellArrayUpdate() ); cellUpdate( null );
if( node.isActive() ) if( node.isActive() )
{ {
@@ -168,6 +174,28 @@ public class GridStorageCache implements IStorageGrid
return (IMEMonitor<T>) this.storageMonitors.get( channel ); return (IMEMonitor<T>) this.storageMonitors.get( channel );
} }
public MECraftingInventory getExtractableList( IActionSource src )
{
if( src instanceof MachineSource )
{
if( src.machine().isPresent() )
{
IActionHost machine = src.machine().get();
if( machine instanceof IInterfaceHost )
{
extractableItemPriorityMap.putIfAbsent( ( (IPriorityHost) machine ).getPriority(), new MECraftingInventory( getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ), src, false, false, false ) );
return extractableItemPriorityMap.get( ( (IPriorityHost) machine ).getPriority() );
}
}
}
if( localCache == null )
{
localCache = new MECraftingInventory( getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ), src, false, false, false );
}
return localCache;
}
private CellChangeTracker addCellProvider( final ICellProvider cc, final CellChangeTracker tracker ) private CellChangeTracker addCellProvider( final ICellProvider cc, final CellChangeTracker tracker )
{ {
if( this.inactiveCellProviders.contains( cc ) ) if( this.inactiveCellProviders.contains( cc ) )
@@ -177,8 +205,7 @@ public class GridStorageCache implements IStorageGrid
final IActionSource actionSrc = cc instanceof IActionHost ? new MachineSource( (IActionHost) cc ) : new BaseActionSource(); final IActionSource actionSrc = cc instanceof IActionHost ? new MachineSource( (IActionHost) cc ) : new BaseActionSource();
this.storageMonitors.forEach( ( channel, monitor ) -> this.storageMonitors.forEach( ( channel, monitor ) -> {
{
for( final IMEInventoryHandler<?> h : cc.getCellArray( channel ) ) for( final IMEInventoryHandler<?> h : cc.getCellArray( channel ) )
{ {
tracker.postChanges( channel, 1, h, actionSrc ); tracker.postChanges( channel, 1, h, actionSrc );
@@ -198,8 +225,7 @@ public class GridStorageCache implements IStorageGrid
final IActionSource actionSrc = cc instanceof IActionHost ? new MachineSource( (IActionHost) cc ) : new BaseActionSource(); final IActionSource actionSrc = cc instanceof IActionHost ? new MachineSource( (IActionHost) cc ) : new BaseActionSource();
this.storageMonitors.forEach( ( channel, monitor ) -> this.storageMonitors.forEach( ( channel, monitor ) -> {
{
for( final IMEInventoryHandler<IAEItemStack> h : cc.getCellArray( channel ) ) for( final IMEInventoryHandler<IAEItemStack> h : cc.getCellArray( channel ) )
{ {
tracker.postChanges( channel, -1, h, actionSrc ); tracker.postChanges( channel, -1, h, actionSrc );
@@ -213,6 +239,11 @@ public class GridStorageCache implements IStorageGrid
@MENetworkEventSubscribe @MENetworkEventSubscribe
public void cellUpdate( final MENetworkCellArrayUpdate ev ) public void cellUpdate( final MENetworkCellArrayUpdate ev )
{ {
if( localDepth > 0 )
{
return;
}
localDepth++;
this.storageNetworks.clear(); this.storageNetworks.clear();
final List<ICellProvider> ll = new ArrayList<ICellProvider>(); final List<ICellProvider> ll = new ArrayList<ICellProvider>();
@@ -247,10 +278,9 @@ public class GridStorageCache implements IStorageGrid
this.removeCellProvider( cc, tracker ); this.removeCellProvider( cc, tracker );
} }
} }
this.storageMonitors.forEach( ( channel, monitor ) -> monitor.forceUpdate() );
tracker.applyChanges(); tracker.applyChanges();
localDepth--;
this.storageMonitors.forEach( ( channel, monitor ) -> monitor.setForceUpdate( true ) );
} }
private <T extends IAEStack<T>, C extends IStorageChannel<T>> void postChangesToNetwork( final C chan, final int upOrDown, final IItemList<T> availableItems, final IActionSource src ) private <T extends IAEStack<T>, C extends IStorageChannel<T>> void postChangesToNetwork( final C chan, final int upOrDown, final IItemList<T> availableItems, final IActionSource src )
@@ -281,6 +311,12 @@ public class GridStorageCache implements IStorageGrid
this.storageMonitors.get( chan ).postChange( true, (Iterable) input, src ); 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 @Override
public void registerCellProvider( final ICellProvider provider ) public void registerCellProvider( final ICellProvider provider )
{ {
@@ -324,7 +360,10 @@ public class GridStorageCache implements IStorageGrid
public void applyChanges() 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 );
}
} }
} }
+143 -102
View File
@@ -19,20 +19,9 @@
package appeng.me.cache; 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.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import appeng.api.AEApi;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Queues;
import appeng.api.config.AccessRestriction; import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
import appeng.api.networking.events.MENetworkStorageEvent; import appeng.api.networking.events.MENetworkStorageEvent;
@@ -41,15 +30,26 @@ import appeng.api.storage.IMEInventoryHandler;
import appeng.api.storage.IMEMonitor; import appeng.api.storage.IMEMonitor;
import appeng.api.storage.IMEMonitorHandlerReceiver; import appeng.api.storage.IMEMonitorHandlerReceiver;
import appeng.api.storage.IStorageChannel; 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.IAEStack;
import appeng.api.storage.data.IItemList; import appeng.api.storage.data.IItemList;
import appeng.me.storage.ItemWatcher; import appeng.me.storage.ItemWatcher;
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> public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
{ {
@Nonnull @Nonnull
private static final Deque<NetworkMonitor<?>> GLOBAL_DEPTH = Queues.newArrayDeque(); private static final HashMap<IActionSource, LinkedList<NetworkMonitor<?>>> src2MonitorsMap = new HashMap<>();
private static final Set<IActionSource> nestingSources = new HashSet<>();
protected boolean wasNested = false;
protected boolean isNested = false;
@Nonnull @Nonnull
private final GridStorageCache myGridCache; private final GridStorageCache myGridCache;
@@ -58,19 +58,19 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
@Nonnull @Nonnull
private final IItemList<T> cachedList; private final IItemList<T> cachedList;
@Nonnull @Nonnull
private final Map<IMEMonitorHandlerReceiver<T>, Object> listeners; private final Object2ObjectMap<IMEMonitorHandlerReceiver<T>, Object> listeners;
private boolean sendEvent = false; private boolean sendEvent = false;
private boolean hasChanged = false; private long gridItemCount;
@Nonnegative private long gridFluidCount;
private int localDepthSemaphore = 0; public boolean forceUpdate;
public NetworkMonitor( final GridStorageCache cache, final IStorageChannel<T> chan ) public NetworkMonitor( final GridStorageCache cache, final IStorageChannel<T> chan )
{ {
this.myGridCache = cache; this.myGridCache = cache;
this.myChannel = chan; this.myChannel = chan;
this.cachedList = chan.createList(); this.cachedList = chan.createList();
this.listeners = new HashMap<>(); this.listeners = new Object2ObjectOpenHashMap<>();
} }
@Override @Override
@@ -88,21 +88,7 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
@Override @Override
public T extractItems( final T request, final Actionable mode, final IActionSource src ) 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.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;
} }
@Override @Override
@@ -135,38 +121,42 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
return this.getHandler().getSlot(); 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 @Nonnull
@Override @Override
public IItemList<T> getStorageList() public IItemList<T> getStorageList()
{ {
if( hasChanged )
{
hasChanged = false;
this.cachedList.resetStatus();
return this.getAvailableItems( this.cachedList );
}
return this.cachedList; return this.cachedList;
} }
@Override @Override
public T injectItems( final T input, final Actionable mode, final IActionSource src ) 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.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;
} }
@Override @Override
@@ -198,36 +188,15 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
return this.listeners.entrySet().iterator(); 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 ) private void notifyListenersOfChange( final Iterable<T> diff, final IActionSource src )
{ {
this.hasChanged = true;
final Iterator<Entry<IMEMonitorHandlerReceiver<T>, Object>> i = this.getListeners(); final Iterator<Entry<IMEMonitorHandlerReceiver<T>, Object>> i = this.getListeners();
while( i.hasNext() ) while( i.hasNext() )
{ {
final Entry<IMEMonitorHandlerReceiver<T>, Object> o = i.next(); final Entry<IMEMonitorHandlerReceiver<T>, Object> o = i.next();
final IMEMonitorHandlerReceiver<T> receiver = o.getKey(); final IMEMonitorHandlerReceiver<T> receiver = o.getKey();
if( receiver.isValid( o.getValue() ) ) if( receiver.isValid( o.getValue() ) )
{ {
receiver.postChange( this, diff, src ); receiver.postChange( this, diff, src );
@@ -239,46 +208,57 @@ 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 ) protected void postChange( final boolean add, final Iterable<T> changes, final IActionSource src )
{ {
if( this.localDepthSemaphore > 0 || GLOBAL_DEPTH.contains( this ) ) src2MonitorsMap.putIfAbsent( src, new LinkedList<>() );
if( src2MonitorsMap.get( src ).contains( this ) )
{ {
nestingSources.add( src );
return; return;
} }
src2MonitorsMap.get( src ).add( this );
GLOBAL_DEPTH.push( this );
this.localDepthSemaphore++;
this.sendEvent = true; this.sendEvent = true;
this.notifyListenersOfChange( changes, src ); for( final T change : changes )
for( final T changedItem : changes )
{ {
T difference = changedItem; //T change = changed;
if( !add && change != null )
if( !add && changedItem != null )
{ {
difference = changedItem.copy(); //change = changed.copy();
difference.setStackSize( -changedItem.getStackSize() ); 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() ) if( !list.isEmpty() )
{ {
IAEStack<T> fullStack = this.getStorageList().findPrecise( changedItem ); IAEStack<T> fullStack = this.getStorageList().findPrecise( change );
if( fullStack == null ) if( fullStack == null )
{ {
fullStack = changedItem.copy(); fullStack = change.copy();
fullStack.setStackSize( 0 ); fullStack.setStackSize( 0 );
} }
@@ -286,7 +266,7 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
for( final ItemWatcher iw : list ) 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(); this.myGridCache.getInterestManager().disableTransactions();
@@ -294,21 +274,78 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
} }
} }
final NetworkMonitor<?> last = GLOBAL_DEPTH.pop(); this.notifyListenersOfChange( changes, src );
this.localDepthSemaphore--;
if( last != this ) if( src2MonitorsMap.get( src ).getFirst() == this )
{ {
throw new IllegalStateException( "Invalid Access to Networked Storage API detected." ); boolean nested = nestingSources.contains( src );
src2MonitorsMap.get( src ).forEach( networkMonitor -> networkMonitor.isNested = nested );
src2MonitorsMap.get( src ).forEach( networkMonitor -> {
if( networkMonitor.isNested != networkMonitor.wasNested )
{
networkMonitor.wasNested = networkMonitor.isNested;
networkMonitor.setForceUpdate( true );
}
} );
src2MonitorsMap.remove( src );
nestingSources.remove( src );
} }
} }
public void setForceUpdate( boolean forceUpdate )
{
this.forceUpdate = forceUpdate;
}
void 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(); final Iterator<Entry<IMEMonitorHandlerReceiver<T>, Object>> i = this.getListeners();
while( i.hasNext() ) while ( i.hasNext() )
{ {
final Entry<IMEMonitorHandlerReceiver<T>, Object> o = i.next(); final Entry<IMEMonitorHandlerReceiver<T>, Object> o = i.next();
final IMEMonitorHandlerReceiver<T> receiver = o.getKey(); final IMEMonitorHandlerReceiver<T> receiver = o.getKey();
@@ -326,6 +363,10 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
void onTick() void onTick()
{ {
if( forceUpdate )
{
forceUpdate();
}
if( this.sendEvent ) if( this.sendEvent )
{ {
this.sendEvent = false; this.sendEvent = false;
+56 -17
View File
@@ -19,7 +19,7 @@
package appeng.me.cache; package appeng.me.cache;
import java.util.HashMap; import java.util.Collection;
import java.util.Random; import java.util.Random;
import com.google.common.collect.LinkedHashMultimap; 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 static final TunnelCollection<PartP2PTunnel> NULL_COLLECTION = new TunnelCollection<PartP2PTunnel>( null, null );
private final IGrid myGrid; 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 Multimap<Short, PartP2PTunnel> outputs = LinkedHashMultimap.create();
private final Random frequencyGenerator; private final Random frequencyGenerator;
@@ -110,10 +110,19 @@ public class P2PCache implements IGridCache
} }
else 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.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 ) private void updateTunnel( final short freq, final boolean updateOutputs, final boolean configChange )
{ {
for( final PartP2PTunnel p : this.outputs.get( freq ) ) for( final PartP2PTunnel p : this.outputs.get( freq ) )
@@ -175,8 +198,7 @@ public class P2PCache implements IGridCache
p.onTunnelNetworkChange(); p.onTunnelNetworkChange();
} }
final PartP2PTunnel in = this.inputs.get( freq ); for( final PartP2PTunnel in : this.inputs.get( freq ) )
if( in != null )
{ {
if( configChange ) if( configChange )
{ {
@@ -195,7 +217,7 @@ public class P2PCache implements IGridCache
if( this.inputs.containsValue( t ) ) if( this.inputs.containsValue( t ) )
{ {
this.inputs.remove( t.getFrequency() ); this.inputs.remove( t.getFrequency(), t );
} }
t.setFrequency( newFrequency ); t.setFrequency( newFrequency );
@@ -211,7 +233,6 @@ public class P2PCache implements IGridCache
// AELog.info( "update-" + (t.output ? "output: " : "input: ") + t.freq ); // AELog.info( "update-" + (t.output ? "output: " : "input: ") + t.freq );
this.updateTunnel( t.getFrequency(), t.isOutput(), true ); this.updateTunnel( t.getFrequency(), t.isOutput(), true );
this.updateTunnel( t.getFrequency(), !t.isOutput(), true );
} }
public short newFrequency() public short newFrequency()
@@ -236,25 +257,43 @@ public class P2PCache implements IGridCache
public TunnelCollection<PartP2PTunnel> getOutputs( final short freq, final Class<? extends PartP2PTunnel> c ) 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 ) if( in == null )
{ {
return NULL_COLLECTION; 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 ) if( out == null )
{ {
return NULL_COLLECTION; return NULL_COLLECTION;
} }
return out; TunnelCollection<PartP2PTunnel> in;
} for( PartP2PTunnel part : this.outputs.get( freq ) )
{
public PartP2PTunnel getInput( final short freq ) in = part.getCollection( this.inputs.get( freq ), c );
{ if( in != null )
return this.inputs.get( freq ); {
return in;
}
}
return NULL_COLLECTION;
} }
} }
+1 -1
View File
@@ -314,7 +314,7 @@ public class PathGridCache implements IPathingGrid
int depth = 0; int depth = 0;
for( final IGridNode nodes : this.requireChannels ) for( final IGridNode nodes : this.requireChannels )
{ {
if( !this.semiOpen.contains( nodes ) ) if( !this.semiOpen.contains( (IPathItem) nodes ) )
{ {
final IGridBlock gb = nodes.getGridBlock(); final IGridBlock gb = nodes.getGridBlock();
final EnumSet<GridFlags> flags = gb.getFlags(); final EnumSet<GridFlags> flags = gb.getFlags();
-1
View File
@@ -138,7 +138,6 @@ public class TickManagerCache implements ITickManager
tt.addEntityCrashInfo( crashreportcategory ); tt.addEntityCrashInfo( crashreportcategory );
throw new ReportedException( crashreport ); throw new ReportedException( crashreport );
} }
PartLevelEmitter.wipeCache();
} }
private void addToQueue( final TickTracker tt ) private void addToQueue( final TickTracker tt )
@@ -19,18 +19,6 @@
package appeng.me.cluster.implementations; package appeng.me.cluster.implementations;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import com.google.common.collect.ImmutableList;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
import appeng.api.AEApi; import appeng.api.AEApi;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
import appeng.api.config.FuzzyMode; import appeng.api.config.FuzzyMode;
@@ -39,14 +27,7 @@ import appeng.api.implementations.ICraftingPatternItem;
import appeng.api.networking.IGrid; import appeng.api.networking.IGrid;
import appeng.api.networking.IGridHost; import appeng.api.networking.IGridHost;
import appeng.api.networking.IGridNode; import appeng.api.networking.IGridNode;
import appeng.api.networking.crafting.CraftingItemList; import appeng.api.networking.crafting.*;
import appeng.api.networking.crafting.ICraftingCPU;
import appeng.api.networking.crafting.ICraftingGrid;
import appeng.api.networking.crafting.ICraftingJob;
import appeng.api.networking.crafting.ICraftingLink;
import appeng.api.networking.crafting.ICraftingMedium;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.networking.crafting.ICraftingRequester;
import appeng.api.networking.energy.IEnergyGrid; import appeng.api.networking.energy.IEnergyGrid;
import appeng.api.networking.events.MENetworkCraftingCpuChange; import appeng.api.networking.events.MENetworkCraftingCpuChange;
import appeng.api.networking.security.IActionSource; import appeng.api.networking.security.IActionSource;
@@ -59,11 +40,8 @@ import appeng.api.storage.data.IItemList;
import appeng.api.util.WorldCoord; import appeng.api.util.WorldCoord;
import appeng.container.ContainerNull; import appeng.container.ContainerNull;
import appeng.core.AELog; import appeng.core.AELog;
import appeng.crafting.CraftBranchFailure; import appeng.crafting.*;
import appeng.crafting.CraftingJob; import appeng.helpers.PatternHelper;
import appeng.crafting.CraftingLink;
import appeng.crafting.CraftingWatcher;
import appeng.crafting.MECraftingInventory;
import appeng.me.cache.CraftingGridCache; import appeng.me.cache.CraftingGridCache;
import appeng.me.cluster.IAECluster; import appeng.me.cluster.IAECluster;
import appeng.me.helpers.MachineSource; import appeng.me.helpers.MachineSource;
@@ -71,6 +49,17 @@ import appeng.tile.crafting.TileCraftingMonitorTile;
import appeng.tile.crafting.TileCraftingTile; import appeng.tile.crafting.TileCraftingTile;
import appeng.util.Platform; import appeng.util.Platform;
import appeng.util.item.AEItemStack; import appeng.util.item.AEItemStack;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
public final class CraftingCPUCluster implements IAECluster, ICraftingCPU public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
@@ -98,6 +87,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
private IAEItemStack finalOutput; private IAEItemStack finalOutput;
private boolean waiting = false; private boolean waiting = false;
private IItemList<IAEItemStack> waitingFor = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); private IItemList<IAEItemStack> waitingFor = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList();
private IItemList<IAEItemStack> neededForLoop = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList();
private long availableStorage = 0; private long availableStorage = 0;
private MachineSource machineSrc = null; private MachineSource machineSrc = null;
private int accelerator = 0; private int accelerator = 0;
@@ -220,20 +210,19 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
public boolean canAccept( final IAEItemStack input ) public boolean canAccept( final IAEItemStack input )
{ {
if( input instanceof IAEItemStack ) if( input != null )
{ {
final IAEItemStack is = this.waitingFor.findPrecise( input ); final IAEItemStack is = this.waitingFor.findPrecise( input );
if( is != null && is.getStackSize() > 0 ) return is != null && is.getStackSize() > 0;
{
return true;
}
} }
return false; return false;
} }
public IAEItemStack injectItems( final IAEItemStack input, final Actionable type, final IActionSource src ) 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; return input;
} }
@@ -292,15 +281,34 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{ {
is.decStackSize( what.getStackSize() ); is.decStackSize( what.getStackSize() );
this.updateElapsedTime( what ); this.updateRemainingItemCount( what );
this.markDirty(); this.markDirty();
this.postCraftingStatusChange( what.copy().setStackSize( -what.getStackSize() ) ); this.postCraftingStatusChange( what.copy().setStackSize( -what.getStackSize() ) );
if( this.finalOutput.equals( what ) ) if( this.finalOutput.equals( what ) )
{ {
IAEItemStack isLoop = neededForLoop.findPrecise( finalOutput );
IAEItemStack leftover = what; IAEItemStack leftover = what;
this.finalOutput.decStackSize( what.getStackSize() ); if( isLoop != null && isLoop.getStackSize() > 0 )
{
if( isLoop.getStackSize() >= what.getStackSize() )
{
leftover = this.inventory.injectItems( what.copy(), type, src );
isLoop.decStackSize( what.getStackSize() );
}
else
{
leftover = this.inventory.injectItems( what.copy().setStackSize( what.getStackSize() - isLoop.getStackSize() ), type, src );
isLoop.decStackSize( what.getStackSize() - isLoop.getStackSize() );
}
if( leftover == null )
{
return null;
}
}
this.finalOutput.decStackSize( leftover.getStackSize() );
if( this.myLastLink != null ) if( this.myLastLink != null )
{ {
@@ -330,9 +338,28 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
if( this.finalOutput.equals( insert ) ) if( this.finalOutput.equals( insert ) )
{ {
IAEItemStack isLoop = neededForLoop.findPrecise( finalOutput );
IAEItemStack leftover = input; IAEItemStack leftover = input;
this.finalOutput.decStackSize( insert.getStackSize() ); if( isLoop != null && isLoop.getStackSize() > 0 )
{
if( isLoop.getStackSize() >= insert.getStackSize() )
{
leftover = this.inventory.injectItems( insert.copy(), type, src );
isLoop.decStackSize( insert.getStackSize() );
}
else
{
leftover = this.inventory.injectItems( insert.copy().setStackSize( insert.getStackSize() - isLoop.getStackSize() ), type, src );
isLoop.decStackSize( insert.getStackSize() - isLoop.getStackSize() );
}
if( leftover == null )
{
return null;
}
}
this.finalOutput.decStackSize( leftover.getStackSize() );
if( this.myLastLink != null ) if( this.myLastLink != null )
{ {
@@ -370,7 +397,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{ {
final ImmutableList<IAEItemStack> single = ImmutableList.of( diff.copy() ); final ImmutableList<IAEItemStack> single = ImmutableList.of( diff.copy() );
while( i.hasNext() ) while ( i.hasNext() )
{ {
final Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object> o = i.next(); final Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object> o = i.next();
final IMEMonitorHandlerReceiver<IAEItemStack> receiver = o.getKey(); final IMEMonitorHandlerReceiver<IAEItemStack> receiver = o.getKey();
@@ -431,6 +458,11 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
AELog.crafting( LOG_MARK_AS_COMPLETE, logStack ); 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.remainingItemCount = 0;
this.startItemCount = 0; this.startItemCount = 0;
this.lastTime = 0; this.lastTime = 0;
@@ -487,10 +519,73 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
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() )
{ {
// Processing patterns are relatively easy
for( IAEItemStack input : condensedInputs )
{
final IAEItemStack ais = this.inventory.extractItems( input.copy(), Actionable.SIMULATE, this.machineSrc );
if( details.isCraftable() ) if( ais == null || ais.getStackSize() < input.getStackSize() )
{
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;
}
boolean found = false;
for( IAEItemStack substitute : substitutes )
{
for( IAEItemStack fuzz : this.inventory.getItemList().findFuzzy( substitute, FuzzyMode.IGNORE_ALL ) )
{
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;
}
}
if( found )
{
break;
}
}
if( !found )
{
return false;
}
}
}
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; boolean found = false;
@@ -500,7 +595,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
fuzz.setStackSize( g.getStackSize() ); fuzz.setStackSize( g.getStackSize() );
final IAEItemStack ais = this.inventory.extractItems( fuzz, Actionable.SIMULATE, this.machineSrc ); final IAEItemStack ais = this.inventory.extractItems( fuzz, Actionable.SIMULATE, this.machineSrc );
if (ais != null && ais.getStackSize() == g.getStackSize()) if( ais != null && ais.getStackSize() >= g.getStackSize() )
{ {
found = true; found = true;
break; break;
@@ -517,15 +612,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
return false; return false;
} }
} }
else
{
final IAEItemStack ais = this.inventory.extractItems( g.copy(), Actionable.SIMULATE, this.machineSrc );
if (ais == null || ais.getStackSize() < g.getStackSize())
{
return false;
}
}
} }
return true; return true;
@@ -608,8 +695,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{ {
this.somethingChanged = false; this.somethingChanged = false;
this.executeCrafting( eg, cc ); this.executeCrafting( eg, cc );
} } while ( this.somethingChanged && this.remainingOperations > 0 );
while( this.somethingChanged && this.remainingOperations > 0 );
} }
this.usedOps[2] = this.usedOps[1]; this.usedOps[2] = this.usedOps[1];
this.usedOps[1] = this.usedOps[0]; this.usedOps[1] = this.usedOps[0];
@@ -625,7 +711,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{ {
final Iterator<Entry<ICraftingPatternDetails, TaskProgress>> i = this.tasks.entrySet().iterator(); final Iterator<Entry<ICraftingPatternDetails, TaskProgress>> i = this.tasks.entrySet().iterator();
while( i.hasNext() ) while ( i.hasNext() )
{ {
final Entry<ICraftingPatternDetails, TaskProgress> e = i.next(); final Entry<ICraftingPatternDetails, TaskProgress> e = i.next();
@@ -641,12 +727,12 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{ {
InventoryCrafting ic = null; InventoryCrafting ic = null;
if (!visitedMediums.containsKey( details ) || visitedMediums.get( details ).isEmpty()) if( !visitedMediums.containsKey( details ) || visitedMediums.get( details ).isEmpty() )
{ {
visitedMediums.put( details, new ArrayDeque<>( cc.getMediums( details ).stream().filter( Objects::nonNull ).collect( Collectors.toList()) ) ); visitedMediums.put( details, new ArrayDeque<>( cc.getMediums( details ).stream().filter( Objects::nonNull ).collect( Collectors.toList() ) ) );
} }
while (!visitedMediums.get( details ).isEmpty()) while ( !visitedMediums.get( details ).isEmpty() )
{ {
ICraftingMedium m = visitedMediums.get( details ).poll(); ICraftingMedium m = visitedMediums.get( details ).poll();
@@ -676,8 +762,15 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{ {
continue; continue;
} }
if( details.isCraftable() )
{
ic = new InventoryCrafting( new ContainerNull(), 3, 3 );
}
else
{
ic = new InventoryCrafting( new ContainerNull(), PatternHelper.PROCESSING_INPUT_WIDTH, PatternHelper.PROCESSING_INPUT_HEIGHT );
}
ic = new InventoryCrafting( new ContainerNull(), 3, 3 );
boolean found = false; boolean found = false;
for( int x = 0; x < input.length; x++ ) for( int x = 0; x < input.length; x++ )
@@ -692,7 +785,13 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
if( details.canSubstitute() ) if( details.canSubstitute() )
{ {
itemList = this.inventory.getItemList().findFuzzy( input[x], FuzzyMode.IGNORE_ALL ); final List<IAEItemStack> substitutes = details.getSubstituteInputs( x );
itemList = new ArrayList<>( substitutes.size() );
for( IAEItemStack stack : substitutes )
{
itemList.addAll( this.inventory.getItemList().findFuzzy( stack, FuzzyMode.IGNORE_ALL ) );
}
} }
else else
{ {
@@ -828,6 +927,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
private void storeItems() private void storeItems()
{ {
Preconditions.checkState( isComplete, "CPU should be complete to prevent re-insertion when dumping items" );
final IGrid g = this.getGrid(); final IGrid g = this.getGrid();
if( g == null ) if( g == null )
@@ -838,23 +938,24 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
final IStorageGrid sg = g.getCache( IStorageGrid.class ); final IStorageGrid sg = g.getCache( IStorageGrid.class );
final IMEInventory<IAEItemStack> ii = sg.getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.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.setStackSize( remainder.getStackSize() );
is = ii.injectItems( is, Actionable.MODULATE, this.machineSrc );
} }
else
if( is != null )
{ {
this.inventory.injectItems( is, Actionable.MODULATE, this.machineSrc ); is.reset();
} }
} }
if( this.inventory.getItemList().isEmpty() ) if( itemList.isEmpty() )
{ {
this.inventory = new MECraftingInventory(); this.inventory = new MECraftingInventory();
} }
@@ -886,10 +987,12 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
try try
{ {
this.waitingFor.resetStatus(); this.waitingFor.resetStatus();
this.neededForLoop.resetStatus();
( (CraftingJob) job ).getTree().setJob( ci, this, src ); ( (CraftingJob) job ).getTree().setJob( ci, this, src );
if( ci.commit( src ) ) if( ci.commit( src ) )
{ {
this.finalOutput = job.getOutput(); this.finalOutput = job.getOutput();
this.neededForLoop = ( (CraftingJob) job ).getNeededForLoop();
this.waiting = false; this.waiting = false;
this.isComplete = false; this.isComplete = false;
this.markDirty(); this.markDirty();
@@ -939,14 +1042,12 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
@Override @Override
public boolean isBusy() 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 ) this.updateElapsedTime();
{
i.remove();
}
} }
return !this.tasks.isEmpty() || !this.waitingFor.isEmpty(); return !this.tasks.isEmpty() || !this.waitingFor.isEmpty();
@@ -1000,8 +1101,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
final int hash = System.identityHashCode( this ); final int hash = System.identityHashCode( this );
final int hmm = this.finalOutput == null ? 0 : this.finalOutput.hashCode(); final int hmm = this.finalOutput == null ? 0 : this.finalOutput.hashCode();
return Long.toString( now, Character.MAX_RADIX ) + '-' + Integer.toString( hash, Character.MAX_RADIX ) + '-' + Integer.toString( hmm, return Long.toString( now, Character.MAX_RADIX ) + '-' + Integer.toString( hash, Character.MAX_RADIX ) + '-' + Integer.toString( hmm, Character.MAX_RADIX );
Character.MAX_RADIX );
} }
private NBTTagCompound generateLinkData( final String craftingID, final boolean standalone, final boolean req ) private NBTTagCompound generateLinkData( final String craftingID, final boolean standalone, final boolean req )
@@ -1028,7 +1128,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
public void getListOfItem( final IItemList<IAEItemStack> list, final CraftingItemList whichList ) public void getListOfItem( final IItemList<IAEItemStack> list, final CraftingItemList whichList )
{ {
switch( whichList ) switch ( whichList )
{ {
case ACTIVE: case ACTIVE:
for( final IAEItemStack ais : this.waitingFor ) for( final IAEItemStack ais : this.waitingFor )
@@ -1099,7 +1199,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
{ {
IAEItemStack is; IAEItemStack is;
switch( storage2 ) switch ( storage2 )
{ {
case STORAGE: case STORAGE:
is = this.inventory.getItemList().findPrecise( what ); is = this.inventory.getItemList().findPrecise( what );
@@ -1338,12 +1438,16 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU
this.remainingItemCount = itemCount; 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(); final long nextStartTime = System.nanoTime();
this.elapsedTime = this.getElapsedTime() + nextStartTime - this.lastTime; this.elapsedTime = this.getElapsedTime() + nextStartTime - this.lastTime;
this.lastTime = nextStartTime; this.lastTime = nextStartTime;
this.remainingItemCount = this.getRemainingItemCount() - is.getStackSize();
} }
public long getElapsedTime() public long getElapsedTime()
@@ -123,4 +123,4 @@ public class GenericInterestManager<T>
this.iw = watcher; this.iw = watcher;
} }
} }
} }
@@ -28,8 +28,6 @@ import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map.Entry; import java.util.Map.Entry;
import com.google.common.collect.ImmutableList;
import appeng.api.config.AccessRestriction; import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
import appeng.api.networking.security.IActionSource; import appeng.api.networking.security.IActionSource;
@@ -85,11 +83,7 @@ public class MEMonitorHandler<T extends IAEStack<T>> implements IMEMonitor<T>
@Override @Override
public T injectItems( final T input, final Actionable mode, final IActionSource src ) 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.getHandler().injectItems( input, mode, src );
}
return this.monitorDifference( input.copy(), this.getHandler().injectItems( input, mode, src ), false, src );
} }
protected IMEInventoryHandler<T> getHandler() protected IMEInventoryHandler<T> getHandler()
@@ -97,28 +91,7 @@ public class MEMonitorHandler<T extends IAEStack<T>> implements IMEMonitor<T>
return this.internalHandler; return this.internalHandler;
} }
private T monitorDifference( final T original, final T leftOvers, final boolean extraction, final IActionSource src ) public void postChangesToListeners( final Iterable<T> changes, 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 )
{ {
this.notifyListenersOfChange( changes, src ); this.notifyListenersOfChange( changes, src );
} }
@@ -150,11 +123,7 @@ public class MEMonitorHandler<T extends IAEStack<T>> implements IMEMonitor<T>
@Override @Override
public T extractItems( final T request, final Actionable mode, final IActionSource src ) 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.getHandler().extractItems( request, mode, src );
}
return this.monitorDifference( request.copy(), this.getHandler().extractItems( request, mode, src ), true, src );
} }
@Override @Override
@@ -19,6 +19,7 @@
package appeng.me.helpers; package appeng.me.helpers;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
@@ -55,4 +56,24 @@ public class MachineSource implements IActionSource
return Optional.empty(); 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 );
}
} }

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