Bigger Boxes

- Added the Item Vault
This commit is contained in:
simibubi 2021-11-10 21:07:47 +01:00
parent 6224a3e444
commit 2078899ed9
43 changed files with 1111 additions and 27 deletions

View file

@ -200,6 +200,7 @@ be3bef7e091d8b50bfc1c6b7275946d1f636aefd assets/create/blockstates/horizontal_fr
18d9fdaa1352a7e2ec91135e46dae5c02ccd8f8f assets/create/blockstates/horizontal_framed_glass_pane.json
30ec347dfc827a9ae52cf3da964b828005acede1 assets/create/blockstates/hose_pulley.json
6651c84ea621777d572a3d7aa13b75d9f061191b assets/create/blockstates/item_drain.json
10ef455fd61ed1ca831d27bf2b533d05dec9c67d assets/create/blockstates/item_vault.json
5d851c90d23de5087ce546d4bbe509e112b84c49 assets/create/blockstates/jungle_window.json
b15bea757ef981e0ca60f740ca234ee2014eb7b7 assets/create/blockstates/jungle_window_pane.json
f651091db216b009b3379b2f48d56d03481c8675 assets/create/blockstates/large_cogwheel.json
@ -442,20 +443,20 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo
6801fa1f466f172700e573e5b8ee8ee5f9ca4583 assets/create/blockstates/yellow_valve_handle.json
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
7c31858e6239b72e4da8830fa4cf1748ef2a7ae1 assets/create/lang/en_ud.json
124dd97c100eda3e8078c5e524db74ba91bf206c assets/create/lang/en_us.json
738b1c5391dedb308e2b782d48cf867c8a8bf041 assets/create/lang/unfinished/de_de.json
a987345dd3375ad01fe4900f93941570d374dba9 assets/create/lang/unfinished/es_es.json
9c26f0e9e28c76ef1f5e5e8bf6d0de8eb4d956d6 assets/create/lang/unfinished/fr_fr.json
211c4c8cbd62546a08616b2482319c63d87083a5 assets/create/lang/unfinished/it_it.json
9590169c9c1708af58db1adba3e38e7c58952cfd assets/create/lang/unfinished/ja_jp.json
97eb7f70b3dffea14fc4df5a0147395c3663f321 assets/create/lang/unfinished/ko_kr.json
a9a7bacadde4d6daa4f4ae85da2821c33252442b assets/create/lang/unfinished/nl_nl.json
e8a42aacad3b0b606cf79a30d209dabe6e13a6b3 assets/create/lang/unfinished/pl_pl.json
1a0fa057db601d3aa35c971a9e3d113d3cf61cca assets/create/lang/unfinished/pt_br.json
4d0e6890f838528bed5c7ec58703b4369b10a0b4 assets/create/lang/unfinished/ru_ru.json
6aeaa68280d6fb85aa0e3eabc27d4723a2af4b8b assets/create/lang/unfinished/zh_cn.json
a4b3fceb0d539b6f9cc27d6d81ea1f862f83f3c0 assets/create/lang/unfinished/zh_tw.json
1467113c879a243b2f077b196839491306733e98 assets/create/lang/en_ud.json
b2c605fc34b13c7239521f9269498e81f9206df8 assets/create/lang/en_us.json
a6a58d7de53eb8604d4931ebae0ac2db21cdc294 assets/create/lang/unfinished/de_de.json
1e17cccd3640755df4791103703321b20939270a assets/create/lang/unfinished/es_es.json
b3080971e3ee4fa68a939aa950a2efb526c2514b assets/create/lang/unfinished/fr_fr.json
d049c3352e50b7e712a7e8f960bacbf05ccd67c2 assets/create/lang/unfinished/it_it.json
f5b457214c5e016819cfc40963a8416b87f0f6c0 assets/create/lang/unfinished/ja_jp.json
dc58414c920b5a133aabc0199c31c6d1825cf49b assets/create/lang/unfinished/ko_kr.json
020b76171c6c05ed68aa850e7178a5d3b66dc726 assets/create/lang/unfinished/nl_nl.json
eb77d2c1b2e596811a201d8ad99c05fd1a2f87ec assets/create/lang/unfinished/pl_pl.json
0b5a48da526045a8ca23aabb7ee188bdf799355a assets/create/lang/unfinished/pt_br.json
5e853989000583f44b25721d8f3fe6d456ef3127 assets/create/lang/unfinished/ru_ru.json
baf3023293ad9565d6898ec18e54109e0fc9c7e1 assets/create/lang/unfinished/zh_cn.json
b5d55f65cf5ac2b262622b0bf15cfd2b03100dcf assets/create/lang/unfinished/zh_tw.json
487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json
b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json
3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json
@ -1498,6 +1499,7 @@ ff92f6a9dfb73a6ee1eaaed3279c89390ff04a80 assets/create/models/item/hose_pulley.j
153a185852af79654f0fb216c4b1b8e69c85ee8a assets/create/models/item/incomplete_precision_mechanism.json
9d605ce0da83a73b535bce45c107e604364e2b20 assets/create/models/item/iron_sheet.json
52e435014cb03e93411666c4799ebff206e55fc9 assets/create/models/item/item_drain.json
76ab46c9b64faf5e94391579eec5115360dff73d assets/create/models/item/item_vault.json
83fa8699318e51f838b483b40b3e897c34ed53d1 assets/create/models/item/jungle_window.json
766323f6026c3505a75db2dee2996d342370d9c2 assets/create/models/item/jungle_window_pane.json
bcaaf60d9a853cce90169dabcb36d29a3ce19e18 assets/create/models/item/large_cogwheel.json
@ -2674,6 +2676,7 @@ b80ea3ecf06dc3b394eb5006ed22a1cc1c276be7 data/create/loot_tables/blocks/haunted_
6a95342ca2e88c1e829a649d33c9b4aa8ea9b590 data/create/loot_tables/blocks/horizontal_framed_glass_pane.json
a40f78789e92c72d248cf5c99c04682e4fd29d28 data/create/loot_tables/blocks/hose_pulley.json
d913437bf5ea95e80abd389fffa031343e14c49f data/create/loot_tables/blocks/item_drain.json
34d7db36bfc0a6da4a8f1803a24de0d9765ce003 data/create/loot_tables/blocks/item_vault.json
88a1de3ac08023cbc920c338db9f97a4ffecbd5d data/create/loot_tables/blocks/jungle_window.json
bf2d5854965b850fe72fac1992924bf4a0bba456 data/create/loot_tables/blocks/jungle_window_pane.json
7935444e5cef99d58c2dc26d72f234732b6b5632 data/create/loot_tables/blocks/large_cogwheel.json

View file

@ -0,0 +1,18 @@
{
"variants": {
"axis=x,large=false": {
"model": "create:block/item_vault",
"y": 90
},
"axis=z,large=false": {
"model": "create:block/item_vault"
},
"axis=x,large=true": {
"model": "create:block/item_vault",
"y": 90
},
"axis=z,large=true": {
"model": "create:block/item_vault"
}
}
}

View file

@ -201,6 +201,7 @@
"block.create.horizontal_framed_glass_pane": "\u01DDu\u0250\u0500 ss\u0250\u05DF\u2141 p\u01DD\u026F\u0250\u0279\u2132 \u05DF\u0250\u0287uoz\u0131\u0279oH",
"block.create.hose_pulley": "\u028E\u01DD\u05DF\u05DFn\u0500 \u01DDsoH",
"block.create.item_drain": "u\u0131\u0250\u0279\u15E1 \u026F\u01DD\u0287I",
"block.create.item_vault": "\u0287\u05DFn\u0250\u039B \u026F\u01DD\u0287I",
"block.create.jungle_window": "\u028Dopu\u0131M \u01DD\u05DFbun\u017F",
"block.create.jungle_window_pane": "\u01DDu\u0250\u0500 \u028Dopu\u0131M \u01DD\u05DFbun\u017F",
"block.create.large_cogwheel": "\u05DF\u01DD\u01DD\u0265\u028Dbo\u0186 \u01DDb\u0279\u0250\uA780",

View file

@ -204,6 +204,7 @@
"block.create.horizontal_framed_glass_pane": "Horizontal Framed Glass Pane",
"block.create.hose_pulley": "Hose Pulley",
"block.create.item_drain": "Item Drain",
"block.create.item_vault": "Item Vault",
"block.create.jungle_window": "Jungle Window",
"block.create.jungle_window_pane": "Jungle Window Pane",
"block.create.large_cogwheel": "Large Cogwheel",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 1166",
"_": "Missing Localizations: 1167",
"_": "->------------------------] Game Elements [------------------------<-",
@ -205,6 +205,7 @@
"block.create.horizontal_framed_glass_pane": "Horizontal Gerahmte Glasscheibe",
"block.create.hose_pulley": "Umlenkrolle",
"block.create.item_drain": "Abfluss",
"block.create.item_vault": "UNLOCALIZED: Item Vault",
"block.create.jungle_window": "Tropenholzfenster",
"block.create.jungle_window_pane": "Tropenholzfensterscheibe",
"block.create.large_cogwheel": "Großes Zahnrad",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 44",
"_": "Missing Localizations: 45",
"_": "->------------------------] Game Elements [------------------------<-",
@ -205,6 +205,7 @@
"block.create.horizontal_framed_glass_pane": "Panel de cristal con marco horizontal",
"block.create.hose_pulley": "Polea de manguera",
"block.create.item_drain": "Drenador de objetos",
"block.create.item_vault": "UNLOCALIZED: Item Vault",
"block.create.jungle_window": "Ventana de jungla",
"block.create.jungle_window_pane": "Panel de ventana de jungla",
"block.create.large_cogwheel": "Engranaje grande",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 1417",
"_": "Missing Localizations: 1418",
"_": "->------------------------] Game Elements [------------------------<-",
@ -205,6 +205,7 @@
"block.create.horizontal_framed_glass_pane": "Vitre encadrée horizontale",
"block.create.hose_pulley": "UNLOCALIZED: Hose Pulley",
"block.create.item_drain": "UNLOCALIZED: Item Drain",
"block.create.item_vault": "UNLOCALIZED: Item Vault",
"block.create.jungle_window": "UNLOCALIZED: Jungle Window",
"block.create.jungle_window_pane": "UNLOCALIZED: Jungle Window Pane",
"block.create.large_cogwheel": "Grande roue dentée",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 946",
"_": "Missing Localizations: 947",
"_": "->------------------------] Game Elements [------------------------<-",
@ -205,6 +205,7 @@
"block.create.horizontal_framed_glass_pane": "Pannello di finestra di vetro orizzontale",
"block.create.hose_pulley": "Carrucola per tubi",
"block.create.item_drain": "Drenante di oggetti",
"block.create.item_vault": "UNLOCALIZED: Item Vault",
"block.create.jungle_window": "Finestra della giungla",
"block.create.jungle_window_pane": "Pannello di finestra della giungla",
"block.create.large_cogwheel": "Ruota dentata grande",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 53",
"_": "Missing Localizations: 54",
"_": "->------------------------] Game Elements [------------------------<-",
@ -205,6 +205,7 @@
"block.create.horizontal_framed_glass_pane": "横型ガラス窓板",
"block.create.hose_pulley": "ホースプーリー",
"block.create.item_drain": "アイテム排液口",
"block.create.item_vault": "UNLOCALIZED: Item Vault",
"block.create.jungle_window": "ジャングルの窓",
"block.create.jungle_window_pane": "ジャングルの窓板",
"block.create.large_cogwheel": "大きな歯車",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 68",
"_": "Missing Localizations: 69",
"_": "->------------------------] Game Elements [------------------------<-",
@ -205,6 +205,7 @@
"block.create.horizontal_framed_glass_pane": "수평 유리판",
"block.create.hose_pulley": "호스 도르래",
"block.create.item_drain": "아이템 배수구",
"block.create.item_vault": "UNLOCALIZED: Item Vault",
"block.create.jungle_window": "정글나무 유리창",
"block.create.jungle_window_pane": "정글나무 유리판",
"block.create.large_cogwheel": "큰 톱니바퀴",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 1795",
"_": "Missing Localizations: 1796",
"_": "->------------------------] Game Elements [------------------------<-",
@ -205,6 +205,7 @@
"block.create.horizontal_framed_glass_pane": "UNLOCALIZED: Horizontal Framed Glass Pane",
"block.create.hose_pulley": "UNLOCALIZED: Hose Pulley",
"block.create.item_drain": "UNLOCALIZED: Item Drain",
"block.create.item_vault": "UNLOCALIZED: Item Vault",
"block.create.jungle_window": "UNLOCALIZED: Jungle Window",
"block.create.jungle_window_pane": "UNLOCALIZED: Jungle Window Pane",
"block.create.large_cogwheel": "Groot Tandwiel",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 44",
"_": "Missing Localizations: 45",
"_": "->------------------------] Game Elements [------------------------<-",
@ -205,6 +205,7 @@
"block.create.horizontal_framed_glass_pane": "Pozioma oprawiona szyba",
"block.create.hose_pulley": "Krążek z wężem",
"block.create.item_drain": "Odpływ",
"block.create.item_vault": "UNLOCALIZED: Item Vault",
"block.create.jungle_window": "Dżunglowe okno",
"block.create.jungle_window_pane": "Dżunglowa szyba okienna",
"block.create.large_cogwheel": "Duże koło zębate",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 1644",
"_": "Missing Localizations: 1645",
"_": "->------------------------] Game Elements [------------------------<-",
@ -205,6 +205,7 @@
"block.create.horizontal_framed_glass_pane": "UNLOCALIZED: Horizontal Framed Glass Pane",
"block.create.hose_pulley": "Polia de Mangueira",
"block.create.item_drain": "Dreno de Item",
"block.create.item_vault": "UNLOCALIZED: Item Vault",
"block.create.jungle_window": "UNLOCALIZED: Jungle Window",
"block.create.jungle_window_pane": "UNLOCALIZED: Jungle Window Pane",
"block.create.large_cogwheel": "Roda Dentada Grande",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 49",
"_": "Missing Localizations: 50",
"_": "->------------------------] Game Elements [------------------------<-",
@ -205,6 +205,7 @@
"block.create.horizontal_framed_glass_pane": "Горизонтальная обрамлённая стеклянная панель",
"block.create.hose_pulley": "Шкив со шлангом",
"block.create.item_drain": "Предметный осушитель",
"block.create.item_vault": "UNLOCALIZED: Item Vault",
"block.create.jungle_window": "Окно из тропического дерева",
"block.create.jungle_window_pane": "Панель окна из тропического дерева",
"block.create.large_cogwheel": "Большая шестерня",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 48",
"_": "Missing Localizations: 49",
"_": "->------------------------] Game Elements [------------------------<-",
@ -205,6 +205,7 @@
"block.create.horizontal_framed_glass_pane": "竖直边框玻璃板",
"block.create.hose_pulley": "软管滑轮",
"block.create.item_drain": "分液池",
"block.create.item_vault": "UNLOCALIZED: Item Vault",
"block.create.jungle_window": "丛林木窗户",
"block.create.jungle_window_pane": "丛林木窗户板",
"block.create.large_cogwheel": "大齿轮",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 63",
"_": "Missing Localizations: 64",
"_": "->------------------------] Game Elements [------------------------<-",
@ -205,6 +205,7 @@
"block.create.horizontal_framed_glass_pane": "豎直邊框玻璃片",
"block.create.hose_pulley": "軟管滑輪",
"block.create.item_drain": "分液池",
"block.create.item_vault": "UNLOCALIZED: Item Vault",
"block.create.jungle_window": "叢林木窗戶",
"block.create.jungle_window_pane": "叢林木窗戶片",
"block.create.large_cogwheel": "大齒輪",

View file

@ -0,0 +1,3 @@
{
"parent": "create:block/item_vault"
}

View file

@ -0,0 +1,21 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1.0,
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"name": "create:item_vault"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
],
"functions": []
}
]
}

View file

@ -160,6 +160,9 @@ import com.simibubi.create.content.logistics.block.redstone.RedstoneContactBlock
import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkBlock;
import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkGenerator;
import com.simibubi.create.content.logistics.block.redstone.StockpileSwitchBlock;
import com.simibubi.create.content.logistics.block.vault.VaultBlock;
import com.simibubi.create.content.logistics.block.vault.VaultCTBehaviour;
import com.simibubi.create.content.logistics.block.vault.VaultItem;
import com.simibubi.create.content.logistics.item.LecternControllerBlock;
import com.simibubi.create.content.schematics.block.SchematicTableBlock;
import com.simibubi.create.content.schematics.block.SchematicannonBlock;
@ -181,6 +184,7 @@ import com.tterrag.registrate.providers.RegistrateRecipeProvider;
import com.tterrag.registrate.util.entry.BlockEntry;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.Direction.Axis;
import net.minecraft.core.Direction.AxisDirection;
import net.minecraft.data.recipes.ShapedRecipeBuilder;
import net.minecraft.resources.ResourceLocation;
@ -1241,6 +1245,19 @@ public class AllBlocks {
.transform(customItemModel())
.register();
public static final BlockEntry<VaultBlock> ITEM_VAULT = REGISTRATE.block("item_vault", VaultBlock::new)
.initialProperties(SharedProperties::softMetal)
.properties(p -> p.sound(SoundType.NETHERITE_BLOCK))
.blockstate((c, p) -> p.getVariantBuilder(c.get())
.forAllStates(s -> ConfiguredModel.builder()
.modelFile(AssetLookup.standardModel(c, p))
.rotationY(s.getValue(VaultBlock.HORIZONTAL_AXIS) == Axis.X ? 90 : 0)
.build()))
.onRegister(connectedTextures(new VaultCTBehaviour()))
.item(VaultItem::new)
.build()
.register();
public static final BlockEntry<AndesiteFunnelBlock> ANDESITE_FUNNEL =
REGISTRATE.block("andesite_funnel", AndesiteFunnelBlock::new)
.initialProperties(SharedProperties::stone)

View file

@ -13,9 +13,11 @@ import com.simibubi.create.content.palettes.PaletteBlockPattern;
import com.simibubi.create.content.palettes.PaletteBlockPattern.CTs;
import com.simibubi.create.content.palettes.PaletteStoneVariants;
import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry;
import com.simibubi.create.foundation.block.connected.CTSpriteShifter;
import com.simibubi.create.foundation.block.connected.CTSpriteShifter.CTType;
import com.simibubi.create.foundation.block.render.SpriteShiftEntry;
import com.simibubi.create.foundation.block.render.SpriteShifter;
import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.world.item.DyeColor;
@ -58,6 +60,9 @@ public class AllSpriteShifts {
FLUID_TANK = getCT(CTType.CROSS, "fluid_tank"),
CREATIVE_FLUID_TANK = getCT(CTType.CROSS, "creative_fluid_tank");
public static final Couple<CTSpriteShiftEntry> VAULT_TOP = vault("top"), VAULT_FRONT = vault("front"),
VAULT_SIDE = vault("side"), VAULT_BOTTOM = vault("bottom");
public static final SpriteShiftEntry BELT = SpriteShifter.get("block/belt", "block/belt_scroll"),
BELT_OFFSET = SpriteShifter.get("block/belt_offset", "block/belt_scroll"),
BELT_DIAGONAL = SpriteShifter.get("block/belt_diagonal", "block/belt_diagonal_scroll"),
@ -108,6 +113,12 @@ public class AllSpriteShifts {
}
}
static Couple<CTSpriteShiftEntry> vault(String name) {
final String prefixed = "vault_" + name;
return Couple
.createWithContext(b -> getCT(CTSpriteShifter.CTType.CROSS, prefixed, b ? prefixed : prefixed + "_large"));
}
//
static CTSpriteShiftEntry omni(String name) {

View file

@ -163,6 +163,7 @@ import com.simibubi.create.content.logistics.block.redstone.NixieTubeRenderer;
import com.simibubi.create.content.logistics.block.redstone.NixieTubeTileEntity;
import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkTileEntity;
import com.simibubi.create.content.logistics.block.redstone.StockpileSwitchTileEntity;
import com.simibubi.create.content.logistics.block.vault.VaultTileEntity;
import com.simibubi.create.content.logistics.item.LecternControllerRenderer;
import com.simibubi.create.content.logistics.item.LecternControllerTileEntity;
import com.simibubi.create.content.schematics.block.SchematicTableTileEntity;
@ -406,6 +407,11 @@ public class AllTileEntities {
.validBlocks(AllBlocks.MECHANICAL_ARM)
.renderer(() -> ArmRenderer::new)
.register();
public static final TileEntityEntry<VaultTileEntity> ITEM_VAULT = Create.registrate()
.tileEntity("item_vault", VaultTileEntity::new)
.validBlocks(AllBlocks.ITEM_VAULT)
.register();
public static final TileEntityEntry<MechanicalPistonTileEntity> MECHANICAL_PISTON = Create.registrate()
.tileEntity("mechanical_piston", MechanicalPistonTileEntity::new)

View file

@ -29,6 +29,8 @@ import com.simibubi.create.content.contraptions.components.structureMovement.pul
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock;
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankConnectivityHandler;
import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkBlock;
import com.simibubi.create.content.logistics.block.vault.VaultBlock;
import com.simibubi.create.content.logistics.block.vault.VaultConnectivityHandler;
import com.simibubi.create.foundation.config.ContraptionMovementSetting;
import net.minecraft.core.BlockPos;
@ -331,6 +333,8 @@ public class BlockMovementChecks {
.getAxis();
if (state.getBlock() instanceof FluidTankBlock)
return FluidTankConnectivityHandler.isConnected(world, pos, pos.relative(direction));
if (state.getBlock() instanceof VaultBlock)
return VaultConnectivityHandler.isConnected(world, pos, pos.relative(direction));
if (AllBlocks.STICKER.has(state) && state.getValue(StickerBlock.EXTENDED)) {
return direction == state.getValue(StickerBlock.FACING)
&& !isNotSupportive(world.getBlockState(pos.relative(direction)), direction.getOpposite());

View file

@ -59,6 +59,7 @@ import com.simibubi.create.content.contraptions.relays.belt.BeltBlock;
import com.simibubi.create.content.logistics.block.inventories.AdjustableCrateBlock;
import com.simibubi.create.content.logistics.block.inventories.CreativeCrateTileEntity;
import com.simibubi.create.content.logistics.block.redstone.RedstoneContactBlock;
import com.simibubi.create.content.logistics.block.vault.VaultTileEntity;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.fluid.CombinedTankWrapper;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
@ -656,7 +657,8 @@ public abstract class Contraption {
nbt.remove("y");
nbt.remove("z");
if (tileentity instanceof FluidTankTileEntity && nbt.contains("Controller"))
if ((tileentity instanceof FluidTankTileEntity || tileentity instanceof VaultTileEntity)
&& nbt.contains("Controller"))
nbt.put("Controller",
NbtUtils.writeBlockPos(toLocalPos(NbtUtils.readBlockPos(nbt.getCompound("Controller")))));

View file

@ -0,0 +1,177 @@
package com.simibubi.create.content.logistics.block.vault;
import javax.annotation.Nullable;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
import com.simibubi.create.foundation.block.ITE;
import com.simibubi.create.foundation.item.ItemHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.core.Direction.AxisDirection;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition.Builder;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraftforge.common.util.ForgeSoundType;
import net.minecraftforge.items.CapabilityItemHandler;
public class VaultBlock extends Block implements IWrenchable, ITE<VaultTileEntity> {
public static final Property<Axis> HORIZONTAL_AXIS = BlockStateProperties.HORIZONTAL_AXIS;
public static final BooleanProperty LARGE = BooleanProperty.create("large");
public VaultBlock(Properties p_i48440_1_) {
super(p_i48440_1_);
registerDefaultState(defaultBlockState().setValue(LARGE, false));
}
@Override
protected void createBlockStateDefinition(Builder<Block, BlockState> pBuilder) {
pBuilder.add(HORIZONTAL_AXIS, LARGE);
super.createBlockStateDefinition(pBuilder);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext pContext) {
if (pContext.getPlayer() == null || !pContext.getPlayer()
.isSteppingCarefully()) {
BlockState placedOn = pContext.getLevel()
.getBlockState(pContext.getClickedPos()
.relative(pContext.getClickedFace()
.getOpposite()));
Axis preferredAxis = getVaultBlockAxis(placedOn);
if (preferredAxis != null)
return this.defaultBlockState()
.setValue(HORIZONTAL_AXIS, preferredAxis);
}
return this.defaultBlockState()
.setValue(HORIZONTAL_AXIS, pContext.getHorizontalDirection()
.getAxis());
}
@Override
public void onPlace(BlockState pState, Level pLevel, BlockPos pPos, BlockState pOldState, boolean pIsMoving) {
if (pOldState.getBlock() == pState.getBlock())
return;
if (pIsMoving)
return;
withTileEntityDo(pLevel, pPos, VaultTileEntity::updateConnectivity);
}
@Override
public InteractionResult onWrenched(BlockState state, UseOnContext context) {
if (context.getClickedFace()
.getAxis()
.isVertical()) {
BlockEntity te = context.getLevel()
.getBlockEntity(context.getClickedPos());
if (te instanceof VaultTileEntity) {
VaultTileEntity vault = (VaultTileEntity) te;
VaultConnectivityHandler.splitVault(vault);
vault.removeController(true);
}
state = state.setValue(LARGE, false);
}
InteractionResult onWrenched = IWrenchable.super.onWrenched(state, context);
return onWrenched;
}
@Override
public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean pIsMoving) {
if (state.hasBlockEntity() && (state.getBlock() != newState.getBlock() || !newState.hasBlockEntity())) {
BlockEntity te = world.getBlockEntity(pos);
if (!(te instanceof VaultTileEntity))
return;
VaultTileEntity tankTE = (VaultTileEntity) te;
ItemHelper.dropContents(world, pos, tankTE.inventory);
world.removeBlockEntity(pos);
VaultConnectivityHandler.splitVault(tankTE);
}
}
public static boolean isVault(BlockState state) {
return AllBlocks.ITEM_VAULT.has(state);
}
@Nullable
public static Axis getVaultBlockAxis(BlockState state) {
if (!isVault(state))
return null;
return state.getValue(HORIZONTAL_AXIS);
}
public static boolean isLarge(BlockState state) {
if (!isVault(state))
return false;
return state.getValue(LARGE);
}
@Override
public BlockState rotate(BlockState state, Rotation rot) {
Axis axis = state.getValue(HORIZONTAL_AXIS);
return state.setValue(HORIZONTAL_AXIS, rot.rotate(Direction.fromAxisAndDirection(axis, AxisDirection.POSITIVE))
.getAxis());
}
@Override
public BlockState mirror(BlockState state, Mirror mirrorIn) {
return state;
}
// Vaults are less noisy when placed in batch
public static final SoundType SILENCED_METAL =
new ForgeSoundType(0.1F, 1.5F, () -> SoundEvents.NETHERITE_BLOCK_BREAK, () -> SoundEvents.NETHERITE_BLOCK_STEP,
() -> SoundEvents.NETHERITE_BLOCK_PLACE, () -> SoundEvents.NETHERITE_BLOCK_HIT,
() -> SoundEvents.NETHERITE_BLOCK_FALL);
@Override
public SoundType getSoundType(BlockState state, LevelReader world, BlockPos pos, Entity entity) {
SoundType soundType = super.getSoundType(state, world, pos, entity);
if (entity != null && entity.getPersistentData()
.contains("SilenceVaultSound"))
return SILENCED_METAL;
return soundType;
}
@Override
public boolean hasAnalogOutputSignal(BlockState p_149740_1_) {
return true;
}
@Override
public int getAnalogOutputSignal(BlockState pState, Level pLevel, BlockPos pPos) {
return getTileEntityOptional(pLevel, pPos)
.map(vte -> vte.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY))
.map(lo -> lo.map(ItemHelper::calcRedstoneFromInventory)
.orElse(0))
.orElse(0);
}
@Override
public BlockEntityType<? extends VaultTileEntity> getTileEntityType() {
return AllTileEntities.ITEM_VAULT.get();
}
@Override
public Class<VaultTileEntity> getTileEntityClass() {
return VaultTileEntity.class;
}
}

View file

@ -0,0 +1,68 @@
package com.simibubi.create.content.logistics.block.vault;
import com.simibubi.create.AllSpriteShifts;
import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry;
import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.core.Direction.AxisDirection;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
public class VaultCTBehaviour extends ConnectedTextureBehaviour {
@Override
public CTSpriteShiftEntry get(BlockState state, Direction direction) {
Axis vaultBlockAxis = VaultBlock.getVaultBlockAxis(state);
boolean small = !VaultBlock.isLarge(state);
if (vaultBlockAxis == null)
return null;
if (direction.getAxis() == vaultBlockAxis)
return AllSpriteShifts.VAULT_FRONT.get(small);
if (direction == Direction.UP)
return AllSpriteShifts.VAULT_TOP.get(small);
if (direction == Direction.DOWN)
return AllSpriteShifts.VAULT_BOTTOM.get(small);
return AllSpriteShifts.VAULT_SIDE.get(small);
}
@Override
protected Direction getUpDirection(BlockAndTintGetter reader, BlockPos pos, BlockState state, Direction face) {
Axis vaultBlockAxis = VaultBlock.getVaultBlockAxis(state);
boolean alongX = vaultBlockAxis == Axis.X;
if (face.getAxis()
.isVertical() && alongX)
return super.getUpDirection(reader, pos, state, face).getClockWise();
if (face.getAxis() == vaultBlockAxis || face.getAxis()
.isVertical())
return super.getUpDirection(reader, pos, state, face);
return Direction.fromAxisAndDirection(vaultBlockAxis, alongX ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE);
}
@Override
protected Direction getRightDirection(BlockAndTintGetter reader, BlockPos pos, BlockState state, Direction face) {
Axis vaultBlockAxis = VaultBlock.getVaultBlockAxis(state);
if (face.getAxis()
.isVertical() && vaultBlockAxis == Axis.X)
return super.getRightDirection(reader, pos, state, face).getClockWise();
if (face.getAxis() == vaultBlockAxis || face.getAxis()
.isVertical())
return super.getRightDirection(reader, pos, state, face);
return Direction.fromAxisAndDirection(Axis.Y, face.getAxisDirection());
}
public boolean buildContextForOccludedDirections() {
return super.buildContextForOccludedDirections();
}
@Override
public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos,
BlockPos otherPos, Direction face) {
return state == other && VaultConnectivityHandler.isConnected(reader, pos, otherPos);
}
}

View file

@ -0,0 +1,329 @@
package com.simibubi.create.content.logistics.block.vault;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.PriorityQueue;
import java.util.Set;
import javax.annotation.Nullable;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.core.Direction.AxisDirection;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
public class VaultConnectivityHandler {
public static void formVaults(VaultTileEntity te) {
VaultSearchCache cache = new VaultSearchCache();
List<VaultTileEntity> frontier = new ArrayList<>();
frontier.add(te);
formVaults(te.getType(), te.getLevel(), cache, frontier);
}
private static void formVaults(BlockEntityType<?> type, BlockGetter world, VaultSearchCache cache,
List<VaultTileEntity> frontier) {
PriorityQueue<Pair<Integer, VaultTileEntity>> creationQueue = makeCreationQueue();
Set<BlockPos> visited = new HashSet<>();
int minY = Integer.MAX_VALUE;
for (VaultTileEntity fluidTankTileEntity : frontier) {
BlockPos pos = fluidTankTileEntity.getBlockPos();
minY = Math.min(pos.getY(), minY);
}
minY -= 3;
while (!frontier.isEmpty()) {
VaultTileEntity tank = frontier.remove(0);
BlockPos tankPos = tank.getBlockPos();
if (visited.contains(tankPos))
continue;
visited.add(tankPos);
int amount = tryToFormNewVault(tank, cache, true);
if (amount > 1)
creationQueue.add(Pair.of(amount, tank));
for (Axis axis : Iterate.axes) {
Direction d = Direction.fromAxisAndDirection(axis, AxisDirection.NEGATIVE);
BlockPos next = tankPos.relative(d);
if (next.getY() <= minY)
continue;
if (visited.contains(next))
continue;
VaultTileEntity nextTank = vaultAt(type, world, next);
if (nextTank == null)
continue;
if (nextTank.isRemoved())
continue;
frontier.add(nextTank);
}
}
visited.clear();
while (!creationQueue.isEmpty()) {
Pair<Integer, VaultTileEntity> next = creationQueue.poll();
VaultTileEntity toCreate = next.getValue();
if (visited.contains(toCreate.getBlockPos()))
continue;
visited.add(toCreate.getBlockPos());
tryToFormNewVault(toCreate, cache, false);
}
}
public static void splitVault(VaultTileEntity te) {
splitVaultAndInvalidate(te, null, false);
}
private static int tryToFormNewVault(VaultTileEntity te, VaultSearchCache cache, boolean simulate) {
int bestWidth = 1;
int bestAmount = -1;
if (!te.isController())
return 0;
for (int w = 1; w <= 3; w++) {
int amount = tryToFormNewVaultOfRadius(te, w, cache, true);
if (amount < bestAmount)
continue;
bestWidth = w;
bestAmount = amount;
}
if (!simulate) {
if (te.radius == bestWidth && te.radius * te.radius * te.length == bestAmount)
return bestAmount;
splitVaultAndInvalidate(te, cache, false);
tryToFormNewVaultOfRadius(te, bestWidth, cache, simulate);
te.updateConnectivity = false;
te.radius = bestWidth;
te.length = bestAmount / bestWidth / bestWidth;
BlockState state = te.getBlockState();
if (VaultBlock.isVault(state))
te.getLevel()
.setBlock(te.getBlockPos(), state.setValue(VaultBlock.LARGE, te.radius > 2), 22);
te.itemCapability.invalidate();
te.setChanged();
}
return bestAmount;
}
private static int tryToFormNewVaultOfRadius(VaultTileEntity te, int width, VaultSearchCache cache,
boolean simulate) {
int amount = 0;
int height = 0;
BlockEntityType<?> type = te.getType();
Level world = te.getLevel();
BlockPos origin = te.getBlockPos();
boolean alongZ = VaultBlock.getVaultBlockAxis(te.getBlockState()) == Axis.Z;
Search:
for (int yOffset = 0; yOffset < VaultTileEntity.getMaxLength(width); yOffset++) {
for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos pos =
alongZ ? origin.offset(xOffset, zOffset, yOffset) : origin.offset(yOffset, xOffset, zOffset);
Optional<VaultTileEntity> tank = cache.getOrCache(type, world, pos);
if (!tank.isPresent())
break Search;
VaultTileEntity controller = tank.get();
int otherWidth = controller.radius;
if (otherWidth > width)
break Search;
if (otherWidth == width && controller.length == VaultTileEntity.getMaxLength(width))
break Search;
if ((VaultBlock.getVaultBlockAxis(controller.getBlockState()) == Axis.Z) != alongZ)
break Search;
BlockPos controllerPos = controller.getBlockPos();
if (!controllerPos.equals(origin)) {
if (alongZ && controllerPos.getX() < origin.getX())
break Search;
if (controllerPos.getY() < origin.getY())
break Search;
if (!alongZ && controllerPos.getZ() < origin.getZ())
break Search;
if (alongZ && controllerPos.getX() + otherWidth > origin.getX() + width)
break Search;
if (controllerPos.getY() + otherWidth > origin.getY() + width)
break Search;
if (!alongZ && controllerPos.getZ() + otherWidth > origin.getZ() + width)
break Search;
}
}
}
amount += width * width;
height++;
}
if (simulate)
return amount;
for (int yOffset = 0; yOffset < height; yOffset++) {
for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos pos =
alongZ ? origin.offset(xOffset, zOffset, yOffset) : origin.offset(yOffset, xOffset, zOffset);
VaultTileEntity tank = vaultAt(type, world, pos);
if (tank == te)
continue;
splitVaultAndInvalidate(tank, cache, false);
tank.setController(origin);
tank.updateConnectivity = false;
cache.put(pos, te);
BlockState state = world.getBlockState(pos);
if (!VaultBlock.isVault(state))
continue;
state = state.setValue(VaultBlock.LARGE, width > 2);
world.setBlock(pos, state, 22);
}
}
}
return amount;
}
private static void splitVaultAndInvalidate(VaultTileEntity te, @Nullable VaultSearchCache cache,
boolean tryReconnect) {
// tryReconnect helps whenever only few tanks have been removed
te = te.getControllerTE();
if (te == null)
return;
int height = te.length;
int width = te.radius;
BlockState state = te.getBlockState();
boolean alongZ = VaultBlock.getVaultBlockAxis(state) == Axis.Z;
if (width == 1 && height == 1)
return;
Level world = te.getLevel();
BlockPos origin = te.getBlockPos();
List<VaultTileEntity> frontier = new ArrayList<>();
for (int yOffset = 0; yOffset < height; yOffset++) {
for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos pos =
alongZ ? origin.offset(xOffset, zOffset, yOffset) : origin.offset(yOffset, xOffset, zOffset);
VaultTileEntity tankAt = vaultAt(te.getType(), world, pos);
if (tankAt == null)
continue;
if (!tankAt.getController()
.equals(origin))
continue;
tankAt.removeController(true);
if (tryReconnect) {
frontier.add(tankAt);
tankAt.updateConnectivity = false;
}
if (cache != null)
cache.put(pos, tankAt);
}
}
}
te.itemCapability.invalidate();
if (tryReconnect)
formVaults(te.getType(), world, cache == null ? new VaultSearchCache() : cache, frontier);
}
private static PriorityQueue<Pair<Integer, VaultTileEntity>> makeCreationQueue() {
return new PriorityQueue<>(new Comparator<Pair<Integer, VaultTileEntity>>() {
@Override
public int compare(Pair<Integer, VaultTileEntity> o1, Pair<Integer, VaultTileEntity> o2) {
return o2.getKey() - o1.getKey();
}
});
}
@Nullable
public static VaultTileEntity vaultAt(BlockEntityType<?> type, BlockGetter world, BlockPos pos) {
BlockEntity te = world.getBlockEntity(pos);
if (te instanceof VaultTileEntity && te.getType() == type)
return (VaultTileEntity) te;
return null;
}
private static class VaultSearchCache {
Map<BlockPos, Optional<VaultTileEntity>> controllerMap;
public VaultSearchCache() {
controllerMap = new HashMap<>();
}
void put(BlockPos pos, VaultTileEntity target) {
controllerMap.put(pos, Optional.of(target));
}
void putEmpty(BlockPos pos) {
controllerMap.put(pos, Optional.empty());
}
boolean hasVisited(BlockPos pos) {
return controllerMap.containsKey(pos);
}
Optional<VaultTileEntity> getOrCache(BlockEntityType<?> type, BlockGetter world, BlockPos pos) {
if (hasVisited(pos))
return controllerMap.get(pos);
VaultTileEntity tankAt = vaultAt(type, world, pos);
if (tankAt == null) {
putEmpty(pos);
return Optional.empty();
}
VaultTileEntity controller = tankAt.getControllerTE();
if (controller == null) {
putEmpty(pos);
return Optional.empty();
}
put(pos, controller);
return Optional.of(controller);
}
}
public static boolean isConnected(BlockGetter world, BlockPos tankPos, BlockPos otherTankPos) {
BlockEntity te1 = world.getBlockEntity(tankPos);
BlockEntity te2 = world.getBlockEntity(otherTankPos);
if (!(te1 instanceof VaultTileEntity) || !(te2 instanceof VaultTileEntity))
return false;
return ((VaultTileEntity) te1).getController()
.equals(((VaultTileEntity) te2).getController());
}
}

View file

@ -0,0 +1,128 @@
package com.simibubi.create.content.logistics.block.vault;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.core.Direction.AxisDirection;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
public class VaultItem extends BlockItem {
public VaultItem(Block p_i48527_1_, Properties p_i48527_2_) {
super(p_i48527_1_, p_i48527_2_);
}
@Override
public InteractionResult place(BlockPlaceContext ctx) {
InteractionResult initialResult = super.place(ctx);
if (!initialResult.consumesAction())
return initialResult;
tryMultiPlace(ctx);
return initialResult;
}
@Override
protected boolean updateCustomBlockEntityTag(BlockPos p_195943_1_, Level p_195943_2_, Player p_195943_3_,
ItemStack p_195943_4_, BlockState p_195943_5_) {
MinecraftServer minecraftserver = p_195943_2_.getServer();
if (minecraftserver == null)
return false;
CompoundTag nbt = p_195943_4_.getTagElement("BlockEntityTag");
if (nbt != null) {
nbt.remove("Length");
nbt.remove("Size");
nbt.remove("Controller");
nbt.remove("LastKnownPos");
}
return super.updateCustomBlockEntityTag(p_195943_1_, p_195943_2_, p_195943_3_, p_195943_4_, p_195943_5_);
}
private void tryMultiPlace(BlockPlaceContext ctx) {
Player player = ctx.getPlayer();
if (player == null)
return;
if (player.isSteppingCarefully())
return;
Direction face = ctx.getClickedFace();
ItemStack stack = ctx.getItemInHand();
Level world = ctx.getLevel();
BlockPos pos = ctx.getClickedPos();
BlockPos placedOnPos = pos.relative(face.getOpposite());
BlockState placedOnState = world.getBlockState(placedOnPos);
if (!VaultBlock.isVault(placedOnState))
return;
VaultTileEntity tankAt = VaultConnectivityHandler.vaultAt(AllTileEntities.ITEM_VAULT.get(), world, placedOnPos);
if (tankAt == null)
return;
VaultTileEntity controllerTE = tankAt.getControllerTE();
if (controllerTE == null)
return;
int width = controllerTE.radius;
if (width == 1)
return;
int tanksToPlace = 0;
Axis vaultBlockAxis = VaultBlock.getVaultBlockAxis(placedOnState);
if (vaultBlockAxis == null)
return;
if (face.getAxis() != vaultBlockAxis)
return;
Direction vaultFacing = Direction.fromAxisAndDirection(vaultBlockAxis, AxisDirection.POSITIVE);
BlockPos startPos = face == vaultFacing.getOpposite() ? controllerTE.getBlockPos()
.relative(vaultFacing.getOpposite())
: controllerTE.getBlockPos()
.relative(vaultFacing, controllerTE.length);
if (VecHelper.getCoordinate(startPos, vaultBlockAxis) != VecHelper.getCoordinate(pos, vaultBlockAxis))
return;
for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos offsetPos = vaultBlockAxis == Axis.X ? startPos.offset(0, xOffset, zOffset)
: startPos.offset(xOffset, zOffset, 0);
BlockState blockState = world.getBlockState(offsetPos);
if (VaultBlock.isVault(blockState))
continue;
if (!blockState.getMaterial()
.isReplaceable())
return;
tanksToPlace++;
}
}
if (!player.isCreative() && stack.getCount() < tanksToPlace)
return;
for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos offsetPos = vaultBlockAxis == Axis.X ? startPos.offset(0, xOffset, zOffset)
: startPos.offset(xOffset, zOffset, 0);
BlockState blockState = world.getBlockState(offsetPos);
if (VaultBlock.isVault(blockState))
continue;
BlockPlaceContext context = BlockPlaceContext.at(ctx, offsetPos, face);
player.getPersistentData()
.putBoolean("SilenceVaultSound", true);
super.place(context);
player.getPersistentData()
.remove("SilenceVaultSound");
}
}
}
}

View file

@ -0,0 +1,245 @@
package com.simibubi.create.content.logistics.block.vault;
import java.util.List;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.wrapper.CombinedInvWrapper;
public class VaultTileEntity extends SmartTileEntity {
protected LazyOptional<IItemHandler> itemCapability;
protected ItemStackHandler inventory;
protected BlockPos controller;
protected BlockPos lastKnownPos;
protected boolean updateConnectivity;
protected int radius;
protected int length;
protected Axis axis;
public VaultTileEntity(BlockEntityType<?> tileEntityTypeIn, BlockPos pos, BlockState state) {
super(tileEntityTypeIn, pos, state);
inventory = new ItemStackHandler(AllConfigs.SERVER.logistics.vaultCapacity.get()) {
@Override
protected void onContentsChanged(int slot) {
super.onContentsChanged(slot);
updateComparators();
}
};
itemCapability = LazyOptional.empty();
radius = 1;
length = 1;
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {}
protected void updateConnectivity() {
updateConnectivity = false;
if (level.isClientSide())
return;
if (!isController())
return;
VaultConnectivityHandler.formVaults(this);
}
protected void updateComparators() {
VaultTileEntity controllerTE = getControllerTE();
if (controllerTE == null)
return;
BlockPos pos = controllerTE.getBlockPos();
for (int y = 0; y < controllerTE.radius; y++) {
for (int z = 0; z < (controllerTE.axis == Axis.X ? controllerTE.radius : controllerTE.length); z++) {
for (int x = 0; x < (controllerTE.axis == Axis.Z ? controllerTE.radius : controllerTE.length); x++) {
level.updateNeighbourForOutputSignal(pos.offset(x, y, z), getBlockState().getBlock());
}
}
}
}
@Override
public void tick() {
super.tick();
if (lastKnownPos == null)
lastKnownPos = getBlockPos();
else if (!lastKnownPos.equals(worldPosition) && worldPosition != null) {
onPositionChanged();
return;
}
if (updateConnectivity)
updateConnectivity();
}
public boolean isController() {
return controller == null || worldPosition.getX() == controller.getX()
&& worldPosition.getY() == controller.getY() && worldPosition.getZ() == controller.getZ();
}
private void onPositionChanged() {
removeController(true);
lastKnownPos = worldPosition;
}
public VaultTileEntity getControllerTE() {
if (isController())
return this;
BlockEntity tileEntity = level.getBlockEntity(controller);
if (tileEntity instanceof VaultTileEntity)
return (VaultTileEntity) tileEntity;
return null;
}
public void removeController(boolean keepContents) {
if (level.isClientSide())
return;
updateConnectivity = true;
controller = null;
radius = 1;
length = 1;
BlockState state = getBlockState();
if (VaultBlock.isVault(state)) {
state = state.setValue(VaultBlock.LARGE, false);
getLevel().setBlock(worldPosition, state, 22);
}
itemCapability.invalidate();
setChanged();
sendData();
}
public void setController(BlockPos controller) {
if (level.isClientSide())
return;
if (controller.equals(this.controller))
return;
this.controller = controller;
itemCapability.invalidate();
setChanged();
sendData();
}
public BlockPos getController() {
return isController() ? worldPosition : controller;
}
@Override
protected void fromTag(CompoundTag compound, boolean clientPacket) {
super.fromTag(compound, clientPacket);
BlockPos controllerBefore = controller;
int prevSize = radius;
int prevLength = length;
updateConnectivity = compound.contains("Uninitialized");
controller = null;
lastKnownPos = null;
if (compound.contains("LastKnownPos"))
lastKnownPos = NbtUtils.readBlockPos(compound.getCompound("LastKnownPos"));
if (compound.contains("Controller"))
controller = NbtUtils.readBlockPos(compound.getCompound("Controller"));
if (isController()) {
radius = compound.getInt("Size");
length = compound.getInt("Length");
}
if (!clientPacket) {
inventory.deserializeNBT(compound.getCompound("Inventory"));
return;
}
boolean changeOfController =
controllerBefore == null ? controller != null : !controllerBefore.equals(controller);
if (hasLevel() && (changeOfController || prevSize != radius || prevLength != length))
level.setBlocksDirty(getBlockPos(), Blocks.AIR.defaultBlockState(), getBlockState());
}
@Override
protected void write(CompoundTag compound, boolean clientPacket) {
if (updateConnectivity)
compound.putBoolean("Uninitialized", true);
if (lastKnownPos != null)
compound.put("LastKnownPos", NbtUtils.writeBlockPos(lastKnownPos));
if (!isController())
compound.put("Controller", NbtUtils.writeBlockPos(controller));
if (isController()) {
compound.putInt("Size", radius);
compound.putInt("Length", length);
}
super.write(compound, clientPacket);
if (!clientPacket)
compound.put("Inventory", inventory.serializeNBT());
}
@Override
public <T> LazyOptional<T> getCapability(Capability<T> cap, Direction side) {
if (isItemHandlerCap(cap)) {
initCapability();
return itemCapability.cast();
}
return super.getCapability(cap, side);
}
private void initCapability() {
if (itemCapability.isPresent())
return;
if (!isController()) {
VaultTileEntity controllerTE = getControllerTE();
if (controllerTE == null)
return;
controllerTE.initCapability();
itemCapability = controllerTE.itemCapability;
return;
}
boolean alongZ = VaultBlock.getVaultBlockAxis(getBlockState()) == Axis.Z;
IItemHandlerModifiable[] invs = new IItemHandlerModifiable[length * radius * radius];
for (int yOffset = 0; yOffset < length; yOffset++) {
for (int xOffset = 0; xOffset < radius; xOffset++) {
for (int zOffset = 0; zOffset < radius; zOffset++) {
BlockPos vaultPos = alongZ ? worldPosition.offset(xOffset, zOffset, yOffset)
: worldPosition.offset(yOffset, xOffset, zOffset);
VaultTileEntity vaultAt =
VaultConnectivityHandler.vaultAt(AllTileEntities.ITEM_VAULT.get(), level, vaultPos);
invs[yOffset * radius * radius + xOffset * radius + zOffset] =
vaultAt != null ? vaultAt.inventory : new ItemStackHandler();
}
}
}
CombinedInvWrapper combinedInvWrapper = new CombinedInvWrapper(invs);
itemCapability = LazyOptional.of(() -> combinedInvWrapper);
}
public static int getMaxLength(int radius) {
return radius * 3;
}
}

View file

@ -7,6 +7,7 @@ public class CLogistics extends ConfigBase {
public final ConfigInt psiTimeout = i(20, 1, "psiTimeout", Comments.psiTimeout);
public final ConfigInt mechanicalArmRange = i(5, 1, "mechanicalArmRange", Comments.mechanicalArmRange);
public final ConfigInt linkRange = i(128, 1, "linkRange", Comments.linkRange);
public final ConfigInt vaultCapacity = i(27, 1, "vaultCapacity", Comments.vaultCapacity);
@Override
public String getName() {
@ -22,6 +23,7 @@ public class CLogistics extends ConfigBase {
static String psiTimeout =
"The amount of ticks a portable storage interface waits for transfers until letting contraptions move along.";
static String mechanicalArmRange = "Maximum distance in blocks a Mechanical Arm can reach across.";
static String vaultCapacity = "The total amount of stacks a vault can hold per block in size.";
}
}

View file

@ -30,6 +30,10 @@ public class Couple<T> extends Pair<T, T> implements Iterable<T> {
return new Couple<>(factory.get(), factory.get());
}
public static <T> Couple<T> createWithContext(Function<Boolean, T> factory) {
return new Couple<>(factory.apply(true), factory.apply(false));
}
public T get(boolean first) {
return first ? getFirst() : getSecond();
}

View file

@ -0,0 +1,32 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"0": "create:block/vault_bottom",
"1": "create:block/vault_front",
"2": "create:block/vault_side",
"3": "create:block/vault_top",
"particle": "create:block/vault_bottom"
},
"elements": [
{
"from": [0, 0, 0],
"to": [16, 16, 16],
"faces": {
"north": {"uv": [0, 0, 16, 16], "texture": "#1"},
"east": {"uv": [0, 0, 16, 16], "rotation": 90, "texture": "#2"},
"south": {"uv": [0, 0, 16, 16], "texture": "#1"},
"west": {"uv": [0, 16, 16, 0], "rotation": 90, "texture": "#2"},
"up": {"uv": [0, 0, 16, 16], "texture": "#3"},
"down": {"uv": [0, 0, 16, 16], "texture": "#0"}
}
}
],
"display": {
"gui": {
"rotation": [ 30, 135, 0 ],
"translation": [ 0, 0, 0],
"scale":[ 0.625, 0.625, 0.625 ]
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB