Compare commits
201 Commits
a03c2d5eb4
...
ddab73bad1
Author | SHA1 | Date | |
---|---|---|---|
ddab73bad1 | |||
3e5f47c9a3 | |||
f57ccafcfa | |||
f82c7977fa | |||
640aeabb07 | |||
c98a1573aa | |||
072d2187f8 | |||
2d1c9184f4 | |||
c93fa7bb7a | |||
4db52b83c4 | |||
571c7bc339 | |||
f5e21f5582 | |||
8454db6785 | |||
78fad5d3cc | |||
3e593748f7 | |||
3fab525345 | |||
af24f391df | |||
10421570be | |||
4d51ed5210 | |||
39a996f79f | |||
a26840f670 | |||
5281a5aeee | |||
750f941525 | |||
7405989b97 | |||
140bdab59c | |||
c2f20a76f6 | |||
a3ed886900 | |||
1087e755ff | |||
c965bcdc82 | |||
5663b262eb | |||
e93c766edb | |||
85dde24e59 | |||
4fc646a13a | |||
9f8e7693a8 | |||
65bbc56014 | |||
524c36aade | |||
faba736bd7 | |||
17dfa953db | |||
d17e64f335 | |||
eed3b04555 | |||
6cf218a184 | |||
45181c9e55 | |||
01d3cbf7b2 | |||
be2011cf96 | |||
9413ae5f2b | |||
dc73ac7b55 | |||
a6361f10f2 | |||
f16b003cdf | |||
07e0c73479 | |||
2547478914 | |||
dcff861e71 | |||
9be8596a5f | |||
29c51617b9 | |||
70ed0cfcba | |||
65bf4dc9d0 | |||
5b1ae12f85 | |||
85c4aa4dc4 | |||
bd4622fc0d | |||
36f6a12395 | |||
06a621d370 | |||
d6f53946d9 | |||
091ffc8c9f | |||
f7a4623830 | |||
c9dca76870 | |||
ef2602895b | |||
0a0b0e3819 | |||
8f40717ff6 | |||
d48dbf3ec9 | |||
a84df28cf8 | |||
03c64425a9 | |||
d41d331e0f | |||
d89d5b9672 | |||
ee4b12e687 | |||
95f19bc18f | |||
d5a9632c97 | |||
cf32fd9d2a | |||
427b5f9179 | |||
fd9960bd86 | |||
7c6d58b782 | |||
5d15425fa4 | |||
0efc520782 | |||
8b38504a26 | |||
69d9aaab50 | |||
448041fe2e | |||
54012cf136 | |||
70c5382e9d | |||
01215d647c | |||
3a5f37bd76 | |||
4ab667b37e | |||
2943026dd5 | |||
90a22a093d | |||
c43be6eb62 | |||
59eab74b44 | |||
bdeb740df0 | |||
621661c9fe | |||
d0904da1db | |||
05bdff6a37 | |||
b076d29560 | |||
a2263c5725 | |||
d57371ca13 | |||
305ddbd0d4 | |||
b42a503096 | |||
ade2c0499d | |||
e699147f9f | |||
4dad60dfbb | |||
55c3c16172 | |||
1455e12da3 | |||
566538f8a7 | |||
c08ea8a43d | |||
1f8cd2cfe3 | |||
a2b2acd3f0 | |||
8d58dfff14 | |||
5e1ae7e77d | |||
17e4856b10 | |||
847ec81928 | |||
5e23300ddf | |||
6d14e6a396 | |||
bb77ecddb0 | |||
00830c2986 | |||
b4eb0f7056 | |||
101bf52113 | |||
54c2964deb | |||
762926d2cc | |||
4107ec2313 | |||
af4123990f | |||
45651d81b5 | |||
ebc49b03c4 | |||
b4977ea6ae | |||
51be2c89f4 | |||
d88da8f244 | |||
bbf4e752e7 | |||
f011c1a912 | |||
e3a11b3b9e | |||
784930e396 | |||
3e086dcacf | |||
fbd34f3414 | |||
67fc8f99f6 | |||
06f8d8838a | |||
d1a9825ea8 | |||
caa8d1bb90 | |||
6c42af9f30 | |||
16d492073b | |||
cfd64fac07 | |||
8967d3aafa | |||
e0e1ba864d | |||
e8ba5916b1 | |||
f8e9a67994 | |||
bc2cfccffe | |||
a73ad5484d | |||
84d4ed78ea | |||
7a4ce4f394 | |||
c31549792e | |||
5422f0fec8 | |||
c376a99da0 | |||
9806e1ec52 | |||
de79019f56 | |||
efbc93e16a | |||
861b94a30a | |||
83d11d531d | |||
45a32dce3c | |||
3910e38add | |||
5942ab2126 | |||
8696d268ad | |||
8aae573110 | |||
892beddfc6 | |||
14e6ee4916 | |||
d558252db9 | |||
7f9af78734 | |||
d76f2fe015 | |||
70bfa114c8 | |||
a5b96fa4c4 | |||
cff5988767 | |||
6e7b90a8e8 | |||
edb3aa657d | |||
6e5e64baeb | |||
3ed935001b | |||
4292713874 | |||
1b5476de40 | |||
bf7c9277ee | |||
a6891362d9 | |||
2b2f78e528 | |||
454783a99a | |||
d2ff43946e | |||
abf74e4a2b | |||
66a4adecf9 | |||
1702f95370 | |||
f79b49d422 | |||
30263bf30e | |||
ffdd44357d | |||
5e8ab76f49 | |||
9f6b9ad85b | |||
ab1446b682 | |||
6764af0dcc | |||
6747d5f471 | |||
124a1b3db6 | |||
a0b04fc1f4 | |||
8a4abb90bd | |||
fc1d9d6448 | |||
b39c82e79a | |||
b1b6843400 | |||
ca6ff30414 |
@ -22,7 +22,7 @@ mixin_version=0.8.5
|
|||||||
neogradle.subsystems.parchment.minecraftVersion=1.21.1
|
neogradle.subsystems.parchment.minecraftVersion=1.21.1
|
||||||
neogradle.subsystems.parchment.mappingsVersion=2024.11.17
|
neogradle.subsystems.parchment.mappingsVersion=2024.11.17
|
||||||
|
|
||||||
kommons_version=3.5.2
|
kommons_version=3.6.0
|
||||||
caffeine_cache_version=3.1.5
|
caffeine_cache_version=3.1.5
|
||||||
|
|
||||||
jei_version=19.16.4.171
|
jei_version=19.16.4.171
|
||||||
|
@ -631,6 +631,8 @@ private fun blocks(provider: MatteryLanguageProvider) {
|
|||||||
add(MBlocks.ENERGY_COUNTER[null]!!, "switch", "Switch input facing")
|
add(MBlocks.ENERGY_COUNTER[null]!!, "switch", "Switch input facing")
|
||||||
add(MBlocks.ENERGY_COUNTER[null]!!, "limit", "I/O Limit. -1 means no limit")
|
add(MBlocks.ENERGY_COUNTER[null]!!, "limit", "I/O Limit. -1 means no limit")
|
||||||
add(MBlocks.ENERGY_COUNTER[null]!!, "display_this", "Display this information on block's screen")
|
add(MBlocks.ENERGY_COUNTER[null]!!, "display_this", "Display this information on block's screen")
|
||||||
|
add(MBlocks.ENERGY_COUNTER[null]!!, "do_pull", "Pull energy from input side and push to output")
|
||||||
|
add(MBlocks.ENERGY_COUNTER[null]!!, "dont_pull", "Don't pull energy")
|
||||||
|
|
||||||
addBlock(MBlocks.CHEMICAL_GENERATOR.values, "Chemical Generator")
|
addBlock(MBlocks.CHEMICAL_GENERATOR.values, "Chemical Generator")
|
||||||
addBlock(MBlocks.CHEMICAL_GENERATOR.values, "desc", "Generates power by burning solid fuels")
|
addBlock(MBlocks.CHEMICAL_GENERATOR.values, "desc", "Generates power by burning solid fuels")
|
||||||
@ -987,6 +989,18 @@ private fun androidFeatures(provider: MatteryLanguageProvider) {
|
|||||||
|
|
||||||
private fun gui(provider: MatteryLanguageProvider) {
|
private fun gui(provider: MatteryLanguageProvider) {
|
||||||
with(provider.english) {
|
with(provider.english) {
|
||||||
|
gui("quickmove_from.restock", "Restock from storage")
|
||||||
|
gui("quickmove_from.restock_with_move", "Quickstack from storage")
|
||||||
|
gui("quickmove_from.move", "Take all")
|
||||||
|
|
||||||
|
gui("quickmove_to.restock", "Restock to storage")
|
||||||
|
gui("quickmove_to.restock_with_move", "Quickstack to storage")
|
||||||
|
gui("quickmove_to.move", "Deposit all")
|
||||||
|
gui("quickmove.exchange", "Smart exchange with storage")
|
||||||
|
gui("quickmove.exchange.desc", "Filtered slots get restocked, everything else gets quickstacked from Exopack")
|
||||||
|
|
||||||
|
gui("quickmove_hint", "Right click to show all variants")
|
||||||
|
|
||||||
gui("exopack.accept_wireless_charge", "Accept wireless charging")
|
gui("exopack.accept_wireless_charge", "Accept wireless charging")
|
||||||
gui("exopack.dont_accept_wireless_charge", "Do not accept wireless charging")
|
gui("exopack.dont_accept_wireless_charge", "Do not accept wireless charging")
|
||||||
|
|
||||||
|
@ -635,6 +635,8 @@ private fun blocks(provider: MatteryLanguageProvider) {
|
|||||||
add(MBlocks.ENERGY_COUNTER[null]!!, "switch", "Сменить сторону входа")
|
add(MBlocks.ENERGY_COUNTER[null]!!, "switch", "Сменить сторону входа")
|
||||||
add(MBlocks.ENERGY_COUNTER[null]!!, "limit", "Лимит ввода/вывода. -1 для отключения лимитов")
|
add(MBlocks.ENERGY_COUNTER[null]!!, "limit", "Лимит ввода/вывода. -1 для отключения лимитов")
|
||||||
add(MBlocks.ENERGY_COUNTER[null]!!, "display_this", "Отображать эти данные на экране блока")
|
add(MBlocks.ENERGY_COUNTER[null]!!, "display_this", "Отображать эти данные на экране блока")
|
||||||
|
add(MBlocks.ENERGY_COUNTER[null]!!, "do_pull", "Забирать энергию на входе и выталкивать её на выходе")
|
||||||
|
add(MBlocks.ENERGY_COUNTER[null]!!, "dont_pull", "Не забирать энергию на входе")
|
||||||
|
|
||||||
addBlock(MBlocks.CHEMICAL_GENERATOR.values, "Химический генератор")
|
addBlock(MBlocks.CHEMICAL_GENERATOR.values, "Химический генератор")
|
||||||
addBlock(MBlocks.CHEMICAL_GENERATOR.values, "desc", "Генерирует энергию сжигая твёрдое топливо")
|
addBlock(MBlocks.CHEMICAL_GENERATOR.values, "desc", "Генерирует энергию сжигая твёрдое топливо")
|
||||||
@ -980,6 +982,18 @@ private fun androidFeatures(provider: MatteryLanguageProvider) {
|
|||||||
|
|
||||||
private fun gui(provider: MatteryLanguageProvider) {
|
private fun gui(provider: MatteryLanguageProvider) {
|
||||||
with(provider.russian) {
|
with(provider.russian) {
|
||||||
|
gui("quickmove_from.restock", "Быстрое пополнение из хранилища")
|
||||||
|
gui("quickmove_from.restock_with_move", "Быстрое складирование из хранилища")
|
||||||
|
gui("quickmove_from.move", "Взять всё")
|
||||||
|
|
||||||
|
gui("quickmove_to.restock", "Быстрое пополнение в хранилище")
|
||||||
|
gui("quickmove_to.restock_with_move", "Быстрое складирование в хранилище")
|
||||||
|
gui("quickmove_to.move", "Переместить всё")
|
||||||
|
gui("quickmove.exchange", "Умный обмен с хранилищем")
|
||||||
|
gui("quickmove.exchange.desc", "Слоты с фильтрами заполняются до максимума, всё остальное быстро складируется из экзопака")
|
||||||
|
|
||||||
|
gui("quickmove_hint", "Правый клик чтоб увидеть все варианты")
|
||||||
|
|
||||||
gui("exopack.accept_wireless_charge", "Принимать заряд от беспроводных зарядников")
|
gui("exopack.accept_wireless_charge", "Принимать заряд от беспроводных зарядников")
|
||||||
gui("exopack.dont_accept_wireless_charge", "Не принимать заряд от беспроводных зарядников")
|
gui("exopack.dont_accept_wireless_charge", "Не принимать заряд от беспроводных зарядников")
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@ import ru.dbotthepony.mc.otm.capability.matter.IReplicationTaskProvider;
|
|||||||
import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage;
|
import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage;
|
||||||
import ru.dbotthepony.mc.otm.graph.matter.MatterNode;
|
import ru.dbotthepony.mc.otm.graph.matter.MatterNode;
|
||||||
import ru.dbotthepony.mc.otm.graph.storage.StorageNode;
|
import ru.dbotthepony.mc.otm.graph.storage.StorageNode;
|
||||||
import ru.dbotthepony.mc.otm.storage.StorageStack;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
@ -70,4 +69,8 @@ public class MatteryCapability {
|
|||||||
@Nonnull
|
@Nonnull
|
||||||
@NotNull
|
@NotNull
|
||||||
public static final ItemCapability<IMatteryUpgrade, Void> UPGRADE = ItemCapability.createVoid(ResourceLocation.fromNamespaceAndPath(OverdriveThatMatters.MOD_ID, "machine_upgrade"), IMatteryUpgrade.class);
|
public static final ItemCapability<IMatteryUpgrade, Void> UPGRADE = ItemCapability.createVoid(ResourceLocation.fromNamespaceAndPath(OverdriveThatMatters.MOD_ID, "machine_upgrade"), IMatteryUpgrade.class);
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@NotNull
|
||||||
|
public static final BlockCapability<IQuickStackContainer, Void> QUICK_STACK_CONTAINER = BlockCapability.createVoid(ResourceLocation.fromNamespaceAndPath(OverdriveThatMatters.MOD_ID, "quick_stack_container"), IQuickStackContainer.class);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.mixin;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
|
import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
|
import ru.dbotthepony.mc.otm.compat.vanilla.MatteryShulkerBoxMenu;
|
||||||
|
|
||||||
|
@Mixin(ShulkerBoxBlockEntity.class)
|
||||||
|
public abstract class ShulkerBoxBlockEntityMixin {
|
||||||
|
@Overwrite(remap = false)
|
||||||
|
public AbstractContainerMenu createMenu(int p_59312_, Inventory p_59313_) {
|
||||||
|
return new MatteryShulkerBoxMenu(p_59312_, p_59313_, (ShulkerBoxBlockEntity) (Object) this);
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,8 @@ import ru.dbotthepony.mc.otm.player.android.AndroidResearchResults
|
|||||||
import ru.dbotthepony.mc.otm.player.android.feature.EnderTeleporterFeature
|
import ru.dbotthepony.mc.otm.player.android.feature.EnderTeleporterFeature
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.decorative.DevChestBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.decorative.DevChestBlockEntity
|
||||||
|
import ru.dbotthepony.mc.otm.block.entity.tech.AbstractPoweredFurnaceBlockEntity
|
||||||
|
import ru.dbotthepony.mc.otm.block.entity.tech.PlatePressBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.player.MatteryPlayer
|
import ru.dbotthepony.mc.otm.player.MatteryPlayer
|
||||||
import ru.dbotthepony.mc.otm.capability.drive.DrivePool
|
import ru.dbotthepony.mc.otm.capability.drive.DrivePool
|
||||||
import ru.dbotthepony.mc.otm.client.AndroidAbilityKeyMapping
|
import ru.dbotthepony.mc.otm.client.AndroidAbilityKeyMapping
|
||||||
@ -41,6 +43,7 @@ import ru.dbotthepony.mc.otm.client.render.blockentity.MatterBatteryBankRenderer
|
|||||||
import ru.dbotthepony.mc.otm.compat.curios.isCuriosLoaded
|
import ru.dbotthepony.mc.otm.compat.curios.isCuriosLoaded
|
||||||
import ru.dbotthepony.mc.otm.compat.curios.onCuriosSlotModifiersUpdated
|
import ru.dbotthepony.mc.otm.compat.curios.onCuriosSlotModifiersUpdated
|
||||||
import ru.dbotthepony.mc.otm.compat.vanilla.MatteryChestMenu
|
import ru.dbotthepony.mc.otm.compat.vanilla.MatteryChestMenu
|
||||||
|
import ru.dbotthepony.mc.otm.compat.vanilla.VanillaMenuTypes
|
||||||
import ru.dbotthepony.mc.otm.config.PlayerConfig
|
import ru.dbotthepony.mc.otm.config.PlayerConfig
|
||||||
import ru.dbotthepony.mc.otm.config.CablesConfig
|
import ru.dbotthepony.mc.otm.config.CablesConfig
|
||||||
import ru.dbotthepony.mc.otm.config.ClientConfig
|
import ru.dbotthepony.mc.otm.config.ClientConfig
|
||||||
@ -49,6 +52,7 @@ import ru.dbotthepony.mc.otm.config.ItemsConfig
|
|||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.config.ServerConfig
|
import ru.dbotthepony.mc.otm.config.ServerConfig
|
||||||
import ru.dbotthepony.mc.otm.config.ToolsConfig
|
import ru.dbotthepony.mc.otm.config.ToolsConfig
|
||||||
|
import ru.dbotthepony.mc.otm.container.ItemFilter
|
||||||
import ru.dbotthepony.mc.otm.data.FlywheelMaterials
|
import ru.dbotthepony.mc.otm.data.FlywheelMaterials
|
||||||
import ru.dbotthepony.mc.otm.data.world.BooleanProvider
|
import ru.dbotthepony.mc.otm.data.world.BooleanProvider
|
||||||
import ru.dbotthepony.mc.otm.data.world.DecimalProvider
|
import ru.dbotthepony.mc.otm.data.world.DecimalProvider
|
||||||
@ -131,7 +135,7 @@ object OverdriveThatMatters {
|
|||||||
MLootNumberProviders.register(MOD_BUS)
|
MLootNumberProviders.register(MOD_BUS)
|
||||||
|
|
||||||
StorageStack.register(MOD_BUS)
|
StorageStack.register(MOD_BUS)
|
||||||
MatteryChestMenu.register(MOD_BUS)
|
VanillaMenuTypes.register(MOD_BUS)
|
||||||
|
|
||||||
MCreativeTabs.initialize(MOD_BUS)
|
MCreativeTabs.initialize(MOD_BUS)
|
||||||
|
|
||||||
@ -146,6 +150,7 @@ object OverdriveThatMatters {
|
|||||||
|
|
||||||
AbstractRegistryAction.register(MOD_BUS)
|
AbstractRegistryAction.register(MOD_BUS)
|
||||||
IMatterFunction.register(MOD_BUS)
|
IMatterFunction.register(MOD_BUS)
|
||||||
|
ItemFilter.register(MOD_BUS)
|
||||||
|
|
||||||
MRegistry.initialize(MOD_BUS)
|
MRegistry.initialize(MOD_BUS)
|
||||||
MatterManager.initialize(MOD_BUS)
|
MatterManager.initialize(MOD_BUS)
|
||||||
@ -247,6 +252,9 @@ object OverdriveThatMatters {
|
|||||||
|
|
||||||
FORGE_BUS.addListener(EventPriority.NORMAL, MStructureTags::registerVillagerTrades)
|
FORGE_BUS.addListener(EventPriority.NORMAL, MStructureTags::registerVillagerTrades)
|
||||||
|
|
||||||
|
FORGE_BUS.addListener(EventPriority.LOWEST, PlatePressBlockEntity::onReload)
|
||||||
|
FORGE_BUS.addListener(EventPriority.LOWEST, AbstractPoweredFurnaceBlockEntity.Companion::onReload)
|
||||||
|
|
||||||
if (isCuriosLoaded) {
|
if (isCuriosLoaded) {
|
||||||
FORGE_BUS.addListener(EventPriority.NORMAL, ::onCuriosSlotModifiersUpdated)
|
FORGE_BUS.addListener(EventPriority.NORMAL, ::onCuriosSlotModifiersUpdated)
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@ import net.minecraft.network.chat.Component
|
|||||||
import net.minecraft.network.chat.ComponentSerialization
|
import net.minecraft.network.chat.ComponentSerialization
|
||||||
import net.minecraft.server.level.ServerLevel
|
import net.minecraft.server.level.ServerLevel
|
||||||
import net.minecraft.util.RandomSource
|
import net.minecraft.util.RandomSource
|
||||||
import net.minecraft.world.Containers
|
|
||||||
import net.minecraft.world.InteractionResult
|
import net.minecraft.world.InteractionResult
|
||||||
import net.minecraft.world.MenuProvider
|
import net.minecraft.world.MenuProvider
|
||||||
import net.minecraft.world.entity.LivingEntity
|
import net.minecraft.world.entity.LivingEntity
|
||||||
@ -36,8 +35,6 @@ import net.minecraft.world.phys.shapes.VoxelShape
|
|||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import ru.dbotthepony.mc.otm.block.entity.IRedstoneControlled
|
import ru.dbotthepony.mc.otm.block.entity.IRedstoneControlled
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity.Companion
|
|
||||||
import ru.dbotthepony.mc.otm.block.entity.WorkerState
|
import ru.dbotthepony.mc.otm.block.entity.WorkerState
|
||||||
import ru.dbotthepony.mc.otm.core.TooltipList
|
import ru.dbotthepony.mc.otm.core.TooltipList
|
||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
@ -149,6 +146,9 @@ open class MatteryBlock(properties: Properties = DEFAULT_PROPERTIES) : Block(pro
|
|||||||
return getShapeForEachState(ArrayList(stateDefinition.properties), mapper)
|
return getShapeForEachState(ArrayList(stateDefinition.properties), mapper)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected open val neverOpensAMenu: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
override fun useWithoutItem(
|
override fun useWithoutItem(
|
||||||
blockState: BlockState,
|
blockState: BlockState,
|
||||||
level: Level,
|
level: Level,
|
||||||
@ -156,18 +156,17 @@ open class MatteryBlock(properties: Properties = DEFAULT_PROPERTIES) : Block(pro
|
|||||||
ply: Player,
|
ply: Player,
|
||||||
blockHitResult: BlockHitResult
|
blockHitResult: BlockHitResult
|
||||||
): InteractionResult {
|
): InteractionResult {
|
||||||
if (this is EntityBlock && !level.isClientSide) {
|
if (!neverOpensAMenu && this is EntityBlock) {
|
||||||
val tile = level.getBlockEntity(blockPos)
|
val tile = level.getBlockEntity(blockPos)
|
||||||
|
|
||||||
if (tile is MenuProvider) {
|
if (tile is MenuProvider) {
|
||||||
ply.openMenu(tile)
|
if (!level.isClientSide)
|
||||||
return InteractionResult.CONSUME
|
ply.openMenu(tile)
|
||||||
|
|
||||||
|
return InteractionResult.sidedSuccess(level.isClientSide)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this is EntityBlock && level.isClientSide)
|
|
||||||
return InteractionResult.SUCCESS
|
|
||||||
|
|
||||||
return super.useWithoutItem(blockState, level, blockPos, ply, blockHitResult)
|
return super.useWithoutItem(blockState, level, blockPos, ply, blockHitResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +117,10 @@ class ExperienceStorage(val maxExperience: DoubleSupplier = DoubleSupplier { Dou
|
|||||||
experience = (nbt?.asDouble ?: 0.0).coerceAtLeast(0.0)
|
experience = (nbt?.asDouble ?: 0.0).coerceAtLeast(0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val liquidXPMilliBuckets: Int get() {
|
||||||
|
return (experience * XP_TO_LIQUID_RATIO).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
override fun getTanks(): Int {
|
override fun getTanks(): Int {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@ -125,7 +129,7 @@ class ExperienceStorage(val maxExperience: DoubleSupplier = DoubleSupplier { Dou
|
|||||||
if (tank != 0)
|
if (tank != 0)
|
||||||
return FluidStack.EMPTY
|
return FluidStack.EMPTY
|
||||||
|
|
||||||
return FluidStack(MFluids.LIQUID_XP, (experience * XP_TO_LIQUID_RATIO).toInt())
|
return FluidStack(MFluids.LIQUID_XP, liquidXPMilliBuckets)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTankCapacity(tank: Int): Int {
|
override fun getTankCapacity(tank: Int): Int {
|
||||||
@ -148,13 +152,13 @@ class ExperienceStorage(val maxExperience: DoubleSupplier = DoubleSupplier { Dou
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun drain(maxDrain: Int, action: IFluidHandler.FluidAction): FluidStack {
|
override fun drain(maxDrain: Int, action: IFluidHandler.FluidAction): FluidStack {
|
||||||
val actualDrain = maxDrain.coerceAtMost((experience * XP_TO_LIQUID_RATIO).toInt()).let { it / XP_TO_LIQUID_RATIO * XP_TO_LIQUID_RATIO }
|
val actualDrain = maxDrain.coerceAtMost(liquidXPMilliBuckets)
|
||||||
|
|
||||||
if (actualDrain <= 0)
|
if (actualDrain <= 0)
|
||||||
return FluidStack.EMPTY
|
return FluidStack.EMPTY
|
||||||
|
|
||||||
if (action.execute())
|
if (action.execute())
|
||||||
experience -= actualDrain / XP_TO_LIQUID_RATIO
|
experience -= actualDrain.toDouble() / XP_TO_LIQUID_RATIO
|
||||||
|
|
||||||
return FluidStack(MFluids.LIQUID_XP, actualDrain)
|
return FluidStack(MFluids.LIQUID_XP, actualDrain)
|
||||||
}
|
}
|
||||||
|
@ -6,13 +6,12 @@ import net.minecraft.world.level.block.state.BlockState
|
|||||||
import ru.dbotthepony.mc.otm.capability.energy
|
import ru.dbotthepony.mc.otm.capability.energy
|
||||||
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.capability.extractEnergy
|
import ru.dbotthepony.mc.otm.capability.extractEnergy
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
|
|
||||||
abstract class MatteryPoweredBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(p_155228_, p_155229_, p_155230_) {
|
abstract class MatteryPoweredBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(p_155228_, p_155229_, p_155230_) {
|
||||||
val batteryContainer = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
|
val batteryContainer = SlottedContainer.simple(1, AutomationFilters.DISCHARGABLE.filteredProvider, ::markDirtyFast).also(::addDroppableContainer)
|
||||||
val batteryItemHandler = batteryContainer.handler(HandlerFilter.Dischargeable)
|
|
||||||
open val energy: IMatteryEnergyStorage?
|
open val energy: IMatteryEnergyStorage?
|
||||||
get() = null
|
get() = null
|
||||||
|
|
||||||
|
@ -17,12 +17,16 @@ import net.minecraft.world.level.gameevent.GameEvent
|
|||||||
import net.neoforged.neoforge.capabilities.Capabilities
|
import net.neoforged.neoforge.capabilities.Capabilities
|
||||||
import ru.dbotthepony.mc.otm.block.decorative.CargoCrateBlock
|
import ru.dbotthepony.mc.otm.block.decorative.CargoCrateBlock
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.capability.IQuickStackContainer
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
import ru.dbotthepony.mc.otm.core.otmRandom
|
import ru.dbotthepony.mc.otm.core.otmRandom
|
||||||
|
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
||||||
import ru.dbotthepony.mc.otm.core.util.BlockLootTableHolder
|
import ru.dbotthepony.mc.otm.core.util.BlockLootTableHolder
|
||||||
import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu
|
import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu
|
||||||
|
import ru.dbotthepony.mc.otm.menu.makeSlots
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MSoundEvents
|
import ru.dbotthepony.mc.otm.registry.game.MSoundEvents
|
||||||
|
|
||||||
@ -30,20 +34,28 @@ class CargoCrateBlockEntity(
|
|||||||
p_155229_: BlockPos,
|
p_155229_: BlockPos,
|
||||||
p_155230_: BlockState
|
p_155230_: BlockState
|
||||||
) : MatteryDeviceBlockEntity(MBlockEntities.CARGO_CRATE, p_155229_, p_155230_) {
|
) : MatteryDeviceBlockEntity(MBlockEntities.CARGO_CRATE, p_155229_, p_155230_) {
|
||||||
val container = MatteryContainer(this::setChanged, CAPACITY).also(::addDroppableContainer)
|
private inner class Slot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) {
|
||||||
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
|
return super<FilteredContainerSlot>.canAutomationPlaceItem(itemStack) && loot.lootTable == null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canAutomationTakeItem(desired: Int): Boolean {
|
||||||
|
return super.canAutomationTakeItem(desired) && loot.lootTable == null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val container = SlottedContainer.Builder()
|
||||||
|
.add(CAPACITY, ::Slot)
|
||||||
|
.onChanged(::setChanged)
|
||||||
|
.build()
|
||||||
|
.also(::addDroppableContainer)
|
||||||
|
|
||||||
|
init {
|
||||||
|
exposeSideless(MatteryCapability.QUICK_STACK_CONTAINER, IQuickStackContainer.Simple(makeSlots(container, ::MatteryMenuSlot)))
|
||||||
|
}
|
||||||
|
|
||||||
private var interactingPlayers = 0
|
private var interactingPlayers = 0
|
||||||
|
|
||||||
val handler = container.handler(object : HandlerFilter {
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return loot.lootTable == null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
|
||||||
return loot.lootTable == null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
override fun dropItems(
|
override fun dropItems(
|
||||||
oldBlockState: BlockState,
|
oldBlockState: BlockState,
|
||||||
level: ServerLevel,
|
level: ServerLevel,
|
||||||
@ -81,7 +93,7 @@ class CargoCrateBlockEntity(
|
|||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
exposeGlobally(Capabilities.ItemHandler.BLOCK, handler)
|
exposeGlobally(Capabilities.ItemHandler.BLOCK, container)
|
||||||
savetablesLevel.stateful(::container, INVENTORY_KEY)
|
savetablesLevel.stateful(::container, INVENTORY_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,9 +18,12 @@ import ru.dbotthepony.mc.otm.capability.item.CombinedItemHandler
|
|||||||
import ru.dbotthepony.mc.otm.capability.fluid.BlockMatteryFluidHandler
|
import ru.dbotthepony.mc.otm.capability.fluid.BlockMatteryFluidHandler
|
||||||
import ru.dbotthepony.mc.otm.capability.moveFluid
|
import ru.dbotthepony.mc.otm.capability.moveFluid
|
||||||
import ru.dbotthepony.mc.otm.config.ItemsConfig
|
import ru.dbotthepony.mc.otm.config.ItemsConfig
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
|
||||||
import ru.dbotthepony.mc.otm.container.get
|
import ru.dbotthepony.mc.otm.container.get
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilter
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||||
import ru.dbotthepony.mc.otm.core.isNotSameAs
|
import ru.dbotthepony.mc.otm.core.isNotSameAs
|
||||||
import ru.dbotthepony.mc.otm.menu.decorative.FluidTankMenu
|
import ru.dbotthepony.mc.otm.menu.decorative.FluidTankMenu
|
||||||
@ -37,28 +40,42 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
|
|||||||
}
|
}
|
||||||
}), FluidStack.OPTIONAL_STREAM_CODEC.wrap()))
|
}), FluidStack.OPTIONAL_STREAM_CODEC.wrap()))
|
||||||
|
|
||||||
val fillInput = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
|
private inner class FillSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) {
|
||||||
val drainInput = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
val output = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
|
if (!super.canAutomationPlaceItem(itemStack))
|
||||||
|
return false
|
||||||
|
|
||||||
|
if (fluid.isEmpty) {
|
||||||
|
return itemStack.getCapability(Capabilities.FluidHandler.ITEM)?.let { it.tanks > 0 } ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemStack.getCapability(Capabilities.FluidHandler.ITEM)?.let { it.fill(fluid[0], IFluidHandler.FluidAction.SIMULATE) > 0 } ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canAutomationTakeItem(desired: Int): Boolean {
|
||||||
|
return super.canAutomationTakeItem(desired) && !canAutomationPlaceItem(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val inputContainer = SlottedContainer.Builder()
|
||||||
|
.add(DRAIN_TAG, AutomationFilters.DRAINABLE_FLUID_CONTAINERS.filteredProvider)
|
||||||
|
.add(FILL_TAG, ::FillSlot)
|
||||||
|
.onChanged(::markDirtyFast)
|
||||||
|
.build()
|
||||||
|
.also(::addDroppableContainer)
|
||||||
|
|
||||||
|
val outputContainer = SlottedContainer.Builder()
|
||||||
|
.add(AutomationFilters.ONLY_OUT.simpleProvider)
|
||||||
|
.onChanged(::markDirtyFast)
|
||||||
|
.build()
|
||||||
|
.also(::addDroppableContainer)
|
||||||
|
|
||||||
|
private val fillSlot = inputContainer[FILL_TAG]
|
||||||
|
private val drainSlot = inputContainer[DRAIN_TAG]
|
||||||
|
|
||||||
val itemConfig = ConfigurableItemHandler(
|
val itemConfig = ConfigurableItemHandler(
|
||||||
input = CombinedItemHandler(
|
input = inputContainer,
|
||||||
drainInput.handler(HandlerFilter.DrainableFluidContainers),
|
output = outputContainer,
|
||||||
fillInput.handler(object : HandlerFilter {
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
if (fluid.isEmpty) {
|
|
||||||
return stack.getCapability(Capabilities.FluidHandler.ITEM)?.let { it.tanks > 0 } ?: false
|
|
||||||
}
|
|
||||||
|
|
||||||
return stack.getCapability(Capabilities.FluidHandler.ITEM)?.let { it.fill(fluid[0], IFluidHandler.FluidAction.SIMULATE) > 0 } ?: false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
|
||||||
return !canInsert(slot, stack)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
),
|
|
||||||
output = output.handler(HandlerFilter.OnlyOut),
|
|
||||||
frontDefault = ItemHandlerMode.INPUT_OUTPUT,
|
frontDefault = ItemHandlerMode.INPUT_OUTPUT,
|
||||||
backDefault = ItemHandlerMode.INPUT_OUTPUT,
|
backDefault = ItemHandlerMode.INPUT_OUTPUT,
|
||||||
leftDefault = ItemHandlerMode.INPUT_OUTPUT,
|
leftDefault = ItemHandlerMode.INPUT_OUTPUT,
|
||||||
@ -71,20 +88,19 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
savetables.stateful(::fluid, FLUID_KEY)
|
savetables.stateful(::fluid, FLUID_KEY)
|
||||||
savetables.stateful(::fillInput)
|
savetables.stateful(::inputContainer)
|
||||||
savetables.stateful(::drainInput)
|
savetables.stateful(::outputContainer)
|
||||||
savetables.stateful(::output)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun drainItem() {
|
private fun drainItem() {
|
||||||
val item = drainInput[0]
|
val item = drainSlot.item
|
||||||
|
|
||||||
if (item.isNotEmpty) {
|
if (item.isNotEmpty) {
|
||||||
val cap = (if (item.count == 1) item else item.copyWithCount(1)).getCapability(Capabilities.FluidHandler.ITEM)
|
val cap = (if (item.count == 1) item else item.copyWithCount(1)).getCapability(Capabilities.FluidHandler.ITEM)
|
||||||
|
|
||||||
if (cap == null) {
|
if (cap == null) {
|
||||||
if (output.consumeItem(item, simulate = false)) {
|
if (outputContainer.consumeItem(item, simulate = false)) {
|
||||||
drainInput.setChanged(0)
|
drainSlot.setChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -95,17 +111,17 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
|
|||||||
val moved0 = moveFluid(source = cap, destination = fluid)
|
val moved0 = moveFluid(source = cap, destination = fluid)
|
||||||
|
|
||||||
if (moved0.isNotEmpty) {
|
if (moved0.isNotEmpty) {
|
||||||
drainInput[0] = cap.container
|
drainSlot.item = cap.container
|
||||||
|
|
||||||
if (output.consumeItem(drainInput[0], simulate = false)) {
|
if (outputContainer.consumeItem(drainSlot.item, simulate = false)) {
|
||||||
drainInput.setChanged(0)
|
drainSlot.setChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val moved0 = moveFluid(source = cap, destination = fluid, actuallyFill = false)
|
val moved0 = moveFluid(source = cap, destination = fluid, actuallyFill = false)
|
||||||
|
|
||||||
if (moved0.isNotEmpty) {
|
if (moved0.isNotEmpty) {
|
||||||
if (output.consumeItem(cap.container, simulate = true)) {
|
if (outputContainer.consumeItem(cap.container, simulate = true)) {
|
||||||
val cap1 = item.copyWithCount(1).getCapability(Capabilities.FluidHandler.ITEM) ?: throw ConcurrentModificationException()
|
val cap1 = item.copyWithCount(1).getCapability(Capabilities.FluidHandler.ITEM) ?: throw ConcurrentModificationException()
|
||||||
|
|
||||||
val moved1 = moveFluid(source = cap1, destination = fluid)
|
val moved1 = moveFluid(source = cap1, destination = fluid)
|
||||||
@ -114,9 +130,9 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
|
|||||||
LOGGER.error("Error moving fluids in Fluid tank at $blockPos: moved $moved0 during simulation from ${cap.container}, moved $moved1 from ${cap1.container} during execution. This is likely a bug in OTM or other mod!")
|
LOGGER.error("Error moving fluids in Fluid tank at $blockPos: moved $moved0 during simulation from ${cap.container}, moved $moved1 from ${cap1.container} during execution. This is likely a bug in OTM or other mod!")
|
||||||
} else {
|
} else {
|
||||||
item.count--
|
item.count--
|
||||||
drainInput.setChanged(0)
|
drainSlot.setChanged()
|
||||||
|
|
||||||
if (!output.consumeItem(cap1.container, simulate = false)) {
|
if (!outputContainer.consumeItem(cap1.container, simulate = false)) {
|
||||||
LOGGER.error("Unable to insert ${cap1.container} into output slot of Fluid tank at $blockPos, popping item in world instead to avoid item loss! This is likely a bug in OTM or other mod!")
|
LOGGER.error("Unable to insert ${cap1.container} into output slot of Fluid tank at $blockPos, popping item in world instead to avoid item loss! This is likely a bug in OTM or other mod!")
|
||||||
(level as? ServerLevel)?.addFreshEntity(ItemEntity(level!!, blockPos.x.toDouble(), blockPos.y.toDouble(), blockPos.z.toDouble(), cap1.container))
|
(level as? ServerLevel)?.addFreshEntity(ItemEntity(level!!, blockPos.x.toDouble(), blockPos.y.toDouble(), blockPos.z.toDouble(), cap1.container))
|
||||||
}
|
}
|
||||||
@ -129,14 +145,14 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun fillItem() {
|
private fun fillItem() {
|
||||||
val item = fillInput[0]
|
val item = fillSlot.item
|
||||||
|
|
||||||
if (item.isNotEmpty) {
|
if (item.isNotEmpty) {
|
||||||
val cap = (if (item.count == 1) item else item.copyWithCount(1)).getCapability(Capabilities.FluidHandler.ITEM)
|
val cap = (if (item.count == 1) item else item.copyWithCount(1)).getCapability(Capabilities.FluidHandler.ITEM)
|
||||||
|
|
||||||
if (cap == null) {
|
if (cap == null) {
|
||||||
if (output.consumeItem(item, simulate = false)) {
|
if (outputContainer.consumeItem(item, simulate = false)) {
|
||||||
fillInput.setChanged(0)
|
fillSlot.setChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -147,17 +163,17 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
|
|||||||
val moved0 = moveFluid(source = fluid, destination = cap)
|
val moved0 = moveFluid(source = fluid, destination = cap)
|
||||||
|
|
||||||
if (moved0.isNotEmpty) {
|
if (moved0.isNotEmpty) {
|
||||||
fillInput[0] = cap.container
|
fillSlot.item = cap.container
|
||||||
|
|
||||||
if (output.consumeItem(fillInput[0], simulate = false)) {
|
if (outputContainer.consumeItem(fillSlot.item, simulate = false)) {
|
||||||
fillInput.setChanged(0)
|
fillSlot.setChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val moved0 = moveFluid(source = fluid, destination = cap, actuallyDrain = false)
|
val moved0 = moveFluid(source = fluid, destination = cap, actuallyDrain = false)
|
||||||
|
|
||||||
if (moved0.isNotEmpty) {
|
if (moved0.isNotEmpty) {
|
||||||
if (output.consumeItem(cap.container, simulate = true)) {
|
if (outputContainer.consumeItem(cap.container, simulate = true)) {
|
||||||
val cap1 = item.copyWithCount(1).getCapability(Capabilities.FluidHandler.ITEM) ?: throw ConcurrentModificationException()
|
val cap1 = item.copyWithCount(1).getCapability(Capabilities.FluidHandler.ITEM) ?: throw ConcurrentModificationException()
|
||||||
|
|
||||||
val moved1 = moveFluid(source = fluid, destination = cap1)
|
val moved1 = moveFluid(source = fluid, destination = cap1)
|
||||||
@ -166,9 +182,9 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
|
|||||||
LOGGER.error("Error moving fluids in Fluid tank at $blockPos: moved $moved0 during simulation from ${cap.container}, moved $moved1 from ${cap1.container} during execution. This is likely a bug in OTM or other mod!")
|
LOGGER.error("Error moving fluids in Fluid tank at $blockPos: moved $moved0 during simulation from ${cap.container}, moved $moved1 from ${cap1.container} during execution. This is likely a bug in OTM or other mod!")
|
||||||
} else {
|
} else {
|
||||||
item.count--
|
item.count--
|
||||||
fillInput.setChanged(0)
|
fillSlot.setChanged()
|
||||||
|
|
||||||
if (!output.consumeItem(cap1.container, simulate = false)) {
|
if (!outputContainer.consumeItem(cap1.container, simulate = false)) {
|
||||||
LOGGER.error("Unable to insert ${cap1.container} into output slot of Fluid tank at $blockPos, popping item in world instead to avoid item loss! This is likely a bug in OTM or other mod!")
|
LOGGER.error("Unable to insert ${cap1.container} into output slot of Fluid tank at $blockPos, popping item in world instead to avoid item loss! This is likely a bug in OTM or other mod!")
|
||||||
(level as? ServerLevel)?.addFreshEntity(ItemEntity(level!!, blockPos.x.toDouble(), blockPos.y.toDouble(), blockPos.z.toDouble(), cap1.container))
|
(level as? ServerLevel)?.addFreshEntity(ItemEntity(level!!, blockPos.x.toDouble(), blockPos.y.toDouble(), blockPos.z.toDouble(), cap1.container))
|
||||||
}
|
}
|
||||||
@ -194,5 +210,8 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
|
|||||||
companion object {
|
companion object {
|
||||||
const val FLUID_KEY = "fluid"
|
const val FLUID_KEY = "fluid"
|
||||||
private val LOGGER = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
|
||||||
|
private val FILL_TAG = SlottedContainer.tag<FilteredContainerSlot>()
|
||||||
|
private val DRAIN_TAG = SlottedContainer.tag<FilteredContainerSlot>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import net.minecraft.core.BlockPos
|
|||||||
import net.minecraft.core.HolderLookup
|
import net.minecraft.core.HolderLookup
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
|
import net.minecraft.resources.ResourceLocation
|
||||||
import net.minecraft.server.level.ServerLevel
|
import net.minecraft.server.level.ServerLevel
|
||||||
import net.minecraft.world.Containers
|
import net.minecraft.world.Containers
|
||||||
import net.minecraft.world.MenuProvider
|
import net.minecraft.world.MenuProvider
|
||||||
@ -19,12 +20,16 @@ import net.minecraft.world.item.crafting.SmokingRecipe
|
|||||||
import net.minecraft.world.level.block.Block
|
import net.minecraft.world.level.block.Block
|
||||||
import net.minecraft.world.level.block.state.BlockState
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
import ru.dbotthepony.kommons.util.Delegate
|
import ru.dbotthepony.kommons.util.Delegate
|
||||||
|
import ru.dbotthepony.kommons.util.KOptional
|
||||||
import ru.dbotthepony.mc.otm.block.IBlockWithCustomName
|
import ru.dbotthepony.mc.otm.block.IBlockWithCustomName
|
||||||
import ru.dbotthepony.mc.otm.block.decorative.GrillBlock
|
import ru.dbotthepony.mc.otm.block.decorative.GrillBlock
|
||||||
import ru.dbotthepony.mc.otm.block.entity.ExperienceStorage
|
import ru.dbotthepony.mc.otm.block.entity.ExperienceStorage
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.set
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.core.TextComponent
|
import ru.dbotthepony.mc.otm.core.TextComponent
|
||||||
import ru.dbotthepony.mc.otm.core.get
|
import ru.dbotthepony.mc.otm.core.get
|
||||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||||
@ -38,47 +43,45 @@ import ru.dbotthepony.mc.otm.menu.decorative.GrillMenu
|
|||||||
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
||||||
|
|
||||||
class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBlockEntity(MBlockEntities.GRILL, blockPos, blockState), MenuProvider, IBlockWithCustomName {
|
class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBlockEntity(MBlockEntities.GRILL, blockPos, blockState), MenuProvider, IBlockWithCustomName {
|
||||||
val fuelSlot = object : MatteryContainer(this@GrillBlockEntity::markDirtyFast, 1) {
|
val fuelSlot = SlottedContainer.simple(1, FUEL_SLOT_PROVIDER, ::markDirtyFast)
|
||||||
override fun getMaxStackSize(): Int {
|
|
||||||
return 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val inputSlots = object : MatteryContainer(this@GrillBlockEntity::markDirtyFast, SLOTS) {
|
private inner class InputSlot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) {
|
||||||
override fun getMaxStackSize(): Int {
|
override val maxStackSize: Int
|
||||||
return 1
|
get() = 1
|
||||||
}
|
|
||||||
|
|
||||||
private fun clearSlot(slot: Int) {
|
|
||||||
|
private fun clearSlot() {
|
||||||
inputProgress[slot] = 0
|
inputProgress[slot] = 0
|
||||||
outputs[slot] = null
|
outputs[slot] = null
|
||||||
|
outputsRecipeNames[slot] = null
|
||||||
activeSlots.rem(slot)
|
activeSlots.rem(slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
|
override fun notifyChanged(old: ItemStack) {
|
||||||
super.setChanged(slot, new, old)
|
super.notifyChanged(old)
|
||||||
|
|
||||||
if (new.isEmpty || new.count > 1) {
|
if (item.isEmpty || item.count > 1) {
|
||||||
clearSlot(slot)
|
clearSlot()
|
||||||
} else {
|
} else {
|
||||||
val level = level
|
val level = level
|
||||||
|
|
||||||
if (level == null) {
|
if (level == null) {
|
||||||
clearSlot(slot)
|
clearSlot()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val input = SingleRecipeInput(new)
|
val input = SingleRecipeInput(item)
|
||||||
val result = level.recipeManager
|
val result = level.recipeManager
|
||||||
.byType(RecipeType.SMOKING)
|
.byType(RecipeType.SMOKING)
|
||||||
.firstOrNull { it.value.matches(input, level) }
|
.firstOrNull { it.value.matches(input, level) }
|
||||||
|
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
clearSlot(slot)
|
clearSlot()
|
||||||
} else {
|
} else {
|
||||||
if (outputs[slot] != result.value)
|
if (outputsRecipeNames[slot] != result.id)
|
||||||
inputProgress[slot] = 0
|
inputProgress[slot] = 0
|
||||||
|
|
||||||
|
outputsRecipeNames[slot] = result.id
|
||||||
outputs[slot] = result.value
|
outputs[slot] = result.value
|
||||||
activeSlots.add(slot)
|
activeSlots.add(slot)
|
||||||
}
|
}
|
||||||
@ -86,16 +89,18 @@ class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val inputSlots = SlottedContainer.simple(SLOTS, ::InputSlot, ::markDirtyFast)
|
||||||
override var customDisplayName: Component? = null
|
override var customDisplayName: Component? = null
|
||||||
|
|
||||||
override fun createMenu(p_39954_: Int, p_39955_: Inventory, p_39956_: Player): AbstractContainerMenu {
|
override fun createMenu(containerID: Int, inventory: Inventory, player: Player): AbstractContainerMenu {
|
||||||
return GrillMenu(p_39954_, p_39955_, this)
|
return GrillMenu(containerID, inventory, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDisplayName(): Component {
|
override fun getDisplayName(): Component {
|
||||||
return customDisplayName ?: level?.getBlockState(blockPos)?.block?.name ?: TextComponent("null at $blockPos")
|
return customDisplayName ?: level?.getBlockState(blockPos)?.block?.name ?: TextComponent("null at $blockPos")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val outputsRecipeNames = arrayOfNulls<ResourceLocation>(SLOTS)
|
||||||
private val outputs = arrayOfNulls<SmokingRecipe>(SLOTS)
|
private val outputs = arrayOfNulls<SmokingRecipe>(SLOTS)
|
||||||
private val activeSlots = IntArrayList()
|
private val activeSlots = IntArrayList()
|
||||||
private val inputProgress = IntArray(SLOTS)
|
private val inputProgress = IntArray(SLOTS)
|
||||||
@ -132,9 +137,12 @@ class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBloc
|
|||||||
savetables.stateful(::fuelSlot)
|
savetables.stateful(::fuelSlot)
|
||||||
savetables.stateful(::experience)
|
savetables.stateful(::experience)
|
||||||
|
|
||||||
|
outputsRecipeNames.fill(null)
|
||||||
|
|
||||||
// TODO: could have been done as list (and get more space efficient storage), but we use an array, oh well
|
// TODO: could have been done as list (and get more space efficient storage), but we use an array, oh well
|
||||||
for (i in inputProgress.indices) {
|
for (i in inputProgress.indices) {
|
||||||
savetables.codec(Delegate.Of({ inputProgress[i] }, { inputProgress[i] = it }), progressCodec, "inputProgress${i}")
|
savetables.codec(Delegate.Of({ inputProgress[i] }, { inputProgress[i] = it }), progressCodec, "inputProgress${i}")
|
||||||
|
savetables.codecNullable(Delegate.Of({ outputsRecipeNames[i] }, { outputsRecipeNames[i] = it }), ResourceLocation.CODEC, "recipeName${i}")
|
||||||
}
|
}
|
||||||
|
|
||||||
// addDroppableContainer(inputSlots)
|
// addDroppableContainer(inputSlots)
|
||||||
@ -207,5 +215,6 @@ class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBloc
|
|||||||
const val SLOTS = 6
|
const val SLOTS = 6
|
||||||
|
|
||||||
private val progressCodec = Codec.INT.minRange(0)
|
private val progressCodec = Codec.INT.minRange(0)
|
||||||
|
val FUEL_SLOT_PROVIDER = ContainerSlot.Simple(maxStackSize = 4, filter = AutomationFilters.CHEMICAL_FUEL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,8 @@ import net.neoforged.neoforge.capabilities.Capabilities
|
|||||||
import net.neoforged.neoforge.fluids.FluidStack
|
import net.neoforged.neoforge.fluids.FluidStack
|
||||||
import net.neoforged.neoforge.fluids.capability.IFluidHandler
|
import net.neoforged.neoforge.fluids.capability.IFluidHandler
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.core.immutableList
|
import ru.dbotthepony.mc.otm.core.immutableList
|
||||||
import ru.dbotthepony.mc.otm.core.immutableMap
|
import ru.dbotthepony.mc.otm.core.immutableMap
|
||||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||||
@ -34,7 +34,39 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
|
|||||||
return PainterMenu(containerID, inventory, this)
|
return PainterMenu(containerID, inventory, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
val dyeInput = MatteryContainer(this::markDirtyFast, 1)
|
private inner class InputSlot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) {
|
||||||
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
|
if (!super.canAutomationPlaceItem(itemStack))
|
||||||
|
return false
|
||||||
|
|
||||||
|
if (waterStored() < MAX_WATER_STORAGE) {
|
||||||
|
itemStack.getCapability(Capabilities.FluidHandler.ITEM)?.let {
|
||||||
|
val drain = it.drain(FluidStack(Fluids.WATER, MAX_WATER_STORAGE - waterStored()), IFluidHandler.FluidAction.SIMULATE)
|
||||||
|
|
||||||
|
if (drain.isNotEmpty) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val dye = DyeColor.getColor(itemStack) ?: return false
|
||||||
|
return dyeStored(dye) + HUE_PER_ITEM <= MAX_STORAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canAutomationTakeItem(desired: Int): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun modifyAutomationPlaceCount(itemStack: ItemStack): Int {
|
||||||
|
if (itemStack.getCapability(Capabilities.FluidHandler.ITEM) != null)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
val dye = DyeColor.getColor(itemStack) ?: return 0
|
||||||
|
return itemStack.count.coerceAtMost((MAX_STORAGE - dyeStored(dye)) / HUE_PER_ITEM - item.count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val dyeInput = SlottedContainer.simple(1, ::InputSlot, ::markDirtyFast)
|
||||||
// null - water
|
// null - water
|
||||||
val dyeStored = Object2IntArrayMap<DyeColor?>()
|
val dyeStored = Object2IntArrayMap<DyeColor?>()
|
||||||
|
|
||||||
@ -108,34 +140,7 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
|
|||||||
markDirtyFast()
|
markDirtyFast()
|
||||||
}
|
}
|
||||||
|
|
||||||
val config = ConfigurableItemHandler(input = dyeInput.handler(object : HandlerFilter {
|
val config = ConfigurableItemHandler(input = dyeInput)
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
if (waterStored() < MAX_WATER_STORAGE) {
|
|
||||||
stack.getCapability(Capabilities.FluidHandler.ITEM)?.let {
|
|
||||||
val drain = it.drain(FluidStack(Fluids.WATER, MAX_WATER_STORAGE - waterStored()), IFluidHandler.FluidAction.SIMULATE)
|
|
||||||
|
|
||||||
if (drain.isNotEmpty) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val dye = DyeColor.entries.firstOrNull { stack.`is`(it.tag) } ?: return false
|
|
||||||
return dyeStored(dye) + HUE_PER_ITEM <= MAX_STORAGE
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun modifyInsertCount(slot: Int, stack: ItemStack, existing: ItemStack, simulate: Boolean): Int {
|
|
||||||
if (!ItemStack.isSameItemSameComponents(stack, existing))
|
|
||||||
return super.modifyInsertCount(slot, stack, existing, simulate)
|
|
||||||
|
|
||||||
val dye = DyeColor.entries.firstOrNull { stack.`is`(it.tag) } ?: return 0
|
|
||||||
return stack.count.coerceAtMost((MAX_STORAGE - dyeStored(dye)) / HUE_PER_ITEM - existing.count)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
|
|
||||||
fun waterStored(): Int {
|
fun waterStored(): Int {
|
||||||
return dyeStored.getInt(null)
|
return dyeStored.getInt(null)
|
||||||
|
@ -21,39 +21,37 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
|||||||
import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
|
import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
|
||||||
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
|
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
|
||||||
import ru.dbotthepony.mc.otm.container.UpgradeContainer
|
import ru.dbotthepony.mc.otm.container.UpgradeContainer
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.menu.matter.MatterBottlerMenu
|
import ru.dbotthepony.mc.otm.menu.matter.MatterBottlerMenu
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
|
import ru.dbotthepony.mc.otm.core.util.countingLazy
|
||||||
import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
|
import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
|
||||||
import java.util.function.BooleanSupplier
|
import java.util.function.BooleanSupplier
|
||||||
|
|
||||||
class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) :
|
class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) :
|
||||||
MatteryPoweredBlockEntity(MBlockEntities.MATTER_BOTTLER, blockPos, blockState) {
|
MatteryPoweredBlockEntity(MBlockEntities.MATTER_BOTTLER, blockPos, blockState) {
|
||||||
|
|
||||||
val upgrades = UpgradeContainer(3, UpgradeType.BASIC_MATTER, BooleanSupplier { blockState.getValue(WorkerState.SEMI_WORKER_STATE) !== WorkerState.IDLE }, ::markDirtyFast)
|
val upgrades = UpgradeContainer(3, UpgradeType.BASIC_MATTER, BooleanSupplier { this.blockState.getValue(WorkerState.SEMI_WORKER_STATE) !== WorkerState.IDLE }, ::markDirtyFast)
|
||||||
override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::markDirtyFast, upgrades.transform(MachinesConfig.MatterBottler.VALUES)))
|
override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::markDirtyFast, upgrades.transform(MachinesConfig.MatterBottler.VALUES)))
|
||||||
val energyConfig = ConfigurableEnergy(energy)
|
val energyConfig = ConfigurableEnergy(energy)
|
||||||
|
|
||||||
private inner class Container : MatteryContainer(3) {
|
private inner class BottlingSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) {
|
||||||
init {
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
addDroppableContainer(this)
|
return super.canAutomationPlaceItem(itemStack) && isBottling && itemStack.getCapability(MatteryCapability.MATTER_ITEM)?.receiveMatterChecked(Decimal.ONE, true)?.isPositive == true
|
||||||
}
|
|
||||||
|
|
||||||
override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
|
|
||||||
markDirtyFast()
|
|
||||||
updateBlockState()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val unbottling: MatteryContainer = Container()
|
private inner class UnBottlingSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) {
|
||||||
val bottling: MatteryContainer = Container()
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
|
return super.canAutomationPlaceItem(itemStack) && !isBottling && itemStack.getCapability(MatteryCapability.MATTER_ITEM)?.extractMatterChecked(Decimal.ONE, true)?.isPositive == true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val unbottling = SlottedContainer.simple(3, ::UnBottlingSlot, ::updateBlockState)
|
||||||
|
val bottling = SlottedContainer.simple(3, ::BottlingSlot, ::updateBlockState)
|
||||||
|
|
||||||
var isBottling: Boolean = true
|
var isBottling: Boolean = true
|
||||||
set(value) {
|
set(value) {
|
||||||
@ -63,11 +61,11 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) :
|
|||||||
this.markDirtyFast()
|
this.markDirtyFast()
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
inputHandler.parent = bottlingHandler
|
inputHandler.parent = bottling
|
||||||
outputHandler.parent = unbottlingHandler
|
outputHandler.parent = unbottling
|
||||||
} else {
|
} else {
|
||||||
inputHandler.parent = unbottlingHandler
|
inputHandler.parent = unbottling
|
||||||
outputHandler.parent = bottlingHandler
|
outputHandler.parent = bottling
|
||||||
}
|
}
|
||||||
|
|
||||||
updateBlockState()
|
updateBlockState()
|
||||||
@ -79,25 +77,13 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) :
|
|||||||
this.markDirtyFast()
|
this.markDirtyFast()
|
||||||
}
|
}
|
||||||
|
|
||||||
val bottlingHandler = bottling.handler(object : HandlerFilter {
|
private val inputHandler = ProxiedItemHandler(bottling)
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
private val outputHandler = ProxiedItemHandler(unbottling)
|
||||||
return isBottling && stack.getCapability(MatteryCapability.MATTER_ITEM)?.let { it.matterFlow.input && it.missingMatter.isPositive } ?: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
val unbottlingHandler = unbottling.handler(object : HandlerFilter {
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return !isBottling && stack.getCapability(MatteryCapability.MATTER_ITEM)?.let { it.matterFlow.output && it.storedMatter.isPositive } ?: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
private val inputHandler = ProxiedItemHandler(bottlingHandler)
|
|
||||||
private val outputHandler = ProxiedItemHandler(unbottlingHandler)
|
|
||||||
|
|
||||||
val itemConfig = ConfigurableItemHandler(
|
val itemConfig = ConfigurableItemHandler(
|
||||||
input = inputHandler,
|
input = inputHandler,
|
||||||
output = outputHandler,
|
output = outputHandler,
|
||||||
battery = batteryItemHandler
|
battery = batteryContainer
|
||||||
)
|
)
|
||||||
|
|
||||||
val matter: ProfiledMatterStorage<MatterStorageImpl> = ProfiledMatterStorage(object : MatterStorageImpl(this@MatterBottlerBlockEntity::markDirtyFast, FlowDirection.BI_DIRECTIONAL, upgrades.matterCapacity(MachinesConfig.MatterBottler.VALUES::matterCapacity)) {
|
val matter: ProfiledMatterStorage<MatterStorageImpl> = ProfiledMatterStorage(object : MatterStorageImpl(this@MatterBottlerBlockEntity::markDirtyFast, FlowDirection.BI_DIRECTIONAL, upgrades.matterCapacity(MachinesConfig.MatterBottler.VALUES::matterCapacity)) {
|
||||||
@ -141,12 +127,12 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) :
|
|||||||
matterNode.isValid = false
|
matterNode.isValid = false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateBlockState(container: MatteryContainer) {
|
private fun updateBlockState(container: SlottedContainer) {
|
||||||
val level = level as? ServerLevel ?: return
|
val level = level as? ServerLevel ?: return
|
||||||
var state = blockState
|
var state = blockState
|
||||||
|
|
||||||
for (i in 0 .. 2) {
|
for ((i, slot) in container.slotIterator().withIndex()) {
|
||||||
val desired = !container.getItem(i).isEmpty && container.getItem(i).getCapability(MatteryCapability.MATTER_ITEM) != null
|
val desired = !slot.isEmpty && slot.item.getCapability(MatteryCapability.MATTER_ITEM) != null
|
||||||
|
|
||||||
if (state.getValue(MatterBottlerBlock.SLOT_PROPERTIES[i]) != desired) {
|
if (state.getValue(MatterBottlerBlock.SLOT_PROPERTIES[i]) != desired) {
|
||||||
state = state.setValue(MatterBottlerBlock.SLOT_PROPERTIES[i], desired)
|
state = state.setValue(MatterBottlerBlock.SLOT_PROPERTIES[i], desired)
|
||||||
@ -154,26 +140,156 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state !== blockState) {
|
if (state !== blockState) {
|
||||||
level.setBlock(blockPos, state, Block.UPDATE_CLIENTS)
|
level.setBlock(blockPos, state, Block.UPDATE_ALL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateBlockState() {
|
private fun updateBlockState() {
|
||||||
|
markDirtyFast()
|
||||||
if (isBottling)
|
if (isBottling)
|
||||||
updateBlockState(bottling)
|
updateBlockState(bottling)
|
||||||
else
|
else
|
||||||
updateBlockState(unbottling)
|
updateBlockState(unbottling)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val workerState by countingLazy(blockStateChangesCounter) {
|
||||||
|
this.blockState.getValue(WorkerState.SEMI_WORKER_STATE)
|
||||||
|
}
|
||||||
|
|
||||||
private fun blockstateToWorking() {
|
private fun blockstateToWorking() {
|
||||||
if (blockState.getValue(WorkerState.SEMI_WORKER_STATE) !== WorkerState.WORKING) {
|
if (workerState !== WorkerState.WORKING) {
|
||||||
level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING), Block.UPDATE_CLIENTS)
|
level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING), Block.UPDATE_ALL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun blockstateToIdle() {
|
private fun blockstateToIdle() {
|
||||||
if (blockState.getValue(WorkerState.SEMI_WORKER_STATE) !== WorkerState.IDLE) {
|
if (workerState !== WorkerState.IDLE) {
|
||||||
level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS)
|
level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_ALL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tickBottling() {
|
||||||
|
var isWorking = false
|
||||||
|
var hasCapacitors = false
|
||||||
|
|
||||||
|
for (slot in bottling.slotIterator()) {
|
||||||
|
val item = slot.item
|
||||||
|
val capability = item.getCapability(MatteryCapability.MATTER_ITEM) ?: continue
|
||||||
|
|
||||||
|
if (!capability.receiveMatterChecked(Decimal.LONG_MAX_VALUE, true).isPositive) {
|
||||||
|
unbottling.consumeItem(item, false)
|
||||||
|
slot.setChanged()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
hasCapacitors = true
|
||||||
|
initialCapacity = initialCapacity ?: capability.storedMatter
|
||||||
|
val rate = MachinesConfig.MatterBottler.RATE * (1.0 + upgrades.speedBonus)
|
||||||
|
val energyRate = MachinesConfig.MatterBottler.VALUES.energyConsumption * (1.0 + upgrades.speedBonus)
|
||||||
|
|
||||||
|
if (matter.storedMatter < rate) {
|
||||||
|
val toExtract = matter.missingMatter
|
||||||
|
.coerceAtMost(rate * 200)
|
||||||
|
.coerceAtMost(capability.missingMatter - matter.storedMatter)
|
||||||
|
|
||||||
|
matter.receiveMatter(matterNode.graph.extractMatter(toExtract, false), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matter.storedMatter.isPositive) {
|
||||||
|
val energyRatio = if (energyRate <= Decimal.ZERO) Decimal.ONE else energy.extractEnergy(energyRate, true) / energyRate
|
||||||
|
val matterRatio = matter.extractMatter(capability.receiveMatter(rate.coerceAtMost(matter.storedMatter), true), true) / rate
|
||||||
|
|
||||||
|
val minRatio = minOf(matterRatio, energyRatio)
|
||||||
|
|
||||||
|
if (minRatio > Decimal.ZERO) {
|
||||||
|
isWorking = true
|
||||||
|
energy.extractEnergy(energyRate * minRatio, false)
|
||||||
|
matter.extractMatter(capability.receiveMatter(rate * minRatio, false), false)
|
||||||
|
workProgress = ((capability.storedMatter - initialCapacity!!) / capability.maxStoredMatter).toFloat()
|
||||||
|
slot.setChanged()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (spitItemsWhenCantWork) {
|
||||||
|
unbottling.consumeItem(item, false)
|
||||||
|
slot.setChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isWorking) {
|
||||||
|
blockstateToWorking()
|
||||||
|
} else {
|
||||||
|
blockstateToIdle()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasCapacitors) {
|
||||||
|
matter.extractMatter(matterNode.graph.receiveMatter(matter.storedMatter, false), false)
|
||||||
|
initialCapacity = null
|
||||||
|
workProgress = 0f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tickUnbottling() {
|
||||||
|
matter.extractMatter(matterNode.graph.receiveMatter(matter.storedMatter, false), false)
|
||||||
|
|
||||||
|
if (!matter.missingMatter.isPositive) {
|
||||||
|
if (spitItemsWhenCantWork) {
|
||||||
|
for (slot in unbottling.slotIterator()) {
|
||||||
|
bottling.consumeItem(slot.item, false)
|
||||||
|
slot.setChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blockstateToIdle()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var any = false
|
||||||
|
var hasCapacitors = false
|
||||||
|
|
||||||
|
for (slot in unbottling.slotIterator()) {
|
||||||
|
val item = slot.item
|
||||||
|
val it = item.getCapability(MatteryCapability.MATTER_ITEM) ?: continue
|
||||||
|
|
||||||
|
if (!it.extractMatterChecked(Decimal.LONG_MAX_VALUE, true).isPositive) {
|
||||||
|
bottling.consumeItem(item, false)
|
||||||
|
slot.setChanged()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
initialCapacity = initialCapacity ?: it.storedMatter
|
||||||
|
|
||||||
|
hasCapacitors = true
|
||||||
|
val rate = MachinesConfig.MatterBottler.RATE * (1.0 + upgrades.speedBonus)
|
||||||
|
val energyRate = MachinesConfig.MatterBottler.VALUES.energyConsumption * (1.0 + upgrades.speedBonus)
|
||||||
|
|
||||||
|
val energyRatio = if (energyRate <= Decimal.ZERO) Decimal.ONE else energy.extractEnergy(energyRate, true) / energyRate
|
||||||
|
val matterRatio = matter.receiveMatter(it.extractMatterChecked(rate, true), true) / rate
|
||||||
|
|
||||||
|
val minRatio = minOf(energyRatio, matterRatio)
|
||||||
|
|
||||||
|
if (minRatio > Decimal.ZERO) {
|
||||||
|
any = true
|
||||||
|
energy.extractEnergy(energyRate * energyRatio, false)
|
||||||
|
matter.receiveMatter(it.extractMatterChecked(rate * minRatio, false), false)
|
||||||
|
|
||||||
|
workProgress = 1f - (it.storedMatter / initialCapacity!!).toFloat()
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (any) {
|
||||||
|
blockstateToWorking()
|
||||||
|
} else {
|
||||||
|
blockstateToIdle()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasCapacitors) {
|
||||||
|
initialCapacity = null
|
||||||
|
workProgress = 0f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,105 +302,9 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isBottling) {
|
if (isBottling) {
|
||||||
var any = false
|
tickBottling()
|
||||||
var idle = false
|
|
||||||
|
|
||||||
for (slot in bottling.slotIterator()) {
|
|
||||||
val item = slot.item
|
|
||||||
item.getCapability(MatteryCapability.MATTER_ITEM)?.let {
|
|
||||||
if (!it.missingMatter.isPositive) {
|
|
||||||
unbottling.consumeItem(item, false)
|
|
||||||
slot.setChanged()
|
|
||||||
} else {
|
|
||||||
any = true
|
|
||||||
initialCapacity = initialCapacity ?: it.storedMatter
|
|
||||||
val rate = MachinesConfig.MatterBottler.RATE * (1.0 + upgrades.speedBonus)
|
|
||||||
|
|
||||||
if (matter.storedMatter < rate) {
|
|
||||||
matter.receiveMatter(matterNode.graph.extractMatter(matter.missingMatter
|
|
||||||
.coerceAtMost(rate * 200)
|
|
||||||
.coerceAtMost(it.missingMatter - matter.storedMatter), false), false)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matter.storedMatter.isPositive) {
|
|
||||||
matter.extractMatter(it.receiveMatter(rate.coerceAtMost(matter.storedMatter), false), false)
|
|
||||||
|
|
||||||
if (!it.missingMatter.isPositive) {
|
|
||||||
initialCapacity = null
|
|
||||||
workProgress = 0f
|
|
||||||
} else {
|
|
||||||
workProgress = ((it.storedMatter - initialCapacity!!) / it.maxStoredMatter).toFloat()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
idle = true
|
|
||||||
|
|
||||||
if (spitItemsWhenCantWork) {
|
|
||||||
unbottling.consumeItem(item, false)
|
|
||||||
slot.setChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (any) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (any && !idle) {
|
|
||||||
blockstateToWorking()
|
|
||||||
} else {
|
|
||||||
matter.extractMatter(matterNode.graph.receiveMatter(matter.storedMatter, false), false)
|
|
||||||
blockstateToIdle()
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
matter.extractMatter(matterNode.graph.receiveMatter(matter.storedMatter, false), false)
|
tickUnbottling()
|
||||||
|
|
||||||
if (!matter.missingMatter.isPositive) {
|
|
||||||
if (spitItemsWhenCantWork) {
|
|
||||||
for (slot in unbottling.slotIterator()) {
|
|
||||||
bottling.consumeItem(slot.item, false)
|
|
||||||
slot.setChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
blockstateToIdle()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var any = false
|
|
||||||
|
|
||||||
for (slot in unbottling.slotIterator()) {
|
|
||||||
val item = slot.item
|
|
||||||
|
|
||||||
item.getCapability(MatteryCapability.MATTER_ITEM)?.let {
|
|
||||||
if (!it.storedMatter.isPositive) {
|
|
||||||
bottling.consumeItem(item, false)
|
|
||||||
slot.setChanged()
|
|
||||||
} else {
|
|
||||||
any = true
|
|
||||||
initialCapacity = initialCapacity ?: it.storedMatter
|
|
||||||
matter.receiveMatter(it.extractMatter(MachinesConfig.MatterBottler.RATE, false), false)
|
|
||||||
|
|
||||||
if (!it.storedMatter.isPositive) {
|
|
||||||
initialCapacity = null
|
|
||||||
workProgress = 0f
|
|
||||||
} else {
|
|
||||||
workProgress = 1f - (it.storedMatter / initialCapacity!!).toFloat()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (any) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (any) {
|
|
||||||
blockstateToWorking()
|
|
||||||
} else {
|
|
||||||
blockstateToIdle()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,16 +16,15 @@ import ru.dbotthepony.mc.otm.capability.FlowDirection
|
|||||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||||
import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage
|
import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage
|
||||||
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
|
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.core.immutableList
|
import ru.dbotthepony.mc.otm.core.immutableList
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
|
import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
|
||||||
import ru.dbotthepony.mc.otm.menu.matter.MatterCapacitorBankMenu
|
import ru.dbotthepony.mc.otm.menu.matter.MatterCapacitorBankMenu
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
||||||
|
|
||||||
class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(
|
class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.MATTER_CAPACITOR_BANK, p_155229_, p_155230_), IMatterStorage {
|
||||||
MBlockEntities.MATTER_CAPACITOR_BANK, p_155229_, p_155230_), IMatterStorage {
|
|
||||||
var gaugeLevel by syncher.float()
|
var gaugeLevel by syncher.float()
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@ -40,10 +39,9 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
|
|||||||
var summ = Decimal.ZERO
|
var summ = Decimal.ZERO
|
||||||
|
|
||||||
for (stack in container)
|
for (stack in container)
|
||||||
if (!stack.isEmpty)
|
stack.getCapability(MatteryCapability.MATTER_ITEM)?.let {
|
||||||
stack.getCapability(MatteryCapability.MATTER_ITEM)?.let {
|
summ += it.storedMatter
|
||||||
summ += it.storedMatter
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return summ
|
return summ
|
||||||
}
|
}
|
||||||
@ -51,19 +49,35 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
|
|||||||
throw UnsupportedOperationException()
|
throw UnsupportedOperationException()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val maxStoredMatter: Decimal
|
override val maxStoredMatter: Decimal get() {
|
||||||
get() {
|
|
||||||
var summ = Decimal.ZERO
|
var summ = Decimal.ZERO
|
||||||
|
|
||||||
for (stack in container)
|
for (stack in container)
|
||||||
if (!stack.isEmpty)
|
stack.getCapability(MatteryCapability.MATTER_ITEM)?.let {
|
||||||
stack.getCapability(MatteryCapability.MATTER_ITEM)?.let {
|
summ += it.maxStoredMatter
|
||||||
summ += it.maxStoredMatter
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return summ
|
return summ
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateGaugeLevel() {
|
||||||
|
var stored = Decimal.ZERO
|
||||||
|
var maxStored = Decimal.ZERO
|
||||||
|
|
||||||
|
for (stack in container) {
|
||||||
|
val cap = stack.getCapability(MatteryCapability.MATTER_ITEM) ?: continue
|
||||||
|
stored += cap.storedMatter
|
||||||
|
maxStored += cap.maxStoredMatter
|
||||||
|
}
|
||||||
|
|
||||||
|
gaugeLevel = stored.percentage(maxStored)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tick() {
|
||||||
|
super.tick()
|
||||||
|
updateGaugeLevel()
|
||||||
|
}
|
||||||
|
|
||||||
override fun receiveMatter(howMuch: Decimal, simulate: Boolean): Decimal {
|
override fun receiveMatter(howMuch: Decimal, simulate: Boolean): Decimal {
|
||||||
if (!howMuch.isPositive)
|
if (!howMuch.isPositive)
|
||||||
return Decimal.ZERO
|
return Decimal.ZERO
|
||||||
@ -73,21 +87,18 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
|
|||||||
var summ = Decimal.ZERO
|
var summ = Decimal.ZERO
|
||||||
|
|
||||||
for (stack in container) {
|
for (stack in container) {
|
||||||
if (!stack.isEmpty) {
|
val it = stack.getCapability(MatteryCapability.MATTER_ITEM) ?: continue
|
||||||
stack.getCapability(MatteryCapability.MATTER_ITEM)?.let {
|
val diff = it.receiveMatterChecked(howMuch, simulate)
|
||||||
val diff = it.receiveMatterChecked(howMuch, simulate)
|
summ += diff
|
||||||
summ += diff
|
howMuch -= diff
|
||||||
howMuch -= diff
|
|
||||||
}
|
|
||||||
|
|
||||||
if (howMuch.isZero) {
|
if (howMuch.isZero) {
|
||||||
break
|
break
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (summ.isPositive && !simulate) {
|
if (!simulate && !summ.isZero) {
|
||||||
gaugeLevel = storedMatter.percentage(maxStoredMatter)
|
markDirtyFast()
|
||||||
}
|
}
|
||||||
|
|
||||||
return summ
|
return summ
|
||||||
@ -102,21 +113,18 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
|
|||||||
var summ = Decimal.ZERO
|
var summ = Decimal.ZERO
|
||||||
|
|
||||||
for (stack in container) {
|
for (stack in container) {
|
||||||
if (!stack.isEmpty) {
|
val it = stack.getCapability(MatteryCapability.MATTER_ITEM) ?: continue
|
||||||
stack.getCapability(MatteryCapability.MATTER_ITEM)?.let {
|
val diff = it.extractMatterChecked(howMuch, simulate)
|
||||||
val diff = it.extractMatterChecked(howMuch, simulate)
|
summ += diff
|
||||||
summ += diff
|
howMuch -= diff
|
||||||
howMuch -= diff
|
|
||||||
}
|
|
||||||
|
|
||||||
if (howMuch.isZero) {
|
if (howMuch.isZero) {
|
||||||
break
|
break
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (summ.isPositive && !simulate) {
|
if (!simulate && !summ.isZero) {
|
||||||
gaugeLevel = storedMatter.percentage(maxStoredMatter)
|
markDirtyFast()
|
||||||
}
|
}
|
||||||
|
|
||||||
return summ
|
return summ
|
||||||
@ -125,31 +133,38 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
|
|||||||
override val matterFlow: FlowDirection
|
override val matterFlow: FlowDirection
|
||||||
get() = FlowDirection.BI_DIRECTIONAL
|
get() = FlowDirection.BI_DIRECTIONAL
|
||||||
|
|
||||||
val container = object : MatteryContainer(::markDirtyFast, BatteryBankBlockEntity.CAPACITY) {
|
private inner class Slot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) {
|
||||||
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
|
override fun notifyChanged(old: ItemStack) {
|
||||||
super.setChanged(slot, new, old)
|
super.notifyChanged(old)
|
||||||
capacitorStatus[slot].value = new.getCapability(MatteryCapability.MATTER_ITEM) != null
|
|
||||||
gaugeLevel = storedMatter.percentage(maxStoredMatter)
|
capacitorStatus[slot].value = item.getCapability(MatteryCapability.MATTER_ITEM) != null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getMaxStackSize(): Int = 1
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
}.also(::addDroppableContainer)
|
return super.canAutomationPlaceItem(itemStack) && itemStack.getCapability(MatteryCapability.MATTER_ITEM) != null
|
||||||
|
|
||||||
val itemConfig = ConfigurableItemHandler(inputOutput = container.handler(object : HandlerFilter {
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return stack.getCapability(MatteryCapability.MATTER_ITEM) != null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
override fun canAutomationTakeItem(desired: Int): Boolean {
|
||||||
stack.getCapability(MatteryCapability.MATTER_ITEM)?.let {
|
item.getCapability(MatteryCapability.MATTER_ITEM)?.let {
|
||||||
if (it.storedMatter.isPositive) {
|
if (it.storedMatter.isPositive) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return super.canAutomationTakeItem(desired)
|
||||||
}
|
}
|
||||||
}))
|
|
||||||
|
override val maxStackSize: Int
|
||||||
|
get() = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun containerUpdated() {
|
||||||
|
markDirtyFast()
|
||||||
|
updateGaugeLevel()
|
||||||
|
}
|
||||||
|
|
||||||
|
val container = SlottedContainer.simple(BatteryBankBlockEntity.CAPACITY, ::Slot, ::containerUpdated).also(::addDroppableContainer)
|
||||||
|
val itemConfig = ConfigurableItemHandler(inputOutput = container)
|
||||||
|
|
||||||
val capacitorStatus = immutableList(BatteryBankBlockEntity.CAPACITY) {
|
val capacitorStatus = immutableList(BatteryBankBlockEntity.CAPACITY) {
|
||||||
syncher.boolean(false)
|
syncher.boolean(false)
|
||||||
|
@ -21,8 +21,10 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
|||||||
import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
|
import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
|
||||||
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
|
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.otmRandom
|
import ru.dbotthepony.mc.otm.core.otmRandom
|
||||||
import ru.dbotthepony.mc.otm.data.codec.DecimalCodec
|
import ru.dbotthepony.mc.otm.data.codec.DecimalCodec
|
||||||
@ -72,22 +74,23 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState)
|
|||||||
savetables.stateful(::matter, MATTER_STORAGE_KEY)
|
savetables.stateful(::matter, MATTER_STORAGE_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private inner class InputSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) {
|
||||||
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
|
return super.canAutomationPlaceItem(itemStack) && MatterManager.canDecompose(itemStack)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canAutomationTakeItem(desired: Int): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// вход, выход
|
// вход, выход
|
||||||
val inputContainer = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
|
val inputContainer = SlottedContainer.simple(1, ::InputSlot, ::markDirtyFast).also(::addDroppableContainer)
|
||||||
val outputContainer = MatteryContainer(::markDirtyFast, 2).also(::addDroppableContainer)
|
val outputContainer = SlottedContainer.simple(2, AutomationFilters.ONLY_OUT.simpleProvider, ::markDirtyFast).also(::addDroppableContainer)
|
||||||
|
|
||||||
val itemConfig = ConfigurableItemHandler(
|
val itemConfig = ConfigurableItemHandler(
|
||||||
input = inputContainer.handler(object : HandlerFilter {
|
input = inputContainer,
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
output = outputContainer
|
||||||
return MatterManager.canDecompose(stack)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
output = outputContainer.handler(HandlerFilter.OnlyOut)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -8,6 +8,7 @@ import net.minecraft.world.entity.player.Player
|
|||||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.item.crafting.CraftingInput
|
import net.minecraft.world.item.crafting.CraftingInput
|
||||||
|
import net.minecraft.world.item.crafting.RecipeManager
|
||||||
import net.minecraft.world.level.Level
|
import net.minecraft.world.level.Level
|
||||||
import net.minecraft.world.level.block.state.BlockState
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
import net.neoforged.neoforge.capabilities.Capabilities
|
import net.neoforged.neoforge.capabilities.Capabilities
|
||||||
@ -24,19 +25,28 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
|||||||
import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
|
import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
|
||||||
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
|
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryCraftingContainer
|
import ru.dbotthepony.mc.otm.container.IEnhancedCraftingContainer
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
|
import ru.dbotthepony.mc.otm.core.SimpleCache
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.forEach
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.map
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.toList
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
|
import ru.dbotthepony.mc.otm.container.ItemStackKey
|
||||||
|
import ru.dbotthepony.mc.otm.container.asKey
|
||||||
import ru.dbotthepony.mc.otm.data.codec.DecimalCodec
|
import ru.dbotthepony.mc.otm.data.codec.DecimalCodec
|
||||||
import ru.dbotthepony.mc.otm.data.codec.minRange
|
import ru.dbotthepony.mc.otm.data.codec.minRange
|
||||||
import ru.dbotthepony.mc.otm.graph.matter.MatterNode
|
import ru.dbotthepony.mc.otm.graph.matter.MatterNode
|
||||||
import ru.dbotthepony.mc.otm.menu.matter.MatterEntanglerMenu
|
import ru.dbotthepony.mc.otm.menu.matter.MatterEntanglerMenu
|
||||||
|
import ru.dbotthepony.mc.otm.recipe.IMatterEntanglerRecipe
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MRecipes
|
import ru.dbotthepony.mc.otm.registry.game.MRecipes
|
||||||
|
import java.time.Duration
|
||||||
|
|
||||||
class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryWorkerBlockEntity<MatterEntanglerBlockEntity.Job>(
|
class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryWorkerBlockEntity<MatterEntanglerBlockEntity.Job>(MBlockEntities.MATTER_ENTANGLER, blockPos, blockState, Job.CODEC) {
|
||||||
MBlockEntities.MATTER_ENTANGLER, blockPos, blockState, Job.CODEC) {
|
|
||||||
class Job(itemStack: ItemStack, val matter: Decimal, ticks: Double, experience: Float) : ItemJob(itemStack, ticks, MachinesConfig.MATTER_ENTANGLER.energyConsumption, experience = experience) {
|
class Job(itemStack: ItemStack, val matter: Decimal, ticks: Double, experience: Float) : ItemJob(itemStack, ticks, MachinesConfig.MATTER_ENTANGLER.energyConsumption, experience = experience) {
|
||||||
val matterPerTick = matter / ticks
|
val matterPerTick = matter / ticks
|
||||||
|
|
||||||
@ -60,36 +70,67 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M
|
|||||||
val experience = ExperienceStorage(MachinesConfig.MATTER_ENTANGLER::maxExperienceStored).also(::addNeighbourListener)
|
val experience = ExperienceStorage(MachinesConfig.MATTER_ENTANGLER::maxExperienceStored).also(::addNeighbourListener)
|
||||||
val energyConfig = ConfigurableEnergy(energy)
|
val energyConfig = ConfigurableEnergy(energy)
|
||||||
|
|
||||||
val inputs = object : MatteryCraftingContainer(::itemContainerUpdated, 3, 3) {
|
private var recipeCache: Collection<IMatterEntanglerRecipe> = listOf()
|
||||||
override fun getMaxStackSize(): Int {
|
private var seenRecipeManager: RecipeManager? = null
|
||||||
return 1
|
|
||||||
|
private fun getRecipes(): Collection<IMatterEntanglerRecipe> {
|
||||||
|
val level = level!!
|
||||||
|
val manager = level.recipeManager
|
||||||
|
|
||||||
|
if (seenRecipeManager !== manager) {
|
||||||
|
seenRecipeManager = manager
|
||||||
|
val input = inputs.asPositionedCraftInput()
|
||||||
|
|
||||||
|
recipeCache = manager.byType(MRecipes.MATTER_ENTANGLER)
|
||||||
|
.iterator()
|
||||||
|
.map { it.value }
|
||||||
|
.filter { it.preemptivelyMatches(input, level, 3, 3) }
|
||||||
|
.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return recipeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
val output = object : MatteryContainer(::itemContainerUpdated, 1) {
|
private inner class InputSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) {
|
||||||
override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int {
|
// may get stalled on /reload command for up to a minute
|
||||||
return Int.MAX_VALUE
|
// shouldn't cause major issues through, since /reload is not something you frequently be executing
|
||||||
|
val insertCache = SimpleCache<ItemStackKey, Boolean>(Duration.ofMinutes(1))
|
||||||
|
|
||||||
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
|
if (!super.canAutomationPlaceItem(itemStack))
|
||||||
|
return false
|
||||||
|
|
||||||
|
val level = level ?: return false
|
||||||
|
|
||||||
|
return insertCache.get(itemStack.asKey()) {
|
||||||
|
val list = container.toList()
|
||||||
|
list[slot] = itemStack
|
||||||
|
val shadow = CraftingInput.ofPositioned(3, 3, list)
|
||||||
|
getRecipes().any { it.preemptivelyMatches(shadow, level, 3, 3) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun canAutomationTakeItem(desired: Int): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override val maxStackSize: Int
|
||||||
|
get() = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun inputsChanged() {
|
||||||
|
inputs.slotIterator().forEach { (it as InputSlot).insertCache.invalidateAll() }
|
||||||
|
seenRecipeManager = null
|
||||||
|
recipeCache = listOf()
|
||||||
|
setChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
val inputs = IEnhancedCraftingContainer.Wrapper(SlottedContainer.simple(3 * 3, ::InputSlot, ::inputsChanged), 3, 3)
|
||||||
|
val output = SlottedContainer.simple(1, AutomationFilters.ONLY_OUT.unlimitedSimpleProvider, ::markDirtyFast)
|
||||||
|
|
||||||
val itemConfig = ConfigurableItemHandler(
|
val itemConfig = ConfigurableItemHandler(
|
||||||
input = inputs.handler(object : HandlerFilter {
|
input = inputs.parent,
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
output = output
|
||||||
val list = inputs.toList()
|
|
||||||
list[slot] = stack
|
|
||||||
val shadow = CraftingInput.ofPositioned(3, 3, list)
|
|
||||||
|
|
||||||
return (level ?: return false)
|
|
||||||
.recipeManager
|
|
||||||
.byType(MRecipes.MATTER_ENTANGLER)
|
|
||||||
.any { it.value.preemptivelyMatches(shadow, level!!, 3, 3) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
output = output.handler(HandlerFilter.OnlyOut)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -98,7 +139,7 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M
|
|||||||
savetables.stateful(::energy, ENERGY_KEY)
|
savetables.stateful(::energy, ENERGY_KEY)
|
||||||
savetables.stateful(::matter, MATTER_STORAGE_KEY)
|
savetables.stateful(::matter, MATTER_STORAGE_KEY)
|
||||||
savetables.stateful(::upgrades)
|
savetables.stateful(::upgrades)
|
||||||
savetables.stateful(::inputs)
|
savetables.stateful(inputs::parent, "inputs")
|
||||||
savetables.stateful(::output)
|
savetables.stateful(::output)
|
||||||
savetables.stateful(::experience)
|
savetables.stateful(::experience)
|
||||||
|
|
||||||
@ -124,7 +165,7 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M
|
|||||||
val required = status.job.matterPerTick * status.ticksAdvanced
|
val required = status.job.matterPerTick * status.ticksAdvanced
|
||||||
|
|
||||||
if (matter.storedMatter < required) {
|
if (matter.storedMatter < required) {
|
||||||
matter.receiveMatter(node.graph.extractMatter(status.job.matterPerTick.coerceAtLeast(Decimal.TEN).coerceAtMost(matter.missingMatter), false), false)
|
matter.receiveMatter(node.graph.extractMatter(status.job.matterPerTick.coerceIn(Decimal.TEN, matter.missingMatter), false), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
status.scale(matter.extractMatter(required, false) / required)
|
status.scale(matter.extractMatter(required, false) / required)
|
||||||
@ -150,7 +191,7 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M
|
|||||||
if (!energy.batteryLevel.isPositive)
|
if (!energy.batteryLevel.isPositive)
|
||||||
return JobContainer.noEnergy()
|
return JobContainer.noEnergy()
|
||||||
|
|
||||||
val inputs = CraftingInput.of(3, 3, inputs.toList())
|
val inputs = this.inputs.asCraftInput()
|
||||||
|
|
||||||
val recipe = (level ?: return JobContainer.failure())
|
val recipe = (level ?: return JobContainer.failure())
|
||||||
.recipeManager
|
.recipeManager
|
||||||
|
@ -24,9 +24,9 @@ import ru.dbotthepony.mc.otm.capability.matter.PatternState
|
|||||||
import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
|
import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
|
||||||
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
|
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
|
||||||
import ru.dbotthepony.mc.otm.container.UpgradeContainer
|
import ru.dbotthepony.mc.otm.container.UpgradeContainer
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.otmRandom
|
import ru.dbotthepony.mc.otm.core.otmRandom
|
||||||
import ru.dbotthepony.mc.otm.core.registryName
|
import ru.dbotthepony.mc.otm.core.registryName
|
||||||
@ -37,9 +37,35 @@ import ru.dbotthepony.mc.otm.menu.matter.MatterReconstructorMenu
|
|||||||
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
||||||
import java.util.function.BooleanSupplier
|
import java.util.function.BooleanSupplier
|
||||||
|
|
||||||
class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(
|
class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.MATTER_RECONSTRUCTOR, blockPos, blockState) {
|
||||||
MBlockEntities.MATTER_RECONSTRUCTOR, blockPos, blockState) {
|
private inner class Slot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) {
|
||||||
val repairContainer = MatteryContainer(::containerChanged, 1).also(::addDroppableContainer)
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
|
if (!super.canAutomationPlaceItem(itemStack) || !itemStack.isRepairable || !itemStack.isDamaged) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MachinesConfig.MatterReconstructor.ALLOW_TO_SKIP_ANVIL && !MachinesConfig.MatterReconstructor.ONLY_ANVIL && MatterManager.get(itemStack.item).hasMatterValue) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return matterNode.graph
|
||||||
|
.patterns
|
||||||
|
.filter { itemStack.item.isValidRepairItem(itemStack, ItemStack(it.item, 1)) }
|
||||||
|
.findFirst().orElse(null).let {
|
||||||
|
if (it == null) {
|
||||||
|
IMatterValue.ZERO
|
||||||
|
} else {
|
||||||
|
MatterManager.get(it.item)
|
||||||
|
}
|
||||||
|
}.hasMatterValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canAutomationTakeItem(desired: Int): Boolean {
|
||||||
|
return super.canAutomationTakeItem(desired) && (progressPerTick <= 0.0 || matterPerTick <= Decimal.ZERO)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val repairContainer = SlottedContainer.simple(1, ::Slot, ::rescan).also(::addDroppableContainer)
|
||||||
|
|
||||||
private var matterPerTick = Decimal.ZERO
|
private var matterPerTick = Decimal.ZERO
|
||||||
private var progressPerTick = 0.0
|
private var progressPerTick = 0.0
|
||||||
@ -67,15 +93,15 @@ class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onPatternAdded(state: PatternState) {
|
override fun onPatternAdded(state: PatternState) {
|
||||||
containerChanged()
|
rescan()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPatternRemoved(state: PatternState) {
|
override fun onPatternRemoved(state: PatternState) {
|
||||||
containerChanged()
|
rescan()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPatternUpdated(newState: PatternState, oldState: PatternState) {
|
override fun onPatternUpdated(newState: PatternState, oldState: PatternState) {
|
||||||
containerChanged()
|
rescan()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,34 +125,7 @@ class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
|||||||
|
|
||||||
val energyConfig = ConfigurableEnergy(energy)
|
val energyConfig = ConfigurableEnergy(energy)
|
||||||
val itemConfig = ConfigurableItemHandler(
|
val itemConfig = ConfigurableItemHandler(
|
||||||
inputOutput = repairContainer.handler(object : HandlerFilter {
|
inputOutput = repairContainer
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
if (!stack.isRepairable || !stack.isDamaged) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MachinesConfig.MatterReconstructor.ALLOW_TO_SKIP_ANVIL && !MachinesConfig.MatterReconstructor.ONLY_ANVIL) {
|
|
||||||
if (MatterManager.get(stack.item).hasMatterValue) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return matterNode.graph
|
|
||||||
.patterns
|
|
||||||
.filter { stack.item.isValidRepairItem(stack, ItemStack(it.item, 1)) }
|
|
||||||
.findFirst().orElse(null).let {
|
|
||||||
if (it == null) {
|
|
||||||
IMatterValue.ZERO
|
|
||||||
} else {
|
|
||||||
MatterManager.get(it.item)
|
|
||||||
}
|
|
||||||
}.hasMatterValue
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
|
||||||
return progressPerTick <= 0.0 || matterPerTick <= Decimal.ZERO
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
||||||
@ -145,7 +144,7 @@ class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
|||||||
|
|
||||||
private var changeset = 0
|
private var changeset = 0
|
||||||
|
|
||||||
private fun containerChanged() {
|
private fun rescan() {
|
||||||
matterPerTick = Decimal.ZERO
|
matterPerTick = Decimal.ZERO
|
||||||
progressPerTick = 0.0
|
progressPerTick = 0.0
|
||||||
|
|
||||||
@ -196,7 +195,6 @@ class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("name_shadowing")
|
|
||||||
val matter = MatterManager.get(found.item) * 2
|
val matter = MatterManager.get(found.item) * 2
|
||||||
|
|
||||||
progressPerTick = (item.maxDamage / matter.complexity) / MachinesConfig.MatterReconstructor.DIVISOR
|
progressPerTick = (item.maxDamage / matter.complexity) / MachinesConfig.MatterReconstructor.DIVISOR
|
||||||
|
@ -21,9 +21,10 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
|||||||
import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
|
import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
|
||||||
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
|
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
|
import ru.dbotthepony.mc.otm.core.nextDecimal
|
||||||
import ru.dbotthepony.mc.otm.core.otmRandom
|
import ru.dbotthepony.mc.otm.core.otmRandom
|
||||||
import ru.dbotthepony.mc.otm.graph.matter.MatterGraph
|
import ru.dbotthepony.mc.otm.graph.matter.MatterGraph
|
||||||
import ru.dbotthepony.mc.otm.item.matter.MatterDustItem
|
import ru.dbotthepony.mc.otm.item.matter.MatterDustItem
|
||||||
@ -33,9 +34,7 @@ import ru.dbotthepony.mc.otm.data.codec.DecimalCodec
|
|||||||
import ru.dbotthepony.mc.otm.data.codec.minRange
|
import ru.dbotthepony.mc.otm.data.codec.minRange
|
||||||
import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
|
import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
|
||||||
|
|
||||||
class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryWorkerBlockEntity<MatterRecyclerBlockEntity.RecyclerJob>(MBlockEntities.MATTER_RECYCLER, blockPos, blockState, RecyclerJob.CODEC) {
|
||||||
: MatteryWorkerBlockEntity<MatterRecyclerBlockEntity.RecyclerJob>(MBlockEntities.MATTER_RECYCLER, blockPos, blockState, RecyclerJob.CODEC) {
|
|
||||||
|
|
||||||
class RecyclerJob(ticks: Double, powerUsage: Decimal, var totalMatter: Decimal) : Job(ticks, powerUsage) {
|
class RecyclerJob(ticks: Double, powerUsage: Decimal, var totalMatter: Decimal) : Job(ticks, powerUsage) {
|
||||||
companion object {
|
companion object {
|
||||||
val CODEC: Codec<RecyclerJob> by lazy {
|
val CODEC: Codec<RecyclerJob> by lazy {
|
||||||
@ -48,20 +47,22 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
|||||||
|
|
||||||
override val upgrades = makeUpgrades(3, UpgradeType.BASIC_MATTER)
|
override val upgrades = makeUpgrades(3, UpgradeType.BASIC_MATTER)
|
||||||
val matter = ProfiledMatterStorage(MatterStorageImpl(::matterLevelUpdated, FlowDirection.OUTPUT, upgrades.matterCapacity(MachinesConfig.MatterRecycler.VALUES::matterCapacity)))
|
val matter = ProfiledMatterStorage(MatterStorageImpl(::matterLevelUpdated, FlowDirection.OUTPUT, upgrades.matterCapacity(MachinesConfig.MatterRecycler.VALUES::matterCapacity)))
|
||||||
val container = MatteryContainer(::itemContainerUpdated, 1).also(::addDroppableContainer)
|
private class Slot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) {
|
||||||
|
override fun canAutomationTakeItem(desired: Int): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
|
return super.canAutomationPlaceItem(itemStack) && itemStack.item is MatterDustItem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val container = SlottedContainer.simple(1, ::Slot, ::itemContainerUpdated).also(::addDroppableContainer)
|
||||||
|
|
||||||
val matterNode = SimpleMatterNode(matter = matter)
|
val matterNode = SimpleMatterNode(matter = matter)
|
||||||
override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::energyLevelUpdated, upgrades.transform(MachinesConfig.MatterRecycler.VALUES)))
|
override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::energyLevelUpdated, upgrades.transform(MachinesConfig.MatterRecycler.VALUES)))
|
||||||
|
|
||||||
val itemConfig = ConfigurableItemHandler(input = container.handler(object : HandlerFilter {
|
val itemConfig = ConfigurableItemHandler(container)
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return stack.item is MatterDustItem
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
|
|
||||||
val energyConfig = ConfigurableEnergy(energy)
|
val energyConfig = ConfigurableEnergy(energy)
|
||||||
|
|
||||||
@ -137,7 +138,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
|||||||
else if (matter.receiveMatter(toReceive, true) != toReceive)
|
else if (matter.receiveMatter(toReceive, true) != toReceive)
|
||||||
return status.noMatter()
|
return status.noMatter()
|
||||||
|
|
||||||
matter.receiveMatter(toReceive * 0.4 + level!!.otmRandom.nextDouble() * 0.6, false)
|
matter.receiveMatter(toReceive * level!!.otmRandom.nextDecimal(BASE_RECEIVE, Decimal.ONE), false)
|
||||||
job.totalMatter -= toReceive
|
job.totalMatter -= toReceive
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,4 +152,8 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
|||||||
matter.extractMatter(received, false)
|
matter.extractMatter(received, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val BASE_RECEIVE = Decimal("0.4")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,8 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
|||||||
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.capability.matter.*
|
import ru.dbotthepony.mc.otm.capability.matter.*
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.otmRandom
|
import ru.dbotthepony.mc.otm.core.otmRandom
|
||||||
import ru.dbotthepony.mc.otm.data.codec.DecimalCodec
|
import ru.dbotthepony.mc.otm.data.codec.DecimalCodec
|
||||||
@ -71,11 +71,11 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
|||||||
override val upgrades = makeUpgrades(3, UpgradeType.REPLICATOR)
|
override val upgrades = makeUpgrades(3, UpgradeType.REPLICATOR)
|
||||||
override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::energyLevelUpdated, upgrades.transform(MachinesConfig.MATTER_REPLICATOR)))
|
override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::energyLevelUpdated, upgrades.transform(MachinesConfig.MATTER_REPLICATOR)))
|
||||||
val matter = ProfiledMatterStorage(MatterStorageImpl(::matterLevelUpdated, FlowDirection.INPUT, upgrades.matterCapacity(MachinesConfig.MATTER_REPLICATOR::matterCapacity)))
|
val matter = ProfiledMatterStorage(MatterStorageImpl(::matterLevelUpdated, FlowDirection.INPUT, upgrades.matterCapacity(MachinesConfig.MATTER_REPLICATOR::matterCapacity)))
|
||||||
val outputContainer = MatteryContainer(::itemContainerUpdated, 3).also(::addDroppableContainer)
|
val outputContainer = SlottedContainer.simple(3, AutomationFilters.ONLY_OUT.simpleProvider, ::itemContainerUpdated).also(::addDroppableContainer)
|
||||||
val dustContainer = MatteryContainer(::itemContainerUpdated, 2).also(::addDroppableContainer)
|
val dustContainer = SlottedContainer.simple(2, AutomationFilters.ONLY_OUT.simpleProvider, ::itemContainerUpdated).also(::addDroppableContainer)
|
||||||
|
|
||||||
val energyConfig = ConfigurableEnergy(energy)
|
val energyConfig = ConfigurableEnergy(energy)
|
||||||
val itemConfig = ConfigurableItemHandler(output = CombinedItemHandler(outputContainer.handler(HandlerFilter.OnlyOut), dustContainer.handler(HandlerFilter.OnlyOut)))
|
val itemConfig = ConfigurableItemHandler(output = CombinedItemHandler(outputContainer, dustContainer))
|
||||||
|
|
||||||
val matterNode = object : MatterNode() {
|
val matterNode = object : MatterNode() {
|
||||||
override fun getMatterHandler(): IMatterStorage {
|
override fun getMatterHandler(): IMatterStorage {
|
||||||
|
@ -20,8 +20,8 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
|||||||
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.capability.matter.PatternState
|
import ru.dbotthepony.mc.otm.capability.matter.PatternState
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.menu.matter.MatterScannerMenu
|
import ru.dbotthepony.mc.otm.menu.matter.MatterScannerMenu
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
||||||
import ru.dbotthepony.mc.otm.graph.matter.MatterNode
|
import ru.dbotthepony.mc.otm.graph.matter.MatterNode
|
||||||
@ -34,19 +34,20 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
|||||||
MatteryWorkerBlockEntity<ItemJob>(MBlockEntities.MATTER_SCANNER, p_155229_, p_155230_, ItemJob.CODEC) {
|
MatteryWorkerBlockEntity<ItemJob>(MBlockEntities.MATTER_SCANNER, p_155229_, p_155230_, ItemJob.CODEC) {
|
||||||
|
|
||||||
override val upgrades = makeUpgrades(2, UpgradeType.BASIC)
|
override val upgrades = makeUpgrades(2, UpgradeType.BASIC)
|
||||||
val container = MatteryContainer(::itemContainerUpdated, 1).also(::addDroppableContainer)
|
|
||||||
override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::energyLevelUpdated, upgrades.transform(MachinesConfig.MATTER_SCANNER)))
|
override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::energyLevelUpdated, upgrades.transform(MachinesConfig.MATTER_SCANNER)))
|
||||||
|
|
||||||
val itemConfig = ConfigurableItemHandler(inputOutput = container.handler(object : HandlerFilter {
|
private inner class Slot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) {
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
return MatterManager.canDecompose(stack)
|
return super.canAutomationPlaceItem(itemStack) && MatterManager.canDecompose(itemStack)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
override fun canAutomationTakeItem(desired: Int): Boolean {
|
||||||
return jobEventLoops[0].isIdling
|
return jobEventLoops[0].isIdling && super.canAutomationTakeItem(desired)
|
||||||
}
|
}
|
||||||
}))
|
}
|
||||||
|
|
||||||
|
val container = SlottedContainer.simple(1, ::Slot, ::itemContainerUpdated).also(::addDroppableContainer)
|
||||||
|
val itemConfig = ConfigurableItemHandler(inputOutput = container)
|
||||||
val energyConfig = ConfigurableEnergy(energy)
|
val energyConfig = ConfigurableEnergy(energy)
|
||||||
|
|
||||||
val matterNode = object : MatterNode() {
|
val matterNode = object : MatterNode() {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package ru.dbotthepony.mc.otm.block.entity.matter
|
package ru.dbotthepony.mc.otm.block.entity.matter
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.server.level.ServerLevel
|
||||||
import net.minecraft.world.level.block.state.BlockState
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||||
import ru.dbotthepony.mc.otm.block.matter.PatternStorageBlock
|
import ru.dbotthepony.mc.otm.block.matter.PatternStorageBlock
|
||||||
@ -14,7 +14,8 @@ import net.minecraft.world.level.Level
|
|||||||
import net.minecraft.world.level.block.Block
|
import net.minecraft.world.level.block.Block
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.capability.matter.*
|
import ru.dbotthepony.mc.otm.capability.matter.*
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.core.collect.filterNotNull
|
import ru.dbotthepony.mc.otm.core.collect.filterNotNull
|
||||||
import ru.dbotthepony.mc.otm.core.collect.map
|
import ru.dbotthepony.mc.otm.core.collect.map
|
||||||
import ru.dbotthepony.mc.otm.core.filterNotNull
|
import ru.dbotthepony.mc.otm.core.filterNotNull
|
||||||
@ -23,53 +24,48 @@ import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
|
|||||||
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
|
|
||||||
class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.PATTERN_STORAGE, p_155229_, p_155230_), IPatternStorage {
|
||||||
MatteryDeviceBlockEntity(MBlockEntities.PATTERN_STORAGE, p_155229_, p_155230_), IPatternStorage {
|
|
||||||
|
|
||||||
val matterNode = SimpleMatterNode(patterns = this)
|
val matterNode = SimpleMatterNode(patterns = this)
|
||||||
|
|
||||||
val container: MatteryContainer = object : MatteryContainer(::markDirtyFast, 8) {
|
private inner class Slot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) {
|
||||||
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
|
override val maxStackSize: Int
|
||||||
if (!ItemStack.isSameItemSameComponents(new, old)) {
|
get() = 1
|
||||||
|
|
||||||
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
|
return super.canAutomationPlaceItem(itemStack) && itemStack.getCapability(MatteryCapability.PATTERN_ITEM) != null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canAutomationTakeItem(desired: Int): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun notifyChanged(old: ItemStack) {
|
||||||
|
if (!ItemStack.isSameItemSameComponents(item, old)) {
|
||||||
if (!old.isEmpty) {
|
if (!old.isEmpty) {
|
||||||
old.getCapability(MatteryCapability.PATTERN_ITEM)?.let { cap: IPatternStorage ->
|
old.getCapability(MatteryCapability.PATTERN_ITEM)?.let { cap: IPatternStorage ->
|
||||||
cap.patterns.forEach { matterNode.graph.onPatternRemoved(it) }
|
cap.patterns.forEach { matterNode.graph.onPatternRemoved(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!new.isEmpty) {
|
if (!item.isEmpty) {
|
||||||
new.getCapability(MatteryCapability.PATTERN_ITEM)?.let { cap: IPatternStorage ->
|
item.getCapability(MatteryCapability.PATTERN_ITEM)?.let { cap: IPatternStorage ->
|
||||||
cap.patterns.forEach { matterNode.graph.onPatternAdded(it) }
|
cap.patterns.forEach { matterNode.graph.onPatternAdded(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateBlockstate()
|
val level = level
|
||||||
|
|
||||||
|
if (level is ServerLevel) {
|
||||||
|
level.setBlock(blockPos, blockState.setValue(PatternStorageBlock.PATTERN_STORAGE_DISKS_PROPS[slot], item.getCapability(MatteryCapability.PATTERN_ITEM) != null), Block.UPDATE_CLIENTS)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super.setChanged(slot, new, old)
|
super.notifyChanged(old)
|
||||||
}
|
|
||||||
|
|
||||||
override fun getMaxStackSize(): Int = 1
|
|
||||||
}.also(::addDroppableContainer)
|
|
||||||
|
|
||||||
private fun updateBlockstate() {
|
|
||||||
val level = level ?: return
|
|
||||||
|
|
||||||
var state = blockState
|
|
||||||
|
|
||||||
for (i in 0..7) {
|
|
||||||
state = state.setValue(
|
|
||||||
PatternStorageBlock.PATTERN_STORAGE_DISKS_PROPS[i],
|
|
||||||
this.container.getItem(i).getCapability(MatteryCapability.PATTERN_ITEM) != null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state !== blockState) {
|
|
||||||
level.setBlock(blockPos, state, Block.UPDATE_CLIENTS)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val itemConfig = ConfigurableItemHandler(inputOutput = container.handler(HandlerFilter.IsPattern.and(HandlerFilter.OnlyIn)))
|
val container = SlottedContainer.simple(2 * 4, ::Slot, ::markDirtyFast).also(::addDroppableContainer)
|
||||||
|
val itemConfig = ConfigurableItemHandler(inputOutput = container)
|
||||||
|
|
||||||
override fun setLevel(level: Level) {
|
override fun setLevel(level: Level) {
|
||||||
super.setLevel(level)
|
super.setLevel(level)
|
||||||
@ -96,20 +92,12 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val patternCapacity: Int get() {
|
override val patternCapacity: Int get() {
|
||||||
var stored = 0L
|
val stored = container.sumOf { it.getCapability(MatteryCapability.PATTERN_ITEM)?.patternCapacity?.toLong() ?: 0L }
|
||||||
|
|
||||||
for (pattern in this.container.iterator().map { it.getCapability(MatteryCapability.PATTERN_ITEM) }.filterNotNull())
|
|
||||||
stored += pattern.patternCapacity.toLong()
|
|
||||||
|
|
||||||
return if (stored > Int.MAX_VALUE) Int.MAX_VALUE else stored.toInt()
|
return if (stored > Int.MAX_VALUE) Int.MAX_VALUE else stored.toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val storedPatterns: Int get() {
|
override val storedPatterns: Int get() {
|
||||||
var stored = 0L
|
val stored = container.sumOf { it.getCapability(MatteryCapability.PATTERN_ITEM)?.storedPatterns?.toLong() ?: 0L }
|
||||||
|
|
||||||
for (pattern in this.container.iterator().map { it.getCapability(MatteryCapability.PATTERN_ITEM) }.filterNotNull())
|
|
||||||
stored += pattern.storedPatterns.toLong()
|
|
||||||
|
|
||||||
return if (stored > Int.MAX_VALUE) Int.MAX_VALUE else stored.toInt()
|
return if (stored > Int.MAX_VALUE) Int.MAX_VALUE else stored.toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,8 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
|||||||
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.menu.storage.DriveRackMenu
|
import ru.dbotthepony.mc.otm.menu.storage.DriveRackMenu
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
||||||
import ru.dbotthepony.mc.otm.storage.optics.priority
|
import ru.dbotthepony.mc.otm.storage.optics.priority
|
||||||
@ -45,19 +46,21 @@ class DriveRackBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
|
|||||||
markDirtyFast()
|
markDirtyFast()
|
||||||
}
|
}
|
||||||
|
|
||||||
val container: MatteryContainer = object : MatteryContainer(::markDirtyFast, 4) {
|
private inner class Slot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) {
|
||||||
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
|
override fun notifyChanged(old: ItemStack) {
|
||||||
super.setChanged(slot, new, old)
|
super.notifyChanged(old)
|
||||||
|
|
||||||
old.getCapability(MatteryCapability.CONDENSATION_DRIVE)?.let {
|
old.getCapability(MatteryCapability.CONDENSATION_DRIVE)?.let {
|
||||||
cell.removeStorageComponent(it.priority(::insertPriority, ::extractPriority).powered(energy).flow(::mode))
|
cell.removeStorageComponent(it.priority(::insertPriority, ::extractPriority).powered(energy).flow(::mode))
|
||||||
}
|
}
|
||||||
|
|
||||||
new.getCapability(MatteryCapability.CONDENSATION_DRIVE)?.let {
|
item.getCapability(MatteryCapability.CONDENSATION_DRIVE)?.let {
|
||||||
cell.addStorageComponent(it.priority(::insertPriority, ::extractPriority).powered(energy).flow(::mode))
|
cell.addStorageComponent(it.priority(::insertPriority, ::extractPriority).powered(energy).flow(::mode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.also(::addDroppableContainer)
|
}
|
||||||
|
|
||||||
|
val container = SlottedContainer.simple(4, ::Slot, ::markDirtyFast).also(::addDroppableContainer)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
savetables.stateful(::energy, ENERGY_KEY)
|
savetables.stateful(::energy, ENERGY_KEY)
|
||||||
|
@ -17,7 +17,7 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
|||||||
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.EnhancedContainer
|
||||||
import ru.dbotthepony.mc.otm.core.get
|
import ru.dbotthepony.mc.otm.core.get
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.util.ItemStorageStackSorter
|
import ru.dbotthepony.mc.otm.core.util.ItemStorageStackSorter
|
||||||
@ -29,15 +29,16 @@ class DriveViewerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
|
|||||||
override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyUpdated, MachinesConfig.DRIVE_VIEWER))
|
override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyUpdated, MachinesConfig.DRIVE_VIEWER))
|
||||||
val energyConfig = ConfigurableEnergy(energy)
|
val energyConfig = ConfigurableEnergy(energy)
|
||||||
|
|
||||||
val container: MatteryContainer = object : MatteryContainer(::markDirtyFast, 1) {
|
val container: EnhancedContainer.Simple = object : EnhancedContainer.Simple(1) {
|
||||||
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
|
override fun notifySlotChanged(slot: Int, old: ItemStack) {
|
||||||
super.setChanged(slot, new, old)
|
super.notifySlotChanged(slot, old)
|
||||||
|
markDirtyFast()
|
||||||
|
|
||||||
val level = level
|
val level = level
|
||||||
|
|
||||||
if (level is ServerLevel) {
|
if (level is ServerLevel) {
|
||||||
tickList.once {
|
tickList.once {
|
||||||
val isPresent = new.getCapability(MatteryCapability.CONDENSATION_DRIVE) != null
|
val isPresent = get(slot).getCapability(MatteryCapability.CONDENSATION_DRIVE) != null
|
||||||
var state = this@DriveViewerBlockEntity.blockState.setValue(DriveViewerBlock.DRIVE_PRESENT, isPresent)
|
var state = this@DriveViewerBlockEntity.blockState.setValue(DriveViewerBlock.DRIVE_PRESENT, isPresent)
|
||||||
|
|
||||||
if (!isPresent) {
|
if (!isPresent) {
|
||||||
|
@ -29,12 +29,14 @@ import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
|
|||||||
import ru.dbotthepony.mc.otm.client.render.Widgets8
|
import ru.dbotthepony.mc.otm.client.render.Widgets8
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.CombinedContainer
|
import ru.dbotthepony.mc.otm.container.CombinedContainer
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryCraftingContainer
|
import ru.dbotthepony.mc.otm.container.EnhancedContainer
|
||||||
|
import ru.dbotthepony.mc.otm.container.IEnhancedCraftingContainer
|
||||||
import ru.dbotthepony.mc.otm.container.util.slotIterator
|
import ru.dbotthepony.mc.otm.container.util.slotIterator
|
||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
import ru.dbotthepony.mc.otm.core.collect.map
|
import ru.dbotthepony.mc.otm.core.collect.map
|
||||||
import ru.dbotthepony.mc.otm.core.collect.toList
|
import ru.dbotthepony.mc.otm.core.collect.toList
|
||||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||||
|
import ru.dbotthepony.mc.otm.core.nbt.map
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.mapString
|
import ru.dbotthepony.mc.otm.core.nbt.mapString
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||||
import ru.dbotthepony.mc.otm.core.util.ItemStorageStackSorter
|
import ru.dbotthepony.mc.otm.core.util.ItemStorageStackSorter
|
||||||
@ -94,42 +96,42 @@ class ItemMonitorPlayerSettings : INBTSerializable<CompoundTag>, IItemMonitorPla
|
|||||||
enum class IngredientPriority(override val component: Component, icon: Lazy<IGUIRenderable>, override val winding: UVWindingOrder = UVWindingOrder.NORMAL) : Setting {
|
enum class IngredientPriority(override val component: Component, icon: Lazy<IGUIRenderable>, override val winding: UVWindingOrder = UVWindingOrder.NORMAL) : Setting {
|
||||||
// Refill everything from system
|
// Refill everything from system
|
||||||
SYSTEM(TranslatableComponent("otm.gui.item_monitor.refill_source.system"), lazy { Widgets8.WHITE_ARROW_DOWN }, UVWindingOrder.FLIP) {
|
SYSTEM(TranslatableComponent("otm.gui.item_monitor.refill_source.system"), lazy { Widgets8.WHITE_ARROW_DOWN }, UVWindingOrder.FLIP) {
|
||||||
override fun takeOne(item: ItemStack, view: IStorageProvider<ItemStorageStack>?, inventory: CombinedContainer?, id: UUID?): Boolean {
|
override fun takeOne(item: ItemStack, view: IStorageProvider<ItemStorageStack>?, inventory: CombinedContainer<*>?, id: UUID?): Boolean {
|
||||||
return takeOne(id, view)
|
return takeOne(id, view)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Refill everything from player's inventory
|
// Refill everything from player's inventory
|
||||||
INVENTORY(TranslatableComponent("otm.gui.item_monitor.refill_source.inventory"), lazy { Widgets8.WHITE_ARROW_DOWN }) {
|
INVENTORY(TranslatableComponent("otm.gui.item_monitor.refill_source.inventory"), lazy { Widgets8.WHITE_ARROW_DOWN }) {
|
||||||
override fun takeOne(item: ItemStack, view: IStorageProvider<ItemStorageStack>?, inventory: CombinedContainer?, id: UUID?): Boolean {
|
override fun takeOne(item: ItemStack, view: IStorageProvider<ItemStorageStack>?, inventory: CombinedContainer<*>?, id: UUID?): Boolean {
|
||||||
return takeOne(inventory, item)
|
return takeOne(inventory, item)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Refill everything from system, if can't refill from player's inventory
|
// Refill everything from system, if can't refill from player's inventory
|
||||||
SYSTEM_FIRST(TranslatableComponent("otm.gui.item_monitor.refill_source.system_first"), lazy { Widgets8.ARROW_SIDEWAYS }, UVWindingOrder.FLIP) {
|
SYSTEM_FIRST(TranslatableComponent("otm.gui.item_monitor.refill_source.system_first"), lazy { Widgets8.ARROW_SIDEWAYS }, UVWindingOrder.FLIP) {
|
||||||
override fun takeOne(item: ItemStack, view: IStorageProvider<ItemStorageStack>?, inventory: CombinedContainer?, id: UUID?): Boolean {
|
override fun takeOne(item: ItemStack, view: IStorageProvider<ItemStorageStack>?, inventory: CombinedContainer<*>?, id: UUID?): Boolean {
|
||||||
return takeOne(id, view) || takeOne(inventory, item)
|
return takeOne(id, view) || takeOne(inventory, item)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Refill everything from player's inventory, if can't refill from system
|
// Refill everything from player's inventory, if can't refill from system
|
||||||
INVENTORY_FIRST(TranslatableComponent("otm.gui.item_monitor.refill_source.inventory_first"), lazy { Widgets8.ARROW_SIDEWAYS }) {
|
INVENTORY_FIRST(TranslatableComponent("otm.gui.item_monitor.refill_source.inventory_first"), lazy { Widgets8.ARROW_SIDEWAYS }) {
|
||||||
override fun takeOne(item: ItemStack, view: IStorageProvider<ItemStorageStack>?, inventory: CombinedContainer?, id: UUID?): Boolean {
|
override fun takeOne(item: ItemStack, view: IStorageProvider<ItemStorageStack>?, inventory: CombinedContainer<*>?, id: UUID?): Boolean {
|
||||||
return takeOne(inventory, item) || takeOne(id, view)
|
return takeOne(inventory, item) || takeOne(id, view)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Do not refill (?)
|
// Do not refill (?)
|
||||||
DO_NOT(TranslatableComponent("otm.gui.item_monitor.refill_source.do_not"), lazy { Widgets8.MINUS }) {
|
DO_NOT(TranslatableComponent("otm.gui.item_monitor.refill_source.do_not"), lazy { Widgets8.MINUS }) {
|
||||||
override fun takeOne(item: ItemStack, view: IStorageProvider<ItemStorageStack>?, inventory: CombinedContainer?, id: UUID?): Boolean {
|
override fun takeOne(item: ItemStack, view: IStorageProvider<ItemStorageStack>?, inventory: CombinedContainer<*>?, id: UUID?): Boolean {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
override val icon: IGUIRenderable by icon
|
override val icon: IGUIRenderable by icon
|
||||||
|
|
||||||
abstract fun takeOne(item: ItemStack, view: IStorageProvider<ItemStorageStack>?, inventory: CombinedContainer?, id: UUID?): Boolean
|
abstract fun takeOne(item: ItemStack, view: IStorageProvider<ItemStorageStack>?, inventory: CombinedContainer<*>?, id: UUID?): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class ResultTarget(override val component: Component, icon: Lazy<IGUIRenderable>, override val winding: UVWindingOrder = UVWindingOrder.NORMAL) : Setting {
|
enum class ResultTarget(override val component: Component, icon: Lazy<IGUIRenderable>, override val winding: UVWindingOrder = UVWindingOrder.NORMAL) : Setting {
|
||||||
@ -216,17 +218,13 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
|
|||||||
fun howMuchPlayerCrafted(ply: Player): Int = craftingAmount.getInt(ply)
|
fun howMuchPlayerCrafted(ply: Player): Int = craftingAmount.getInt(ply)
|
||||||
fun lastCraftingRecipe(ply: Player) = lastCraftingRecipe[ply]
|
fun lastCraftingRecipe(ply: Player) = lastCraftingRecipe[ply]
|
||||||
|
|
||||||
// a lot of code is hardcoded to take CraftingContainer as it's input
|
val craftingGrid = IEnhancedCraftingContainer.Wrapper(EnhancedContainer.WithListener(3 * 3) {
|
||||||
// hence we are forced to work around this by providing proxy container
|
markDirtyFast()
|
||||||
val craftingGrid = object : MatteryCraftingContainer(::markDirtyFast, 3, 3) {
|
|
||||||
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
|
|
||||||
markDirtyFast()
|
|
||||||
|
|
||||||
if (!inProcessOfCraft) {
|
if (!inProcessOfCraft) {
|
||||||
scanCraftingGrid(false)
|
scanCraftingGrid(false)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.also(::addDroppableContainer)
|
}, 3, 3).also(::addDroppableContainer)
|
||||||
|
|
||||||
private fun scanCraftingGrid(justCheckForRecipeChange: Boolean): Boolean {
|
private fun scanCraftingGrid(justCheckForRecipeChange: Boolean): Boolean {
|
||||||
val level = level ?: return false
|
val level = level ?: return false
|
||||||
@ -346,8 +344,8 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
|
|||||||
|
|
||||||
check(residue.size == craftingGrid.containerSize) { "Container and residue list sizes mismatch: ${residue.size} != ${craftingGrid.containerSize}" }
|
check(residue.size == craftingGrid.containerSize) { "Container and residue list sizes mismatch: ${residue.size} != ${craftingGrid.containerSize}" }
|
||||||
|
|
||||||
val combinedInventory = craftingPlayer.matteryPlayer?.inventoryAndExopack
|
val combinedInventory = craftingPlayer.matteryPlayer.inventoryAndExopack
|
||||||
val copy = craftingGrid.iterator(false).map { it.copy() }.toList()
|
val copy = craftingGrid.parent.copyToList()
|
||||||
|
|
||||||
// удаляем по одному предмету из сетки крафта
|
// удаляем по одному предмету из сетки крафта
|
||||||
for (slot in 0 until craftingGrid.containerSize) {
|
for (slot in 0 until craftingGrid.containerSize) {
|
||||||
@ -381,7 +379,7 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
|
|||||||
remaining = poweredView?.insertStack(ItemStorageStack(remaining), false)?.toItemStack() ?: remaining
|
remaining = poweredView?.insertStack(ItemStorageStack(remaining), false)?.toItemStack() ?: remaining
|
||||||
}
|
}
|
||||||
|
|
||||||
remaining = combinedInventory?.addItem(remaining, false) ?: remaining
|
remaining = combinedInventory.addItem(remaining, false)
|
||||||
|
|
||||||
if (remaining.isNotEmpty) {
|
if (remaining.isNotEmpty) {
|
||||||
craftingPlayer.spawnAtLocation(remaining)
|
craftingPlayer.spawnAtLocation(remaining)
|
||||||
@ -425,7 +423,7 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
nbt["crafting_grid"] = craftingGrid.serializeNBT(registry)
|
nbt["crafting_grid"] = craftingGrid.parent.serializeNBT(registry)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
|
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
|
||||||
@ -438,7 +436,7 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
|
|||||||
check(this.settings.put(UUID.fromString(key), ItemMonitorPlayerSettings().also { it.deserializeNBT(registry, settings.getCompound(key)) }) == null)
|
check(this.settings.put(UUID.fromString(key), ItemMonitorPlayerSettings().also { it.deserializeNBT(registry, settings.getCompound(key)) }) == null)
|
||||||
}
|
}
|
||||||
|
|
||||||
craftingGrid.deserializeNBT(registry, nbt["crafting_grid"])
|
nbt.map("crafting_grid", craftingGrid.parent::deserializeNBT, registry)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSettings(ply: ServerPlayer): ItemMonitorPlayerSettings {
|
fun getSettings(ply: ServerPlayer): ItemMonitorPlayerSettings {
|
||||||
|
@ -23,7 +23,7 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
|||||||
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.ItemFilter
|
import ru.dbotthepony.mc.otm.container.ItemFilterSet
|
||||||
import ru.dbotthepony.mc.otm.core.*
|
import ru.dbotthepony.mc.otm.core.*
|
||||||
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
||||||
import ru.dbotthepony.mc.otm.core.math.isPositive
|
import ru.dbotthepony.mc.otm.core.math.isPositive
|
||||||
@ -123,7 +123,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var filter = ItemFilter(MAX_FILTERS)
|
var filter = ItemFilterSet.EMPTY
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
component?.scan()
|
component?.scan()
|
||||||
@ -131,7 +131,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
|
|||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
savetablesConfig.codec(::filter, ItemFilter.CODEC, FILTER_KEY, Supplier { ItemFilter(MAX_FILTERS) })
|
savetablesConfig.codec(::filter, ItemFilterSet.CODEC, FILTER_KEY, Supplier { ItemFilterSet.EMPTY })
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setLevel(level: Level) {
|
override fun setLevel(level: Level) {
|
||||||
@ -348,7 +348,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun scan(slot: Int) {
|
fun scan(slot: Int) {
|
||||||
val current = parent[slot].let { if (it.isEmpty || !filter.match(it)) null else it }
|
val current = parent[slot].let { if (it.isEmpty || !filter.test(it)) null else it }
|
||||||
val last = slot2itemStack[slot]
|
val last = slot2itemStack[slot]
|
||||||
|
|
||||||
if (current == null && last != null) {
|
if (current == null && last != null) {
|
||||||
@ -374,7 +374,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun insertStack(stack: ItemStorageStack, simulate: Boolean): ItemStorageStack {
|
override fun insertStack(stack: ItemStorageStack, simulate: Boolean): ItemStorageStack {
|
||||||
if (redstoneControl.isBlockedByRedstone || energy.batteryLevel.isZero || !filter.match(stack.toItemStack()) || !mode.input)
|
if (redstoneControl.isBlockedByRedstone || energy.batteryLevel.isZero || !filter.test(stack.toItemStack()) || !mode.input)
|
||||||
return stack
|
return stack
|
||||||
|
|
||||||
val required = StorageStack.ITEMS.energyPerInsert(stack)
|
val required = StorageStack.ITEMS.energyPerInsert(stack)
|
||||||
|
@ -23,7 +23,7 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
|||||||
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.config.EnergyBalanceValues
|
import ru.dbotthepony.mc.otm.config.EnergyBalanceValues
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.ItemFilter
|
import ru.dbotthepony.mc.otm.container.ItemFilterSet
|
||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||||
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
||||||
@ -98,7 +98,7 @@ abstract class AbstractStorageImportExport(
|
|||||||
|
|
||||||
protected val target = CapabilityCache(RelativeSide.FRONT, Capabilities.ItemHandler.BLOCK)
|
protected val target = CapabilityCache(RelativeSide.FRONT, Capabilities.ItemHandler.BLOCK)
|
||||||
|
|
||||||
var filter: ItemFilter = ItemFilter(MAX_FILTERS)
|
var filter: ItemFilterSet = ItemFilterSet.EMPTY
|
||||||
set(value) {
|
set(value) {
|
||||||
if (value != field) {
|
if (value != field) {
|
||||||
field = value
|
field = value
|
||||||
@ -112,7 +112,7 @@ abstract class AbstractStorageImportExport(
|
|||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
savetablesConfig.codec(::filter, ItemFilter.CODEC, FILTER_KEY, Supplier { ItemFilter(MAX_FILTERS) })
|
savetablesConfig.codec(::filter, ItemFilterSet.CODEC, FILTER_KEY, Supplier { ItemFilterSet.EMPTY })
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -168,7 +168,7 @@ class StorageImporterBlockEntity(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean): ItemStack {
|
override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean): ItemStack {
|
||||||
if (redstoneControl.isBlockedByRedstone || !filter.match(stack))
|
if (redstoneControl.isBlockedByRedstone || !filter.test(stack))
|
||||||
return stack
|
return stack
|
||||||
|
|
||||||
return acceptItem(stack, simulate)
|
return acceptItem(stack, simulate)
|
||||||
@ -183,7 +183,7 @@ class StorageImporterBlockEntity(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun isItemValid(slot: Int, stack: ItemStack): Boolean {
|
override fun isItemValid(slot: Int, stack: ItemStack): Boolean {
|
||||||
return filter.match(stack)
|
return filter.test(stack)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tick() {
|
override fun tick() {
|
||||||
@ -205,7 +205,7 @@ class StorageImporterBlockEntity(
|
|||||||
|
|
||||||
val extracted = target.extractItem(lastSlot, MAX_MOVE_PER_OPERATION, true)
|
val extracted = target.extractItem(lastSlot, MAX_MOVE_PER_OPERATION, true)
|
||||||
|
|
||||||
if (extracted.isEmpty || !filter.match(extracted)) {
|
if (extracted.isEmpty || !filter.test(extracted)) {
|
||||||
lastSlot++
|
lastSlot++
|
||||||
} else {
|
} else {
|
||||||
val leftover = acceptItem(extracted, true)
|
val leftover = acceptItem(extracted, true)
|
||||||
@ -244,7 +244,7 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onStackAdded(stack: ItemStorageStack, id: UUID, provider: IStorageProvider<ItemStorageStack>) {
|
override fun onStackAdded(stack: ItemStorageStack, id: UUID, provider: IStorageProvider<ItemStorageStack>) {
|
||||||
if (filter.match(stack.toItemStack())) {
|
if (filter.test(stack.toItemStack())) {
|
||||||
relevantTuples.add(id)
|
relevantTuples.add(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import net.minecraft.world.item.crafting.SmokingRecipe
|
|||||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||||
import net.minecraft.world.level.block.state.BlockState
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
import net.neoforged.neoforge.capabilities.Capabilities
|
import net.neoforged.neoforge.capabilities.Capabilities
|
||||||
|
import net.neoforged.neoforge.event.AddReloadListenerEvent
|
||||||
import ru.dbotthepony.kommons.util.getValue
|
import ru.dbotthepony.kommons.util.getValue
|
||||||
import ru.dbotthepony.kommons.util.setValue
|
import ru.dbotthepony.kommons.util.setValue
|
||||||
import ru.dbotthepony.mc.otm.block.entity.ExperienceStorage
|
import ru.dbotthepony.mc.otm.block.entity.ExperienceStorage
|
||||||
@ -29,33 +30,60 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
|||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.config.WorkerBalanceValues
|
import ru.dbotthepony.mc.otm.config.WorkerBalanceValues
|
||||||
import ru.dbotthepony.mc.otm.container.CombinedContainer
|
import ru.dbotthepony.mc.otm.container.CombinedContainer
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
|
||||||
import ru.dbotthepony.mc.otm.container.balance
|
import ru.dbotthepony.mc.otm.container.balance
|
||||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||||
import ru.dbotthepony.mc.otm.core.collect.maybe
|
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
|
import ru.dbotthepony.mc.otm.core.SimpleCache
|
||||||
import ru.dbotthepony.mc.otm.core.immutableList
|
import ru.dbotthepony.mc.otm.core.immutableList
|
||||||
import ru.dbotthepony.mc.otm.core.otmRandom
|
import ru.dbotthepony.mc.otm.core.otmRandom
|
||||||
|
import ru.dbotthepony.mc.otm.container.ItemStackKey
|
||||||
|
import ru.dbotthepony.mc.otm.container.asKey
|
||||||
import ru.dbotthepony.mc.otm.menu.tech.PoweredFurnaceMenu
|
import ru.dbotthepony.mc.otm.menu.tech.PoweredFurnaceMenu
|
||||||
import ru.dbotthepony.mc.otm.recipe.MatteryCookingRecipe
|
import ru.dbotthepony.mc.otm.recipe.MatteryCookingRecipe
|
||||||
import ru.dbotthepony.mc.otm.recipe.MicrowaveRecipe
|
import ru.dbotthepony.mc.otm.recipe.MicrowaveRecipe
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MRecipes
|
import ru.dbotthepony.mc.otm.registry.game.MRecipes
|
||||||
|
import java.time.Duration
|
||||||
|
|
||||||
sealed class AbstractPoweredFurnaceBlockEntity<P : AbstractCookingRecipe, S : MatteryCookingRecipe>(
|
sealed class AbstractPoweredFurnaceBlockEntity<P : AbstractCookingRecipe, S : MatteryCookingRecipe>(
|
||||||
type: BlockEntityType<*>,
|
type: BlockEntityType<*>,
|
||||||
blockPos: BlockPos,
|
blockPos: BlockPos,
|
||||||
blockState: BlockState,
|
blockState: BlockState,
|
||||||
val recipeType: RecipeType<P>,
|
|
||||||
val secondaryRecipeType: RecipeType<S>?,
|
|
||||||
val config: WorkerBalanceValues,
|
|
||||||
maxJobs: Int = 2
|
maxJobs: Int = 2
|
||||||
) : MatteryWorkerBlockEntity<ItemJob>(type, blockPos, blockState, ItemJob.CODEC, maxJobs) {
|
) : MatteryWorkerBlockEntity<ItemJob>(type, blockPos, blockState, ItemJob.CODEC, maxJobs) {
|
||||||
|
abstract val recipeType: RecipeType<P>
|
||||||
|
abstract val secondaryRecipeType: RecipeType<S>?
|
||||||
|
abstract val config: WorkerBalanceValues
|
||||||
|
|
||||||
final override val upgrades = makeUpgrades(2, UpgradeType.BASIC_PROCESSING)
|
final override val upgrades = makeUpgrades(2, UpgradeType.BASIC_PROCESSING)
|
||||||
final override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyLevelUpdated, upgrades.transform(config)))
|
final override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyLevelUpdated, upgrades.transform(config)))
|
||||||
|
|
||||||
val inputs = MatteryContainer(this::itemContainerUpdated, maxJobs)
|
private inner class InputSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) {
|
||||||
val outputs = MatteryContainer(this::itemContainerUpdated, maxJobs)
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
|
if (!super.canAutomationPlaceItem(itemStack))
|
||||||
|
return false
|
||||||
|
|
||||||
|
val level = level ?: return true
|
||||||
|
|
||||||
|
return acceptableItems.get(itemStack.asKey()) {
|
||||||
|
val input = SingleRecipeInput(itemStack)
|
||||||
|
val secondaryRecipeType = secondaryRecipeType
|
||||||
|
|
||||||
|
if (secondaryRecipeType != null && level.recipeManager.byType(secondaryRecipeType).any { it.value.matches(input, level) })
|
||||||
|
return@get true
|
||||||
|
|
||||||
|
return@get level.recipeManager.byType(recipeType).any { it.value.matches(input, level) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canAutomationTakeItem(desired: Int): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val inputs = SlottedContainer.simple(maxJobs, ::InputSlot, ::itemContainerUpdated)
|
||||||
|
val outputs = SlottedContainer.simple(maxJobs, AutomationFilters.ONLY_OUT.simpleProvider, ::itemContainerUpdated)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
addDroppableContainer(inputs)
|
addDroppableContainer(inputs)
|
||||||
@ -76,9 +104,9 @@ sealed class AbstractPoweredFurnaceBlockEntity<P : AbstractCookingRecipe, S : Ma
|
|||||||
val experience = ExperienceStorage(config::maxExperienceStored).also(::addNeighbourListener)
|
val experience = ExperienceStorage(config::maxExperienceStored).also(::addNeighbourListener)
|
||||||
val energyConfig = ConfigurableEnergy(energy)
|
val energyConfig = ConfigurableEnergy(energy)
|
||||||
val itemConfig = ConfigurableItemHandler(
|
val itemConfig = ConfigurableItemHandler(
|
||||||
input = inputs.handler(HandlerFilter.OnlyIn),
|
input = inputs,
|
||||||
output = outputs.handler(HandlerFilter.OnlyOut),
|
output = outputs,
|
||||||
battery = batteryItemHandler
|
battery = batteryContainer
|
||||||
)
|
)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -127,13 +155,13 @@ sealed class AbstractPoweredFurnaceBlockEntity<P : AbstractCookingRecipe, S : Ma
|
|||||||
return JobContainer.noItem()
|
return JobContainer.noItem()
|
||||||
|
|
||||||
val level = level as? ServerLevel ?: return JobContainer.failure()
|
val level = level as? ServerLevel ?: return JobContainer.failure()
|
||||||
|
val secondaryRecipeType = secondaryRecipeType
|
||||||
|
|
||||||
if (secondaryRecipeType != null) {
|
if (secondaryRecipeType != null) {
|
||||||
val recipe = level.recipeManager
|
val recipe = level.recipeManager
|
||||||
.byType(secondaryRecipeType)
|
.byType(secondaryRecipeType)
|
||||||
.iterator()
|
.firstOrNull { it.value.matches(SingleRecipeInput(inputs[id]), level) }
|
||||||
.filter { it.value.matches(SingleRecipeInput(inputs[id]), level) }
|
?.value
|
||||||
.maybe()?.value
|
|
||||||
|
|
||||||
if (recipe != null) {
|
if (recipe != null) {
|
||||||
val toProcess = inputs[id].count.coerceAtMost(1 + upgrades.processingItems)
|
val toProcess = inputs[id].count.coerceAtMost(1 + upgrades.processingItems)
|
||||||
@ -172,24 +200,51 @@ sealed class AbstractPoweredFurnaceBlockEntity<P : AbstractCookingRecipe, S : Ma
|
|||||||
))
|
))
|
||||||
}.orElse(JobContainer.noItem())
|
}.orElse(JobContainer.noItem())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// shared by all furnace instances, so cache should be large enough
|
||||||
|
private val acceptableItems = SimpleCache<ItemStackKey, Boolean>(Duration.ofMinutes(1))
|
||||||
|
|
||||||
|
internal fun onReload(event: AddReloadListenerEvent) {
|
||||||
|
acceptableItems.invalidateAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PoweredFurnaceBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractPoweredFurnaceBlockEntity<SmeltingRecipe, MatteryCookingRecipe>(
|
class PoweredFurnaceBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractPoweredFurnaceBlockEntity<SmeltingRecipe, MatteryCookingRecipe>(MBlockEntities.POWERED_FURNACE, blockPos, blockState) {
|
||||||
MBlockEntities.POWERED_FURNACE, blockPos, blockState, RecipeType.SMELTING, null, MachinesConfig.POWERED_FURNACE) {
|
override val recipeType: RecipeType<SmeltingRecipe>
|
||||||
|
get() = RecipeType.SMELTING
|
||||||
|
override val secondaryRecipeType: RecipeType<MatteryCookingRecipe>?
|
||||||
|
get() = null
|
||||||
|
override val config: WorkerBalanceValues
|
||||||
|
get() = MachinesConfig.POWERED_FURNACE
|
||||||
|
|
||||||
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
||||||
return PoweredFurnaceMenu.furnace(containerID, inventory, this)
|
return PoweredFurnaceMenu.furnace(containerID, inventory, this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PoweredBlastFurnaceBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractPoweredFurnaceBlockEntity<BlastingRecipe, MatteryCookingRecipe>(
|
class PoweredBlastFurnaceBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractPoweredFurnaceBlockEntity<BlastingRecipe, MatteryCookingRecipe>(MBlockEntities.POWERED_BLAST_FURNACE, blockPos, blockState) {
|
||||||
MBlockEntities.POWERED_BLAST_FURNACE, blockPos, blockState, RecipeType.BLASTING, null, MachinesConfig.POWERED_FURNACE) {
|
override val recipeType: RecipeType<BlastingRecipe>
|
||||||
|
get() = RecipeType.BLASTING
|
||||||
|
override val secondaryRecipeType: RecipeType<MatteryCookingRecipe>?
|
||||||
|
get() = null
|
||||||
|
override val config: WorkerBalanceValues
|
||||||
|
get() = MachinesConfig.POWERED_FURNACE
|
||||||
|
|
||||||
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
||||||
return PoweredFurnaceMenu.blasting(containerID, inventory, this)
|
return PoweredFurnaceMenu.blasting(containerID, inventory, this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PoweredSmokerBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractPoweredFurnaceBlockEntity<SmokingRecipe, MicrowaveRecipe>(
|
class PoweredSmokerBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractPoweredFurnaceBlockEntity<SmokingRecipe, MicrowaveRecipe>(MBlockEntities.POWERED_SMOKER, blockPos, blockState) {
|
||||||
MBlockEntities.POWERED_SMOKER, blockPos, blockState, RecipeType.SMOKING, MRecipes.MICROWAVE, MachinesConfig.POWERED_FURNACE) {
|
override val recipeType: RecipeType<SmokingRecipe>
|
||||||
|
get() = RecipeType.SMOKING
|
||||||
|
override val secondaryRecipeType: RecipeType<MicrowaveRecipe>
|
||||||
|
get() = MRecipes.MICROWAVE
|
||||||
|
override val config: WorkerBalanceValues
|
||||||
|
get() = MachinesConfig.POWERED_FURNACE
|
||||||
|
|
||||||
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
||||||
return PoweredFurnaceMenu.smoking(containerID, inventory, this)
|
return PoweredFurnaceMenu.smoking(containerID, inventory, this)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package ru.dbotthepony.mc.otm.block.entity.tech
|
package ru.dbotthepony.mc.otm.block.entity.tech
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntArrayList
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
import net.minecraft.world.entity.player.Inventory
|
import net.minecraft.world.entity.player.Inventory
|
||||||
import net.minecraft.world.entity.player.Player
|
import net.minecraft.world.entity.player.Player
|
||||||
@ -12,6 +13,7 @@ import ru.dbotthepony.kommons.util.setValue
|
|||||||
import ru.dbotthepony.kommons.util.value
|
import ru.dbotthepony.kommons.util.value
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
||||||
|
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||||
import ru.dbotthepony.mc.otm.capability.energy
|
import ru.dbotthepony.mc.otm.capability.energy
|
||||||
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
||||||
@ -19,9 +21,12 @@ import ru.dbotthepony.mc.otm.capability.energyStoredMattery
|
|||||||
import ru.dbotthepony.mc.otm.capability.matteryEnergy
|
import ru.dbotthepony.mc.otm.capability.matteryEnergy
|
||||||
import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery
|
import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery
|
||||||
import ru.dbotthepony.mc.otm.capability.transcieveEnergy
|
import ru.dbotthepony.mc.otm.capability.transcieveEnergy
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.slotRange
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.core.immutableList
|
import ru.dbotthepony.mc.otm.core.immutableList
|
||||||
|
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.otmRandom
|
import ru.dbotthepony.mc.otm.core.otmRandom
|
||||||
import ru.dbotthepony.mc.otm.core.shuffle
|
import ru.dbotthepony.mc.otm.core.shuffle
|
||||||
@ -33,31 +38,73 @@ class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte
|
|||||||
var gaugeLevel by syncher.float()
|
var gaugeLevel by syncher.float()
|
||||||
private set
|
private set
|
||||||
|
|
||||||
// 6 на 2
|
private var containerSlotIndices = IntArray(0)
|
||||||
val container: MatteryContainer = object : MatteryContainer(::setChanged, CAPACITY) {
|
|
||||||
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
|
private inner class Slot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) {
|
||||||
super.setChanged(slot, new, old)
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
batteryStatus[slot].value = new.getCapability(Capabilities.EnergyStorage.ITEM) != null
|
return super.canAutomationPlaceItem(itemStack) && itemStack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { it.canExtract() && it.extractEnergy(Int.MAX_VALUE, true) > 0 } == true
|
||||||
gaugeLevel = batteryLevel.percentage(maxBatteryLevel)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getMaxStackSize(): Int = 1
|
override fun canAutomationTakeItem(desired: Int): Boolean {
|
||||||
}.also(::addDroppableContainer)
|
return super.canAutomationTakeItem(desired) && item.getCapability(Capabilities.EnergyStorage.ITEM)?.let { !it.canExtract() || it.extractEnergy(Int.MAX_VALUE, true) <= 0 } != false
|
||||||
|
}
|
||||||
|
|
||||||
val batteryStatus = immutableList(CAPACITY) {
|
override fun notifyChanged(old: ItemStack) {
|
||||||
syncher.boolean(false)
|
super.notifyChanged(old)
|
||||||
|
|
||||||
|
batteryStatus[slot].value = item.getCapability(Capabilities.EnergyStorage.ITEM) != null
|
||||||
|
updateGaugeLevel()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val maxStackSize: Int
|
||||||
|
get() = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
val itemConfig = ConfigurableItemHandler(inputOutput = container.handler(HandlerFilter.Dischargeable))
|
private fun containerUpdated() {
|
||||||
|
markDirtyFast()
|
||||||
|
|
||||||
|
val newSlots = IntArrayList()
|
||||||
|
|
||||||
|
for (i in 0 until container.containerSize) {
|
||||||
|
val stack = container[i]
|
||||||
|
|
||||||
|
if (stack.isNotEmpty && stack.energy != null)
|
||||||
|
newSlots.add(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
containerSlotIndices = newSlots.toIntArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6 на 2
|
||||||
|
val container = SlottedContainer.simple(CAPACITY, ::Slot, ::containerUpdated).also(::addDroppableContainer)
|
||||||
|
val batteryStatus = immutableList(CAPACITY) { syncher.boolean(false) }
|
||||||
|
|
||||||
|
val itemConfig = ConfigurableItemHandler(inputOutput = container)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
savetables.stateful(::container, INVENTORY_KEY)
|
savetables.stateful(::container, INVENTORY_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val containerSlotIndices = IntArray(CAPACITY) { it }
|
private fun updateGaugeLevel() {
|
||||||
|
var stored = Decimal.ZERO
|
||||||
|
var maxStored = Decimal.ZERO
|
||||||
|
|
||||||
|
for (stack in container) {
|
||||||
|
val cap = stack.energy ?: continue
|
||||||
|
stored += cap.energyStoredMattery
|
||||||
|
maxStored += cap.maxEnergyStoredMattery
|
||||||
|
}
|
||||||
|
|
||||||
|
gaugeLevel = stored.percentage(maxStored)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tick() {
|
||||||
|
super.tick()
|
||||||
|
updateGaugeLevel()
|
||||||
|
}
|
||||||
|
|
||||||
private fun distributeEnergy(isReceiving: Boolean, howMuch: Decimal, simulate: Boolean): Decimal {
|
private fun distributeEnergy(isReceiving: Boolean, howMuch: Decimal, simulate: Boolean): Decimal {
|
||||||
if (!howMuch.isPositive)
|
if (!howMuch.isPositive || containerSlotIndices.isEmpty())
|
||||||
return Decimal.ZERO
|
return Decimal.ZERO
|
||||||
|
|
||||||
containerSlotIndices.shuffle(level!!.otmRandom)
|
containerSlotIndices.shuffle(level!!.otmRandom)
|
||||||
@ -84,7 +131,6 @@ class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte
|
|||||||
|
|
||||||
if (!simulate && !summ.isZero) {
|
if (!simulate && !summ.isZero) {
|
||||||
markDirtyFast()
|
markDirtyFast()
|
||||||
gaugeLevel = batteryLevel.percentage(maxBatteryLevel)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return summ
|
return summ
|
||||||
@ -108,13 +154,9 @@ class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte
|
|||||||
get() {
|
get() {
|
||||||
var result = Decimal.ZERO
|
var result = Decimal.ZERO
|
||||||
|
|
||||||
for (i in 0 until container.containerSize) {
|
for (stack in container) {
|
||||||
val stack = container.getItem(i)
|
stack.energy?.let {
|
||||||
|
result += it.energyStoredMattery
|
||||||
if (!stack.isEmpty) {
|
|
||||||
stack.energy?.let {
|
|
||||||
result += it.energyStoredMattery
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,13 +170,9 @@ class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte
|
|||||||
get() {
|
get() {
|
||||||
var result = Decimal.ZERO
|
var result = Decimal.ZERO
|
||||||
|
|
||||||
for (i in 0 until container.containerSize) {
|
for (stack in container) {
|
||||||
val stack = container.getItem(i)
|
stack.energy?.let {
|
||||||
|
result += it.maxEnergyStoredMattery
|
||||||
if (!stack.isEmpty) {
|
|
||||||
stack.energy?.let {
|
|
||||||
result += it.maxEnergyStoredMattery
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@ import ru.dbotthepony.mc.otm.capability.*
|
|||||||
import ru.dbotthepony.mc.otm.capability.energy.GeneratorEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.GeneratorEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.menu.tech.ChemicalGeneratorMenu
|
import ru.dbotthepony.mc.otm.menu.tech.ChemicalGeneratorMenu
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
@ -23,20 +23,16 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDe
|
|||||||
return ChemicalGeneratorMenu(containerID, inventory, this)
|
return ChemicalGeneratorMenu(containerID, inventory, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
val batteryContainer = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
|
val batteryContainer = SlottedContainer.simple(1, AutomationFilters.DISCHARGABLE.filteredProvider, ::markDirtyFast).also(::addDroppableContainer)
|
||||||
val residueContainer = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
|
val residueContainer = SlottedContainer.simple(1, AutomationFilters.ONLY_OUT.simpleProvider, ::markDirtyFast).also(::addDroppableContainer)
|
||||||
val fuelContainer = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
|
val fuelContainer = SlottedContainer.simple(1, AutomationFilters.CHEMICAL_FUEL.filteredProvider, ::markDirtyFast).also(::addDroppableContainer)
|
||||||
|
|
||||||
val batteryItemHandler = batteryContainer.handler(HandlerFilter.Chargeable)
|
|
||||||
val residueItemHandler = residueContainer.handler(HandlerFilter.OnlyOut)
|
|
||||||
val fuelItemHandler = fuelContainer.handler(HandlerFilter.ChemicalFuel)
|
|
||||||
|
|
||||||
val energy = ProfiledEnergyStorage(GeneratorEnergyStorage(::markDirtyFast, MachinesConfig.ChemicalGenerator.VALUES::energyCapacity, MachinesConfig.ChemicalGenerator.VALUES::energyThroughput))
|
val energy = ProfiledEnergyStorage(GeneratorEnergyStorage(::markDirtyFast, MachinesConfig.ChemicalGenerator.VALUES::energyCapacity, MachinesConfig.ChemicalGenerator.VALUES::energyThroughput))
|
||||||
|
|
||||||
val itemConfig = ConfigurableItemHandler(
|
val itemConfig = ConfigurableItemHandler(
|
||||||
input = fuelItemHandler,
|
input = fuelContainer,
|
||||||
output = residueItemHandler,
|
output = residueContainer,
|
||||||
battery = batteryItemHandler,
|
battery = batteryContainer,
|
||||||
backDefault = ItemHandlerMode.BATTERY)
|
backDefault = ItemHandlerMode.BATTERY)
|
||||||
|
|
||||||
val energyConfig = ConfigurableEnergy(energy)
|
val energyConfig = ConfigurableEnergy(energy)
|
||||||
|
@ -11,8 +11,8 @@ import ru.dbotthepony.mc.otm.block.entity.ItemJob
|
|||||||
import ru.dbotthepony.mc.otm.block.entity.JobContainer
|
import ru.dbotthepony.mc.otm.block.entity.JobContainer
|
||||||
import ru.dbotthepony.mc.otm.block.entity.JobStatus
|
import ru.dbotthepony.mc.otm.block.entity.JobStatus
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.menu.tech.CobblerMenu
|
import ru.dbotthepony.mc.otm.menu.tech.CobblerMenu
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
||||||
|
|
||||||
@ -22,8 +22,8 @@ class CobblerBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
|||||||
return CobblerMenu(containerID, inventory, this)
|
return CobblerMenu(containerID, inventory, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
val container = MatteryContainer(this::itemContainerUpdated, CONTAINER_SIZE).also(::addDroppableContainer)
|
val container = SlottedContainer.simple(CONTAINER_SIZE, AutomationFilters.ONLY_OUT.simpleProvider, ::itemContainerUpdated).also(::addDroppableContainer)
|
||||||
val itemConfig = ConfigurableItemHandler(output = container.handler(HandlerFilter.OnlyOut))
|
val itemConfig = ConfigurableItemHandler(output = container)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
savetables.stateful(::container, INVENTORY_KEY)
|
savetables.stateful(::container, INVENTORY_KEY)
|
||||||
|
@ -22,7 +22,7 @@ import ru.dbotthepony.mc.otm.core.chart.DecimalHistoryChart
|
|||||||
import ru.dbotthepony.mc.otm.core.math.BlockRotation
|
import ru.dbotthepony.mc.otm.core.math.BlockRotation
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
||||||
import ru.dbotthepony.mc.otm.core.math.getDecimal
|
import ru.dbotthepony.mc.otm.core.nbt.getDecimal
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.mapPresent
|
import ru.dbotthepony.mc.otm.core.nbt.mapPresent
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||||
import ru.dbotthepony.mc.otm.core.util.countingLazy
|
import ru.dbotthepony.mc.otm.core.util.countingLazy
|
||||||
@ -31,6 +31,7 @@ import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
|||||||
|
|
||||||
class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.ENERGY_COUNTER, p_155229_, p_155230_) {
|
class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.ENERGY_COUNTER, p_155229_, p_155230_) {
|
||||||
var passed by syncher.decimal()
|
var passed by syncher.decimal()
|
||||||
|
var pullEnergyFromInput by syncher.boolean()
|
||||||
|
|
||||||
override val blockRotation: BlockRotation by countingLazy(blockStateChangesCounter) {
|
override val blockRotation: BlockRotation by countingLazy(blockStateChangesCounter) {
|
||||||
BlockRotation.of(blockState[EnergyCounterBlock.INPUT_DIRECTION])
|
BlockRotation.of(blockState[EnergyCounterBlock.INPUT_DIRECTION])
|
||||||
@ -86,10 +87,8 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
|
|||||||
savetables.stateful(::history1h)
|
savetables.stateful(::history1h)
|
||||||
savetables.stateful(::history6h)
|
savetables.stateful(::history6h)
|
||||||
savetables.stateful(::history24h)
|
savetables.stateful(::history24h)
|
||||||
}
|
|
||||||
|
|
||||||
override fun saveLevel(nbt: CompoundTag, registry: HolderLookup.Provider) {
|
savetablesConfig.bool(::pullEnergyFromInput)
|
||||||
super.saveLevel(nbt, registry)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
|
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
|
||||||
@ -267,6 +266,14 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
|
|||||||
override fun tick() {
|
override fun tick() {
|
||||||
super.tick()
|
super.tick()
|
||||||
|
|
||||||
|
if (pullEnergyFromInput) {
|
||||||
|
val input = inputCapability
|
||||||
|
val output = outputCapability
|
||||||
|
|
||||||
|
if (input != null && output != null)
|
||||||
|
thisTick += moveEnergy(source = input, destination = output, simulate = false)
|
||||||
|
}
|
||||||
|
|
||||||
lastTick = thisTick
|
lastTick = thisTick
|
||||||
charts.forEach { it.add(thisTick) }
|
charts.forEach { it.add(thisTick) }
|
||||||
thisTick = Decimal.ZERO
|
thisTick = Decimal.ZERO
|
||||||
|
@ -16,8 +16,8 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
|||||||
import ru.dbotthepony.mc.otm.capability.moveEnergy
|
import ru.dbotthepony.mc.otm.capability.moveEnergy
|
||||||
import ru.dbotthepony.mc.otm.config.EnergyBalanceValues
|
import ru.dbotthepony.mc.otm.config.EnergyBalanceValues
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
||||||
import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag
|
import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag
|
||||||
import ru.dbotthepony.mc.otm.menu.tech.EnergyHatchMenu
|
import ru.dbotthepony.mc.otm.menu.tech.EnergyHatchMenu
|
||||||
@ -32,13 +32,12 @@ class EnergyHatchBlockEntity(
|
|||||||
) : MatteryDeviceBlockEntity(type, blockPos, blockState) {
|
) : MatteryDeviceBlockEntity(type, blockPos, blockState) {
|
||||||
val energy = ProfiledEnergyStorage(BlockEnergyStorageImpl(this::markDirtyFast, FlowDirection.input(isInput), capacity))
|
val energy = ProfiledEnergyStorage(BlockEnergyStorageImpl(this::markDirtyFast, FlowDirection.input(isInput), capacity))
|
||||||
|
|
||||||
val container = object : MatteryContainer(::markDirtyFast, CAPACITY) {
|
val container = SlottedContainer.simple(
|
||||||
override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int {
|
CAPACITY,
|
||||||
return 1
|
if (isInput) AutomationFilters.DISCHARGABLE.limitedFilteredProvider else AutomationFilters.CHARGEABLE.limitedFilteredProvider,
|
||||||
}
|
::markDirtyFast
|
||||||
}.also(::addDroppableContainer)
|
).also(::addDroppableContainer)
|
||||||
|
|
||||||
val itemHandler = container.handler(if (isInput) HandlerFilter.Dischargeable else HandlerFilter.Chargeable)
|
|
||||||
private val neighbours = ArrayList<CapabilityCache<IEnergyStorage>>()
|
private val neighbours = ArrayList<CapabilityCache<IEnergyStorage>>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -47,7 +46,7 @@ class EnergyHatchBlockEntity(
|
|||||||
|
|
||||||
// it would cause a lot of frustration if hatches accept stuff only though one face
|
// it would cause a lot of frustration if hatches accept stuff only though one face
|
||||||
exposeEnergyGlobally(energy)
|
exposeEnergyGlobally(energy)
|
||||||
exposeGlobally(Capabilities.ItemHandler.BLOCK, itemHandler)
|
exposeGlobally(Capabilities.ItemHandler.BLOCK, container)
|
||||||
|
|
||||||
if (!isInput) {
|
if (!isInput) {
|
||||||
for (side in RelativeSide.entries) {
|
for (side in RelativeSide.entries) {
|
||||||
|
@ -18,8 +18,8 @@ import ru.dbotthepony.mc.otm.capability.FlowDirection
|
|||||||
import ru.dbotthepony.mc.otm.capability.energy.CombinedProfiledEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.CombinedProfiledEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.capability.moveEnergy
|
import ru.dbotthepony.mc.otm.capability.moveEnergy
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
||||||
import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag
|
import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag
|
||||||
import ru.dbotthepony.mc.otm.core.multiblock.IMultiblockAccess
|
import ru.dbotthepony.mc.otm.core.multiblock.IMultiblockAccess
|
||||||
@ -56,13 +56,11 @@ class EnergyInterfaceBlockEntity(
|
|||||||
targets.invalidate()
|
targets.invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
val container = object : MatteryContainer(::markDirtyFast, CAPACITY) {
|
val container = SlottedContainer.simple(
|
||||||
override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int {
|
CAPACITY,
|
||||||
return 1
|
if (isInput) AutomationFilters.DISCHARGABLE.limitedFilteredProvider else AutomationFilters.CHARGEABLE.limitedFilteredProvider,
|
||||||
}
|
::markDirtyFast).also(::addDroppableContainer)
|
||||||
}.also(::addDroppableContainer)
|
|
||||||
|
|
||||||
val itemHandler = container.handler(if (isInput) HandlerFilter.Dischargeable else HandlerFilter.Chargeable)
|
|
||||||
private val neighbours = ArrayList<CapabilityCache<IEnergyStorage>>()
|
private val neighbours = ArrayList<CapabilityCache<IEnergyStorage>>()
|
||||||
|
|
||||||
override fun setRemoved() {
|
override fun setRemoved() {
|
||||||
@ -75,7 +73,7 @@ class EnergyInterfaceBlockEntity(
|
|||||||
|
|
||||||
// it would cause a lot of frustration if hatches accept stuff only though one face
|
// it would cause a lot of frustration if hatches accept stuff only though one face
|
||||||
exposeEnergyGlobally(energy)
|
exposeEnergyGlobally(energy)
|
||||||
exposeGlobally(Capabilities.ItemHandler.BLOCK, itemHandler)
|
exposeGlobally(Capabilities.ItemHandler.BLOCK, container)
|
||||||
|
|
||||||
if (!isInput) {
|
if (!isInput) {
|
||||||
for (side in RelativeSide.entries) {
|
for (side in RelativeSide.entries) {
|
||||||
|
@ -14,16 +14,19 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
|||||||
import ru.dbotthepony.mc.otm.capability.energyStoredMattery
|
import ru.dbotthepony.mc.otm.capability.energyStoredMattery
|
||||||
import ru.dbotthepony.mc.otm.capability.extractEnergy
|
import ru.dbotthepony.mc.otm.capability.extractEnergy
|
||||||
import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery
|
import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery
|
||||||
|
import ru.dbotthepony.mc.otm.capability.moveEnergy
|
||||||
import ru.dbotthepony.mc.otm.capability.receiveEnergy
|
import ru.dbotthepony.mc.otm.capability.receiveEnergy
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.and
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.menu.tech.EnergyServoMenu
|
import ru.dbotthepony.mc.otm.menu.tech.EnergyServoMenu
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
||||||
|
|
||||||
class EnergyServoBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.ENERGY_SERVO, blockPos, blockState) {
|
class EnergyServoBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.ENERGY_SERVO, blockPos, blockState) {
|
||||||
val discharge = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
|
val discharge = SlottedContainer.simple(1, AutomationFilters.DISCHARGABLE.filteredProvider, ::markDirtyFast).also(::addDroppableContainer)
|
||||||
val charge = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
|
val charge = SlottedContainer.simple(1, AutomationFilters.CHARGEABLE.filteredProvider, ::markDirtyFast).also(::addDroppableContainer)
|
||||||
|
|
||||||
val energy: ProfiledEnergyStorage<IMatteryEnergyStorage> = ProfiledEnergyStorage(object : IMatteryEnergyStorage {
|
val energy: ProfiledEnergyStorage<IMatteryEnergyStorage> = ProfiledEnergyStorage(object : IMatteryEnergyStorage {
|
||||||
override val energyFlow: FlowDirection get() {
|
override val energyFlow: FlowDirection get() {
|
||||||
@ -61,11 +64,7 @@ class EnergyServoBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
|
|||||||
})
|
})
|
||||||
|
|
||||||
val energyConfig = ConfigurableEnergy(energy, possibleModes = FlowDirection.BI_DIRECTIONAL)
|
val energyConfig = ConfigurableEnergy(energy, possibleModes = FlowDirection.BI_DIRECTIONAL)
|
||||||
|
val itemConfig = ConfigurableItemHandler(input = charge, output = discharge)
|
||||||
val itemConfig = ConfigurableItemHandler(
|
|
||||||
input = charge.handler(HandlerFilter.OnlyIn.and(HandlerFilter.Chargeable)),
|
|
||||||
output = discharge.handler(HandlerFilter.OnlyOut.and(HandlerFilter.Dischargeable))
|
|
||||||
)
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
savetables.stateful(::charge)
|
savetables.stateful(::charge)
|
||||||
@ -89,19 +88,7 @@ class EnergyServoBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
|
|||||||
val chargeEnergy = charge.energy ?: return
|
val chargeEnergy = charge.energy ?: return
|
||||||
val dischargeEnergy = discharge.energy ?: return
|
val dischargeEnergy = discharge.energy ?: return
|
||||||
|
|
||||||
val extracted = dischargeEnergy.extractEnergy(Decimal.LONG_MAX_VALUE, true)
|
moveEnergy(source = dischargeEnergy, destination = chargeEnergy, amount = Decimal.LONG_MAX_VALUE, simulate = false)
|
||||||
|
|
||||||
if (extracted.isPositive) {
|
|
||||||
val received = chargeEnergy.receiveEnergy(extracted, true)
|
|
||||||
|
|
||||||
if (received.isPositive) {
|
|
||||||
val extracted2 = dischargeEnergy.extractEnergy(received, false)
|
|
||||||
|
|
||||||
if (extracted2 == received) {
|
|
||||||
chargeEnergy.receiveEnergy(dischargeEnergy.extractEnergy(received, false), false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,10 @@ import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
|||||||
import ru.dbotthepony.mc.otm.block.tech.EssenceStorageBlock
|
import ru.dbotthepony.mc.otm.block.tech.EssenceStorageBlock
|
||||||
import ru.dbotthepony.mc.otm.capability.item.CombinedItemHandler
|
import ru.dbotthepony.mc.otm.capability.item.CombinedItemHandler
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.EnhancedContainer
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.core.getEntitiesInEllipsoid
|
import ru.dbotthepony.mc.otm.core.getEntitiesInEllipsoid
|
||||||
import ru.dbotthepony.mc.otm.core.lookupOrThrow
|
import ru.dbotthepony.mc.otm.core.lookupOrThrow
|
||||||
import ru.dbotthepony.mc.otm.core.math.Vector
|
import ru.dbotthepony.mc.otm.core.math.Vector
|
||||||
@ -36,6 +38,7 @@ import ru.dbotthepony.mc.otm.menu.tech.EssenceStorageMenu
|
|||||||
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MDataComponentTypes
|
import ru.dbotthepony.mc.otm.registry.game.MDataComponentTypes
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MFluids
|
import ru.dbotthepony.mc.otm.registry.game.MFluids
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
class EssenceStorageBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.ESSENCE_STORAGE, blockPos, blockState), IFluidHandler {
|
class EssenceStorageBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.ESSENCE_STORAGE, blockPos, blockState), IFluidHandler {
|
||||||
var experienceStored = 0L
|
var experienceStored = 0L
|
||||||
@ -45,9 +48,29 @@ class EssenceStorageBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma
|
|||||||
markDirtyFast()
|
markDirtyFast()
|
||||||
}
|
}
|
||||||
|
|
||||||
val capsuleContainer = MatteryContainer(::markDirtyFast, 1)
|
private class CapsuleSlot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) {
|
||||||
val servoContainer = MatteryContainer(::markDirtyFast, 1)
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
val mendingContainer = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
|
return super.canAutomationPlaceItem(itemStack) && itemStack.item is EssenceCapsuleItem
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canAutomationTakeItem(desired: Int): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class MendingSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) {
|
||||||
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
|
return super.canAutomationPlaceItem(itemStack) && itemStack.isDamaged && itemStack.getEnchantmentLevel(mending!!) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canAutomationTakeItem(desired: Int): Boolean {
|
||||||
|
return super.canAutomationTakeItem(desired) && (!item.isDamaged || experienceStored <= 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val capsuleContainer = SlottedContainer.simple(1, ::CapsuleSlot, ::markDirtyFast)
|
||||||
|
val servoContainer = EnhancedContainer.WithListener(1, ::markDirtyFast)
|
||||||
|
val mendingContainer = SlottedContainer.simple(1, ::MendingSlot, ::markDirtyFast).also(::addDroppableContainer)
|
||||||
|
|
||||||
private var mending: Holder<Enchantment>? = null
|
private var mending: Holder<Enchantment>? = null
|
||||||
|
|
||||||
@ -63,22 +86,7 @@ class EssenceStorageBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma
|
|||||||
}
|
}
|
||||||
|
|
||||||
val itemConfig = ConfigurableItemHandler(
|
val itemConfig = ConfigurableItemHandler(
|
||||||
inputOutput = CombinedItemHandler(
|
inputOutput = CombinedItemHandler(capsuleContainer, mendingContainer)
|
||||||
capsuleContainer.handler(HandlerFilter.OnlyIn.and(object : HandlerFilter {
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return stack.item is EssenceCapsuleItem
|
|
||||||
}
|
|
||||||
})),
|
|
||||||
mendingContainer.handler(object : HandlerFilter {
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return stack.isDamaged && stack.getEnchantmentLevel(mending!!) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
|
||||||
return !stack.isDamaged || experienceStored <= 0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
|
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
|
||||||
@ -160,7 +168,7 @@ class EssenceStorageBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma
|
|||||||
val capsule = capsuleContainer[0]
|
val capsule = capsuleContainer[0]
|
||||||
|
|
||||||
if (!capsule.isEmpty && capsule.has(MDataComponentTypes.EXPERIENCE)) {
|
if (!capsule.isEmpty && capsule.has(MDataComponentTypes.EXPERIENCE)) {
|
||||||
experienceStored += capsule.get(MDataComponentTypes.EXPERIENCE)!! * capsule.count
|
experienceStored += max(capsule.get(MDataComponentTypes.EXPERIENCE)!! * capsule.count, 0L)
|
||||||
capsuleContainer.clearContent()
|
capsuleContainer.clearContent()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,8 +9,8 @@ import net.minecraft.world.level.block.state.BlockState
|
|||||||
import net.neoforged.neoforge.capabilities.Capabilities
|
import net.neoforged.neoforge.capabilities.Capabilities
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag
|
import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag
|
||||||
import ru.dbotthepony.mc.otm.menu.tech.ItemHatchMenu
|
import ru.dbotthepony.mc.otm.menu.tech.ItemHatchMenu
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
||||||
@ -21,12 +21,11 @@ class ItemHatchBlockEntity(
|
|||||||
blockPos: BlockPos,
|
blockPos: BlockPos,
|
||||||
blockState: BlockState
|
blockState: BlockState
|
||||||
) : MatteryDeviceBlockEntity(type, blockPos, blockState) {
|
) : MatteryDeviceBlockEntity(type, blockPos, blockState) {
|
||||||
val container = MatteryContainer(this::markDirtyFast, CAPACITY).also(::addDroppableContainer)
|
val container = SlottedContainer.simple(CAPACITY, if (isInput) AutomationFilters.ONLY_IN.filteredProvider else AutomationFilters.ONLY_OUT.filteredProvider, this::markDirtyFast).also(::addDroppableContainer)
|
||||||
val itemHandler = container.handler(if (isInput) HandlerFilter.OnlyIn else HandlerFilter.OnlyOut)
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
savetables.stateful(::container, INVENTORY_KEY)
|
savetables.stateful(::container, INVENTORY_KEY)
|
||||||
exposeGlobally(Capabilities.ItemHandler.BLOCK, itemHandler)
|
exposeGlobally(Capabilities.ItemHandler.BLOCK, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
||||||
|
@ -15,8 +15,8 @@ import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
|
|||||||
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
|
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
|
||||||
import ru.dbotthepony.mc.otm.capability.moveMatter
|
import ru.dbotthepony.mc.otm.capability.moveMatter
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag
|
import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag
|
||||||
import ru.dbotthepony.mc.otm.menu.tech.MatterHatchMenu
|
import ru.dbotthepony.mc.otm.menu.tech.MatterHatchMenu
|
||||||
@ -28,26 +28,15 @@ class MatterHatchBlockEntity(
|
|||||||
blockPos: BlockPos,
|
blockPos: BlockPos,
|
||||||
blockState: BlockState
|
blockState: BlockState
|
||||||
) : MatteryDeviceBlockEntity(type, blockPos, blockState) {
|
) : MatteryDeviceBlockEntity(type, blockPos, blockState) {
|
||||||
val container = object : MatteryContainer(::markDirtyFast, CAPACITY) {
|
val container = SlottedContainer.simple(CAPACITY, if (isInput) AutomationFilters.MATTER_PROVIDERS.limitedFilteredProvider else AutomationFilters.MATTER_CONSUMERS.limitedFilteredProvider, ::markDirtyFast).also(::addDroppableContainer)
|
||||||
override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
}.also(::addDroppableContainer)
|
|
||||||
|
|
||||||
val matter = ProfiledMatterStorage(MatterStorageImpl(this::markDirtyFast, FlowDirection.input(isInput), MachinesConfig::MATTER_HATCH))
|
val matter = ProfiledMatterStorage(MatterStorageImpl(this::markDirtyFast, FlowDirection.input(isInput), MachinesConfig::MATTER_HATCH))
|
||||||
|
|
||||||
val itemHandler = if (isInput) {
|
|
||||||
container.handler(HandlerFilter.MatterProviders)
|
|
||||||
} else {
|
|
||||||
container.handler(HandlerFilter.MatterConsumers)
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
savetables.stateful(::container, INVENTORY_KEY)
|
savetables.stateful(::container, INVENTORY_KEY)
|
||||||
savetables.stateful(::matter, MATTER_STORAGE_KEY)
|
savetables.stateful(::matter, MATTER_STORAGE_KEY)
|
||||||
|
|
||||||
// it would cause a lot of frustration if hatches accept stuff only though one face
|
// it would cause a lot of frustration if hatches accept stuff only though one face
|
||||||
exposeGlobally(Capabilities.ItemHandler.BLOCK, itemHandler)
|
exposeGlobally(Capabilities.ItemHandler.BLOCK, container)
|
||||||
exposeGlobally(MatteryCapability.MATTER_BLOCK, matter)
|
exposeGlobally(MatteryCapability.MATTER_BLOCK, matter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,11 @@ import net.minecraft.core.BlockPos
|
|||||||
import net.minecraft.world.entity.player.Inventory
|
import net.minecraft.world.entity.player.Inventory
|
||||||
import net.minecraft.world.entity.player.Player
|
import net.minecraft.world.entity.player.Player
|
||||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.item.crafting.SingleRecipeInput
|
||||||
import net.minecraft.world.level.block.state.BlockState
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
import net.neoforged.neoforge.capabilities.Capabilities
|
import net.neoforged.neoforge.capabilities.Capabilities
|
||||||
|
import net.neoforged.neoforge.event.AddReloadListenerEvent
|
||||||
import ru.dbotthepony.mc.otm.block.entity.ExperienceStorage
|
import ru.dbotthepony.mc.otm.block.entity.ExperienceStorage
|
||||||
import ru.dbotthepony.mc.otm.block.entity.JobContainer
|
import ru.dbotthepony.mc.otm.block.entity.JobContainer
|
||||||
import ru.dbotthepony.mc.otm.block.entity.JobStatus
|
import ru.dbotthepony.mc.otm.block.entity.JobStatus
|
||||||
@ -16,15 +19,18 @@ import ru.dbotthepony.mc.otm.capability.UpgradeType
|
|||||||
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
|
||||||
import ru.dbotthepony.mc.otm.container.balance
|
import ru.dbotthepony.mc.otm.container.balance
|
||||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||||
import ru.dbotthepony.mc.otm.core.collect.maybe
|
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
|
import ru.dbotthepony.mc.otm.core.SimpleCache
|
||||||
import ru.dbotthepony.mc.otm.core.otmRandom
|
import ru.dbotthepony.mc.otm.core.otmRandom
|
||||||
|
import ru.dbotthepony.mc.otm.container.ItemStackKey
|
||||||
|
import ru.dbotthepony.mc.otm.container.asKey
|
||||||
import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu
|
import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
||||||
import ru.dbotthepony.mc.otm.registry.game.MRecipes
|
import ru.dbotthepony.mc.otm.registry.game.MRecipes
|
||||||
|
import java.time.Duration
|
||||||
|
|
||||||
class PlatePressBlockEntity(
|
class PlatePressBlockEntity(
|
||||||
blockPos: BlockPos,
|
blockPos: BlockPos,
|
||||||
@ -33,14 +39,36 @@ class PlatePressBlockEntity(
|
|||||||
) : MatteryWorkerBlockEntity<ItemJob>(if (isTwin) MBlockEntities.TWIN_PLATE_PRESS else MBlockEntities.PLATE_PRESS, blockPos, blockState, ItemJob.CODEC, if (isTwin) 2 else 1) {
|
) : MatteryWorkerBlockEntity<ItemJob>(if (isTwin) MBlockEntities.TWIN_PLATE_PRESS else MBlockEntities.PLATE_PRESS, blockPos, blockState, ItemJob.CODEC, if (isTwin) 2 else 1) {
|
||||||
override val upgrades = makeUpgrades(if (isTwin) 4 else 3, UpgradeType.BASIC_PROCESSING)
|
override val upgrades = makeUpgrades(if (isTwin) 4 else 3, UpgradeType.BASIC_PROCESSING)
|
||||||
override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyLevelUpdated, upgrades.transform(MachinesConfig.PLATE_PRESS)))
|
override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyLevelUpdated, upgrades.transform(MachinesConfig.PLATE_PRESS)))
|
||||||
val inputContainer = MatteryContainer(this::itemContainerUpdated, if (isTwin) 2 else 1).also(::addDroppableContainer)
|
|
||||||
val outputContainer = MatteryContainer(this::itemContainerUpdated, if (isTwin) 2 else 1).also(::addDroppableContainer)
|
private inner class InputSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) {
|
||||||
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
|
if (!super.canAutomationPlaceItem(itemStack))
|
||||||
|
return false
|
||||||
|
|
||||||
|
val level = level ?: return true
|
||||||
|
val input = SingleRecipeInput(itemStack)
|
||||||
|
|
||||||
|
return cache.get(itemStack.asKey()) {
|
||||||
|
return@get level.recipeManager
|
||||||
|
.byType(MRecipes.PLATE_PRESS)
|
||||||
|
.any { it.value.matches(input, level) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canAutomationTakeItem(desired: Int): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val inputContainer = SlottedContainer.simple(if (isTwin) 2 else 1, ::InputSlot, this::itemContainerUpdated).also(::addDroppableContainer)
|
||||||
|
val outputContainer = SlottedContainer.simple(if (isTwin) 2 else 1, AutomationFilters.ONLY_OUT.simpleProvider, this::itemContainerUpdated).also(::addDroppableContainer)
|
||||||
|
|
||||||
val experience = ExperienceStorage(MachinesConfig.PLATE_PRESS::maxExperienceStored).also(::addNeighbourListener)
|
val experience = ExperienceStorage(MachinesConfig.PLATE_PRESS::maxExperienceStored).also(::addNeighbourListener)
|
||||||
val energyConfig = ConfigurableEnergy(energy)
|
val energyConfig = ConfigurableEnergy(energy)
|
||||||
|
|
||||||
val itemConfig = ConfigurableItemHandler(
|
val itemConfig = ConfigurableItemHandler(
|
||||||
input = inputContainer.handler(HandlerFilter.OnlyIn),
|
input = inputContainer,
|
||||||
output = outputContainer.handler(HandlerFilter.OnlyOut),
|
output = outputContainer,
|
||||||
)
|
)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -76,9 +104,7 @@ class PlatePressBlockEntity(
|
|||||||
|
|
||||||
val recipe = level.recipeManager
|
val recipe = level.recipeManager
|
||||||
.byType(MRecipes.PLATE_PRESS)
|
.byType(MRecipes.PLATE_PRESS)
|
||||||
.iterator()
|
.firstOrNull { it.value.matches(inputContainer, id) }?.value ?: return JobContainer.noItem()
|
||||||
.filter { it.value.matches(inputContainer, id) }
|
|
||||||
.maybe()?.value ?: return JobContainer.noItem()
|
|
||||||
|
|
||||||
val toProcess = inputContainer[id].count.coerceAtMost(1 + upgrades.processingItems)
|
val toProcess = inputContainer[id].count.coerceAtMost(1 + upgrades.processingItems)
|
||||||
|
|
||||||
@ -100,4 +126,12 @@ class PlatePressBlockEntity(
|
|||||||
|
|
||||||
super.tick()
|
super.tick()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val cache = SimpleCache<ItemStackKey, Boolean>(Duration.ofMinutes(1L))
|
||||||
|
|
||||||
|
internal fun onReload(event: AddReloadListenerEvent) {
|
||||||
|
cache.invalidateAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,13 +146,13 @@ val ItemStack.matteryEnergy: IMatteryEnergyStorage? get() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun Player.items(includeCosmetics: Boolean = true): Iterator<ItemStack> {
|
fun Player.items(includeCosmetics: Boolean = true): Iterator<ItemStack> {
|
||||||
val matteryPlayer = matteryPlayer ?: return emptyIterator()
|
val matteryPlayer = matteryPlayer
|
||||||
|
|
||||||
val iterators = ArrayList<Iterator<ItemStack>>()
|
val iterators = ArrayList<Iterator<ItemStack>>()
|
||||||
iterators.add(matteryPlayer.wrappedInventory.slotIterator().filter { !it.isForbiddenForAutomation }.map { it.item })
|
iterators.add(matteryPlayer.wrappedInventory.slotIterator().filter { !it.filter.denyAll }.map { it.item })
|
||||||
|
|
||||||
if (matteryPlayer.hasExopack) {
|
if (matteryPlayer.hasExopack) {
|
||||||
iterators.add(matteryPlayer.exopackContainer.slotIterator().filter { !it.isForbiddenForAutomation }.map { it.item })
|
iterators.add(matteryPlayer.exopackContainer.slotIterator().filter { !it.filter.denyAll }.map { it.item })
|
||||||
iterators.add(matteryPlayer.exopackEnergy.parent.iterator())
|
iterators.add(matteryPlayer.exopackEnergy.parent.iterator())
|
||||||
iterators.add(matteryPlayer.exopackChargeSlots.iterator())
|
iterators.add(matteryPlayer.exopackChargeSlots.iterator())
|
||||||
}
|
}
|
||||||
@ -185,10 +185,8 @@ fun Player.awareItemsStream(includeCosmetics: Boolean = false): Stream<out Aware
|
|||||||
val streams = ArrayList<Stream<out AwareItemStack>>()
|
val streams = ArrayList<Stream<out AwareItemStack>>()
|
||||||
streams.add(inventory.awareStream())
|
streams.add(inventory.awareStream())
|
||||||
|
|
||||||
matteryPlayer?.let {
|
if (matteryPlayer.hasExopack) {
|
||||||
if (it.hasExopack) {
|
streams.add(matteryPlayer.exopackContainer.awareStream())
|
||||||
streams.add(it.exopackContainer.awareStream())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCuriosLoaded) {
|
if (isCuriosLoaded) {
|
||||||
|
@ -136,7 +136,7 @@ enum class FlowDirection(val input: Boolean, val output: Boolean, val translatio
|
|||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun input(flag: Boolean): FlowDirection {
|
fun input(flag: Boolean): FlowDirection {
|
||||||
return of(flag, !flag)
|
return if (flag) INPUT else OUTPUT
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.capability
|
||||||
|
|
||||||
|
import net.minecraft.server.level.ServerPlayer
|
||||||
|
import net.minecraft.world.inventory.Slot
|
||||||
|
|
||||||
|
interface IQuickStackContainer {
|
||||||
|
fun getSlotsFor(player: ServerPlayer): Collection<Slot>
|
||||||
|
|
||||||
|
class Simple(private val slots: Collection<Slot>) : IQuickStackContainer {
|
||||||
|
override fun getSlotsFor(player: ServerPlayer): Collection<Slot> {
|
||||||
|
return slots
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@ import ru.dbotthepony.mc.otm.capability.FlowDirection
|
|||||||
import ru.dbotthepony.mc.otm.capability.extractEnergy
|
import ru.dbotthepony.mc.otm.capability.extractEnergy
|
||||||
import ru.dbotthepony.mc.otm.capability.receiveEnergy
|
import ru.dbotthepony.mc.otm.capability.receiveEnergy
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.getDecimal
|
import ru.dbotthepony.mc.otm.core.nbt.getDecimal
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||||
import ru.dbotthepony.mc.otm.registry.StatNames
|
import ru.dbotthepony.mc.otm.registry.StatNames
|
||||||
import ru.dbotthepony.mc.otm.triggers.AndroidBatteryTrigger
|
import ru.dbotthepony.mc.otm.triggers.AndroidBatteryTrigger
|
||||||
|
@ -3,7 +3,7 @@ package ru.dbotthepony.mc.otm.capability.item
|
|||||||
import com.google.common.collect.ImmutableList
|
import com.google.common.collect.ImmutableList
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.neoforged.neoforge.items.IItemHandler
|
import net.neoforged.neoforge.items.IItemHandler
|
||||||
import ru.dbotthepony.mc.otm.container.ContainerHandler
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
|
|
||||||
class CombinedItemHandler(val handlers: ImmutableList<IItemHandler>) : IItemHandler {
|
class CombinedItemHandler(val handlers: ImmutableList<IItemHandler>) : IItemHandler {
|
||||||
@ -11,7 +11,7 @@ class CombinedItemHandler(val handlers: ImmutableList<IItemHandler>) : IItemHand
|
|||||||
constructor(handlers: Collection<IItemHandler>) : this(ImmutableList.copyOf(handlers))
|
constructor(handlers: Collection<IItemHandler>) : this(ImmutableList.copyOf(handlers))
|
||||||
constructor(vararg handlers: IItemHandler) : this(ImmutableList.copyOf(handlers))
|
constructor(vararg handlers: IItemHandler) : this(ImmutableList.copyOf(handlers))
|
||||||
|
|
||||||
private val needsChecking = handlers.any { it !is ContainerHandler }
|
private val needsChecking = handlers.any { it !is SlottedContainer }
|
||||||
private val lastSizes = IntArray(this.handlers.size)
|
private val lastSizes = IntArray(this.handlers.size)
|
||||||
private var totalSize = 0
|
private var totalSize = 0
|
||||||
private val mappings = ArrayList<Mapping>()
|
private val mappings = ArrayList<Mapping>()
|
||||||
|
@ -25,8 +25,11 @@ import ru.dbotthepony.mc.otm.client.setMousePos
|
|||||||
import ru.dbotthepony.mc.otm.client.shouldOpenVanillaInventory
|
import ru.dbotthepony.mc.otm.client.shouldOpenVanillaInventory
|
||||||
import ru.dbotthepony.mc.otm.core.math.integerDivisionDown
|
import ru.dbotthepony.mc.otm.core.math.integerDivisionDown
|
||||||
import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu
|
import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu
|
||||||
|
import ru.dbotthepony.mc.otm.menu.QuickMoveInput
|
||||||
import ru.dbotthepony.mc.otm.network.ExopackMenuOpen
|
import ru.dbotthepony.mc.otm.network.ExopackMenuOpen
|
||||||
|
import ru.dbotthepony.mc.otm.network.QuickStackPacket
|
||||||
import yalter.mousetweaks.api.MouseTweaksDisableWheelTweak
|
import yalter.mousetweaks.api.MouseTweaksDisableWheelTweak
|
||||||
|
import java.util.function.IntConsumer
|
||||||
|
|
||||||
@MouseTweaksDisableWheelTweak
|
@MouseTweaksDisableWheelTweak
|
||||||
class ExopackInventoryScreen(menu: ExopackInventoryMenu) : MatteryScreen<ExopackInventoryMenu>(menu, TranslatableComponent("otm.gui.exopack")) {
|
class ExopackInventoryScreen(menu: ExopackInventoryMenu) : MatteryScreen<ExopackInventoryMenu>(menu, TranslatableComponent("otm.gui.exopack")) {
|
||||||
@ -281,7 +284,9 @@ class ExopackInventoryScreen(menu: ExopackInventoryMenu) : MatteryScreen<Exopack
|
|||||||
curios.x = x
|
curios.x = x
|
||||||
}
|
}
|
||||||
|
|
||||||
EffectListPanel(this, frame, menu.player, x - 56f, gridHeight = 6).tick()
|
EffectListPanel(this, frame, menu.player, x - 56f, gridHeight = 4).tick()
|
||||||
|
|
||||||
|
QuickStackControlsPanel(this, frame, x = -19f, y = 96f + 18f)
|
||||||
|
|
||||||
return frame
|
return frame
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
|
|||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
import net.minecraft.world.entity.player.Inventory
|
import net.minecraft.world.entity.player.Inventory
|
||||||
import net.minecraft.world.inventory.Slot
|
import net.minecraft.world.inventory.Slot
|
||||||
import net.minecraft.world.item.Item
|
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.neoforged.neoforge.client.event.ContainerScreenEvent
|
import net.neoforged.neoforge.client.event.ContainerScreenEvent
|
||||||
import net.neoforged.neoforge.common.NeoForge
|
import net.neoforged.neoforge.common.NeoForge
|
||||||
@ -52,7 +51,7 @@ import ru.dbotthepony.mc.otm.core.math.component1
|
|||||||
import ru.dbotthepony.mc.otm.core.math.component2
|
import ru.dbotthepony.mc.otm.core.math.component2
|
||||||
import ru.dbotthepony.mc.otm.core.math.integerDivisionDown
|
import ru.dbotthepony.mc.otm.core.math.integerDivisionDown
|
||||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||||
import ru.dbotthepony.mc.otm.menu.MatterySlot
|
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
||||||
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
|
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
|
||||||
import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
|
import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -364,8 +363,6 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
|||||||
override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean {
|
override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override var slotFilter: Item? by slot.filter!!
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,7 +422,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
|||||||
matter: LevelGaugeWidget? = null,
|
matter: LevelGaugeWidget? = null,
|
||||||
profiledMatter: ProfiledLevelGaugeWidget<*>? = null,
|
profiledMatter: ProfiledLevelGaugeWidget<*>? = null,
|
||||||
patterns: LevelGaugeWidget? = null,
|
patterns: LevelGaugeWidget? = null,
|
||||||
batterySlot: MatterySlot? = null,
|
batterySlot: MatteryMenuSlot? = null,
|
||||||
) {
|
) {
|
||||||
var bars = 0
|
var bars = 0
|
||||||
if (energy != null) bars++
|
if (energy != null) bars++
|
||||||
|
@ -2,11 +2,13 @@ package ru.dbotthepony.mc.otm.client.screen.decorative
|
|||||||
|
|
||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
import net.minecraft.world.entity.player.Inventory
|
import net.minecraft.world.entity.player.Inventory
|
||||||
|
import ru.dbotthepony.kommons.util.Either
|
||||||
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
|
import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel
|
||||||
|
import ru.dbotthepony.mc.otm.menu.QuickMoveInput
|
||||||
import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu
|
import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu
|
||||||
|
|
||||||
class CargoCrateScreen(menu: CargoCrateMenu, inventory: Inventory, title: Component) : MatteryScreen<CargoCrateMenu>(menu, inventory, title) {
|
class CargoCrateScreen(menu: CargoCrateMenu, inventory: Inventory, title: Component) : MatteryScreen<CargoCrateMenu>(menu, inventory, title) {
|
||||||
@ -20,12 +22,19 @@ class CargoCrateScreen(menu: CargoCrateMenu, inventory: Inventory, title: Compon
|
|||||||
val grid = GridPanel(this, frame, 8f, 18f, 9f * 18f, 6f * 18f, 9, 6)
|
val grid = GridPanel(this, frame, 8f, 18f, 9f * 18f, 6f * 18f, 9, 6)
|
||||||
|
|
||||||
for (slot in menu.storageSlots)
|
for (slot in menu.storageSlots)
|
||||||
UserFilteredSlotPanel.of(this, grid, slot)
|
UserFilteredSlotPanel(this, grid, slot)
|
||||||
|
|
||||||
val controls = DeviceControls(this, frame)
|
val controls = DeviceControls(this, frame)
|
||||||
|
|
||||||
controls.sortingButtons(menu.sort)
|
controls.sortingButtons(menu.sort)
|
||||||
|
|
||||||
|
val leftControls = DeviceControls(this, frame)
|
||||||
|
leftControls.dockOnLeft = true
|
||||||
|
leftControls.quickMoveButtons(menu.quickMoveFromStorage)
|
||||||
|
|
||||||
|
val leftInventoryControls = DeviceControls(this, inventoryFrame!!)
|
||||||
|
leftInventoryControls.dockOnLeft = true
|
||||||
|
leftInventoryControls.quickMoveButtons(menu.quickMoveToStorage, menu.quickMoveFromStorage)
|
||||||
|
|
||||||
return frame
|
return frame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls
|
|||||||
import ru.dbotthepony.mc.otm.client.screen.panels.makeCuriosPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.makeCuriosPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.SpritePanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.SpritePanel
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.widget.FluidGaugePanel
|
import ru.dbotthepony.mc.otm.client.screen.widget.FluidGaugePanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
|
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
|
||||||
import ru.dbotthepony.mc.otm.menu.decorative.FluidTankMenu
|
import ru.dbotthepony.mc.otm.menu.decorative.FluidTankMenu
|
||||||
@ -25,8 +26,8 @@ class FluidTankScreen(menu: FluidTankMenu, inventory: Inventory, title: Componen
|
|||||||
val s = SpritePanel(this, frame, ProgressGaugePanel.GAUGE_BACKGROUND, x = 30f, y = 30f)
|
val s = SpritePanel(this, frame, ProgressGaugePanel.GAUGE_BACKGROUND, x = 30f, y = 30f)
|
||||||
SpritePanel(this, frame, ProgressGaugePanel.GAUGE_BACKGROUND, x = 30f, y = 55f, winding = UVWindingOrder.FLOP)
|
SpritePanel(this, frame, ProgressGaugePanel.GAUGE_BACKGROUND, x = 30f, y = 55f, winding = UVWindingOrder.FLOP)
|
||||||
|
|
||||||
SlotPanel(this, frame, menu.fillInput, x = 30f + s.width + 4f, y = 28f)
|
UserFilteredSlotPanel(this, frame, menu.fillInput, x = 30f + s.width + 4f, y = 28f)
|
||||||
SlotPanel(this, frame, menu.drainInput, x = 30f + s.width + 4f, y = 53f)
|
UserFilteredSlotPanel(this, frame, menu.drainInput, x = 30f + s.width + 4f, y = 53f)
|
||||||
|
|
||||||
SlotPanel(this, frame, menu.output, x = 30f + s.width + 4f + 20f, y = 53f)
|
SlotPanel(this, frame, menu.output, x = 30f + s.width + 4f + 20f, y = 53f)
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
|
|||||||
import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls
|
import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel
|
import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
|
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledMatterGaugePanel
|
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledMatterGaugePanel
|
||||||
@ -25,7 +26,7 @@ class MatterDecomposerScreen(p_97741_: MatterDecomposerMenu, p_97742_: Inventory
|
|||||||
|
|
||||||
BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE)
|
BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE)
|
||||||
|
|
||||||
SlotPanel(this, frame, menu.input, 122f, PROGRESS_SLOT_TOP)
|
UserFilteredSlotPanel(this, frame, menu.input, 122f, PROGRESS_SLOT_TOP)
|
||||||
ProgressGaugePanel(this, frame, menu.progressWidget, 96f, PROGRESS_ARROW_TOP).also { it.flop = true }
|
ProgressGaugePanel(this, frame, menu.progressWidget, 96f, PROGRESS_ARROW_TOP).also { it.flop = true }
|
||||||
SlotPanel(this, frame, menu.outputMain, 74f, PROGRESS_SLOT_TOP)
|
SlotPanel(this, frame, menu.outputMain, 74f, PROGRESS_SLOT_TOP)
|
||||||
SlotPanel(this, frame, menu.outputStacking, 56f, PROGRESS_SLOT_TOP)
|
SlotPanel(this, frame, menu.outputStacking, 56f, PROGRESS_SLOT_TOP)
|
||||||
|
@ -11,6 +11,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.SpritePanel
|
|||||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
|
import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
|
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
|
||||||
import ru.dbotthepony.mc.otm.compat.jei.MatterEntanglerRecipeCategory
|
import ru.dbotthepony.mc.otm.compat.jei.MatterEntanglerRecipeCategory
|
||||||
@ -30,7 +31,7 @@ class MatterEntanglerScreen(menu: MatterEntanglerMenu, inventory: Inventory, tit
|
|||||||
it.dockResize = DockResizeMode.NONE
|
it.dockResize = DockResizeMode.NONE
|
||||||
|
|
||||||
for (slot in menu.inputs)
|
for (slot in menu.inputs)
|
||||||
SlotPanel(this, it, slot)
|
UserFilteredSlotPanel(this, it, slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgressGaugePanel(this, frame, menu.progress).also {
|
ProgressGaugePanel(this, frame, menu.progress).also {
|
||||||
|
@ -10,9 +10,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.PlayerEquipmentPanel
|
|||||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls
|
import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.makeCuriosPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.makeCuriosPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel
|
|
||||||
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
|
|
||||||
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledMatterGaugePanel
|
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledMatterGaugePanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledPowerGaugePanel
|
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledPowerGaugePanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
|
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
|
||||||
@ -27,7 +25,7 @@ class MatterReconstructorScreen(menu: MatterReconstructorMenu, inventory: Invent
|
|||||||
|
|
||||||
BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE)
|
BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE)
|
||||||
|
|
||||||
SlotPanel(this, frame, menu.slot, 66f, PROGRESS_SLOT_TOP)
|
UserFilteredSlotPanel(this, frame, menu.slot, 66f, PROGRESS_SLOT_TOP)
|
||||||
ProgressGaugePanel(this, frame, menu.progress, 37f, PROGRESS_ARROW_TOP)
|
ProgressGaugePanel(this, frame, menu.progress, 37f, PROGRESS_ARROW_TOP)
|
||||||
|
|
||||||
makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, itemConfig = menu.itemConfig, energyConfig = menu.energyConfig, upgrades = menu.upgrades)
|
makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, itemConfig = menu.itemConfig, energyConfig = menu.energyConfig, upgrades = menu.upgrades)
|
||||||
|
@ -62,7 +62,7 @@ open class EffectListPanel<out S : Screen> @JvmOverloads constructor(
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
scroll.visible = false
|
scroll.visible = false
|
||||||
//scissor = true
|
scissor = true
|
||||||
}
|
}
|
||||||
|
|
||||||
open inner class EffectSquare(
|
open inner class EffectSquare(
|
||||||
|
@ -60,7 +60,7 @@ open class PlayerEquipmentPanel<S : MatteryScreen<*>>(
|
|||||||
parent: EditablePanel<*>?,
|
parent: EditablePanel<*>?,
|
||||||
x: Float = 0f,
|
x: Float = 0f,
|
||||||
y: Float = 0f,
|
y: Float = 0f,
|
||||||
val armorSlots: List<PlayerSlot<MatteryMenu.EquipmentSlot, Slot>>
|
val armorSlots: List<PlayerSlot<MatteryMenu.EquipmentMenuSlot, Slot>>
|
||||||
) : EditablePanel<S>(screen, parent, x, y, height = HEIGHT, width = WIDTH) {
|
) : EditablePanel<S>(screen, parent, x, y, height = HEIGHT, width = WIDTH) {
|
||||||
val armorSlotsStrip = EditablePanel(screen, this, width = AbstractSlotPanel.SIZE)
|
val armorSlotsStrip = EditablePanel(screen, this, width = AbstractSlotPanel.SIZE)
|
||||||
val entityPanel = EntityRendererPanel(screen, this, minecraft.player!!)
|
val entityPanel = EntityRendererPanel(screen, this, minecraft.player!!)
|
||||||
|
@ -0,0 +1,120 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.client.screen.panels
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.platform.InputConstants
|
||||||
|
import net.minecraft.ChatFormatting
|
||||||
|
import net.minecraft.client.gui.screens.Screen
|
||||||
|
import net.neoforged.neoforge.network.PacketDistributor
|
||||||
|
import ru.dbotthepony.mc.otm.client.minecraft
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.IGUIRenderable
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.Widgets18
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.panels.button.ButtonPanel
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
|
||||||
|
import ru.dbotthepony.mc.otm.core.TextComponent
|
||||||
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
|
import ru.dbotthepony.mc.otm.menu.QuickMoveInput
|
||||||
|
import ru.dbotthepony.mc.otm.network.QuickStackPacket
|
||||||
|
import java.util.function.IntConsumer
|
||||||
|
|
||||||
|
class QuickStackControlsPanel<out S : Screen>(
|
||||||
|
screen: S,
|
||||||
|
parent: EditablePanel<*>? = null,
|
||||||
|
x: Float = 0f,
|
||||||
|
y: Float = 0f
|
||||||
|
) : EditablePanel<S>(screen, parent, x, y, 18f, 18f) {
|
||||||
|
private val grid = GridPanel(screen, this, columns = 1, rows = 1)
|
||||||
|
private val buttons = ArrayList<EditablePanel<S>>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
grid.dock = Dock.FILL
|
||||||
|
grid.layout = GridPanel.Layout.TOP_RIGHT
|
||||||
|
grid.columnMajorOrder = true
|
||||||
|
|
||||||
|
// so row with main button contains only that button (visibly)
|
||||||
|
val fill = EditablePanel(screen, grid, width = 18f, height = 18f)
|
||||||
|
fill.childrenOrder = 999
|
||||||
|
fill.visible = false
|
||||||
|
fill.dockMargin = DockProperty.bottomRight(1f)
|
||||||
|
buttons.add(fill)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class MainButton : ButtonPanel<S>(screen, grid, width = 18f, height = 18f) {
|
||||||
|
init {
|
||||||
|
dockMargin = DockProperty.bottom(1f)
|
||||||
|
childrenOrder = -100000
|
||||||
|
tooltips.add(TranslatableComponent("otm.gui.quickmove.exchange"))
|
||||||
|
tooltips.add(TranslatableComponent("otm.gui.quickmove.exchange.desc").withStyle(ChatFormatting.GRAY))
|
||||||
|
tooltips.add(TextComponent(""))
|
||||||
|
tooltips.add(TranslatableComponent("otm.gui.quickmove_hint").withStyle(ChatFormatting.GRAY))
|
||||||
|
}
|
||||||
|
|
||||||
|
override var isDisabled: Boolean
|
||||||
|
get() = minecraft.player!!.isSpectator
|
||||||
|
set(value) {}
|
||||||
|
|
||||||
|
override val icon: IGUIRenderable
|
||||||
|
get() = Widgets18.SMART_STORAGE_EXCHANGE
|
||||||
|
|
||||||
|
override fun test(value: Int): Boolean {
|
||||||
|
return value == InputConstants.MOUSE_BUTTON_LEFT || value == InputConstants.MOUSE_BUTTON_RIGHT
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(mouseButton: Int) {
|
||||||
|
if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) {
|
||||||
|
PacketDistributor.sendToServer(QuickStackPacket(QuickMoveInput.Mode.RESTOCK_WITH_MOVE, true))
|
||||||
|
PacketDistributor.sendToServer(QuickStackPacket(QuickMoveInput.Mode.RESTOCK, false))
|
||||||
|
} else {
|
||||||
|
buttons.forEach { it.visible = !it.visible }
|
||||||
|
|
||||||
|
if (buttons[0].visible) {
|
||||||
|
grid.columns = 2
|
||||||
|
grid.rows = 4
|
||||||
|
} else {
|
||||||
|
grid.columns = 1
|
||||||
|
grid.rows = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
this@QuickStackControlsPanel.sizeToContents()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sizeToContents() {
|
||||||
|
val oldWidth = width
|
||||||
|
super.sizeToContents()
|
||||||
|
x -= width - oldWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
for ((i, mode) in QuickMoveInput.Mode.entries.withIndex()) {
|
||||||
|
val button = ButtonPanel.square18(
|
||||||
|
screen, grid,
|
||||||
|
mode.iconFromStorage,
|
||||||
|
onPress = IntConsumer { PacketDistributor.sendToServer(QuickStackPacket(mode, false)) })
|
||||||
|
|
||||||
|
button.childrenOrder = 1000 + i
|
||||||
|
button.dockMargin = DockProperty.bottomRight(1f)
|
||||||
|
button.visible = false
|
||||||
|
button.tooltips.add(mode.textFromStorage)
|
||||||
|
buttons.add(button)
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((i, mode) in QuickMoveInput.Mode.entries.withIndex()) {
|
||||||
|
val button = ButtonPanel.square18(
|
||||||
|
screen, grid,
|
||||||
|
mode.iconToStorage,
|
||||||
|
onPress = IntConsumer { PacketDistributor.sendToServer(QuickStackPacket(mode, true)) })
|
||||||
|
|
||||||
|
button.childrenOrder = i
|
||||||
|
button.dockMargin = DockProperty.bottom(1f)
|
||||||
|
button.visible = false
|
||||||
|
button.tooltips.add(mode.textToStorage)
|
||||||
|
buttons.add(button)
|
||||||
|
}
|
||||||
|
|
||||||
|
MainButton()
|
||||||
|
}
|
||||||
|
}
|
@ -2,12 +2,11 @@ package ru.dbotthepony.mc.otm.client.screen.panels.button
|
|||||||
|
|
||||||
import com.mojang.blaze3d.platform.InputConstants
|
import com.mojang.blaze3d.platform.InputConstants
|
||||||
import net.minecraft.ChatFormatting
|
import net.minecraft.ChatFormatting
|
||||||
import net.minecraft.client.gui.screens.Screen
|
|
||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.item.Items
|
import net.minecraft.world.item.Items
|
||||||
import ru.dbotthepony.kommons.math.RGBAColor
|
|
||||||
import ru.dbotthepony.kommons.util.Delegate
|
import ru.dbotthepony.kommons.util.Delegate
|
||||||
|
import ru.dbotthepony.kommons.util.Either
|
||||||
import ru.dbotthepony.kommons.util.value
|
import ru.dbotthepony.kommons.util.value
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting
|
import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting
|
||||||
@ -21,7 +20,6 @@ import ru.dbotthepony.mc.otm.client.minecraft
|
|||||||
import ru.dbotthepony.mc.otm.client.render.IGUIRenderable
|
import ru.dbotthepony.mc.otm.client.render.IGUIRenderable
|
||||||
import ru.dbotthepony.mc.otm.client.render.sprites.AbstractMatterySprite
|
import ru.dbotthepony.mc.otm.client.render.sprites.AbstractMatterySprite
|
||||||
import ru.dbotthepony.mc.otm.client.render.ItemStackIcon
|
import ru.dbotthepony.mc.otm.client.render.ItemStackIcon
|
||||||
import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
|
|
||||||
import ru.dbotthepony.mc.otm.client.render.Widgets18
|
import ru.dbotthepony.mc.otm.client.render.Widgets18
|
||||||
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.Dock
|
import ru.dbotthepony.mc.otm.client.screen.panels.Dock
|
||||||
@ -38,8 +36,9 @@ import ru.dbotthepony.mc.otm.core.immutableList
|
|||||||
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
||||||
import ru.dbotthepony.mc.otm.core.util.ItemStackSorter
|
import ru.dbotthepony.mc.otm.core.util.ItemStackSorter
|
||||||
import ru.dbotthepony.mc.otm.core.util.getLevelFromXp
|
import ru.dbotthepony.mc.otm.core.util.getLevelFromXp
|
||||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
||||||
import ru.dbotthepony.mc.otm.menu.MatterySlot
|
import ru.dbotthepony.mc.otm.menu.QuickMoveInput
|
||||||
|
import ru.dbotthepony.mc.otm.menu.SortInput
|
||||||
import ru.dbotthepony.mc.otm.menu.UpgradeSlots
|
import ru.dbotthepony.mc.otm.menu.UpgradeSlots
|
||||||
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
|
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
|
||||||
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
|
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
|
||||||
@ -388,13 +387,17 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <P : EditablePanel<@UnsafeVariance S>> addButton(button: P): P {
|
fun <P : EditablePanel<@UnsafeVariance S>> addButton(button: P): P {
|
||||||
buttons.add(button)
|
if (button !in buttons) {
|
||||||
button.parent = this
|
buttons.add(button)
|
||||||
alignButtons()
|
button.parent = this
|
||||||
|
alignButtons()
|
||||||
|
}
|
||||||
|
|
||||||
return button
|
return button
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <P : EditablePanel<@UnsafeVariance S>> addButton(button: P, after: EditablePanel<*>): P {
|
fun <P : EditablePanel<@UnsafeVariance S>> addButton(button: P, after: EditablePanel<*>): P {
|
||||||
|
buttons.remove(button)
|
||||||
val index = buttons.indexOf(after)
|
val index = buttons.indexOf(after)
|
||||||
if (index == -1) throw NoSuchElementException("Unknown panel to add button after: $after")
|
if (index == -1) throw NoSuchElementException("Unknown panel to add button after: $after")
|
||||||
buttons.add(index + 1, button)
|
buttons.add(index + 1, button)
|
||||||
@ -404,9 +407,12 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <P : EditablePanel<@UnsafeVariance S>> prependButton(button: P): P {
|
fun <P : EditablePanel<@UnsafeVariance S>> prependButton(button: P): P {
|
||||||
buttons.add(0, button)
|
if (button !in buttons) {
|
||||||
button.parent = this
|
buttons.add(0, button)
|
||||||
alignButtons()
|
button.parent = this
|
||||||
|
alignButtons()
|
||||||
|
}
|
||||||
|
|
||||||
return button
|
return button
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,9 +458,74 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sortingButtons(input: MatteryMenu.SortInput, unfoldableSettings: Boolean = true) {
|
abstract inner class FoldableButtonPanel() : ButtonPanel<S>(screen, this@DeviceControls, width = 18f, height = 18f) {
|
||||||
object : ButtonPanel<S>(screen, this@DeviceControls, width = 18f, height = 18f) {
|
init {
|
||||||
var buttons: List<EditablePanel<*>>? = null
|
addButton(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var buttons: List<EditablePanel<S>>? = null
|
||||||
|
|
||||||
|
fun makeButtons() {
|
||||||
|
if (buttons == null) {
|
||||||
|
buttons = doMakeButtons().also {
|
||||||
|
it.forEach { addButton(it, this) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeButtons() {
|
||||||
|
if (buttons != null) {
|
||||||
|
buttons!!.forEach { it.remove() }
|
||||||
|
buttons = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun test(value: Int): Boolean {
|
||||||
|
return value == InputConstants.MOUSE_BUTTON_LEFT || hasExtraButtons && value == InputConstants.MOUSE_BUTTON_RIGHT
|
||||||
|
}
|
||||||
|
|
||||||
|
fun switchButtons() {
|
||||||
|
if (buttons == null)
|
||||||
|
makeButtons()
|
||||||
|
else
|
||||||
|
removeButtons()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract val hasExtraButtons: Boolean
|
||||||
|
protected abstract fun performAction()
|
||||||
|
protected abstract fun doMakeButtons(): List<EditablePanel<S>>
|
||||||
|
|
||||||
|
final override fun onClick(mouseButton: Int) {
|
||||||
|
if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) {
|
||||||
|
performAction()
|
||||||
|
} else {
|
||||||
|
switchButtons()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sortingButtons(input: SortInput, unfoldableSettings: Boolean = true) {
|
||||||
|
object : FoldableButtonPanel() {
|
||||||
|
override fun performAction() {
|
||||||
|
input.clientInput()
|
||||||
|
}
|
||||||
|
|
||||||
|
override var isDisabled: Boolean
|
||||||
|
get() { return !input.input.test(minecraft.player ?: return false) }
|
||||||
|
set(value) {}
|
||||||
|
|
||||||
|
override val hasExtraButtons: Boolean
|
||||||
|
get() = unfoldableSettings
|
||||||
|
|
||||||
|
override fun doMakeButtons(): List<EditablePanel<S>> {
|
||||||
|
return sortingButtons(Delegate.Of(input.settings::isAscending), Delegate.Of(input.settings::sorting), ItemStackSorter.DEFAULT) {
|
||||||
|
for (v in ItemStackSorter.entries) {
|
||||||
|
add(v, v.icon, v.title)
|
||||||
|
}
|
||||||
|
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
tooltips.add(TranslatableComponent("otm.gui.sorting.sort_now"))
|
tooltips.add(TranslatableComponent("otm.gui.sorting.sort_now"))
|
||||||
@ -462,50 +533,75 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
|||||||
if (unfoldableSettings) {
|
if (unfoldableSettings) {
|
||||||
tooltips.add(TextComponent(""))
|
tooltips.add(TextComponent(""))
|
||||||
tooltips.add(TranslatableComponent("otm.gui.sorting.sort_settings").withStyle(ChatFormatting.GRAY))
|
tooltips.add(TranslatableComponent("otm.gui.sorting.sort_settings").withStyle(ChatFormatting.GRAY))
|
||||||
}
|
} else {
|
||||||
addButton(this)
|
|
||||||
|
|
||||||
if (!unfoldableSettings) {
|
|
||||||
makeButtons()
|
makeButtons()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val icon: IGUIRenderable
|
override val icon: IGUIRenderable
|
||||||
get() = Widgets18.SORT_NOW
|
get() = Widgets18.SORT_NOW
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun test(value: Int): Boolean {
|
fun quickMoveButtons(
|
||||||
return value == InputConstants.MOUSE_BUTTON_LEFT || unfoldableSettings && value == InputConstants.MOUSE_BUTTON_RIGHT
|
buttons: Map<QuickMoveInput.Mode, QuickMoveInput>,
|
||||||
|
fromStorage: Map<QuickMoveInput.Mode, QuickMoveInput>? = null
|
||||||
|
) {
|
||||||
|
object : FoldableButtonPanel() {
|
||||||
|
override fun performAction() {
|
||||||
|
if (fromStorage == null) {
|
||||||
|
buttons[QuickMoveInput.Mode.MOVE]!!.clientInput()
|
||||||
|
} else {
|
||||||
|
buttons[QuickMoveInput.Mode.RESTOCK_WITH_MOVE]!!.clientInput()
|
||||||
|
fromStorage[QuickMoveInput.Mode.RESTOCK]!!.clientInput()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override var isDisabled: Boolean
|
override var isDisabled: Boolean
|
||||||
get() { return !input.input.test(minecraft.player ?: return false) }
|
get() { return !buttons.values.first().input.test(minecraft.player ?: return false) }
|
||||||
set(value) {}
|
set(value) {}
|
||||||
|
|
||||||
private fun makeButtons() {
|
override val hasExtraButtons: Boolean
|
||||||
buttons = sortingButtons(Delegate.Of(input.settings::isAscending), Delegate.Of(input.settings::sorting), ItemStackSorter.DEFAULT) {
|
get() = true
|
||||||
for (v in ItemStackSorter.entries) {
|
|
||||||
add(v, v.icon, v.title)
|
override fun doMakeButtons(): List<EditablePanel<S>> {
|
||||||
|
var stream = buttons.entries
|
||||||
|
.stream()
|
||||||
|
|
||||||
|
if (fromStorage == null)
|
||||||
|
stream = stream.filter { (m) -> m != QuickMoveInput.Mode.MOVE }
|
||||||
|
|
||||||
|
return stream
|
||||||
|
.map { (m, b) ->
|
||||||
|
square18(
|
||||||
|
screen,
|
||||||
|
this,
|
||||||
|
icon = if (fromStorage == null) m.iconFromStorage else m.iconToStorage,
|
||||||
|
onPress = { b.clientInput() }
|
||||||
|
).also {
|
||||||
|
if (fromStorage == null)
|
||||||
|
it.tooltips.add(m.textFromStorage)
|
||||||
|
else
|
||||||
|
it.tooltips.add(m.textToStorage)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
.toList()
|
||||||
finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
buttons!!.forEach { removeButton(it) }
|
|
||||||
buttons!!.forEach { addButton(it as EditablePanel<S>, this) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onClick(mouseButton: Int) {
|
init {
|
||||||
if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) {
|
if (fromStorage == null)
|
||||||
input.clientInput()
|
tooltips.add(QuickMoveInput.Mode.MOVE.textFromStorage)
|
||||||
} else {
|
else {
|
||||||
if (buttons == null) {
|
tooltips.add(TranslatableComponent("otm.gui.quickmove.exchange"))
|
||||||
makeButtons()
|
tooltips.add(TranslatableComponent("otm.gui.quickmove.exchange.desc").withStyle(ChatFormatting.GRAY))
|
||||||
} else {
|
|
||||||
buttons!!.forEach { it.remove() }
|
|
||||||
buttons = null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tooltips.add(TextComponent(""))
|
||||||
|
tooltips.add(TranslatableComponent("otm.gui.quickmove_hint").withStyle(ChatFormatting.GRAY))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val icon: IGUIRenderable
|
||||||
|
get() = if (fromStorage == null) QuickMoveInput.Mode.MOVE.iconFromStorage else Widgets18.SMART_STORAGE_EXCHANGE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -571,7 +667,7 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
|||||||
val grid = GridPanel(screen, frame, columns = columns, rows = rows)
|
val grid = GridPanel(screen, frame, columns = columns, rows = rows)
|
||||||
|
|
||||||
for (slot in upgrades.slots) {
|
for (slot in upgrades.slots) {
|
||||||
object : SlotPanel<S, MatterySlot>(screen, grid, slot) {
|
object : SlotPanel<S, MatteryMenuSlot>(screen, grid, slot) {
|
||||||
override val cursorType: CursorType
|
override val cursorType: CursorType
|
||||||
get() = if (upgrades.areLocked.get()) CursorType.NOT_ALLOWED else super.cursorType
|
get() = if (upgrades.areLocked.get()) CursorType.NOT_ALLOWED else super.cursorType
|
||||||
}
|
}
|
||||||
|
@ -4,22 +4,36 @@ import net.minecraft.world.item.ItemStack
|
|||||||
import ru.dbotthepony.kommons.util.Delegate
|
import ru.dbotthepony.kommons.util.Delegate
|
||||||
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||||
|
import ru.dbotthepony.mc.otm.container.ItemFilter
|
||||||
|
|
||||||
open class FilterSlotPanel<out S : MatteryScreen<*>> @JvmOverloads constructor(
|
open class FilterSlotPanel<out S : MatteryScreen<*>>(
|
||||||
screen: S,
|
screen: S,
|
||||||
parent: EditablePanel<*>?,
|
parent: EditablePanel<*>?,
|
||||||
val slot: Delegate<ItemStack>,
|
val slot: Delegate<ItemFilter>,
|
||||||
x: Float = 0f,
|
x: Float = 0f,
|
||||||
y: Float = 0f,
|
y: Float = 0f,
|
||||||
width: Float = SIZE,
|
width: Float = SIZE,
|
||||||
height: Float = SIZE
|
height: Float = SIZE
|
||||||
) : AbstractSlotPanel<S>(screen, parent, x, y, width, height) {
|
) : AbstractSlotPanel<S>(screen, parent, x, y, width, height) {
|
||||||
|
private var lastFilteredItemDisplayUpdate = System.nanoTime()
|
||||||
|
private var filteredItemDisplayIndex = 0
|
||||||
|
|
||||||
override val itemStack: ItemStack get() {
|
override val itemStack: ItemStack get() {
|
||||||
return slot.get()
|
val items = slot.get().displayItems
|
||||||
|
|
||||||
|
if (items.isEmpty())
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
|
||||||
|
if (System.nanoTime() - lastFilteredItemDisplayUpdate >= 1_000_000_000L || filteredItemDisplayIndex !in items.indices) {
|
||||||
|
lastFilteredItemDisplayUpdate = System.nanoTime()
|
||||||
|
filteredItemDisplayIndex = random.nextInt(items.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
return items.asList()[filteredItemDisplayIndex].asItemStack()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
|
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
|
||||||
slot.accept(screen.menu.carried)
|
slot.accept(ItemFilter.item(screen.menu.carried))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,10 +18,6 @@ open class InventorySlotPanel<out S : MatteryScreen<*>, out T : MatteryMenu.Inve
|
|||||||
x: Float = 0f,
|
x: Float = 0f,
|
||||||
y: Float = 0f,
|
y: Float = 0f,
|
||||||
) : UserFilteredSlotPanel<S, T>(screen, parent, slot, x, y, SIZE, SIZE) {
|
) : UserFilteredSlotPanel<S, T>(screen, parent, slot, x, y, SIZE, SIZE) {
|
||||||
override var slotFilter: Item?
|
|
||||||
get() = slot.filter?.get()
|
|
||||||
set(value) { slot.filter?.accept(value) }
|
|
||||||
|
|
||||||
override fun renderBackgroundBeforeFilter(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
override fun renderBackgroundBeforeFilter(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||||
if (slot.chargeFlag?.get() == true) {
|
if (slot.chargeFlag?.get() == true) {
|
||||||
Widgets18.CHARGE_SLOT_BACKGROUND.render(graphics, 0f, 0f, width, height)
|
Widgets18.CHARGE_SLOT_BACKGROUND.render(graphics, 0f, 0f, width, height)
|
||||||
|
@ -5,9 +5,13 @@ package ru.dbotthepony.mc.otm.client.screen.panels.slot
|
|||||||
import com.mojang.blaze3d.systems.RenderSystem
|
import com.mojang.blaze3d.systems.RenderSystem
|
||||||
import net.minecraft.ChatFormatting
|
import net.minecraft.ChatFormatting
|
||||||
import net.minecraft.client.renderer.GameRenderer
|
import net.minecraft.client.renderer.GameRenderer
|
||||||
|
import net.minecraft.network.chat.Component
|
||||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||||
import net.minecraft.world.inventory.Slot
|
import net.minecraft.world.inventory.Slot
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.item.Items
|
||||||
|
import net.neoforged.neoforge.client.extensions.common.IClientItemExtensions
|
||||||
|
import ru.dbotthepony.kommons.math.RGBAColor
|
||||||
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
|
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
|
||||||
import ru.dbotthepony.mc.otm.client.minecraft
|
import ru.dbotthepony.mc.otm.client.minecraft
|
||||||
import ru.dbotthepony.mc.otm.client.render.Widgets18
|
import ru.dbotthepony.mc.otm.client.render.Widgets18
|
||||||
@ -15,6 +19,14 @@ import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
|||||||
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||||
import ru.dbotthepony.mc.otm.compat.itemborders.isItemBordersLoaded
|
import ru.dbotthepony.mc.otm.compat.itemborders.isItemBordersLoaded
|
||||||
import ru.dbotthepony.mc.otm.compat.itemborders.renderSlotBorder
|
import ru.dbotthepony.mc.otm.compat.itemborders.renderSlotBorder
|
||||||
|
import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.ItemFilter
|
||||||
|
import ru.dbotthepony.mc.otm.container.ItemStackKey
|
||||||
|
import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull
|
||||||
|
import ru.dbotthepony.mc.otm.core.TextComponent
|
||||||
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
|
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||||
|
import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot
|
||||||
import javax.annotation.Nonnull
|
import javax.annotation.Nonnull
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@ -52,6 +64,49 @@ open class SlotPanel<out S : MatteryScreen<*>, out T : Slot>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected open fun renderBackgroundBeforeFilter(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {}
|
||||||
|
|
||||||
|
private var lastFilteredItemDisplayUpdate = System.nanoTime()
|
||||||
|
private var filteredItemDisplayIndex = 0
|
||||||
|
|
||||||
|
private fun selectRandomItemFromFilter(filter: ItemFilter): ItemStack {
|
||||||
|
val items = filter.displayItems
|
||||||
|
|
||||||
|
if (items.isEmpty()) {
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
} else {
|
||||||
|
if (System.nanoTime() - lastFilteredItemDisplayUpdate >= 1_000_000_000L || filteredItemDisplayIndex !in items.indices) {
|
||||||
|
lastFilteredItemDisplayUpdate = System.nanoTime()
|
||||||
|
filteredItemDisplayIndex = random.nextInt(items.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
return items.asList()[filteredItemDisplayIndex].asItemStack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun renderSlotBackground(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||||
|
super.renderSlotBackground(graphics, mouseX, mouseY, partialTick)
|
||||||
|
|
||||||
|
val containerSlot = slot.container.containerSlotOrNull(slot.slotIndex)
|
||||||
|
|
||||||
|
if (containerSlot is IFilteredContainerSlot) {
|
||||||
|
renderBackgroundBeforeFilter(graphics, mouseX, mouseY, partialTick)
|
||||||
|
|
||||||
|
if (containerSlot.filter.denyAll) {
|
||||||
|
graphics.renderRect(0f, 0f, width, height, color = SLOT_BLOCK_COLOR)
|
||||||
|
} else if (!containerSlot.filter.allowAll) {
|
||||||
|
val itemStack = selectRandomItemFromFilter(containerSlot.filter)
|
||||||
|
|
||||||
|
if (itemStack.isNotEmpty) {
|
||||||
|
screen.renderItemStack(graphics, itemStack, null)
|
||||||
|
clearDepth(graphics)
|
||||||
|
|
||||||
|
graphics.renderRect(0f, 0f, width, height, color = SLOT_FILTER_COLOR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||||
slot.x = absoluteX.roundToInt() - screen.guiLeft
|
slot.x = absoluteX.roundToInt() - screen.guiLeft
|
||||||
slot.y = absoluteY.roundToInt() - screen.guiTop
|
slot.y = absoluteY.roundToInt() - screen.guiTop
|
||||||
@ -120,10 +175,58 @@ open class SlotPanel<out S : MatteryScreen<*>, out T : Slot>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun innerRenderTooltips(@Nonnull graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float): Boolean {
|
override fun innerRenderTooltips(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float): Boolean {
|
||||||
|
val slot = slot.container.containerSlotOrNull(slot.containerSlot) as? IFilteredContainerSlot
|
||||||
|
|
||||||
|
if (isHovered && slot?.filter != null && slot.filter.hasRules && itemStack.isEmpty) {
|
||||||
|
val itemstack = selectRandomItemFromFilter(slot.filter)
|
||||||
|
|
||||||
|
val text: List<Component>
|
||||||
|
|
||||||
|
if (itemstack.isEmpty) {
|
||||||
|
text = listOf(
|
||||||
|
TranslatableComponent("otm.gui.slot_filter.filtered").withStyle(ChatFormatting.GRAY),
|
||||||
|
TranslatableComponent("otm.gui.slot_filter.hint").withStyle(ChatFormatting.GRAY)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
text = getItemStackTooltip(itemstack).toMutableList().also {
|
||||||
|
it.add(0, TranslatableComponent("otm.gui.slot_filter.filtered").withStyle(ChatFormatting.GRAY))
|
||||||
|
it.add(1, TranslatableComponent("otm.gui.slot_filter.hint").withStyle(ChatFormatting.GRAY))
|
||||||
|
it.add(2, TextComponent(""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
graphics.renderComponentTooltip(
|
||||||
|
IClientItemExtensions.of(itemstack).getFont(itemstack, IClientItemExtensions.FontContext.TOOLTIP) ?: font,
|
||||||
|
text,
|
||||||
|
mouseX.toInt(),
|
||||||
|
mouseY.toInt(),
|
||||||
|
itemstack
|
||||||
|
)
|
||||||
|
|
||||||
|
return true
|
||||||
|
} else if (isHovered && slot?.filter?.denyAll == true && itemStack.isEmpty) {
|
||||||
|
graphics.renderComponentTooltip(
|
||||||
|
font,
|
||||||
|
ArrayList<Component>().also {
|
||||||
|
it.add(TranslatableComponent("otm.gui.slot_filter.forbidden").withStyle(ChatFormatting.GRAY))
|
||||||
|
it.add(TranslatableComponent("otm.gui.slot_filter.hint").withStyle(ChatFormatting.GRAY))
|
||||||
|
},
|
||||||
|
mouseX.toInt(),
|
||||||
|
mouseY.toInt()
|
||||||
|
)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// no op, screen does it for us (completely)
|
// no op, screen does it for us (completely)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val SLOT_FILTER_COLOR = RGBAColor(85, 113, 216, 150)
|
||||||
|
val SLOT_BLOCK_COLOR = RGBAColor(219, 113, 113, 150)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <S : MatteryScreen<*>, T : Slot> BatterySlotPanel(
|
fun <S : MatteryScreen<*>, T : Slot> BatterySlotPanel(
|
||||||
@ -134,7 +237,7 @@ fun <S : MatteryScreen<*>, T : Slot> BatterySlotPanel(
|
|||||||
y: Float = 0f,
|
y: Float = 0f,
|
||||||
width: Float = AbstractSlotPanel.SIZE,
|
width: Float = AbstractSlotPanel.SIZE,
|
||||||
height: Float = AbstractSlotPanel.SIZE,
|
height: Float = AbstractSlotPanel.SIZE,
|
||||||
) = SlotPanel(screen, parent, slot, x, y, width, height).also { it.slotBackgroundEmpty = Widgets18.BATTERY_SLOT_BACKGROUND }
|
) = (if (slot is UserFilteredMenuSlot) UserFilteredSlotPanel(screen, parent, slot, x, y, width, height) else SlotPanel(screen, parent, slot, x, y, width, height)).also { it.slotBackgroundEmpty = Widgets18.BATTERY_SLOT_BACKGROUND }
|
||||||
|
|
||||||
fun <S : MatteryScreen<*>, T : Slot> EquipmentBatterySlotPanel(
|
fun <S : MatteryScreen<*>, T : Slot> EquipmentBatterySlotPanel(
|
||||||
screen: S,
|
screen: S,
|
||||||
@ -144,7 +247,7 @@ fun <S : MatteryScreen<*>, T : Slot> EquipmentBatterySlotPanel(
|
|||||||
y: Float = 0f,
|
y: Float = 0f,
|
||||||
width: Float = AbstractSlotPanel.SIZE,
|
width: Float = AbstractSlotPanel.SIZE,
|
||||||
height: Float = AbstractSlotPanel.SIZE,
|
height: Float = AbstractSlotPanel.SIZE,
|
||||||
) = SlotPanel(screen, parent, slot, x, y, width, height).also { it.slotBackgroundEmpty = Widgets18.EQUIPMENT_BATTERY_SLOT_BACKGROUND }
|
) = (if (slot is UserFilteredMenuSlot) UserFilteredSlotPanel(screen, parent, slot, x, y, width, height) else SlotPanel(screen, parent, slot, x, y, width, height)).also { it.slotBackgroundEmpty = Widgets18.EQUIPMENT_BATTERY_SLOT_BACKGROUND }
|
||||||
|
|
||||||
fun <S : MatteryScreen<*>, T : Slot> PatternSlotPanel(
|
fun <S : MatteryScreen<*>, T : Slot> PatternSlotPanel(
|
||||||
screen: S,
|
screen: S,
|
||||||
@ -154,7 +257,7 @@ fun <S : MatteryScreen<*>, T : Slot> PatternSlotPanel(
|
|||||||
y: Float = 0f,
|
y: Float = 0f,
|
||||||
width: Float = AbstractSlotPanel.SIZE,
|
width: Float = AbstractSlotPanel.SIZE,
|
||||||
height: Float = AbstractSlotPanel.SIZE,
|
height: Float = AbstractSlotPanel.SIZE,
|
||||||
) = SlotPanel(screen, parent, slot, x, y, width, height).also { it.slotBackgroundEmpty = Widgets18.PATTERN_SLOT_BACKGROUND }
|
) = (if (slot is UserFilteredMenuSlot) UserFilteredSlotPanel(screen, parent, slot, x, y, width, height) else SlotPanel(screen, parent, slot, x, y, width, height)).also { it.slotBackgroundEmpty = Widgets18.PATTERN_SLOT_BACKGROUND }
|
||||||
|
|
||||||
fun <S : MatteryScreen<*>, T : Slot> MatterCapacitorSlotPanel(
|
fun <S : MatteryScreen<*>, T : Slot> MatterCapacitorSlotPanel(
|
||||||
screen: S,
|
screen: S,
|
||||||
@ -164,4 +267,4 @@ fun <S : MatteryScreen<*>, T : Slot> MatterCapacitorSlotPanel(
|
|||||||
y: Float = 0f,
|
y: Float = 0f,
|
||||||
width: Float = AbstractSlotPanel.SIZE,
|
width: Float = AbstractSlotPanel.SIZE,
|
||||||
height: Float = AbstractSlotPanel.SIZE,
|
height: Float = AbstractSlotPanel.SIZE,
|
||||||
) = SlotPanel(screen, parent, slot, x, y, width, height).also { it.slotBackgroundEmpty = Widgets18.MATTER_CAPACITOR_SLOT_BACKGROUND }
|
) = (if (slot is UserFilteredMenuSlot) UserFilteredSlotPanel(screen, parent, slot, x, y, width, height) else SlotPanel(screen, parent, slot, x, y, width, height)).also { it.slotBackgroundEmpty = Widgets18.MATTER_CAPACITOR_SLOT_BACKGROUND }
|
||||||
|
@ -1,28 +1,17 @@
|
|||||||
package ru.dbotthepony.mc.otm.client.screen.panels.slot
|
package ru.dbotthepony.mc.otm.client.screen.panels.slot
|
||||||
|
|
||||||
import com.mojang.blaze3d.platform.InputConstants
|
import com.mojang.blaze3d.platform.InputConstants
|
||||||
import net.minecraft.ChatFormatting
|
|
||||||
import net.minecraft.network.chat.Component
|
|
||||||
import net.minecraft.world.inventory.Slot
|
|
||||||
import net.minecraft.world.item.Item
|
|
||||||
import net.minecraft.world.item.ItemStack
|
|
||||||
import net.minecraft.world.item.Items
|
|
||||||
import net.neoforged.neoforge.client.extensions.common.IClientItemExtensions
|
|
||||||
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
|
|
||||||
import ru.dbotthepony.mc.otm.client.isCtrlDown
|
import ru.dbotthepony.mc.otm.client.isCtrlDown
|
||||||
import ru.dbotthepony.mc.otm.client.minecraft
|
import ru.dbotthepony.mc.otm.client.minecraft
|
||||||
import ru.dbotthepony.mc.otm.client.playGuiClickSound
|
import ru.dbotthepony.mc.otm.client.playGuiClickSound
|
||||||
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||||
import ru.dbotthepony.mc.otm.core.TextComponent
|
import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot
|
||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.container.ItemFilter
|
||||||
import ru.dbotthepony.kommons.math.RGBAColor
|
import ru.dbotthepony.mc.otm.container.util.containerSlot
|
||||||
import ru.dbotthepony.kommons.util.Delegate
|
import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot
|
||||||
import ru.dbotthepony.kommons.util.getValue
|
|
||||||
import ru.dbotthepony.kommons.util.setValue
|
|
||||||
import ru.dbotthepony.mc.otm.menu.UserFilteredSlot
|
|
||||||
|
|
||||||
abstract class UserFilteredSlotPanel<out S : MatteryScreen<*>, out T : Slot>(
|
open class UserFilteredSlotPanel<out S : MatteryScreen<*>, out T : UserFilteredMenuSlot>(
|
||||||
screen: S,
|
screen: S,
|
||||||
parent: EditablePanel<*>?,
|
parent: EditablePanel<*>?,
|
||||||
slot: T,
|
slot: T,
|
||||||
@ -31,77 +20,22 @@ abstract class UserFilteredSlotPanel<out S : MatteryScreen<*>, out T : Slot>(
|
|||||||
width: Float = SIZE,
|
width: Float = SIZE,
|
||||||
height: Float = SIZE,
|
height: Float = SIZE,
|
||||||
) : SlotPanel<S, T>(screen, parent, slot, x, y, width, height) {
|
) : SlotPanel<S, T>(screen, parent, slot, x, y, width, height) {
|
||||||
abstract var slotFilter: Item?
|
|
||||||
|
|
||||||
protected open fun renderBackgroundBeforeFilter(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {}
|
|
||||||
|
|
||||||
override fun renderSlotBackground(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
|
||||||
super.renderSlotBackground(graphics, mouseX, mouseY, partialTick)
|
|
||||||
|
|
||||||
renderBackgroundBeforeFilter(graphics, mouseX, mouseY, partialTick)
|
|
||||||
|
|
||||||
if (slotFilter != null) {
|
|
||||||
if (slotFilter !== Items.AIR) {
|
|
||||||
val itemStack = ItemStack(slotFilter!!, 1)
|
|
||||||
|
|
||||||
screen.renderItemStack(graphics, itemStack, null)
|
|
||||||
clearDepth(graphics)
|
|
||||||
|
|
||||||
graphics.renderRect(0f, 0f, width, height, color = SLOT_FILTER_COLOR)
|
|
||||||
} else {
|
|
||||||
graphics.renderRect(0f, 0f, width, height, color = SLOT_BLOCK_COLOR)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun innerRenderTooltips(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float): Boolean {
|
|
||||||
if (isHovered && slotFilter != null && slotFilter !== Items.AIR && itemStack.isEmpty) {
|
|
||||||
val itemstack = ItemStack(slotFilter!!, 1)
|
|
||||||
|
|
||||||
graphics.renderComponentTooltip(
|
|
||||||
IClientItemExtensions.of(itemstack).getFont(itemstack, IClientItemExtensions.FontContext.TOOLTIP) ?: font,
|
|
||||||
getItemStackTooltip(itemstack).toMutableList().also {
|
|
||||||
it.add(0, TranslatableComponent("otm.gui.slot_filter.filtered").withStyle(ChatFormatting.GRAY))
|
|
||||||
it.add(1, TranslatableComponent("otm.gui.slot_filter.hint").withStyle(ChatFormatting.GRAY))
|
|
||||||
it.add(2, TextComponent(""))
|
|
||||||
},
|
|
||||||
mouseX.toInt(),
|
|
||||||
mouseY.toInt(),
|
|
||||||
itemstack
|
|
||||||
)
|
|
||||||
|
|
||||||
return true
|
|
||||||
} else if (isHovered && slotFilter === Items.AIR && itemStack.isEmpty) {
|
|
||||||
graphics.renderComponentTooltip(
|
|
||||||
font,
|
|
||||||
ArrayList<Component>().also {
|
|
||||||
it.add(TranslatableComponent("otm.gui.slot_filter.forbidden").withStyle(ChatFormatting.GRAY))
|
|
||||||
it.add(TranslatableComponent("otm.gui.slot_filter.hint").withStyle(ChatFormatting.GRAY))
|
|
||||||
},
|
|
||||||
mouseX.toInt(),
|
|
||||||
mouseY.toInt()
|
|
||||||
)
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.innerRenderTooltips(graphics, mouseX, mouseY, partialTick)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
|
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
|
||||||
|
val filterInput = slot.filterInput ?: return super.mouseClickedInner(x, y, button)
|
||||||
|
val containerSlot = slot.containerSlot() as IFilteredContainerSlot
|
||||||
|
|
||||||
if (button == InputConstants.MOUSE_BUTTON_LEFT && minecraft.window.isCtrlDown) {
|
if (button == InputConstants.MOUSE_BUTTON_LEFT && minecraft.window.isCtrlDown) {
|
||||||
if (slotFilter === null) {
|
if (containerSlot.filter.allowAll) {
|
||||||
if (screen.menu.carried.isEmpty) {
|
if (screen.menu.carried.isEmpty) {
|
||||||
slotFilter = slot.item.item
|
filterInput.accept(ItemFilter.item(slot.item.item))
|
||||||
} else {
|
} else {
|
||||||
slotFilter = screen.menu.carried.item
|
filterInput.accept(ItemFilter.item(screen.menu.carried.item))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
slotFilter = null
|
filterInput.accept(ItemFilter.EMPTY)
|
||||||
}
|
}
|
||||||
|
|
||||||
playGuiClickSound()
|
playGuiClickSound()
|
||||||
|
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return super.mouseClickedInner(x, y, button)
|
return super.mouseClickedInner(x, y, button)
|
||||||
@ -115,40 +49,4 @@ abstract class UserFilteredSlotPanel<out S : MatteryScreen<*>, out T : Slot>(
|
|||||||
|
|
||||||
return super.mouseReleasedInner(x, y, button)
|
return super.mouseReleasedInner(x, y, button)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
val SLOT_FILTER_COLOR = RGBAColor(85, 113, 216, 150)
|
|
||||||
val SLOT_BLOCK_COLOR = RGBAColor(219, 113, 113, 150)
|
|
||||||
|
|
||||||
fun <S : MatteryScreen<*>, T : Slot> of(
|
|
||||||
screen: S,
|
|
||||||
parent: EditablePanel<*>?,
|
|
||||||
slot: T,
|
|
||||||
x: Float = 0f,
|
|
||||||
y: Float = 0f,
|
|
||||||
width: Float = SIZE,
|
|
||||||
height: Float = SIZE,
|
|
||||||
filter: Delegate<Item?>
|
|
||||||
): UserFilteredSlotPanel<S, T> {
|
|
||||||
return object : UserFilteredSlotPanel<S, T>(screen, parent, slot, x, y, width, height) {
|
|
||||||
override var slotFilter: Item? by filter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <S : MatteryScreen<*>, T : UserFilteredSlot> of(
|
|
||||||
screen: S,
|
|
||||||
parent: EditablePanel<*>?,
|
|
||||||
slot: T,
|
|
||||||
x: Float = 0f,
|
|
||||||
y: Float = 0f,
|
|
||||||
width: Float = SIZE,
|
|
||||||
height: Float = SIZE,
|
|
||||||
): UserFilteredSlotPanel<S, T> {
|
|
||||||
return object : UserFilteredSlotPanel<S, T>(screen, parent, slot, x, y, width, height) {
|
|
||||||
override var slotFilter: Item?
|
|
||||||
get() = slot.filter?.get()
|
|
||||||
set(value) { slot.filter?.accept(value) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -66,14 +66,12 @@ class DriveViewerScreen(menu: DriveViewerMenu, inventory: Inventory, title: Comp
|
|||||||
settings.add(filterGrid)
|
settings.add(filterGrid)
|
||||||
|
|
||||||
for (i in 0 until PortableCondensationDriveItem.MAX_FILTERS) {
|
for (i in 0 until PortableCondensationDriveItem.MAX_FILTERS) {
|
||||||
FilterSlotPanel(this, filterGrid, menu.driveFilterSlots[i], 0f, 0f)
|
FilterSlotPanel(this, filterGrid, menu.driveFilter.slots[i], 0f, 0f)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.add(EditablePanel(this, frame, width = 90f).also {
|
settings.add(EditablePanel(this, frame, width = 90f).also {
|
||||||
it.dock = Dock.LEFT
|
it.dock = Dock.LEFT
|
||||||
BooleanButtonPanel.Checkbox(this, it, menu.isWhitelist, TranslatableComponent("otm.gui.filter.is_whitelist")).also { it.dockTop = 20f; it.dock = Dock.TOP }
|
BooleanButtonPanel.Checkbox(this, it, menu.driveFilter.isWhitelist, TranslatableComponent("otm.gui.filter.is_whitelist")).also { it.dockTop = 20f; it.dock = Dock.TOP }
|
||||||
BooleanButtonPanel.Checkbox(this, it, menu.matchTag, TranslatableComponent("otm.gui.filter.match_tag")).also { it.dockTop = 4f; it.dock = Dock.TOP }
|
|
||||||
BooleanButtonPanel.Checkbox(this, it, menu.matchComponents, TranslatableComponent("otm.gui.filter.match_nbt")).also { it.dockTop = 4f; it.dock = Dock.TOP }
|
|
||||||
})
|
})
|
||||||
|
|
||||||
frame.CustomTab(view, activeIcon = ItemStackIcon(ItemStack(MItems.PORTABLE_CONDENSATION_DRIVE)))
|
frame.CustomTab(view, activeIcon = ItemStackIcon(ItemStack(MItems.PORTABLE_CONDENSATION_DRIVE)))
|
||||||
|
@ -34,18 +34,6 @@ class StorageImporterExporterScreen(menu: StorageImporterExporterMenu, inventory
|
|||||||
it.childrenOrder = -1
|
it.childrenOrder = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
BooleanButtonPanel.Checkbox(this, right, menu.filter.matchComponents, TranslatableComponent("otm.gui.filter.match_nbt")).also {
|
|
||||||
it.dock = Dock.BOTTOM
|
|
||||||
it.dockTop = 2f
|
|
||||||
it.childrenOrder = -2
|
|
||||||
}
|
|
||||||
|
|
||||||
BooleanButtonPanel.Checkbox(this, right, menu.filter.matchTag, TranslatableComponent("otm.gui.filter.match_tag")).also {
|
|
||||||
it.dock = Dock.BOTTOM
|
|
||||||
it.dockTop = 2f
|
|
||||||
it.childrenOrder = -3
|
|
||||||
}
|
|
||||||
|
|
||||||
makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig)
|
makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig)
|
||||||
|
|
||||||
return frame
|
return frame
|
||||||
|
@ -12,9 +12,11 @@ import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
|
|||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
|
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.widget.WideProfiledPowerGaugePanel
|
import ru.dbotthepony.mc.otm.client.screen.widget.WideProfiledPowerGaugePanel
|
||||||
import ru.dbotthepony.mc.otm.compat.jei.isJeiLoaded
|
import ru.dbotthepony.mc.otm.compat.jei.isJeiLoaded
|
||||||
|
import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot
|
||||||
import ru.dbotthepony.mc.otm.menu.tech.AbstractProcessingMachineMenu
|
import ru.dbotthepony.mc.otm.menu.tech.AbstractProcessingMachineMenu
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@ -50,9 +52,14 @@ open class AbstractProcessingMachineScreen<M : AbstractProcessingMachineMenu>(me
|
|||||||
row.dock = Dock.TOP
|
row.dock = Dock.TOP
|
||||||
row.dockBottom = 2f
|
row.dockBottom = 2f
|
||||||
|
|
||||||
SlotPanel(this, row, input).also {
|
if (input is UserFilteredMenuSlot)
|
||||||
it.dock = Dock.LEFT
|
UserFilteredSlotPanel(this, row, input).also {
|
||||||
}
|
it.dock = Dock.LEFT
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SlotPanel(this, row, input).also {
|
||||||
|
it.dock = Dock.LEFT
|
||||||
|
}
|
||||||
|
|
||||||
progressPanels.add(ProgressGaugePanel(this, row, progress).also {
|
progressPanels.add(ProgressGaugePanel(this, row, progress).also {
|
||||||
it.dock = Dock.LEFT
|
it.dock = Dock.LEFT
|
||||||
|
@ -9,6 +9,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls
|
|||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
|
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.widget.WideProfiledPowerGaugePanel
|
import ru.dbotthepony.mc.otm.client.screen.widget.WideProfiledPowerGaugePanel
|
||||||
import ru.dbotthepony.mc.otm.menu.tech.ChemicalGeneratorMenu
|
import ru.dbotthepony.mc.otm.menu.tech.ChemicalGeneratorMenu
|
||||||
@ -35,7 +36,7 @@ class ChemicalGeneratorScreen(menu: ChemicalGeneratorMenu, inventory: Inventory,
|
|||||||
progress.setRecipeType { listOf(RecipeTypes.FUELING) }
|
progress.setRecipeType { listOf(RecipeTypes.FUELING) }
|
||||||
|
|
||||||
SlotPanel(this, frame, menu.residueSlot, 56f, PROGRESS_SLOT_TOP)
|
SlotPanel(this, frame, menu.residueSlot, 56f, PROGRESS_SLOT_TOP)
|
||||||
SlotPanel(this, frame, menu.fuelSlot, 104f, PROGRESS_SLOT_TOP)
|
UserFilteredSlotPanel(this, frame, menu.fuelSlot, 104f, PROGRESS_SLOT_TOP)
|
||||||
|
|
||||||
makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, itemConfig = menu.itemConfig, energyConfig = menu.energyConfig)
|
makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, itemConfig = menu.itemConfig, energyConfig = menu.energyConfig)
|
||||||
|
|
||||||
|
@ -111,7 +111,19 @@ class EnergyCounterScreen(menu: EnergyCounterMenu, inventory: Inventory, title:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
makeDeviceControls(this, frame, redstoneConfig = menu.redstone)
|
val controls = makeDeviceControls(this, frame, redstoneConfig = menu.redstone)
|
||||||
|
|
||||||
|
controls.addButton(
|
||||||
|
BooleanButtonPanel.square18(
|
||||||
|
this,
|
||||||
|
controls,
|
||||||
|
menu.pullEnergyFromInput,
|
||||||
|
iconActive = Widgets18.LEFT_CONTROLS.push,
|
||||||
|
iconInactive = Widgets18.LEFT_CONTROLS.output,
|
||||||
|
tooltipActive = TranslatableComponent("block.overdrive_that_matters.energy_counter.do_pull"),
|
||||||
|
tooltipInactive = TranslatableComponent("block.overdrive_that_matters.energy_counter.dont_pull")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return frame
|
return frame
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.button.ButtonPanel
|
|||||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls
|
import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.input.TextInputPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.input.TextInputPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.util.HorizontalStripPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.util.HorizontalStripPanel
|
||||||
import ru.dbotthepony.mc.otm.core.ResourceLocation
|
import ru.dbotthepony.mc.otm.core.ResourceLocation
|
||||||
import ru.dbotthepony.mc.otm.core.TextComponent
|
import ru.dbotthepony.mc.otm.core.TextComponent
|
||||||
@ -279,7 +280,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title
|
|||||||
get() = SET_EXACT
|
get() = SET_EXACT
|
||||||
|
|
||||||
override fun onClick(mouseButton: Int) {
|
override fun onClick(mouseButton: Int) {
|
||||||
val player = minecraft!!.player!! ?: return
|
val player = minecraft!!.player!!
|
||||||
|
|
||||||
if (player.experienceLevel == customDispense) {
|
if (player.experienceLevel == customDispense) {
|
||||||
if (player.experienceProgress > 0f) {
|
if (player.experienceProgress > 0f) {
|
||||||
@ -297,7 +298,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title
|
|||||||
set(_) {}
|
set(_) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
SlotPanel(this, inputs, menu.mendingSlot).also {
|
UserFilteredSlotPanel(this, inputs, menu.mendingSlot).also {
|
||||||
it.dock = Dock.LEFT
|
it.dock = Dock.LEFT
|
||||||
it.tooltips.add(TranslatableComponent("enchantment.minecraft.mending").withStyle(ChatFormatting.GRAY))
|
it.tooltips.add(TranslatableComponent("enchantment.minecraft.mending").withStyle(ChatFormatting.GRAY))
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ class ItemHatchScreen(menu: ItemHatchMenu, inventory: Inventory, title: Componen
|
|||||||
val grid = GridPanel(this, frame, 8f, 18f, 9f * 18f, 6f * 18f, 9, 6)
|
val grid = GridPanel(this, frame, 8f, 18f, 9f * 18f, 6f * 18f, 9, 6)
|
||||||
|
|
||||||
for (slot in menu.storageSlots)
|
for (slot in menu.storageSlots)
|
||||||
UserFilteredSlotPanel.of(this, grid, slot)
|
UserFilteredSlotPanel(this, grid, slot)
|
||||||
|
|
||||||
if (menu.isInput) {
|
if (menu.isInput) {
|
||||||
val controls = DeviceControls(this, frame)
|
val controls = DeviceControls(this, frame)
|
||||||
|
@ -6,7 +6,6 @@ import lain.mods.cos.impl.client.PlayerRenderHandler
|
|||||||
import lain.mods.cos.impl.client.gui.GuiCosArmorInventory
|
import lain.mods.cos.impl.client.gui.GuiCosArmorInventory
|
||||||
import lain.mods.cos.impl.network.payload.PayloadSetSkinArmor
|
import lain.mods.cos.impl.network.payload.PayloadSetSkinArmor
|
||||||
import net.minecraft.client.gui.screens.Screen
|
import net.minecraft.client.gui.screens.Screen
|
||||||
import net.minecraft.network.chat.Component
|
|
||||||
import net.minecraft.resources.ResourceLocation
|
import net.minecraft.resources.ResourceLocation
|
||||||
import net.minecraft.server.level.ServerPlayer
|
import net.minecraft.server.level.ServerPlayer
|
||||||
import net.minecraft.world.Container
|
import net.minecraft.world.Container
|
||||||
@ -20,9 +19,6 @@ import net.neoforged.neoforge.network.PacketDistributor
|
|||||||
import ru.dbotthepony.kommons.math.RGBAColor
|
import ru.dbotthepony.kommons.math.RGBAColor
|
||||||
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
|
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
|
||||||
import ru.dbotthepony.mc.otm.client.minecraft
|
import ru.dbotthepony.mc.otm.client.minecraft
|
||||||
import ru.dbotthepony.mc.otm.client.render.IGUIRenderable
|
|
||||||
import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
|
|
||||||
import ru.dbotthepony.mc.otm.client.render.sprites.MatterySprite
|
|
||||||
import ru.dbotthepony.mc.otm.client.render.sprites.sprite
|
import ru.dbotthepony.mc.otm.client.render.sprites.sprite
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.ButtonPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.button.ButtonPanel
|
||||||
@ -32,7 +28,7 @@ import ru.dbotthepony.mc.otm.container.util.awareStream
|
|||||||
import ru.dbotthepony.mc.otm.container.util.iterator
|
import ru.dbotthepony.mc.otm.container.util.iterator
|
||||||
import ru.dbotthepony.mc.otm.core.collect.AwareItemStack
|
import ru.dbotthepony.mc.otm.core.collect.AwareItemStack
|
||||||
import ru.dbotthepony.mc.otm.core.collect.emptyIterator
|
import ru.dbotthepony.mc.otm.core.collect.emptyIterator
|
||||||
import ru.dbotthepony.mc.otm.menu.MatterySlot
|
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
|
|
||||||
val isCosmeticArmorLoaded by lazy {
|
val isCosmeticArmorLoaded by lazy {
|
||||||
@ -47,7 +43,7 @@ val Player.cosmeticArmorSlots: Map<EquipmentSlot, Slot>? get() {
|
|||||||
return cosmeticArmorSlotsImpl
|
return cosmeticArmorSlotsImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CosmeticSlot(container: Container, private val slot: EquipmentSlot, private val player: Player) : MatterySlot(container, when (slot) {
|
private class CosmeticMenuSlot(container: Container, private val slot: EquipmentSlot, private val player: Player) : MatteryMenuSlot(container, when (slot) {
|
||||||
EquipmentSlot.FEET -> 0
|
EquipmentSlot.FEET -> 0
|
||||||
EquipmentSlot.LEGS -> 1
|
EquipmentSlot.LEGS -> 1
|
||||||
EquipmentSlot.CHEST -> 2
|
EquipmentSlot.CHEST -> 2
|
||||||
@ -127,10 +123,10 @@ private val Player.cosmeticArmorSlotsImpl: Map<EquipmentSlot, Slot>? get() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return mapOf(
|
return mapOf(
|
||||||
EquipmentSlot.HEAD to CosmeticSlot(container, EquipmentSlot.HEAD, this),
|
EquipmentSlot.HEAD to CosmeticMenuSlot(container, EquipmentSlot.HEAD, this),
|
||||||
EquipmentSlot.CHEST to CosmeticSlot(container, EquipmentSlot.CHEST, this),
|
EquipmentSlot.CHEST to CosmeticMenuSlot(container, EquipmentSlot.CHEST, this),
|
||||||
EquipmentSlot.LEGS to CosmeticSlot(container, EquipmentSlot.LEGS, this),
|
EquipmentSlot.LEGS to CosmeticMenuSlot(container, EquipmentSlot.LEGS, this),
|
||||||
EquipmentSlot.FEET to CosmeticSlot(container, EquipmentSlot.FEET, this),
|
EquipmentSlot.FEET to CosmeticMenuSlot(container, EquipmentSlot.FEET, this),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,8 +13,8 @@ import ru.dbotthepony.mc.otm.compat.jade.JadeUids
|
|||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
import ru.dbotthepony.mc.otm.core.getCapability
|
import ru.dbotthepony.mc.otm.core.getCapability
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.getDecimal
|
import ru.dbotthepony.mc.otm.core.nbt.getDecimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.putDecimal
|
import ru.dbotthepony.mc.otm.core.nbt.putDecimal
|
||||||
import ru.dbotthepony.mc.otm.core.util.formatMatter
|
import ru.dbotthepony.mc.otm.core.util.formatMatter
|
||||||
import snownee.jade.api.BlockAccessor
|
import snownee.jade.api.BlockAccessor
|
||||||
import snownee.jade.api.IBlockComponentProvider
|
import snownee.jade.api.IBlockComponentProvider
|
||||||
|
@ -13,8 +13,8 @@ import ru.dbotthepony.mc.otm.core.math.Decimal
|
|||||||
import ru.dbotthepony.kommons.math.RGBAColor
|
import ru.dbotthepony.kommons.math.RGBAColor
|
||||||
import ru.dbotthepony.mc.otm.capability.IProfiledStorage
|
import ru.dbotthepony.mc.otm.capability.IProfiledStorage
|
||||||
import ru.dbotthepony.mc.otm.core.getCapability
|
import ru.dbotthepony.mc.otm.core.getCapability
|
||||||
import ru.dbotthepony.mc.otm.core.math.getDecimal
|
import ru.dbotthepony.mc.otm.core.nbt.getDecimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.putDecimal
|
import ru.dbotthepony.mc.otm.core.nbt.putDecimal
|
||||||
import ru.dbotthepony.mc.otm.core.util.formatPower
|
import ru.dbotthepony.mc.otm.core.util.formatPower
|
||||||
import snownee.jade.api.*
|
import snownee.jade.api.*
|
||||||
import snownee.jade.api.config.IPluginConfig
|
import snownee.jade.api.config.IPluginConfig
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.compat.vanilla
|
||||||
|
|
||||||
|
import net.minecraft.world.Container
|
||||||
|
import net.minecraft.world.entity.player.Inventory
|
||||||
|
import net.minecraft.world.entity.player.Player
|
||||||
|
import net.minecraft.world.inventory.MenuType
|
||||||
|
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||||
|
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
||||||
|
import ru.dbotthepony.mc.otm.menu.QuickMoveInput
|
||||||
|
import ru.dbotthepony.mc.otm.menu.SortInput
|
||||||
|
|
||||||
|
abstract class AbstractVanillaChestMenu(
|
||||||
|
type: MenuType<*>,
|
||||||
|
containerId: Int,
|
||||||
|
inventory: Inventory,
|
||||||
|
val container: Container
|
||||||
|
) : MatteryMenu(type, containerId, inventory) {
|
||||||
|
abstract val rows: Int
|
||||||
|
abstract val columns: Int
|
||||||
|
|
||||||
|
abstract val containerSlots: List<MatteryMenuSlot>
|
||||||
|
abstract val quickMoveToStorage: Map<QuickMoveInput.Mode, QuickMoveInput>
|
||||||
|
abstract val quickMoveFromStorage: Map<QuickMoveInput.Mode, QuickMoveInput>
|
||||||
|
val sort = SortInput(this, container, playerSortSettings)
|
||||||
|
|
||||||
|
override fun stillValid(player: Player): Boolean {
|
||||||
|
return container.stillValid(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removed(player: Player) {
|
||||||
|
super.removed(player)
|
||||||
|
container.stopOpen(player)
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,7 @@ import ru.dbotthepony.mc.otm.player.MatteryPlayer
|
|||||||
import ru.dbotthepony.mc.otm.player.matteryPlayer
|
import ru.dbotthepony.mc.otm.player.matteryPlayer
|
||||||
import ru.dbotthepony.mc.otm.core.ResourceLocation
|
import ru.dbotthepony.mc.otm.core.ResourceLocation
|
||||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||||
import ru.dbotthepony.mc.otm.menu.MatterySlot
|
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
private val menuConfigurations = WeakHashMap<AbstractContainerMenu, MenuConfiguration>()
|
private val menuConfigurations = WeakHashMap<AbstractContainerMenu, MenuConfiguration>()
|
||||||
@ -47,9 +47,9 @@ private class MenuConfiguration(
|
|||||||
|
|
||||||
for (i in 0 .. 8) {
|
for (i in 0 .. 8) {
|
||||||
if (matteryPlayer.exopackContainer.containerSize > i + offset) {
|
if (matteryPlayer.exopackContainer.containerSize > i + offset) {
|
||||||
row.add(MatterySlot(matteryPlayer.exopackContainer, i + offset))
|
row.add(MatteryMenuSlot(matteryPlayer.exopackContainer, i + offset))
|
||||||
} else {
|
} else {
|
||||||
row.add(FakeSlot())
|
row.add(FakeMenuSlot())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ private class MenuConfiguration(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FakeSlot : MatterySlot(SimpleContainer(1), 0, 0, 0) {
|
private class FakeMenuSlot : MatteryMenuSlot(SimpleContainer(1), 0, 0, 0) {
|
||||||
override fun mayPickup(player: Player): Boolean {
|
override fun mayPickup(player: Player): Boolean {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -1,118 +1,78 @@
|
|||||||
package ru.dbotthepony.mc.otm.compat.vanilla
|
package ru.dbotthepony.mc.otm.compat.vanilla
|
||||||
|
|
||||||
import net.minecraft.core.registries.Registries
|
|
||||||
import net.minecraft.world.Container
|
import net.minecraft.world.Container
|
||||||
import net.minecraft.world.SimpleContainer
|
import net.minecraft.world.SimpleContainer
|
||||||
import net.minecraft.world.entity.player.Inventory
|
import net.minecraft.world.entity.player.Inventory
|
||||||
import net.minecraft.world.entity.player.Player
|
|
||||||
import net.minecraft.world.flag.FeatureFlags
|
|
||||||
import net.minecraft.world.inventory.MenuType
|
import net.minecraft.world.inventory.MenuType
|
||||||
import net.neoforged.bus.api.IEventBus
|
import ru.dbotthepony.mc.otm.container.EnhancedContainer
|
||||||
import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent
|
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
||||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
import ru.dbotthepony.mc.otm.menu.QuickMoveInput
|
||||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
|
||||||
import ru.dbotthepony.mc.otm.menu.MatterySlot
|
|
||||||
import ru.dbotthepony.mc.otm.menu.makeSlots
|
import ru.dbotthepony.mc.otm.menu.makeSlots
|
||||||
import ru.dbotthepony.mc.otm.registry.MDeferredRegister
|
|
||||||
|
|
||||||
class MatteryChestMenu(
|
class MatteryChestMenu(
|
||||||
type: MenuType<*>, containerId: Int,
|
type: MenuType<*>, containerId: Int,
|
||||||
inventory: Inventory, val rows: Int, val columns: Int,
|
inventory: Inventory, override val rows: Int, override val columns: Int,
|
||||||
val container: Container = SimpleContainer(rows * columns)
|
container: Container = EnhancedContainer.Simple(rows * columns)
|
||||||
) : MatteryMenu(type, containerId, inventory) {
|
) : AbstractVanillaChestMenu(type, containerId, inventory, container) {
|
||||||
val chestSlots = makeSlots(container, ::MatterySlot)
|
override val containerSlots = makeSlots(container, ::MatteryMenuSlot)
|
||||||
val sort = SortInput(container, playerSortSettings)
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
require(rows * columns == container.containerSize) { "Provided container $container has different dimensions than specified rows x columns: ${container.containerSize} vs $rows x $columns (${rows * columns})" }
|
require(rows * columns == container.containerSize) { "Provided container $container has different dimensions than specified rows x columns: ${container.containerSize} vs $rows x $columns (${rows * columns})" }
|
||||||
container.startOpen(player)
|
container.startOpen(player)
|
||||||
addStorageSlot(chestSlots)
|
addStorageSlot(containerSlots)
|
||||||
addInventorySlots()
|
addInventorySlots()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun stillValid(player: Player): Boolean {
|
override val quickMoveToStorage = QuickMoveInput.create(this, playerCombinedInventorySlots, containerSlots)
|
||||||
return container.stillValid(player)
|
override val quickMoveFromStorage = QuickMoveInput.create(this, containerSlots, playerInventorySlots, false)
|
||||||
}
|
|
||||||
|
|
||||||
override fun removed(player: Player) {
|
|
||||||
super.removed(player)
|
|
||||||
container.stopOpen(player)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val registrar = MDeferredRegister(Registries.MENU, OverdriveThatMatters.MOD_ID)
|
|
||||||
|
|
||||||
private val GENERIC_9x1 by registrar.register("generic_9x1") { MenuType(::c9x1, FeatureFlags.VANILLA_SET) }
|
|
||||||
private val GENERIC_9x2 by registrar.register("generic_9x2") { MenuType(::c9x2, FeatureFlags.VANILLA_SET) }
|
|
||||||
private val GENERIC_9x3 by registrar.register("generic_9x3") { MenuType(::c9x3, FeatureFlags.VANILLA_SET) }
|
|
||||||
private val GENERIC_9x4 by registrar.register("generic_9x4") { MenuType(::c9x4, FeatureFlags.VANILLA_SET) }
|
|
||||||
private val GENERIC_9x5 by registrar.register("generic_9x5") { MenuType(::c9x5, FeatureFlags.VANILLA_SET) }
|
|
||||||
private val GENERIC_9x6 by registrar.register("generic_9x6") { MenuType(::c9x6, FeatureFlags.VANILLA_SET) }
|
|
||||||
private val GENERIC_3x3 by registrar.register("generic_3x3") { MenuType(::c3x3, FeatureFlags.VANILLA_SET) }
|
|
||||||
private val HOPPER by registrar.register("hopper") { MenuType(::hopper, FeatureFlags.VANILLA_SET) }
|
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun c9x1(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(9)): MatteryChestMenu {
|
fun c9x1(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(9)): MatteryChestMenu {
|
||||||
return MatteryChestMenu(GENERIC_9x1, containerId, inventory, 1, 9, container)
|
return MatteryChestMenu(VanillaMenuTypes.GENERIC_9x1, containerId, inventory, 1, 9, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun c9x2(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(9 * 2)): MatteryChestMenu {
|
fun c9x2(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(9 * 2)): MatteryChestMenu {
|
||||||
return MatteryChestMenu(GENERIC_9x2, containerId, inventory, 2, 9, container)
|
return MatteryChestMenu(VanillaMenuTypes.GENERIC_9x2, containerId, inventory, 2, 9, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun c9x3(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(9 * 3)): MatteryChestMenu {
|
fun c9x3(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(9 * 3)): MatteryChestMenu {
|
||||||
return MatteryChestMenu(GENERIC_9x3, containerId, inventory, 3, 9, container)
|
return MatteryChestMenu(VanillaMenuTypes.GENERIC_9x3, containerId, inventory, 3, 9, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun c9x4(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(9 * 4)): MatteryChestMenu {
|
fun c9x4(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(9 * 4)): MatteryChestMenu {
|
||||||
return MatteryChestMenu(GENERIC_9x4, containerId, inventory, 4, 9, container)
|
return MatteryChestMenu(VanillaMenuTypes.GENERIC_9x4, containerId, inventory, 4, 9, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun c9x5(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(9 * 5)): MatteryChestMenu {
|
fun c9x5(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(9 * 5)): MatteryChestMenu {
|
||||||
return MatteryChestMenu(GENERIC_9x5, containerId, inventory, 5, 9, container)
|
return MatteryChestMenu(VanillaMenuTypes.GENERIC_9x5, containerId, inventory, 5, 9, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun c9x6(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(9 * 6)): MatteryChestMenu {
|
fun c9x6(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(9 * 6)): MatteryChestMenu {
|
||||||
return MatteryChestMenu(GENERIC_9x6, containerId, inventory, 6, 9, container)
|
return MatteryChestMenu(VanillaMenuTypes.GENERIC_9x6, containerId, inventory, 6, 9, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun c3x3(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(3 * 3)): MatteryChestMenu {
|
fun c3x3(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(3 * 3)): MatteryChestMenu {
|
||||||
return MatteryChestMenu(GENERIC_3x3, containerId, inventory, 3, 3, container)
|
return MatteryChestMenu(VanillaMenuTypes.GENERIC_3x3, containerId, inventory, 3, 3, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun hopper(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(5)): MatteryChestMenu {
|
fun hopper(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(5)): MatteryChestMenu {
|
||||||
return MatteryChestMenu(HOPPER, containerId, inventory, 1, 5, container)
|
return MatteryChestMenu(VanillaMenuTypes.HOPPER, containerId, inventory, 1, 5, container)
|
||||||
}
|
|
||||||
|
|
||||||
internal fun register(bus: IEventBus) {
|
|
||||||
registrar.register(bus)
|
|
||||||
bus.addListener(this::registerScreens)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun registerScreens(event: RegisterMenuScreensEvent) {
|
|
||||||
event.register(GENERIC_9x1, ::MatteryChestScreen)
|
|
||||||
event.register(GENERIC_9x2, ::MatteryChestScreen)
|
|
||||||
event.register(GENERIC_9x3, ::MatteryChestScreen)
|
|
||||||
event.register(GENERIC_9x4, ::MatteryChestScreen)
|
|
||||||
event.register(GENERIC_9x5, ::MatteryChestScreen)
|
|
||||||
event.register(GENERIC_9x6, ::MatteryChestScreen)
|
|
||||||
event.register(GENERIC_3x3, ::MatteryChestScreen)
|
|
||||||
event.register(HOPPER, ::MatteryChestScreen)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.compat.vanilla
|
||||||
|
|
||||||
|
import net.minecraft.world.Container
|
||||||
|
import net.minecraft.world.entity.player.Inventory
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import ru.dbotthepony.mc.otm.container.EnhancedContainer
|
||||||
|
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
||||||
|
import ru.dbotthepony.mc.otm.menu.QuickMoveInput
|
||||||
|
import ru.dbotthepony.mc.otm.menu.makeSlots
|
||||||
|
|
||||||
|
class MatteryShulkerBoxMenu(
|
||||||
|
containerId: Int,
|
||||||
|
inventory: Inventory,
|
||||||
|
container: Container = EnhancedContainer.Simple(27)
|
||||||
|
) : AbstractVanillaChestMenu(VanillaMenuTypes.SHULKER_BOX, containerId, inventory, container) {
|
||||||
|
override val containerSlots = makeSlots(container, ::Slot)
|
||||||
|
override val rows: Int
|
||||||
|
get() = 3
|
||||||
|
override val columns: Int
|
||||||
|
get() = 9
|
||||||
|
|
||||||
|
init {
|
||||||
|
container.startOpen(player)
|
||||||
|
addStorageSlot(containerSlots)
|
||||||
|
addInventorySlots()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val quickMoveToStorage = QuickMoveInput.create(this, playerCombinedInventorySlots, containerSlots)
|
||||||
|
override val quickMoveFromStorage = QuickMoveInput.create(this, containerSlots, playerInventorySlots, false)
|
||||||
|
|
||||||
|
class Slot(container: Container, slot: Int) : MatteryMenuSlot(container, slot) {
|
||||||
|
override fun mayPlace(stack: ItemStack): Boolean {
|
||||||
|
return super.mayPlace(stack) && stack.item.canFitInsideContainerItems()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.compat.vanilla
|
|||||||
|
|
||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
import net.minecraft.world.entity.player.Inventory
|
import net.minecraft.world.entity.player.Inventory
|
||||||
|
import ru.dbotthepony.kommons.util.Either
|
||||||
import ru.dbotthepony.mc.otm.client.render.RenderGravity
|
import ru.dbotthepony.mc.otm.client.render.RenderGravity
|
||||||
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.Dock
|
import ru.dbotthepony.mc.otm.client.screen.panels.Dock
|
||||||
@ -10,8 +11,9 @@ import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
|
|||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
|
||||||
|
import ru.dbotthepony.mc.otm.menu.QuickMoveInput
|
||||||
|
|
||||||
class MatteryChestScreen(menu: MatteryChestMenu, inventory: Inventory, title: Component) : MatteryScreen<MatteryChestMenu>(menu, inventory, title) {
|
class VanillaChestScreen(menu: AbstractVanillaChestMenu, inventory: Inventory, title: Component) : MatteryScreen<AbstractVanillaChestMenu>(menu, inventory, title) {
|
||||||
override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
|
override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
|
||||||
val frame = FramePanel.padded(this, AbstractSlotPanel.SIZE * menu.columns.coerceAtLeast(9), AbstractSlotPanel.SIZE * menu.rows + 4f, title)
|
val frame = FramePanel.padded(this, AbstractSlotPanel.SIZE * menu.columns.coerceAtLeast(9), AbstractSlotPanel.SIZE * menu.rows + 4f, title)
|
||||||
|
|
||||||
@ -22,12 +24,20 @@ class MatteryChestScreen(menu: MatteryChestMenu, inventory: Inventory, title: Co
|
|||||||
grid.dock = Dock.FILL
|
grid.dock = Dock.FILL
|
||||||
grid.gravity = RenderGravity.BOTTOM_CENTER
|
grid.gravity = RenderGravity.BOTTOM_CENTER
|
||||||
|
|
||||||
for (slot in menu.chestSlots)
|
for (slot in menu.containerSlots)
|
||||||
SlotPanel(this, grid, slot)
|
SlotPanel(this, grid, slot)
|
||||||
|
|
||||||
val controls = DeviceControls(this, frame)
|
val controls = DeviceControls(this, frame)
|
||||||
controls.sortingButtons(menu.sort)
|
controls.sortingButtons(menu.sort)
|
||||||
|
|
||||||
|
val leftControls = DeviceControls(this, frame)
|
||||||
|
leftControls.dockOnLeft = true
|
||||||
|
leftControls.quickMoveButtons(menu.quickMoveFromStorage)
|
||||||
|
|
||||||
|
val leftInventoryControls = DeviceControls(this, inventoryFrame!!)
|
||||||
|
leftInventoryControls.dockOnLeft = true
|
||||||
|
leftInventoryControls.quickMoveButtons(menu.quickMoveToStorage, menu.quickMoveFromStorage)
|
||||||
|
|
||||||
return frame
|
return frame
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.compat.vanilla
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.core.registries.Registries
|
||||||
|
import net.minecraft.world.Container
|
||||||
|
import net.minecraft.world.flag.FeatureFlags
|
||||||
|
import net.minecraft.world.inventory.MenuType
|
||||||
|
import net.minecraft.world.level.Level
|
||||||
|
import net.minecraft.world.level.block.Blocks
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity
|
||||||
|
import net.minecraft.world.level.block.entity.ChestBlockEntity
|
||||||
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
|
import net.neoforged.bus.api.IEventBus
|
||||||
|
import net.neoforged.neoforge.capabilities.IBlockCapabilityProvider
|
||||||
|
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent
|
||||||
|
import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent
|
||||||
|
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||||
|
import ru.dbotthepony.mc.otm.capability.IQuickStackContainer
|
||||||
|
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||||
|
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
||||||
|
import ru.dbotthepony.mc.otm.menu.makeSlots
|
||||||
|
import ru.dbotthepony.mc.otm.registry.MDeferredRegister
|
||||||
|
|
||||||
|
object VanillaMenuTypes {
|
||||||
|
private val registrar = MDeferredRegister(Registries.MENU, OverdriveThatMatters.MOD_ID)
|
||||||
|
|
||||||
|
val GENERIC_9x1 by registrar.register("generic_9x1") { MenuType(MatteryChestMenu::c9x1, FeatureFlags.VANILLA_SET) }
|
||||||
|
val GENERIC_9x2 by registrar.register("generic_9x2") { MenuType(MatteryChestMenu::c9x2, FeatureFlags.VANILLA_SET) }
|
||||||
|
val GENERIC_9x3 by registrar.register("generic_9x3") { MenuType(MatteryChestMenu::c9x3, FeatureFlags.VANILLA_SET) }
|
||||||
|
val GENERIC_9x4 by registrar.register("generic_9x4") { MenuType(MatteryChestMenu::c9x4, FeatureFlags.VANILLA_SET) }
|
||||||
|
val GENERIC_9x5 by registrar.register("generic_9x5") { MenuType(MatteryChestMenu::c9x5, FeatureFlags.VANILLA_SET) }
|
||||||
|
val GENERIC_9x6 by registrar.register("generic_9x6") { MenuType(MatteryChestMenu::c9x6, FeatureFlags.VANILLA_SET) }
|
||||||
|
val GENERIC_3x3 by registrar.register("generic_3x3") { MenuType(MatteryChestMenu::c3x3, FeatureFlags.VANILLA_SET) }
|
||||||
|
val HOPPER by registrar.register("hopper") { MenuType(MatteryChestMenu::hopper, FeatureFlags.VANILLA_SET) }
|
||||||
|
|
||||||
|
val SHULKER_BOX by registrar.register("shulker_box") { MenuType(::MatteryShulkerBoxMenu, FeatureFlags.VANILLA_SET) }
|
||||||
|
|
||||||
|
private fun provider(level: Level, pos: BlockPos, state: BlockState, blockEntity: BlockEntity?, context: Void?): IQuickStackContainer? {
|
||||||
|
val container = blockEntity as? Container ?: return null
|
||||||
|
return IQuickStackContainer.Simple(makeSlots(container, ::MatteryMenuSlot))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun registerCapabilities(event: RegisterCapabilitiesEvent) {
|
||||||
|
event.registerBlock(
|
||||||
|
MatteryCapability.QUICK_STACK_CONTAINER,
|
||||||
|
::provider,
|
||||||
|
Blocks.CHEST,
|
||||||
|
Blocks.TRAPPED_CHEST,
|
||||||
|
Blocks.SHULKER_BOX,
|
||||||
|
Blocks.BARREL,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun register(bus: IEventBus) {
|
||||||
|
registrar.register(bus)
|
||||||
|
bus.addListener(this::registerScreens)
|
||||||
|
bus.addListener(this::registerCapabilities)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun registerScreens(event: RegisterMenuScreensEvent) {
|
||||||
|
event.register(GENERIC_9x1, ::VanillaChestScreen)
|
||||||
|
event.register(GENERIC_9x2, ::VanillaChestScreen)
|
||||||
|
event.register(GENERIC_9x3, ::VanillaChestScreen)
|
||||||
|
event.register(GENERIC_9x4, ::VanillaChestScreen)
|
||||||
|
event.register(GENERIC_9x5, ::VanillaChestScreen)
|
||||||
|
event.register(GENERIC_9x6, ::VanillaChestScreen)
|
||||||
|
event.register(GENERIC_3x3, ::VanillaChestScreen)
|
||||||
|
event.register(HOPPER, ::VanillaChestScreen)
|
||||||
|
event.register(SHULKER_BOX, ::VanillaChestScreen)
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,6 @@ import ru.dbotthepony.kommons.util.Delegate
|
|||||||
import ru.dbotthepony.kommons.util.getValue
|
import ru.dbotthepony.kommons.util.getValue
|
||||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.defineDecimal
|
|
||||||
import ru.dbotthepony.mc.otm.core.util.WriteOnce
|
import ru.dbotthepony.mc.otm.core.util.WriteOnce
|
||||||
|
|
||||||
abstract class AbstractConfig(private val configName: String, private val type: ModConfig.Type = ModConfig.Type.SERVER) {
|
abstract class AbstractConfig(private val configName: String, private val type: ModConfig.Type = ModConfig.Type.SERVER) {
|
||||||
|
@ -3,7 +3,6 @@ package ru.dbotthepony.mc.otm.config
|
|||||||
import ru.dbotthepony.kommons.util.getValue
|
import ru.dbotthepony.kommons.util.getValue
|
||||||
import ru.dbotthepony.kommons.util.setValue
|
import ru.dbotthepony.kommons.util.setValue
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.defineDecimal
|
|
||||||
|
|
||||||
object CablesConfig : AbstractConfig("cables") {
|
object CablesConfig : AbstractConfig("cables") {
|
||||||
enum class E(throughput: Decimal) {
|
enum class E(throughput: Decimal) {
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.config
|
||||||
|
|
||||||
|
import net.neoforged.neoforge.common.ModConfigSpec
|
||||||
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
|
|
||||||
|
class DecimalConfigValue(
|
||||||
|
parent: ModConfigSpec.ConfigValue<String>,
|
||||||
|
val minimum: Decimal? = null,
|
||||||
|
val maximum: Decimal? = null,
|
||||||
|
) : ObservedConfigValue<Decimal>(parent) {
|
||||||
|
override fun fromString(value: String): Decimal? {
|
||||||
|
try {
|
||||||
|
val parsed = Decimal(value)
|
||||||
|
|
||||||
|
if (minimum != null && minimum > parsed) {
|
||||||
|
return minimum
|
||||||
|
} else if (maximum != null && maximum < parsed) {
|
||||||
|
return maximum
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed
|
||||||
|
} catch (err: java.lang.NumberFormatException) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(value: Decimal): Pair<String, Decimal> {
|
||||||
|
if (minimum != null && minimum > value) {
|
||||||
|
return minimum.toString() to minimum
|
||||||
|
} else if (maximum != null && maximum < value) {
|
||||||
|
return maximum.toString() to maximum
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.toString() to value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ModConfigSpec.Builder.commentRange(minimum: Decimal?, maximum: Decimal?) {
|
||||||
|
if (minimum != null && maximum != null) {
|
||||||
|
comment("Range: $minimum ~ $maximum")
|
||||||
|
} else if (minimum != null) {
|
||||||
|
comment("Range: >= $minimum")
|
||||||
|
} else if (maximum != null) {
|
||||||
|
comment("Range: <= $maximum")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ModConfigSpec.Builder.defineDecimal(path: String, defaultValue: Decimal, minimum: Decimal? = null, maximum: Decimal? = null): DecimalConfigValue {
|
||||||
|
commentRange(minimum, maximum)
|
||||||
|
comment("Default: $defaultValue")
|
||||||
|
return DecimalConfigValue(define(path, defaultValue.toString()), minimum, maximum)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ModConfigSpec.Builder.defineDecimal(path: List<String>, defaultValue: Decimal, minimum: Decimal? = null, maximum: Decimal? = null): DecimalConfigValue {
|
||||||
|
commentRange(minimum, maximum)
|
||||||
|
comment("Default: $defaultValue")
|
||||||
|
return DecimalConfigValue(define(path, defaultValue.toString()), minimum, maximum)
|
||||||
|
}
|
@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.config
|
|||||||
|
|
||||||
import ru.dbotthepony.kommons.util.getValue
|
import ru.dbotthepony.kommons.util.getValue
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.defineDecimal
|
|
||||||
|
|
||||||
object ExopackConfig : AbstractConfig("exopack") {
|
object ExopackConfig : AbstractConfig("exopack") {
|
||||||
val ENERGY_CAPACITY by builder
|
val ENERGY_CAPACITY by builder
|
||||||
|
@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.config
|
|||||||
|
|
||||||
import ru.dbotthepony.kommons.util.getValue
|
import ru.dbotthepony.kommons.util.getValue
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.defineDecimal
|
|
||||||
import ru.dbotthepony.mc.otm.registry.MNames
|
import ru.dbotthepony.mc.otm.registry.MNames
|
||||||
|
|
||||||
object ItemsConfig : AbstractConfig("items") {
|
object ItemsConfig : AbstractConfig("items") {
|
||||||
|
@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.config
|
|||||||
|
|
||||||
import ru.dbotthepony.kommons.util.getValue
|
import ru.dbotthepony.kommons.util.getValue
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.defineDecimal
|
|
||||||
import ru.dbotthepony.mc.otm.registry.MNames
|
import ru.dbotthepony.mc.otm.registry.MNames
|
||||||
|
|
||||||
object MachinesConfig : AbstractConfig("machines") {
|
object MachinesConfig : AbstractConfig("machines") {
|
||||||
@ -60,7 +59,7 @@ object MachinesConfig : AbstractConfig("machines") {
|
|||||||
private val MATTER_BOTTLER = workerValues(
|
private val MATTER_BOTTLER = workerValues(
|
||||||
MNames.MATTER_BOTTLER,
|
MNames.MATTER_BOTTLER,
|
||||||
energyStorage = Decimal(40_000),
|
energyStorage = Decimal(40_000),
|
||||||
energyConsumption = Decimal(10),
|
energyConsumption = Decimal(40),
|
||||||
energyThroughput = Decimal(200),
|
energyThroughput = Decimal(200),
|
||||||
matterCapacity = Decimal(400),
|
matterCapacity = Decimal(400),
|
||||||
workTimeMultiplier = null
|
workTimeMultiplier = null
|
||||||
@ -85,7 +84,7 @@ object MachinesConfig : AbstractConfig("machines") {
|
|||||||
|
|
||||||
object MatterBottler {
|
object MatterBottler {
|
||||||
val VALUES by ::MATTER_BOTTLER
|
val VALUES by ::MATTER_BOTTLER
|
||||||
val RATE by builder.comment("Matter transferred per tick").defineDecimal("RATE", Decimal("2.0"), Decimal.ONE_TENTH)
|
val RATE by builder.comment("Matter transferred per tick").defineDecimal("RATE", Decimal("10.0"), Decimal.ONE_TENTH)
|
||||||
}
|
}
|
||||||
|
|
||||||
object MatterRecycler {
|
object MatterRecycler {
|
||||||
@ -111,8 +110,8 @@ object MachinesConfig : AbstractConfig("machines") {
|
|||||||
|
|
||||||
private val MATTER_RECONSTRUCTOR = workerValues(
|
private val MATTER_RECONSTRUCTOR = workerValues(
|
||||||
MNames.MATTER_RECONSTRUCTOR,
|
MNames.MATTER_RECONSTRUCTOR,
|
||||||
energyStorage = Decimal(100_000),
|
energyStorage = Decimal(200_000),
|
||||||
energyThroughput = Decimal(1000),
|
energyThroughput = Decimal(4_000),
|
||||||
energyConsumption = Decimal(400),
|
energyConsumption = Decimal(400),
|
||||||
matterCapacity = Decimal(200),
|
matterCapacity = Decimal(200),
|
||||||
workTimeMultiplier = null,
|
workTimeMultiplier = null,
|
||||||
|
@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.config
|
|||||||
|
|
||||||
import ru.dbotthepony.kommons.util.getValue
|
import ru.dbotthepony.kommons.util.getValue
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.defineDecimal
|
|
||||||
|
|
||||||
object PlayerConfig : AbstractConfig("player") {
|
object PlayerConfig : AbstractConfig("player") {
|
||||||
init {
|
init {
|
||||||
|
@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.config
|
|||||||
|
|
||||||
import ru.dbotthepony.kommons.util.getValue
|
import ru.dbotthepony.kommons.util.getValue
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.defineDecimal
|
|
||||||
|
|
||||||
object ServerConfig : AbstractConfig("misc") {
|
object ServerConfig : AbstractConfig("misc") {
|
||||||
val LABORATORY_LAMP_LIGHT_LENGTH: Int by builder.comment("In blocks").defineInRange("LABORATORY_LAMP_LIGHT_LENGTH", 6, 1, 128)
|
val LABORATORY_LAMP_LIGHT_LENGTH: Int by builder.comment("In blocks").defineInRange("LABORATORY_LAMP_LIGHT_LENGTH", 6, 1, 128)
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.container
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntCollection
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import ru.dbotthepony.kommons.collect.iterateClearBits
|
||||||
|
import ru.dbotthepony.kommons.collect.iterateSetBits
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.IntRange2Set
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.map
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
abstract class BitmapTrackingContainer<out S : IContainerSlot> : IEnhancedContainer<S> {
|
||||||
|
protected val bitmap = BitSet()
|
||||||
|
|
||||||
|
final override fun isEmpty(): Boolean {
|
||||||
|
return bitmap.isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun nextEmptySlot(startIndex: Int): Int {
|
||||||
|
if (startIndex >= containerSize)
|
||||||
|
return -1
|
||||||
|
else if (startIndex < 0)
|
||||||
|
return bitmap.nextClearBit(0)
|
||||||
|
else
|
||||||
|
return bitmap.nextClearBit(startIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun nextNonEmptySlot(startIndex: Int): Int {
|
||||||
|
if (startIndex >= containerSize)
|
||||||
|
return -1
|
||||||
|
else if (startIndex < 0)
|
||||||
|
return bitmap.nextSetBit(0)
|
||||||
|
else
|
||||||
|
return bitmap.nextSetBit(startIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun iterator(): Iterator<ItemStack> {
|
||||||
|
return bitmap.iterateSetBits(containerSize).map { this[it] }
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun nonEmptySlotIndexIterator(): IntIterator {
|
||||||
|
return bitmap.iterateSetBits(containerSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun emptySlotIndexIterator(): IntIterator {
|
||||||
|
return bitmap.iterateClearBits(containerSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun emptySlotIndexIterator(allowedSlots: IntCollection): IntIterator {
|
||||||
|
if (allowedSlots is IntRange2Set && allowedSlots.isNotEmpty())
|
||||||
|
return bitmap.iterateClearBits(allowedSlots.firstInt(), allowedSlots.lastInt() + 1)
|
||||||
|
|
||||||
|
return super.emptySlotIndexIterator(allowedSlots)
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun nonEmptySlotIndexIterator(allowedSlots: IntCollection): IntIterator {
|
||||||
|
if (allowedSlots is IntRange2Set && allowedSlots.isNotEmpty())
|
||||||
|
return bitmap.iterateSetBits(allowedSlots.firstInt(), allowedSlots.lastInt() + 1)
|
||||||
|
|
||||||
|
return super.nonEmptySlotIndexIterator(allowedSlots)
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import com.google.common.collect.ImmutableMap
|
|||||||
import com.google.common.collect.ImmutableSet
|
import com.google.common.collect.ImmutableSet
|
||||||
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet
|
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList
|
import it.unimi.dsi.fastutil.ints.IntArrayList
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet
|
||||||
import it.unimi.dsi.fastutil.ints.IntSet
|
import it.unimi.dsi.fastutil.ints.IntSet
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
|
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
|
||||||
@ -22,39 +23,36 @@ import ru.dbotthepony.mc.otm.core.isNotEmpty
|
|||||||
import ru.dbotthepony.mc.otm.core.stream
|
import ru.dbotthepony.mc.otm.core.stream
|
||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
|
|
||||||
class CombinedContainer(containers: Stream<Pair<Container, Iterable<Int>>>) : IMatteryContainer {
|
class CombinedContainer<S : IContainerSlot>(containers: Stream<Pair<IEnhancedContainer<S>, Iterable<Int>>>) : ISlottedContainer<S> {
|
||||||
constructor(vararg containers: Container) : this(containers.stream().map { it to (0 until it.containerSize) })
|
constructor(vararg containers: IEnhancedContainer<S>) : this(containers.stream().map { it to (0 until it.containerSize) })
|
||||||
constructor(containers: Collection<Container>) : this(containers.stream().map { it to (0 until it.containerSize) })
|
constructor(containers: Collection<IEnhancedContainer<S>>) : this(containers.stream().map { it to (0 until it.containerSize) })
|
||||||
|
|
||||||
private inner class Slot(override val slot: Int, val outer: IContainerSlot) : IContainerSlot by outer {
|
private val slots: ImmutableList<S>
|
||||||
override val container: Container
|
private val slotsMap: ImmutableMap<Container, List<S>>
|
||||||
get() = this@CombinedContainer
|
|
||||||
}
|
|
||||||
|
|
||||||
private val slots: ImmutableList<Slot>
|
|
||||||
private val slotsMap: ImmutableMap<Container, List<IContainerSlot>>
|
|
||||||
private val containers: ImmutableSet<Container>
|
private val containers: ImmutableSet<Container>
|
||||||
private val fullCoverage: ImmutableList<Container>
|
private val fullCoverage: ImmutableList<Container>
|
||||||
private val notFullCoverage: ImmutableMap<Container, List<IContainerSlot>>
|
private val notFullCoverage: ImmutableMap<Container, List<S>>
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val list = ImmutableList.Builder<Slot>()
|
val list = ImmutableList.Builder<S>()
|
||||||
var i = 0
|
|
||||||
val validationMap = Reference2ObjectOpenHashMap<Container, IntSet>()
|
val validationMap = Reference2ObjectOpenHashMap<Container, IntSet>()
|
||||||
val slotsMap = Reference2ObjectOpenHashMap<Container, ArrayList<IContainerSlot>>()
|
val slotsMap = Reference2ObjectOpenHashMap<Container, ArrayList<S>>()
|
||||||
|
var i = 0
|
||||||
|
|
||||||
for ((container, slots) in containers) {
|
for ((container, slots) in containers) {
|
||||||
val validator = validationMap.computeIfAbsent(container, Object2ObjectFunction { IntAVLTreeSet() })
|
val validator = validationMap.computeIfAbsent(container, Object2ObjectFunction { IntOpenHashSet() })
|
||||||
val slotList = slotsMap.computeIfAbsent(container, Object2ObjectFunction { ArrayList() })
|
val slotList = slotsMap.computeIfAbsent(container, Object2ObjectFunction { ArrayList() })
|
||||||
|
|
||||||
for (slot in slots) {
|
for (slot in slots) {
|
||||||
if (validator.add(slot)) {
|
if (validator.add(slot)) {
|
||||||
val slotObj = container.containerSlot(slot)
|
val slotObj = container.containerSlot(slot)
|
||||||
list.add(Slot(i++, slotObj))
|
list.add(slotObj)
|
||||||
slotList.add(slotObj)
|
slotList.add(slotObj)
|
||||||
} else {
|
} else {
|
||||||
throw IllegalArgumentException("Duplicate mapping for $container at $i for slot $slot")
|
throw IllegalArgumentException("Duplicate mapping for $container at $i for slot $slot")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +76,8 @@ class CombinedContainer(containers: Stream<Pair<Container, Iterable<Int>>>) : IM
|
|||||||
.collect(ImmutableMap.toImmutableMap({ it.key }, { it.value }))
|
.collect(ImmutableMap.toImmutableMap({ it.key }, { it.value }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val hasFilterableSlots: Boolean = super.hasFilterableSlots
|
||||||
|
|
||||||
override fun clearContent() {
|
override fun clearContent() {
|
||||||
for (container in fullCoverage) {
|
for (container in fullCoverage) {
|
||||||
container.clearContent()
|
container.clearContent()
|
||||||
@ -85,20 +85,7 @@ class CombinedContainer(containers: Stream<Pair<Container, Iterable<Int>>>) : IM
|
|||||||
|
|
||||||
for (slots in notFullCoverage.values) {
|
for (slots in notFullCoverage.values) {
|
||||||
for (slot in slots) {
|
for (slot in slots) {
|
||||||
slot.item = ItemStack.EMPTY
|
slot.remove()
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun clearSlotFilters() {
|
|
||||||
for (container in fullCoverage) {
|
|
||||||
if (container is IMatteryContainer)
|
|
||||||
container.clearSlotFilters()
|
|
||||||
}
|
|
||||||
|
|
||||||
for (slots in notFullCoverage.values) {
|
|
||||||
for (slot in slots) {
|
|
||||||
slot.setFilter()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,37 +95,7 @@ class CombinedContainer(containers: Stream<Pair<Container, Iterable<Int>>>) : IM
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun isEmpty(): Boolean {
|
override fun isEmpty(): Boolean {
|
||||||
if (fullCoverage.isNotEmpty())
|
return fullCoverage.all { it.isEmpty } && notFullCoverage.values.all { it.all { it.isEmpty } }
|
||||||
for (container in fullCoverage)
|
|
||||||
if (!container.isEmpty)
|
|
||||||
return false
|
|
||||||
|
|
||||||
if (notFullCoverage.isNotEmpty())
|
|
||||||
for (slots in notFullCoverage.values)
|
|
||||||
for (slot in slots)
|
|
||||||
if (!slot.isEmpty)
|
|
||||||
return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItem(slot: Int): ItemStack {
|
|
||||||
// do not violate contract of getItem not throwing exceptions when index is invalid
|
|
||||||
return slots.getOrNull(slot)?.item ?: ItemStack.EMPTY
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun removeItem(slot: Int, amount: Int): ItemStack {
|
|
||||||
val data = slots.getOrNull(slot) ?: return ItemStack.EMPTY
|
|
||||||
return data.outer.container.removeItem(data.outer.slot, amount)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun removeItemNoUpdate(slot: Int): ItemStack {
|
|
||||||
val data = slots.getOrNull(slot) ?: return ItemStack.EMPTY
|
|
||||||
return data.outer.container.removeItemNoUpdate(data.outer.slot)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setItem(slot: Int, itemStack: ItemStack) {
|
|
||||||
slots.getOrNull(slot)?.item = itemStack
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setChanged() {
|
override fun setChanged() {
|
||||||
@ -148,82 +105,87 @@ class CombinedContainer(containers: Stream<Pair<Container, Iterable<Int>>>) : IM
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun stillValid(player: Player): Boolean {
|
override fun stillValid(player: Player): Boolean {
|
||||||
for (container in containers)
|
return containers.all { it.stillValid(player) }
|
||||||
if (!container.stillValid(player))
|
|
||||||
return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun iterator(nonEmpty: Boolean): Iterator<ItemStack> {
|
override fun iterator(): Iterator<ItemStack> {
|
||||||
if (notFullCoverage.isEmpty())
|
if (notFullCoverage.isEmpty())
|
||||||
return fullCoverage.iterator().flatMap { it.iterator(nonEmpty) }
|
return fullCoverage.iterator().flatMap { it.iterator() }
|
||||||
|
|
||||||
return concatIterators(
|
return concatIterators(
|
||||||
fullCoverage.iterator().flatMap { it.iterator(nonEmpty) },
|
fullCoverage.iterator().flatMap { it.iterator() },
|
||||||
notFullCoverage.values.iterator().flatMap { it.iterator() }.map { it.item }.let { if (nonEmpty) it.filter { it.isNotEmpty } else it }
|
notFullCoverage.values.iterator().flatMap { it.iterator() }.map { it.item }.filter { it.isNotEmpty }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun slotIterator(nonEmpty: Boolean): Iterator<IContainerSlot> {
|
override fun slotIterator(): Iterator<S> {
|
||||||
if (nonEmpty)
|
|
||||||
return slots.iterator().filter { it.isNotEmpty }
|
|
||||||
|
|
||||||
return slots.iterator()
|
return slots.iterator()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun containerSlot(slot: Int): IContainerSlot {
|
override fun containerSlot(slot: Int): S {
|
||||||
return slots[slot]
|
return slots[slot]
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSlotFilter(slot: Int): Item? {
|
|
||||||
return slots[slot].getFilter()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setChanged(slot: Int) {
|
override fun setChanged(slot: Int) {
|
||||||
slots[slot].setChanged()
|
slots[slot].setChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setSlotFilter(slot: Int, filter: Item?): Boolean {
|
class Builder<S : IContainerSlot> {
|
||||||
return slots[slot].setFilter(filter)
|
private val values = ArrayList<Pair<IEnhancedContainer<S>, Iterable<Int>>>()
|
||||||
}
|
|
||||||
|
|
||||||
class Builder {
|
fun add(container: Container): Builder<S> {
|
||||||
private val values = ArrayList<Pair<Container, Iterable<Int>>>()
|
return add(IEnhancedContainer.wrap(container))
|
||||||
|
}
|
||||||
|
|
||||||
fun add(container: Container): Builder {
|
fun add(container: Container, slots: Iterator<Int>): Builder<S> {
|
||||||
|
return add(IEnhancedContainer.wrap(container), slots)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(container: Container, slot: Int): Builder<S> {
|
||||||
|
return add(IEnhancedContainer.wrap(container), slot)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(container: Container, from: Int, to: Int): Builder<S> {
|
||||||
|
return add(IEnhancedContainer.wrap(container), from, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(container: Container, slots: Iterable<Int>): Builder<S> {
|
||||||
|
return add(IEnhancedContainer.wrap(container), slots)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(container: IEnhancedContainer<S>): Builder<S> {
|
||||||
values.add(container to container.slotRange)
|
values.add(container to container.slotRange)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun add(container: Container, slots: Iterator<Int>): Builder {
|
fun add(container: IEnhancedContainer<S>, slots: Iterator<Int>): Builder<S> {
|
||||||
values.add(container to IntArrayList(slots))
|
values.add(container to IntArrayList(slots))
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun add(container: Container, slot: Int): Builder {
|
fun add(container: IEnhancedContainer<S>, slot: Int): Builder<S> {
|
||||||
values.add(container to intArrayOf(slot).asIterable())
|
values.add(container to intArrayOf(slot).asIterable())
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun add(container: Container, from: Int, to: Int): Builder {
|
fun add(container: IEnhancedContainer<S>, from: Int, to: Int): Builder<S> {
|
||||||
values.add(container to (from .. to))
|
values.add(container to (from .. to))
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun add(container: Container, slots: Iterable<Int>): Builder {
|
fun add(container: IEnhancedContainer<S>, slots: Iterable<Int>): Builder<S> {
|
||||||
values.add(container to slots)
|
values.add(container to slots)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun build(): CombinedContainer {
|
fun build(): CombinedContainer<S> {
|
||||||
return CombinedContainer(values.stream())
|
return CombinedContainer(values.stream())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromMenuSlots(slots: Iterator<net.minecraft.world.inventory.Slot>): CombinedContainer {
|
fun fromMenuSlots(slots: Iterator<net.minecraft.world.inventory.Slot>): CombinedContainer<IContainerSlot> {
|
||||||
val builder = Builder()
|
val builder = Builder<IContainerSlot>()
|
||||||
|
|
||||||
for (slot in slots) {
|
for (slot in slots) {
|
||||||
builder.add(slot.container, slot.slotIndex)
|
builder.add(slot.container, slot.slotIndex)
|
||||||
|
@ -1,89 +0,0 @@
|
|||||||
package ru.dbotthepony.mc.otm.container
|
|
||||||
|
|
||||||
import net.minecraft.world.item.ItemStack
|
|
||||||
import net.neoforged.neoforge.items.IItemHandler
|
|
||||||
|
|
||||||
class ContainerHandler(
|
|
||||||
private val container: IMatteryContainer,
|
|
||||||
private val filter: HandlerFilter = HandlerFilter.Both,
|
|
||||||
) : IItemHandler {
|
|
||||||
override fun getSlots() = container.containerSize
|
|
||||||
override fun getStackInSlot(slot: Int) = container[slot]
|
|
||||||
|
|
||||||
override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean): ItemStack {
|
|
||||||
if (!container.testSlotFilter(slot, stack) || !filter.canInsert(slot, stack))
|
|
||||||
return stack
|
|
||||||
|
|
||||||
filter.preInsert(slot, stack, simulate)
|
|
||||||
|
|
||||||
val localStack = container[slot]
|
|
||||||
var amount = filter.modifyInsertCount(slot, stack, localStack, simulate)
|
|
||||||
|
|
||||||
if (amount <= 0)
|
|
||||||
return stack
|
|
||||||
|
|
||||||
if (localStack.isEmpty) {
|
|
||||||
amount = stack.count.coerceAtMost(container.getMaxStackSize(slot, stack)).coerceAtMost(amount)
|
|
||||||
|
|
||||||
if (!simulate) {
|
|
||||||
container.setItem(slot, stack.copyWithCount(amount))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stack.count <= amount) {
|
|
||||||
return ItemStack.EMPTY
|
|
||||||
} else {
|
|
||||||
return stack.copyWithCount(stack.count - amount)
|
|
||||||
}
|
|
||||||
} else if (localStack.isStackable && container.getMaxStackSize(slot, localStack) > localStack.count && ItemStack.isSameItemSameComponents(localStack, stack)) {
|
|
||||||
val newCount = container.getMaxStackSize(slot, localStack).coerceAtMost(localStack.count + stack.count.coerceAtMost(amount))
|
|
||||||
val diff = newCount - localStack.count
|
|
||||||
|
|
||||||
if (diff != 0) {
|
|
||||||
if (!simulate) {
|
|
||||||
localStack.grow(diff)
|
|
||||||
container.setChanged(slot)
|
|
||||||
}
|
|
||||||
|
|
||||||
val copy = stack.copy()
|
|
||||||
copy.shrink(diff)
|
|
||||||
return copy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return stack
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun extractItem(slot: Int, amount: Int, simulate: Boolean): ItemStack {
|
|
||||||
if (amount <= 0 || container.isSlotForbiddenForAutomation(slot))
|
|
||||||
return ItemStack.EMPTY
|
|
||||||
|
|
||||||
val localStack = container.getItem(slot)
|
|
||||||
if (localStack.isEmpty) return ItemStack.EMPTY
|
|
||||||
|
|
||||||
@Suppress("name_shadowing")
|
|
||||||
val amount = filter.modifyExtractCount(slot, amount, simulate)
|
|
||||||
if (amount <= 0) return ItemStack.EMPTY
|
|
||||||
if (!filter.canExtract(slot, amount, localStack)) return ItemStack.EMPTY
|
|
||||||
|
|
||||||
filter.preExtract(slot, amount, simulate)
|
|
||||||
|
|
||||||
val minimal = amount.coerceAtMost(localStack.count)
|
|
||||||
val copy = localStack.copy()
|
|
||||||
copy.count = minimal
|
|
||||||
|
|
||||||
if (!simulate) {
|
|
||||||
localStack.shrink(minimal)
|
|
||||||
container.setChanged(slot)
|
|
||||||
}
|
|
||||||
|
|
||||||
return copy
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getSlotLimit(slot: Int): Int {
|
|
||||||
return container.maxStackSize
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isItemValid(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return container.testSlotFilter(slot, stack) && filter.canInsert(slot, stack)
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,6 +9,7 @@ import it.unimi.dsi.fastutil.ints.IntIterator
|
|||||||
import it.unimi.dsi.fastutil.ints.IntList
|
import it.unimi.dsi.fastutil.ints.IntList
|
||||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet
|
||||||
import it.unimi.dsi.fastutil.ints.IntSet
|
import it.unimi.dsi.fastutil.ints.IntSet
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntSortedSet
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
||||||
@ -22,6 +23,7 @@ import ru.dbotthepony.mc.otm.container.util.ItemStackHashStrategy
|
|||||||
import ru.dbotthepony.mc.otm.container.util.containerSlot
|
import ru.dbotthepony.mc.otm.container.util.containerSlot
|
||||||
import ru.dbotthepony.mc.otm.container.util.slotIterator
|
import ru.dbotthepony.mc.otm.container.util.slotIterator
|
||||||
import ru.dbotthepony.mc.otm.core.addAll
|
import ru.dbotthepony.mc.otm.core.addAll
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.IntRange2Set
|
||||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||||
import ru.dbotthepony.mc.otm.core.collect.toList
|
import ru.dbotthepony.mc.otm.core.collect.toList
|
||||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||||
@ -38,89 +40,12 @@ inline operator fun Container.get(index: Int): ItemStack = getItem(index)
|
|||||||
@Suppress("nothing_to_inline")
|
@Suppress("nothing_to_inline")
|
||||||
inline operator fun IFluidHandler.get(index: Int) = getFluidInTank(index)
|
inline operator fun IFluidHandler.get(index: Int) = getFluidInTank(index)
|
||||||
|
|
||||||
val Container.slotRange: IntIterable get() {
|
val Container.slotRange: IntRange2Set get() {
|
||||||
return IntIterable {
|
return IntRange2Set.openEnded(0, containerSize)
|
||||||
val i = (0 until containerSize).iterator()
|
|
||||||
|
|
||||||
object : IntIterator {
|
|
||||||
override fun hasNext(): Boolean {
|
|
||||||
return i.hasNext()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun remove() {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun nextInt(): Int {
|
|
||||||
return i.nextInt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Container.addItem(stack: ItemStack, simulate: Boolean, slots: IntIterable = slotRange): ItemStack {
|
fun Container.addItem(stack: ItemStack, simulate: Boolean, slots: IntSet = slotRange): ItemStack {
|
||||||
if (this is IMatteryContainer) {
|
return IEnhancedContainer.wrap(this).addItem(stack, simulate, slots)
|
||||||
return this.addItem(stack, simulate, slots)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stack.isEmpty)
|
|
||||||
return stack
|
|
||||||
|
|
||||||
val copy = stack.copy()
|
|
||||||
|
|
||||||
// двигаем в одинаковые слоты
|
|
||||||
var i = slots.intIterator()
|
|
||||||
|
|
||||||
while (i.hasNext()) {
|
|
||||||
val slot = i.nextInt()
|
|
||||||
|
|
||||||
if (ItemStack.isSameItemSameComponents(this[slot], copy)) {
|
|
||||||
val slotStack = this[slot]
|
|
||||||
val slotLimit = maxStackSize.coerceAtMost(slotStack.maxStackSize)
|
|
||||||
|
|
||||||
if (slotStack.count < slotLimit) {
|
|
||||||
val newCount = (slotStack.count + copy.count).coerceAtMost(slotLimit)
|
|
||||||
val diff = newCount - slotStack.count
|
|
||||||
|
|
||||||
if (!simulate) {
|
|
||||||
slotStack.count = newCount
|
|
||||||
setChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
copy.shrink(diff)
|
|
||||||
|
|
||||||
if (copy.isEmpty) {
|
|
||||||
return copy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// двигаем в пустые слоты
|
|
||||||
i = slots.intIterator()
|
|
||||||
|
|
||||||
while (i.hasNext()) {
|
|
||||||
val slot = i.nextInt()
|
|
||||||
|
|
||||||
if (this[slot].isEmpty) {
|
|
||||||
val diff = copy.count.coerceAtMost(maxStackSize.coerceAtMost(copy.maxStackSize))
|
|
||||||
|
|
||||||
if (!simulate) {
|
|
||||||
val copyToPut = copy.copy()
|
|
||||||
copyToPut.count = diff
|
|
||||||
this[slot] = copyToPut
|
|
||||||
setChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
copy.shrink(diff)
|
|
||||||
|
|
||||||
if (copy.isEmpty) {
|
|
||||||
return copy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return copy
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Container.vanishCursedItems() {
|
fun Container.vanishCursedItems() {
|
||||||
@ -131,7 +56,7 @@ fun Container.vanishCursedItems() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Container.balance(slots: IntSet, checkForEmpty: Boolean = true) {
|
fun Container.balance(slots: IntCollection, checkForEmpty: Boolean = true) {
|
||||||
if (slots.isEmpty() || checkForEmpty && !slots.any { getItem(it).isNotEmpty }) return
|
if (slots.isEmpty() || checkForEmpty && !slots.any { getItem(it).isNotEmpty }) return
|
||||||
|
|
||||||
val empty = IntArrayList()
|
val empty = IntArrayList()
|
||||||
@ -312,12 +237,18 @@ fun Container.sortWithIndices(sortedSlots: IntCollection) {
|
|||||||
if (value in 0 until containerSize && seen.add(value)) {
|
if (value in 0 until containerSize && seen.add(value)) {
|
||||||
val slot = containerSlot(value)
|
val slot = containerSlot(value)
|
||||||
|
|
||||||
if (
|
val condition: Boolean
|
||||||
slot.isNotEmpty &&
|
|
||||||
!slot.isForbiddenForAutomation &&
|
if (slot is IFilteredContainerSlot) {
|
||||||
slot.item.count <= slot.getMaxStackSize() &&
|
condition = slot.isNotEmpty &&
|
||||||
(!slot.hasFilter || slot.getFilter() != slot.item.item || slot.getMaxStackSize() > 1)
|
!slot.filter.denyAll &&
|
||||||
) {
|
slot.item.count <= slot.maxStackSize(slot.item) &&
|
||||||
|
(slot.filter.allowAll || !slot.filter.test(slot.item) || slot.maxStackSize(slot.item) > 1)
|
||||||
|
} else {
|
||||||
|
condition = slot.isNotEmpty && slot.item.count <= slot.maxStackSize(slot.item)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (condition) {
|
||||||
valid.add(slot)
|
valid.add(slot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -335,21 +266,24 @@ fun Container.computeSortedIndices(comparator: Comparator<ItemStack> = ItemStack
|
|||||||
if (isEmpty)
|
if (isEmpty)
|
||||||
return IntList.of()
|
return IntList.of()
|
||||||
|
|
||||||
val slots = slotIterator().filter { !it.isForbiddenForAutomation && it.getMaxStackSize() >= it.item.count }.toList()
|
val slots = slotIterator()
|
||||||
|
.withIndex()
|
||||||
|
.filter { (_, it) -> (it !is IFilteredContainerSlot || !it.filter.denyAll) && it.maxStackSize(it.item) >= it.item.count }
|
||||||
|
.toList()
|
||||||
|
|
||||||
if (slots.isEmpty())
|
if (slots.isEmpty())
|
||||||
return IntList.of()
|
return IntList.of()
|
||||||
|
|
||||||
val items = Object2ObjectOpenCustomHashMap<ItemStack, Pair<ItemStack, IntList>>(ItemStackHashStrategy)
|
val items = Object2ObjectOpenCustomHashMap<ItemStack, Pair<ItemStack, IntList>>(ItemStackHashStrategy)
|
||||||
|
|
||||||
slots.forEach {
|
slots.forEach { (index, it) ->
|
||||||
val get = items[it.item]
|
val get = items[it.item]
|
||||||
|
|
||||||
if (get == null) {
|
if (get == null) {
|
||||||
items[it.item] = it.item.copy() to IntArrayList().also { s -> s.add(it.slot) }
|
items[it.item] = it.item.copy() to IntArrayList().also { s -> s.add(index) }
|
||||||
} else {
|
} else {
|
||||||
get.first.count += it.item.count
|
get.first.count += it.item.count
|
||||||
get.second.add(it.slot)
|
get.second.add(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,81 +0,0 @@
|
|||||||
package ru.dbotthepony.mc.otm.container
|
|
||||||
|
|
||||||
import net.minecraft.world.Container
|
|
||||||
import net.minecraft.world.entity.player.Player
|
|
||||||
import net.minecraft.world.item.Item
|
|
||||||
import net.minecraft.world.item.ItemStack
|
|
||||||
import java.util.function.Predicate
|
|
||||||
import java.util.function.Supplier
|
|
||||||
|
|
||||||
/**
|
|
||||||
* because mods tend to do crazy shit
|
|
||||||
*/
|
|
||||||
class DynamicallyProxiedContainer(private val toProxy: Supplier<Container>) : IContainer {
|
|
||||||
override fun clearContent() {
|
|
||||||
return toProxy.get().clearContent()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getContainerSize(): Int {
|
|
||||||
return toProxy.get().containerSize
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isEmpty(): Boolean {
|
|
||||||
return toProxy.get().isEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItem(slot: Int): ItemStack {
|
|
||||||
return toProxy.get().getItem(slot)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun removeItem(slot: Int, amount: Int): ItemStack {
|
|
||||||
return toProxy.get().removeItem(slot, amount)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun removeItemNoUpdate(slot: Int): ItemStack {
|
|
||||||
return toProxy.get().removeItemNoUpdate(slot)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setItem(slot: Int, itemStack: ItemStack) {
|
|
||||||
return toProxy.get().setItem(slot, itemStack)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setChanged() {
|
|
||||||
return toProxy.get().setChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun stillValid(player: Player): Boolean {
|
|
||||||
return toProxy.get().stillValid(player)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getMaxStackSize(): Int {
|
|
||||||
return toProxy.get().getMaxStackSize()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun startOpen(player: Player) {
|
|
||||||
toProxy.get().startOpen(player)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun stopOpen(player: Player) {
|
|
||||||
toProxy.get().stopOpen(player)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean {
|
|
||||||
return toProxy.get().canPlaceItem(slot, itemStack)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canTakeItem(container: Container, slot: Int, itemStack: ItemStack): Boolean {
|
|
||||||
return toProxy.get().canTakeItem(container, slot, itemStack)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun countItem(item: Item): Int {
|
|
||||||
return toProxy.get().countItem(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasAnyOf(items: Set<Item>): Boolean {
|
|
||||||
return toProxy.get().hasAnyOf(items)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasAnyMatching(predicate: Predicate<ItemStack>): Boolean {
|
|
||||||
return toProxy.get().hasAnyMatching(predicate)
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,212 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.container
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntCollection
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet
|
||||||
|
import net.minecraft.core.HolderLookup.Provider
|
||||||
|
import net.minecraft.nbt.CompoundTag
|
||||||
|
import net.minecraft.nbt.ListTag
|
||||||
|
import net.minecraft.nbt.NbtOps
|
||||||
|
import net.minecraft.nbt.Tag
|
||||||
|
import net.minecraft.resources.RegistryOps
|
||||||
|
import net.minecraft.world.SimpleContainer
|
||||||
|
import net.minecraft.world.entity.player.Player
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.neoforged.neoforge.common.util.INBTSerializable
|
||||||
|
import org.apache.logging.log4j.LogManager
|
||||||
|
import ru.dbotthepony.kommons.collect.iterateClearBits
|
||||||
|
import ru.dbotthepony.kommons.collect.iterateSetBits
|
||||||
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.IntRange2Set
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.map
|
||||||
|
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||||
|
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||||
|
import java.util.BitSet
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flexible base implementation of [IEnhancedContainer], designed to be inherited, or used as-is
|
||||||
|
* if no specific logic is required (this implementation is more efficient than one provided by [SlottedContainer.simple]).
|
||||||
|
*
|
||||||
|
* This is supposed to be counterpart to [SimpleContainer] of Minecraft itself, with more features
|
||||||
|
* and improved performance (inside [IEnhancedContainer] defined methods).
|
||||||
|
*/
|
||||||
|
abstract class EnhancedContainer<out S : IContainerSlot>(private val size: Int) : BitmapTrackingContainer<S>(), INBTSerializable<CompoundTag> {
|
||||||
|
private val items = Array(size) { ItemStack.EMPTY }
|
||||||
|
private val observedItems = Array(size) { ItemStack.EMPTY }
|
||||||
|
|
||||||
|
protected open fun notifySlotChanged(slot: Int, old: ItemStack) {}
|
||||||
|
|
||||||
|
private fun observeSlotChanges(slot: Int) {
|
||||||
|
if (items[slot].count != observedItems[slot].count || !ItemStack.isSameItemSameComponents(items[slot], observedItems[slot])) {
|
||||||
|
notifySlotChanged(slot, observedItems[slot])
|
||||||
|
|
||||||
|
if (items[slot].isEmpty) {
|
||||||
|
items[slot] = ItemStack.EMPTY
|
||||||
|
observedItems[slot] = ItemStack.EMPTY
|
||||||
|
bitmap[slot] = false
|
||||||
|
} else {
|
||||||
|
notifySlotChanged(slot, observedItems[slot])
|
||||||
|
observedItems[slot] = items[slot].copy()
|
||||||
|
bitmap[slot] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setChanged(slot: Int) {
|
||||||
|
observeSlotChanges(slot)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearContent() {
|
||||||
|
items.fill(ItemStack.EMPTY)
|
||||||
|
observedItems.fill(ItemStack.EMPTY)
|
||||||
|
bitmap.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setChanged() {
|
||||||
|
for (slot in 0 until size)
|
||||||
|
observeSlotChanges(slot)
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun getContainerSize(): Int {
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun getItem(slot: Int): ItemStack {
|
||||||
|
return items[slot]
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun removeItem(slot: Int, amount: Int): ItemStack {
|
||||||
|
val item = items[slot]
|
||||||
|
|
||||||
|
if (item.isEmpty)
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
else if (item.count >= amount)
|
||||||
|
return removeItemNoUpdate(slot)
|
||||||
|
else {
|
||||||
|
val split = item.split(amount)
|
||||||
|
notifySlotChanged(slot, observedItems[slot])
|
||||||
|
observedItems[slot] = item.copy()
|
||||||
|
return split
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun removeItemNoUpdate(slot: Int): ItemStack {
|
||||||
|
val item = items[slot]
|
||||||
|
|
||||||
|
if (item.isEmpty)
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
|
||||||
|
items[slot] = ItemStack.EMPTY
|
||||||
|
notifySlotChanged(slot, observedItems[slot])
|
||||||
|
observedItems[slot] = ItemStack.EMPTY
|
||||||
|
bitmap[slot] = false
|
||||||
|
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun setItem(slot: Int, itemStack: ItemStack) {
|
||||||
|
if (itemStack.count != items[slot].count || !ItemStack.isSameItemSameComponents(itemStack, items[slot])) {
|
||||||
|
items[slot] = itemStack
|
||||||
|
notifySlotChanged(slot, observedItems[slot])
|
||||||
|
observedItems[slot] = itemStack.copy()
|
||||||
|
bitmap[slot] = itemStack.isNotEmpty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stillValid(player: Player): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called from inside [serializeNBT] per slot, return true if you have written something into [nbt].
|
||||||
|
* If returning false, and slot does not contain an item, tag entry is discarded
|
||||||
|
*/
|
||||||
|
protected open fun attachSlotData(provider: Provider, slot: Int, nbt: CompoundTag, ops: RegistryOps<Tag>): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun loadSlotData(provider: Provider, slot: Int, nbt: CompoundTag, ops: RegistryOps<Tag>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serializeNBT(provider: Provider): CompoundTag {
|
||||||
|
val ops = provider.createSerializationContext(NbtOps.INSTANCE)
|
||||||
|
|
||||||
|
return CompoundTag().also {
|
||||||
|
it["items"] = ListTag().also {
|
||||||
|
for (i in 0 until size) {
|
||||||
|
val tag = CompoundTag()
|
||||||
|
var attached = attachSlotData(provider, i, tag, ops)
|
||||||
|
|
||||||
|
if (items[i].isNotEmpty) {
|
||||||
|
attached = true
|
||||||
|
tag["item"] = ItemStack.OPTIONAL_CODEC.encodeStart(ops, items[i])
|
||||||
|
.getOrThrow { RuntimeException("Unable to serialize item ${items[i]} at slot $i: $it") }
|
||||||
|
}
|
||||||
|
|
||||||
|
tag["slot"] = i
|
||||||
|
|
||||||
|
if (attached) {
|
||||||
|
it.add(tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deserializeNBT(provider: Provider, nbt: CompoundTag) {
|
||||||
|
val copy = observedItems.copyOf()
|
||||||
|
items.fill(ItemStack.EMPTY)
|
||||||
|
observedItems.fill(ItemStack.EMPTY)
|
||||||
|
bitmap.clear()
|
||||||
|
|
||||||
|
val seenSlots = IntOpenHashSet()
|
||||||
|
val ops = provider.createSerializationContext(NbtOps.INSTANCE)
|
||||||
|
|
||||||
|
if ("items" in nbt) {
|
||||||
|
for (element in nbt.getList("items", Tag.TAG_COMPOUND.toInt())) {
|
||||||
|
element as CompoundTag
|
||||||
|
|
||||||
|
if ("slot" !in element) continue
|
||||||
|
val slot = element.getInt("slot")
|
||||||
|
if (!seenSlots.add(slot)) continue
|
||||||
|
|
||||||
|
if ("item" in element) {
|
||||||
|
ItemStack.OPTIONAL_CODEC.decode(ops, element["item"])
|
||||||
|
.map { it.first }
|
||||||
|
.ifError { LOGGER.error("Failed to deserialize item stack in slot $slot: ${it.message()}") }
|
||||||
|
.ifSuccess {
|
||||||
|
if (it.isNotEmpty) {
|
||||||
|
items[slot] = it
|
||||||
|
observedItems[slot] = it.copy()
|
||||||
|
bitmap[slot] = true
|
||||||
|
|
||||||
|
if (it.count != copy[slot].count || !ItemStack.isSameItemSameComponents(it, copy[slot]))
|
||||||
|
notifySlotChanged(slot, copy[slot])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadSlotData(provider, slot, element, ops)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class Simple(size: Int) : EnhancedContainer<IContainerSlot>(size) {
|
||||||
|
private val slots by lazy(LazyThreadSafetyMode.PUBLICATION) { Array(size) { IContainerSlot.Simple(it, this) } }
|
||||||
|
|
||||||
|
override fun containerSlot(slot: Int): IContainerSlot {
|
||||||
|
return slots[slot]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class WithListener(size: Int, private val listener: Runnable) : Simple(size) {
|
||||||
|
override fun notifySlotChanged(slot: Int, old: ItemStack) {
|
||||||
|
super.notifySlotChanged(slot, old)
|
||||||
|
listener.run()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
}
|
||||||
|
}
|
@ -1,153 +0,0 @@
|
|||||||
package ru.dbotthepony.mc.otm.container
|
|
||||||
|
|
||||||
import net.minecraft.world.item.ItemStack
|
|
||||||
import net.neoforged.neoforge.capabilities.Capabilities
|
|
||||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
|
||||||
import ru.dbotthepony.mc.otm.capability.fluid.stream
|
|
||||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
|
||||||
|
|
||||||
interface HandlerFilter {
|
|
||||||
fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun preInsert(slot: Int, stack: ItemStack, simulate: Boolean) {}
|
|
||||||
fun preExtract(slot: Int, amount: Int, simulate: Boolean) {}
|
|
||||||
|
|
||||||
fun modifyInsertCount(slot: Int, stack: ItemStack, existing: ItemStack, simulate: Boolean): Int {
|
|
||||||
return stack.count
|
|
||||||
}
|
|
||||||
|
|
||||||
fun modifyExtractCount(slot: Int, amount: Int, simulate: Boolean): Int {
|
|
||||||
return amount
|
|
||||||
}
|
|
||||||
|
|
||||||
fun and(other: HandlerFilter): HandlerFilter {
|
|
||||||
return object : HandlerFilter {
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return this@HandlerFilter.canInsert(slot, stack) && other.canInsert(slot, stack)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
|
||||||
return this@HandlerFilter.canExtract(slot, amount, stack) && other.canExtract(slot, amount, stack)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun preInsert(slot: Int, stack: ItemStack, simulate: Boolean) {
|
|
||||||
this@HandlerFilter.preInsert(slot, stack, simulate)
|
|
||||||
other.preInsert(slot, stack, simulate)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun preExtract(slot: Int, amount: Int, simulate: Boolean) {
|
|
||||||
this@HandlerFilter.preExtract(slot, amount, simulate)
|
|
||||||
other.preExtract(slot, amount, simulate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object FluidContainers : HandlerFilter {
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return stack.getCapability(Capabilities.FluidHandler.ITEM)?.let { it.tanks > 0 } ?: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object DrainableFluidContainers : HandlerFilter {
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return stack.getCapability(Capabilities.FluidHandler.ITEM)?.let { it.stream().anyMatch { it.isNotEmpty } } ?: false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
|
||||||
return !canInsert(slot, stack)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object OnlyIn : HandlerFilter {
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object OnlyOut : HandlerFilter {
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object Both : HandlerFilter
|
|
||||||
|
|
||||||
object Dischargeable : HandlerFilter {
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return stack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { it.canExtract() && it.extractEnergy(Int.MAX_VALUE, true) > 0 } ?: false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
|
||||||
return stack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { !it.canExtract() || it.extractEnergy(Int.MAX_VALUE, true) <= 0 } ?: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object Chargeable : HandlerFilter {
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return stack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { it.canReceive() && it.receiveEnergy(Int.MAX_VALUE, true) > 0 } ?: false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
|
||||||
return stack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { !it.canReceive() || it.receiveEnergy(Int.MAX_VALUE, true) <= 0 } ?: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object ChemicalFuel : HandlerFilter {
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
|
||||||
return stack.getBurnTime(null) <= 0
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return stack.getBurnTime(null) > 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object IsPattern : HandlerFilter {
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return stack.getCapability(MatteryCapability.PATTERN_ITEM) != null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object MatterProviders : HandlerFilter {
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return stack.getCapability(MatteryCapability.MATTER_ITEM)
|
|
||||||
?.let { it.matterFlow.output && it.extractMatterChecked(Decimal.POSITIVE_INFINITY, true) > Decimal.ZERO }
|
|
||||||
?: false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
|
||||||
return stack.getCapability(MatteryCapability.MATTER_ITEM)
|
|
||||||
?.let { !it.matterFlow.output || it.extractMatterChecked(Decimal.POSITIVE_INFINITY, true) <= Decimal.ZERO }
|
|
||||||
?: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object MatterConsumers : HandlerFilter {
|
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
|
||||||
return stack.getCapability(MatteryCapability.MATTER_ITEM)
|
|
||||||
?.let { it.matterFlow.input && it.receiveMatterChecked(Decimal.POSITIVE_INFINITY, true) > Decimal.ZERO }
|
|
||||||
?: false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
|
||||||
return stack.getCapability(MatteryCapability.MATTER_ITEM)
|
|
||||||
?.let { !it.matterFlow.input || it.receiveMatterChecked(Decimal.POSITIVE_INFINITY, true) <= Decimal.ZERO }
|
|
||||||
?: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,44 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.container
|
||||||
|
|
||||||
|
import net.minecraft.world.Container
|
||||||
|
import net.minecraft.world.entity.player.Player
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.neoforged.neoforge.items.IItemHandler
|
||||||
|
import net.neoforged.neoforge.items.IItemHandlerModifiable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reinforced [ISlottedContainer] which slots are [IAutomatedContainerSlot]s, which
|
||||||
|
* subsequently allow this container to implement [IItemHandler]
|
||||||
|
*/
|
||||||
|
interface IAutomatedContainer<out S : IAutomatedContainerSlot> : ISlottedContainer<S>, IItemHandlerModifiable {
|
||||||
|
override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean {
|
||||||
|
return containerSlot(slot).canAutomationPlaceItem(itemStack)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canTakeItem(container: Container, slot: Int, itemStack: ItemStack): Boolean {
|
||||||
|
return containerSlot(slot).canAutomationTakeItem()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSlots() = containerSize
|
||||||
|
override fun getStackInSlot(slot: Int) = containerSlot(slot).item
|
||||||
|
|
||||||
|
override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean): ItemStack {
|
||||||
|
return containerSlot(slot).insertItem(stack, simulate)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun extractItem(slot: Int, amount: Int, simulate: Boolean): ItemStack {
|
||||||
|
return containerSlot(slot).extractItem(amount, simulate)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSlotLimit(slot: Int): Int {
|
||||||
|
return containerSlot(slot).maxStackSize
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setStackInSlot(slot: Int, stack: ItemStack) {
|
||||||
|
setItem(slot, stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isItemValid(slot: Int, stack: ItemStack): Boolean {
|
||||||
|
return canPlaceItem(slot, stack)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.container
|
||||||
|
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.neoforged.neoforge.items.IItemHandler
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slot of [IAutomatedContainer], with additional methods to implement interaction behavior for both for players and mechanisms
|
||||||
|
*/
|
||||||
|
interface IAutomatedContainerSlot : IContainerSlot {
|
||||||
|
fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun canAutomationTakeItem(desired: Int = item.count): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun modifyAutomationPlaceCount(itemStack: ItemStack): Int {
|
||||||
|
return itemStack.count
|
||||||
|
}
|
||||||
|
|
||||||
|
fun modifyAutomationExtractionCount(desired: Int): Int {
|
||||||
|
return desired
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slot-specific implementation for [IItemHandler.insertItem]
|
||||||
|
*/
|
||||||
|
fun insertItem(stack: ItemStack, simulate: Boolean): ItemStack {
|
||||||
|
if (!canAutomationPlaceItem(stack))
|
||||||
|
return stack
|
||||||
|
|
||||||
|
var amount = modifyAutomationPlaceCount(stack)
|
||||||
|
|
||||||
|
if (amount <= 0)
|
||||||
|
return stack
|
||||||
|
|
||||||
|
if (item.isEmpty) {
|
||||||
|
amount = stack.count.coerceAtMost(maxStackSize(stack)).coerceAtMost(amount)
|
||||||
|
|
||||||
|
if (!simulate) {
|
||||||
|
item = stack.copyWithCount(amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stack.count <= amount) {
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
} else {
|
||||||
|
return stack.copyWithCount(stack.count - amount)
|
||||||
|
}
|
||||||
|
} else if (item.isStackable && maxStackSize(item) > item.count && ItemStack.isSameItemSameComponents(item, stack)) {
|
||||||
|
val newCount = maxStackSize(item).coerceAtMost(item.count + stack.count.coerceAtMost(amount))
|
||||||
|
val diff = newCount - item.count
|
||||||
|
|
||||||
|
if (diff != 0) {
|
||||||
|
if (!simulate) {
|
||||||
|
item.grow(diff)
|
||||||
|
setChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
val copy = stack.copy()
|
||||||
|
copy.shrink(diff)
|
||||||
|
return copy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stack
|
||||||
|
}
|
||||||
|
|
||||||
|
fun extractItem(amount: Int, simulate: Boolean): ItemStack {
|
||||||
|
if (amount <= 0 || !canAutomationTakeItem(amount) || item.isEmpty)
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
|
||||||
|
@Suppress("name_shadowing")
|
||||||
|
val amount = modifyAutomationExtractionCount(amount)
|
||||||
|
if (amount <= 0 || !canAutomationTakeItem(amount)) return ItemStack.EMPTY
|
||||||
|
|
||||||
|
val minimal = amount.coerceAtMost(item.count)
|
||||||
|
val copy = item.copy()
|
||||||
|
copy.count = minimal
|
||||||
|
|
||||||
|
if (!simulate) {
|
||||||
|
if (item.count == minimal) {
|
||||||
|
item = ItemStack.EMPTY
|
||||||
|
} else {
|
||||||
|
item.shrink(minimal)
|
||||||
|
}
|
||||||
|
|
||||||
|
setChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
return copy
|
||||||
|
}
|
||||||
|
}
|
@ -1,95 +0,0 @@
|
|||||||
package ru.dbotthepony.mc.otm.container
|
|
||||||
|
|
||||||
import net.minecraft.world.Container
|
|
||||||
import net.minecraft.world.entity.player.Player
|
|
||||||
import net.minecraft.world.item.Item
|
|
||||||
import net.minecraft.world.item.ItemStack
|
|
||||||
import java.util.function.Predicate
|
|
||||||
|
|
||||||
// passthrough all default methods to fix Kotlin bug related to implementation delegation not properly working on Java interfaces
|
|
||||||
// and also to give params proper names
|
|
||||||
// https://youtrack.jetbrains.com/issue/KT-55080/Change-the-behavior-of-inheritance-delegation-to-delegates-implementing-Java-interfaces-with-default-methods
|
|
||||||
interface IContainer : Container {
|
|
||||||
override fun getMaxStackSize(): Int {
|
|
||||||
return super.getMaxStackSize()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun startOpen(player: Player) {
|
|
||||||
super.startOpen(player)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun stopOpen(player: Player) {
|
|
||||||
super.stopOpen(player)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean {
|
|
||||||
return super.canPlaceItem(slot, itemStack)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canTakeItem(container: Container, slot: Int, itemStack: ItemStack): Boolean {
|
|
||||||
return super.canTakeItem(container, slot, itemStack)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun countItem(item: Item): Int {
|
|
||||||
return super.countItem(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasAnyOf(items: Set<Item>): Boolean {
|
|
||||||
return super.hasAnyOf(items)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasAnyMatching(predicate: Predicate<ItemStack>): Boolean {
|
|
||||||
return super.hasAnyMatching(predicate)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun clearContent()
|
|
||||||
override fun getContainerSize(): Int
|
|
||||||
override fun isEmpty(): Boolean
|
|
||||||
override fun getItem(slot: Int): ItemStack
|
|
||||||
override fun removeItem(slot: Int, amount: Int): ItemStack
|
|
||||||
override fun removeItemNoUpdate(slot: Int): ItemStack
|
|
||||||
override fun setItem(slot: Int, itemStack: ItemStack)
|
|
||||||
override fun setChanged()
|
|
||||||
|
|
||||||
override fun stillValid(player: Player): Boolean
|
|
||||||
companion object {
|
|
||||||
fun wrap(container: Container): IContainer {
|
|
||||||
if (container is IContainer)
|
|
||||||
return container
|
|
||||||
else
|
|
||||||
return object : IContainer, Container by container {
|
|
||||||
override fun getMaxStackSize(): Int {
|
|
||||||
return container.getMaxStackSize()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun startOpen(player: Player) {
|
|
||||||
container.startOpen(player)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun stopOpen(player: Player) {
|
|
||||||
container.stopOpen(player)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean {
|
|
||||||
return container.canPlaceItem(slot, itemStack)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canTakeItem(container: Container, slot: Int, itemStack: ItemStack): Boolean {
|
|
||||||
return container.canTakeItem(container, slot, itemStack)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun countItem(item: Item): Int {
|
|
||||||
return container.countItem(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasAnyOf(items: Set<Item>): Boolean {
|
|
||||||
return container.hasAnyOf(items)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasAnyMatching(predicate: Predicate<ItemStack>): Boolean {
|
|
||||||
return container.hasAnyMatching(predicate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +1,7 @@
|
|||||||
package ru.dbotthepony.mc.otm.container
|
package ru.dbotthepony.mc.otm.container
|
||||||
|
|
||||||
import net.minecraft.world.Container
|
import net.minecraft.world.Container
|
||||||
import net.minecraft.world.item.Item
|
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.item.Items
|
|
||||||
import ru.dbotthepony.kommons.util.Delegate
|
import ru.dbotthepony.kommons.util.Delegate
|
||||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||||
|
|
||||||
@ -12,57 +10,64 @@ import ru.dbotthepony.mc.otm.core.isNotEmpty
|
|||||||
* for Player interaction.
|
* for Player interaction.
|
||||||
*/
|
*/
|
||||||
interface IContainerSlot : Delegate<ItemStack> {
|
interface IContainerSlot : Delegate<ItemStack> {
|
||||||
val slot: Int
|
fun setChanged()
|
||||||
val container: Container
|
var item: ItemStack
|
||||||
|
|
||||||
operator fun component1() = slot
|
|
||||||
operator fun component2() = item
|
|
||||||
|
|
||||||
fun getMaxStackSize(item: ItemStack = this.item): Int {
|
|
||||||
return container.maxStackSize
|
|
||||||
}
|
|
||||||
|
|
||||||
val isForbiddenForAutomation: Boolean get() {
|
|
||||||
return getFilter() === Items.AIR
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getFilter(): Item?
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return whenever the filter was set. Returns false only if container can't be filtered.
|
* Max stack size regardless of item
|
||||||
|
*
|
||||||
|
* Prefer to use ItemStack version instead
|
||||||
*/
|
*/
|
||||||
fun setFilter(filter: Item? = null): Boolean
|
val maxStackSize: Int
|
||||||
|
|
||||||
val hasFilter: Boolean
|
/**
|
||||||
get() = getFilter() != null
|
* Max amount of [item] that can be stored in this slot.
|
||||||
|
*
|
||||||
fun remove() {
|
* This may be larger or smaller than value returned [ItemStack.getMaxStackSize],
|
||||||
container[slot] = ItemStack.EMPTY
|
* and as such returned value by this method should be ground truth
|
||||||
|
*/
|
||||||
|
fun maxStackSize(item: ItemStack): Int {
|
||||||
|
return maxStackSize.coerceAtMost(item.maxStackSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun remove(count: Int): ItemStack {
|
fun remove(): ItemStack
|
||||||
return container.removeItem(slot, count)
|
fun remove(count: Int): ItemStack
|
||||||
}
|
|
||||||
|
|
||||||
override fun get(): ItemStack {
|
override fun get(): ItemStack {
|
||||||
return container[slot]
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun accept(t: ItemStack) {
|
override fun accept(t: ItemStack) {
|
||||||
container[slot] = t
|
item = t
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setChanged() {
|
|
||||||
container.setChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
var item: ItemStack
|
|
||||||
get() = container[slot]
|
|
||||||
set(value) { container[slot] = value }
|
|
||||||
|
|
||||||
val isEmpty: Boolean
|
val isEmpty: Boolean
|
||||||
get() = container[slot].isEmpty
|
get() = item.isEmpty
|
||||||
|
|
||||||
val isNotEmpty: Boolean
|
val isNotEmpty: Boolean
|
||||||
get() = container[slot].isNotEmpty
|
get() = item.isNotEmpty
|
||||||
|
|
||||||
|
open class Simple(protected val slot: Int, protected val container: Container) : IContainerSlot {
|
||||||
|
override fun setChanged() {
|
||||||
|
container.setChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override var item: ItemStack
|
||||||
|
get() = container[slot]
|
||||||
|
set(value) { container[slot] = value }
|
||||||
|
override val maxStackSize: Int
|
||||||
|
get() = container.maxStackSize
|
||||||
|
|
||||||
|
override fun remove(count: Int): ItemStack {
|
||||||
|
return container.removeItem(slot, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun remove(): ItemStack {
|
||||||
|
return container.removeItemNoUpdate(slot)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun maxStackSize(item: ItemStack): Int {
|
||||||
|
return maxStackSize.coerceAtMost(item.maxStackSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,477 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.container
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntCollection
|
||||||
|
import net.minecraft.world.Container
|
||||||
|
import net.minecraft.world.entity.player.Player
|
||||||
|
import net.minecraft.world.entity.player.StackedContents
|
||||||
|
import net.minecraft.world.inventory.StackedContentsCompatible
|
||||||
|
import net.minecraft.world.item.Item
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.item.Items
|
||||||
|
import net.minecraft.world.item.crafting.RecipeInput
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.any
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.map
|
||||||
|
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||||
|
import java.util.function.Predicate
|
||||||
|
import java.util.stream.Stream
|
||||||
|
import java.util.stream.StreamSupport
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Backward-compatible" enhanced container interface, where all methods can be derived/emulated from existing [Container] code
|
||||||
|
*
|
||||||
|
* This is useful because it allows to interact with actually enhanced and regular containers through unified interface,
|
||||||
|
* and actual implementations of this interface are likely to provide efficient method implementations in place of derived/emulated ones.
|
||||||
|
*/
|
||||||
|
interface IEnhancedContainer<out S : IContainerSlot> : Container, RecipeInput, Iterable<ItemStack>, StackedContentsCompatible {
|
||||||
|
// https://youtrack.jetbrains.com/issue/KT-55080/Change-the-behavior-of-inheritance-delegation-to-delegates-implementing-Java-interfaces-with-default-methods
|
||||||
|
override fun getMaxStackSize(): Int {
|
||||||
|
return super.getMaxStackSize()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun startOpen(player: Player) {
|
||||||
|
super.startOpen(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stopOpen(player: Player) {
|
||||||
|
super.stopOpen(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean {
|
||||||
|
return super.canPlaceItem(slot, itemStack)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canTakeItem(container: Container, slot: Int, itemStack: ItemStack): Boolean {
|
||||||
|
return super.canTakeItem(container, slot, itemStack)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearContent()
|
||||||
|
override fun getContainerSize(): Int
|
||||||
|
override fun getItem(slot: Int): ItemStack
|
||||||
|
override fun removeItem(slot: Int, amount: Int): ItemStack
|
||||||
|
override fun removeItemNoUpdate(slot: Int): ItemStack
|
||||||
|
override fun setItem(slot: Int, itemStack: ItemStack)
|
||||||
|
override fun setChanged()
|
||||||
|
|
||||||
|
// provide non-ambiguous get and set operators
|
||||||
|
operator fun get(slot: Int): ItemStack {
|
||||||
|
return getItem(slot)
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun set(slot: Int, value: ItemStack) {
|
||||||
|
setItem(slot, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun containerSlot(slot: Int): S
|
||||||
|
|
||||||
|
override fun fillStackedContents(contents: StackedContents) {
|
||||||
|
forEach { contents.accountStack(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns iterator over **all** slots this container has
|
||||||
|
*/
|
||||||
|
fun slotIterator(): Iterator<S> {
|
||||||
|
return (0 until containerSize).iterator().map { containerSlot(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nonEmptySlotIterator(): Iterator<S> {
|
||||||
|
return nonEmptySlotIndexIterator().map { containerSlot(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun emptySlotIterator(): Iterator<S> {
|
||||||
|
return emptySlotIndexIterator().map { containerSlot(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nonEmptySlotIterator(allowedSlots: IntCollection): Iterator<S> {
|
||||||
|
return nonEmptySlotIndexIterator(allowedSlots).map { containerSlot(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun emptySlotIterator(allowedSlots: IntCollection): Iterator<S> {
|
||||||
|
return emptySlotIndexIterator(allowedSlots).map { containerSlot(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun slotIndexWalker(allowedSlots: IntCollection, predicate: Predicate<ItemStack>): IntIterator {
|
||||||
|
return object : IntIterator() {
|
||||||
|
private val parent = allowedSlots.intIterator()
|
||||||
|
private var foundNext = false
|
||||||
|
private var next = -1
|
||||||
|
|
||||||
|
private fun findNext() {
|
||||||
|
if (!foundNext) {
|
||||||
|
foundNext = true
|
||||||
|
next = -1
|
||||||
|
|
||||||
|
while (parent.hasNext()) {
|
||||||
|
val i = parent.nextInt()
|
||||||
|
|
||||||
|
if (predicate.test(this@IEnhancedContainer[i])) {
|
||||||
|
next = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun nextInt(): Int {
|
||||||
|
findNext()
|
||||||
|
|
||||||
|
if (next == -1)
|
||||||
|
throw NoSuchElementException()
|
||||||
|
|
||||||
|
foundNext = false
|
||||||
|
val next = next
|
||||||
|
this.next = -1
|
||||||
|
return next
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasNext(): Boolean {
|
||||||
|
findNext()
|
||||||
|
return next != -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun emptySlotIndexIterator(allowedSlots: IntCollection): IntIterator {
|
||||||
|
return slotIndexWalker(allowedSlots) { it.isEmpty }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nonEmptySlotIndexIterator(allowedSlots: IntCollection): IntIterator {
|
||||||
|
return slotIndexWalker(allowedSlots) { it.isNotEmpty }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun emptySlotIndexIterator(): IntIterator {
|
||||||
|
return emptySlotIndexIterator(slotRange)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nonEmptySlotIndexIterator(): IntIterator {
|
||||||
|
return nonEmptySlotIndexIterator(slotRange)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun slotIndexWithItemIterator(item: Item): IntIterator {
|
||||||
|
return slotIndexWithItemIterator(item, slotRange)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun slotIndexWithItemIterator(item: Item, allowedSlots: IntCollection): IntIterator {
|
||||||
|
val parent = nonEmptySlotIndexIterator(allowedSlots).filter { this[it].isNotEmpty && this[it].item === item }
|
||||||
|
|
||||||
|
return object : IntIterator() {
|
||||||
|
override fun nextInt(): Int {
|
||||||
|
return parent.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasNext(): Boolean {
|
||||||
|
return parent.hasNext()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun slotWithItemIterator(item: Item): Iterator<S> {
|
||||||
|
return slotWithItemIterator(item, slotRange)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun slotWithItemIterator(item: Item, allowedSlots: IntCollection): Iterator<S> {
|
||||||
|
return slotIndexWithItemIterator(item, allowedSlots).map { containerSlot(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nextEmptySlot(startIndex: Int): Int {
|
||||||
|
for (i in startIndex until containerSize) {
|
||||||
|
if (this[i].isEmpty) {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nextNonEmptySlot(startIndex: Int): Int {
|
||||||
|
for (i in startIndex until containerSize) {
|
||||||
|
if (this[i].isNotEmpty) {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nextSlotWithItem(startIndex: Int, item: Item): Int {
|
||||||
|
var find = nextNonEmptySlot(startIndex)
|
||||||
|
|
||||||
|
while (find != -1 && this[find].item !== item)
|
||||||
|
find = nextNonEmptySlot(find + 1)
|
||||||
|
|
||||||
|
return find
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setChanged(slot: Int) {
|
||||||
|
return setChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int {
|
||||||
|
return maxStackSize
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns iterator over **non-empty** [ItemStack]s inside this container
|
||||||
|
*/
|
||||||
|
override fun iterator(): Iterator<ItemStack> {
|
||||||
|
return (0 until containerSize).iterator().map { this[it] }.filter { it.isNotEmpty }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isEmpty(): Boolean {
|
||||||
|
return nextNonEmptySlot(0) != -1
|
||||||
|
}
|
||||||
|
|
||||||
|
val hasEmptySlots: Boolean get() {
|
||||||
|
return nextEmptySlot(0) != -1
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun size(): Int {
|
||||||
|
return containerSize
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun countItem(item: Item): Int {
|
||||||
|
var count = 0
|
||||||
|
|
||||||
|
for (slot in slotWithItemIterator(item))
|
||||||
|
count += slot.item.count
|
||||||
|
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasAnyOf(items: Set<Item>): Boolean {
|
||||||
|
if (Items.AIR in items && hasEmptySlots)
|
||||||
|
return true
|
||||||
|
|
||||||
|
return iterator().any { it.item in items }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasAnyMatching(predicate: Predicate<ItemStack>): Boolean {
|
||||||
|
if (predicate.test(ItemStack.EMPTY) && hasEmptySlots)
|
||||||
|
return true
|
||||||
|
|
||||||
|
return iterator().any(predicate)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toList(): MutableList<ItemStack> {
|
||||||
|
val list = ArrayList<ItemStack>(containerSize)
|
||||||
|
|
||||||
|
for (i in 0 until containerSize) {
|
||||||
|
list.add(this[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
fun copyToList(): MutableList<ItemStack> {
|
||||||
|
val list = ArrayList<ItemStack>(containerSize)
|
||||||
|
|
||||||
|
for (i in 0 until containerSize) {
|
||||||
|
list.add(this[i].copy())
|
||||||
|
}
|
||||||
|
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addItem(stack: ItemStack, simulate: Boolean, filterPass: Boolean, slots: IntCollection, onlyIntoExisting: Boolean, popTime: Int?, ignoreFilters: Boolean): ItemStack {
|
||||||
|
if (stack.isEmpty || slots.isEmpty())
|
||||||
|
return stack
|
||||||
|
|
||||||
|
// двигаем в одинаковые слоты
|
||||||
|
for (slot in slotWithItemIterator(stack.item, slots)) {
|
||||||
|
val condition: Boolean
|
||||||
|
|
||||||
|
if (slot is IFilteredContainerSlot) {
|
||||||
|
condition = (ignoreFilters || !slot.filter.denyAll) &&
|
||||||
|
ItemStack.isSameItemSameComponents(slot.item, stack) &&
|
||||||
|
(ignoreFilters || !filterPass && slot.filter.allowAll || filterPass && !slot.filter.allowAll && slot.filter.test(stack))
|
||||||
|
} else {
|
||||||
|
condition = (ignoreFilters || !filterPass) && ItemStack.isSameItemSameComponents(slot.item, stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (condition) {
|
||||||
|
val slotLimit = slot.maxStackSize(slot.item)
|
||||||
|
|
||||||
|
if (slot.item.count < slotLimit) {
|
||||||
|
val newCount = (slot.item.count + stack.count).coerceAtMost(slotLimit)
|
||||||
|
val diff = newCount - slot.item.count
|
||||||
|
|
||||||
|
if (!simulate) {
|
||||||
|
slot.item.count = newCount
|
||||||
|
slot.setChanged()
|
||||||
|
|
||||||
|
if (popTime != null) {
|
||||||
|
slot.item.popTime = popTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stack.shrink(diff)
|
||||||
|
|
||||||
|
if (stack.isEmpty)
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!onlyIntoExisting) {
|
||||||
|
for (slot in emptySlotIterator(slots)) {
|
||||||
|
val condition: Boolean
|
||||||
|
|
||||||
|
if (slot is IFilteredContainerSlot) {
|
||||||
|
condition = (ignoreFilters || !slot.filter.denyAll) &&
|
||||||
|
(ignoreFilters || !filterPass && slot.filter.allowAll || filterPass && !slot.filter.allowAll && slot.filter.test(stack))
|
||||||
|
} else {
|
||||||
|
condition = ignoreFilters || !filterPass
|
||||||
|
}
|
||||||
|
|
||||||
|
if (condition) {
|
||||||
|
val diff = stack.count.coerceAtMost(slot.maxStackSize(stack))
|
||||||
|
|
||||||
|
if (!simulate) {
|
||||||
|
val copyToPut = stack.copy()
|
||||||
|
copyToPut.count = diff
|
||||||
|
slot.item = copyToPut
|
||||||
|
|
||||||
|
if (popTime != null) {
|
||||||
|
copyToPut.popTime = popTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stack.shrink(diff)
|
||||||
|
|
||||||
|
if (stack.isEmpty)
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stack
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hint used internally by [IEnhancedContainer] to potentially speed up default method implementations
|
||||||
|
*/
|
||||||
|
val hasFilterableSlots: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
|
fun addItem(stack: ItemStack, simulate: Boolean, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean = false): ItemStack {
|
||||||
|
if (stack.isEmpty || slots.isEmpty())
|
||||||
|
return stack
|
||||||
|
|
||||||
|
if (ignoreFilters || !hasFilterableSlots) {
|
||||||
|
return addItem(stack.copy(), simulate, filterPass = true, slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = true)
|
||||||
|
} else {
|
||||||
|
var copy = addItem(stack.copy(), simulate, filterPass = true, slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = false)
|
||||||
|
copy = addItem(copy, simulate, filterPass = false, slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = false)
|
||||||
|
return copy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlike [addItem], modifies original [stack]
|
||||||
|
*
|
||||||
|
* @return Whenever [stack] was modified
|
||||||
|
*/
|
||||||
|
fun consumeItem(stack: ItemStack, simulate: Boolean, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean = false): Boolean {
|
||||||
|
if (stack.isEmpty)
|
||||||
|
return false
|
||||||
|
|
||||||
|
val result = addItem(stack, simulate = simulate, slots = slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = ignoreFilters)
|
||||||
|
if (!simulate) stack.count = result.count
|
||||||
|
return result.count != stack.count
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fullyAddItem(stack: ItemStack, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean = false): Boolean {
|
||||||
|
if (!addItem(stack, simulate = true, slots = slots, popTime = popTime, onlyIntoExisting = onlyIntoExisting, ignoreFilters = ignoreFilters).isEmpty)
|
||||||
|
return false
|
||||||
|
|
||||||
|
return addItem(stack, simulate = false, slots = slots, popTime = popTime, onlyIntoExisting = onlyIntoExisting, ignoreFilters = ignoreFilters).isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stream(): Stream<ItemStack> {
|
||||||
|
return StreamSupport.stream(spliterator(), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Wrapper(private val parent: Container) : IEnhancedContainer<IContainerSlot> {
|
||||||
|
override fun containerSlot(slot: Int): IContainerSlot {
|
||||||
|
return IContainerSlot.Simple(slot, parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearContent() {
|
||||||
|
return parent.clearContent()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setChanged() {
|
||||||
|
return parent.setChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getContainerSize(): Int {
|
||||||
|
return parent.containerSize
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItem(slot: Int): ItemStack {
|
||||||
|
return parent.getItem(slot)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeItem(slot: Int, amount: Int): ItemStack {
|
||||||
|
return parent.removeItem(slot, amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeItemNoUpdate(slot: Int): ItemStack {
|
||||||
|
return parent.removeItemNoUpdate(slot)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setItem(slot: Int, itemStack: ItemStack) {
|
||||||
|
return parent.setItem(slot, itemStack)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stillValid(player: Player): Boolean {
|
||||||
|
return parent.stillValid(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMaxStackSize(): Int {
|
||||||
|
return parent.maxStackSize
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun startOpen(player: Player) {
|
||||||
|
parent.startOpen(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stopOpen(player: Player) {
|
||||||
|
parent.stopOpen(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean {
|
||||||
|
return parent.canPlaceItem(slot, itemStack)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canTakeItem(container: Container, slot: Int, itemStack: ItemStack): Boolean {
|
||||||
|
return parent.canTakeItem(container, slot, itemStack)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isEmpty(): Boolean {
|
||||||
|
return parent.isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasAnyMatching(predicate: Predicate<ItemStack>): Boolean {
|
||||||
|
return parent.hasAnyMatching(predicate)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasAnyOf(items: Set<Item>): Boolean {
|
||||||
|
return parent.hasAnyOf(items)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun countItem(item: Item): Int {
|
||||||
|
return parent.countItem(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun wrap(other: Container): IEnhancedContainer<*> {
|
||||||
|
if (other is IEnhancedContainer<*>)
|
||||||
|
return other
|
||||||
|
|
||||||
|
return Wrapper(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.container
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.player.StackedContents
|
||||||
|
import net.minecraft.world.inventory.CraftingContainer
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
|
||||||
|
interface IEnhancedCraftingContainer<out S : IContainerSlot> : IEnhancedContainer<S>, CraftingContainer {
|
||||||
|
override fun getItems(): MutableList<ItemStack> {
|
||||||
|
return toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fillStackedContents(contents: StackedContents) {
|
||||||
|
forEach { contents.accountSimpleStack(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
class Wrapper<out C : IEnhancedContainer<S>, out S : IContainerSlot>(val parent: C, private val width: Int, private val height: Int) : IEnhancedCraftingContainer<S>, IEnhancedContainer<S> by parent {
|
||||||
|
init {
|
||||||
|
require(width * height == parent.containerSize) { "Crafting container dimensions ($width x $height) do not match container size provided (${parent.containerSize})" }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getWidth(): Int {
|
||||||
|
return width
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getHeight(): Int {
|
||||||
|
return height
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fillStackedContents(contents: StackedContents) {
|
||||||
|
super<IEnhancedCraftingContainer>.fillStackedContents(contents)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.container
|
||||||
|
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.item.Items
|
||||||
|
|
||||||
|
interface IFilteredAutomatedContainerSlot : IFilteredContainerSlot, IAutomatedContainerSlot {
|
||||||
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
|
return super.canAutomationPlaceItem(itemStack) && filter.test(itemStack)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canAutomationTakeItem(desired: Int): Boolean {
|
||||||
|
return super.canAutomationTakeItem(desired) && !filter.denyAll
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.container
|
||||||
|
|
||||||
|
interface IFilteredContainerSlot : IContainerSlot {
|
||||||
|
var filter: ItemFilter
|
||||||
|
}
|
@ -1,255 +0,0 @@
|
|||||||
package ru.dbotthepony.mc.otm.container
|
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntIterable
|
|
||||||
import net.minecraft.world.item.Item
|
|
||||||
import net.minecraft.world.item.ItemStack
|
|
||||||
import net.minecraft.world.item.Items
|
|
||||||
import net.minecraft.world.item.crafting.RecipeInput
|
|
||||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
|
||||||
import ru.dbotthepony.mc.otm.core.collect.map
|
|
||||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
|
||||||
|
|
||||||
interface IMatteryContainer : IContainer, RecipeInput, Iterable<ItemStack> {
|
|
||||||
fun getSlotFilter(slot: Int): Item?
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return whenever the filter was set. Returns false only if container can't be filtered.
|
|
||||||
*/
|
|
||||||
fun setSlotFilter(slot: Int, filter: Item? = null): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clearSlotFilters()
|
|
||||||
|
|
||||||
override fun isEmpty(): Boolean
|
|
||||||
fun setChanged(slot: Int)
|
|
||||||
|
|
||||||
override fun size(): Int {
|
|
||||||
return containerSize
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterates over non-empty itemstacks of this container
|
|
||||||
*/
|
|
||||||
override fun iterator(): Iterator<ItemStack> {
|
|
||||||
return iterator(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterates non-empty slots of this container
|
|
||||||
*/
|
|
||||||
fun slotIterator(): Iterator<IContainerSlot> {
|
|
||||||
return slotIterator(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun iterator(nonEmpty: Boolean): Iterator<ItemStack> {
|
|
||||||
if (nonEmpty) {
|
|
||||||
return (0 until containerSize).iterator().map { this[it] }.filter { it.isNotEmpty }
|
|
||||||
} else {
|
|
||||||
return (0 until containerSize).iterator().map { this[it] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open class ContainerSlot(override val slot: Int, override val container: IMatteryContainer) : IContainerSlot {
|
|
||||||
override val isForbiddenForAutomation: Boolean
|
|
||||||
get() = container.isSlotForbiddenForAutomation(slot)
|
|
||||||
|
|
||||||
override fun getFilter(): Item? {
|
|
||||||
return container.getSlotFilter(slot)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setFilter(filter: Item?): Boolean {
|
|
||||||
return container.setSlotFilter(slot, filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getMaxStackSize(item: ItemStack): Int {
|
|
||||||
return container.getMaxStackSize(slot, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setChanged() {
|
|
||||||
container.setChanged(slot)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterates either non-empty slots of container or all slots of container
|
|
||||||
*/
|
|
||||||
fun slotIterator(nonEmpty: Boolean): Iterator<IContainerSlot> {
|
|
||||||
if (nonEmpty) {
|
|
||||||
return (0 until containerSize).iterator().filter { this[it].isNotEmpty }.map { containerSlot(it) }
|
|
||||||
} else {
|
|
||||||
return (0 until containerSize).iterator().map { containerSlot(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun containerSlot(slot: Int): IContainerSlot {
|
|
||||||
return ContainerSlot(slot, this)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hasSlotFilter(slot: Int) = getSlotFilter(slot) !== null
|
|
||||||
fun isSlotForbiddenForAutomation(slot: Int) = getSlotFilter(slot) === Items.AIR
|
|
||||||
|
|
||||||
fun testSlotFilter(slot: Int, itemStack: ItemStack): Boolean {
|
|
||||||
return testSlotFilter(slot, itemStack.item)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun testSlotFilter(slot: Int, item: Item): Boolean {
|
|
||||||
if (getSlotFilter(slot) == null) {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return getSlotFilter(slot) === item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getMaxStackSize(slot: Int, itemStack: ItemStack) = maxStackSize.coerceAtMost(itemStack.maxStackSize)
|
|
||||||
|
|
||||||
private fun addItem(stack: ItemStack, simulate: Boolean, filterPass: Boolean, slots: IntIterable, onlyIntoExisting: Boolean, popTime: Int?, ignoreFilters: Boolean): ItemStack {
|
|
||||||
if (stack.isEmpty)
|
|
||||||
return stack
|
|
||||||
|
|
||||||
// двигаем в одинаковые слоты
|
|
||||||
var i = slots.intIterator()
|
|
||||||
|
|
||||||
while (i.hasNext()) {
|
|
||||||
val slot = i.nextInt()
|
|
||||||
|
|
||||||
if (
|
|
||||||
(ignoreFilters || !isSlotForbiddenForAutomation(slot)) &&
|
|
||||||
ItemStack.isSameItemSameComponents(getItem(slot), stack) &&
|
|
||||||
(ignoreFilters || !filterPass && !hasSlotFilter(slot) || filterPass && hasSlotFilter(slot) && testSlotFilter(slot, stack))
|
|
||||||
) {
|
|
||||||
val slotStack = getItem(slot)
|
|
||||||
val slotLimit = getMaxStackSize(slot, slotStack)
|
|
||||||
|
|
||||||
if (slotStack.count < slotLimit) {
|
|
||||||
val newCount = (slotStack.count + stack.count).coerceAtMost(slotLimit)
|
|
||||||
val diff = newCount - slotStack.count
|
|
||||||
|
|
||||||
if (!simulate) {
|
|
||||||
slotStack.count = newCount
|
|
||||||
setChanged(slot)
|
|
||||||
|
|
||||||
if (popTime != null) {
|
|
||||||
slotStack.popTime = popTime
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stack.shrink(diff)
|
|
||||||
|
|
||||||
if (stack.isEmpty) {
|
|
||||||
return stack
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!onlyIntoExisting) {
|
|
||||||
i = slots.intIterator()
|
|
||||||
|
|
||||||
// двигаем в пустые слоты
|
|
||||||
while (i.hasNext()) {
|
|
||||||
val slot = i.nextInt()
|
|
||||||
|
|
||||||
if (
|
|
||||||
getItem(slot).isEmpty &&
|
|
||||||
(ignoreFilters || !isSlotForbiddenForAutomation(slot)) &&
|
|
||||||
(ignoreFilters || !filterPass && !hasSlotFilter(slot) || filterPass && hasSlotFilter(slot) && testSlotFilter(slot, stack))
|
|
||||||
) {
|
|
||||||
val diff = stack.count.coerceAtMost(getMaxStackSize(slot, stack))
|
|
||||||
|
|
||||||
if (!simulate) {
|
|
||||||
val copyToPut = stack.copy()
|
|
||||||
copyToPut.count = diff
|
|
||||||
setItem(slot, copyToPut)
|
|
||||||
|
|
||||||
if (popTime != null) {
|
|
||||||
copyToPut.popTime = popTime
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stack.shrink(diff)
|
|
||||||
|
|
||||||
if (stack.isEmpty) {
|
|
||||||
return stack
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return stack
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addItem(stack: ItemStack, simulate: Boolean, slots: IntIterable = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean = false): ItemStack {
|
|
||||||
if (stack.isEmpty)
|
|
||||||
return stack
|
|
||||||
|
|
||||||
if (ignoreFilters) {
|
|
||||||
return addItem(stack.copy(), simulate, true, slots, onlyIntoExisting, popTime, true)
|
|
||||||
} else {
|
|
||||||
var copy = addItem(stack.copy(), simulate, true, slots, onlyIntoExisting, popTime, false)
|
|
||||||
copy = addItem(copy, simulate, false, slots, onlyIntoExisting, popTime, false)
|
|
||||||
return copy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun handler(filter: HandlerFilter = HandlerFilter.Both): ContainerHandler {
|
|
||||||
return ContainerHandler(this, filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unlike [addItem], modifies original [stack]
|
|
||||||
*
|
|
||||||
* @return Whenever [stack] was modified
|
|
||||||
*/
|
|
||||||
fun consumeItem(stack: ItemStack, simulate: Boolean, slots: IntIterable = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean = false): Boolean {
|
|
||||||
if (stack.isEmpty)
|
|
||||||
return false
|
|
||||||
|
|
||||||
val result = addItem(stack, simulate, slots, onlyIntoExisting, popTime, ignoreFilters)
|
|
||||||
|
|
||||||
if (result.count != stack.count) {
|
|
||||||
if (!simulate) {
|
|
||||||
stack.count = result.count
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fullyAddItem(stack: ItemStack, slots: IntIterable = slotRange, ignoreFilters: Boolean = false): Boolean {
|
|
||||||
if (!addItem(stack, true, slots, ignoreFilters).isEmpty)
|
|
||||||
return false
|
|
||||||
|
|
||||||
return addItem(stack, false, slots, ignoreFilters).isEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
fun toList(): MutableList<ItemStack> {
|
|
||||||
val list = ArrayList<ItemStack>(size())
|
|
||||||
|
|
||||||
for (i in 0 until size()) {
|
|
||||||
list.add(this[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
fun shrink(slot: Int, amount: Int): Boolean {
|
|
||||||
if (slot < 0 || slot > size())
|
|
||||||
return false
|
|
||||||
|
|
||||||
val item = this[slot]
|
|
||||||
if (item.isEmpty)
|
|
||||||
return false
|
|
||||||
|
|
||||||
if (item.count <= amount) {
|
|
||||||
this[slot] = ItemStack.EMPTY
|
|
||||||
} else {
|
|
||||||
item.shrink(amount)
|
|
||||||
setChanged(slot)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,36 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.container
|
||||||
|
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import ru.dbotthepony.kommons.collect.any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Skeletal implementation for containers which revolve around [IContainerSlot]
|
||||||
|
*/
|
||||||
|
interface ISlottedContainer<out S : IContainerSlot> : IEnhancedContainer<S> {
|
||||||
|
override fun setChanged(slot: Int) {
|
||||||
|
containerSlot(slot).setChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int {
|
||||||
|
return containerSlot(slot).maxStackSize(itemStack)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItem(slot: Int): ItemStack {
|
||||||
|
return containerSlot(slot).item
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeItem(slot: Int, amount: Int): ItemStack {
|
||||||
|
return containerSlot(slot).remove(amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeItemNoUpdate(slot: Int): ItemStack {
|
||||||
|
return containerSlot(slot).remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setItem(slot: Int, itemStack: ItemStack) {
|
||||||
|
containerSlot(slot).item = itemStack
|
||||||
|
}
|
||||||
|
|
||||||
|
override val hasFilterableSlots: Boolean
|
||||||
|
get() = slotIterator().any { it is IFilteredContainerSlot }
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user