mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-16 18:53:41 +01:00
More unfinished basin business
- Fixed players flailing their limbs around while standing still on a moving contraption - Attempted to reduce drag of remote player positions while on a contraption - Contraptions no longer log out with the player riding them - Attribute filters are now made of brass - Added the ability to disable auto-compat with vanilla recipe types in the configs - Added a recipe type for custom basin/press compacting - Basins can now process items and liquids in recipes - Input items/fluids of a basin can now be extracted or reused in further processing - A basin diagonally below another basin with collect outputs of recipes processed in the top basin for ease of automation - (Temporary debug recipes)
This commit is contained in:
parent
b14e94929c
commit
378164b8b9
63 changed files with 1685 additions and 716 deletions
|
@ -18,7 +18,7 @@ a579c40c43dc2174afb66f42d00d0c4a0efaaeee assets/create/blockstates/andesite_bric
|
|||
11908c2f8603e61bec88010bc6d0890e6339c6b1 assets/create/blockstates/andesite_funnel.json
|
||||
398922758a6219544e5b85c91c9cf8a543b437e5 assets/create/blockstates/andesite_pillar.json
|
||||
1d2d8081581e07d9be4b382aede4f2de4401cc6b assets/create/blockstates/andesite_tunnel.json
|
||||
f9fa6aa530eb0891a74eadfbebc663172a57147a assets/create/blockstates/basin.json
|
||||
e555e3c2b2d3f01440e48db4ba88f7e00fd99b6f assets/create/blockstates/basin.json
|
||||
f25693a9429f6337149ff24f27900dc4eb82a7c2 assets/create/blockstates/belt.json
|
||||
cf9045eb16e5299a1d917c4cb536289f49411276 assets/create/blockstates/birch_window.json
|
||||
94a1a91403eb4b035fec48071e7fcae57a8a6abd assets/create/blockstates/birch_window_pane.json
|
||||
|
@ -1045,7 +1045,7 @@ b0f664dd6de3d0ee9afcb6223fbcd53b97fa0d65 assets/create/models/item/andesite_cobb
|
|||
7490819e7e5445019b6b8cb2538f12a5b6717a46 assets/create/models/item/andesite_funnel.json
|
||||
75b8b00c2418b9660d35a7fabd0774925cf1c02f assets/create/models/item/andesite_pillar.json
|
||||
c0e35daccfb398947532e9499d6bda963387cd9c assets/create/models/item/andesite_tunnel.json
|
||||
bf1fc6bdf7fca6f1958a2d3e96202c1cecb50669 assets/create/models/item/basin.json
|
||||
421e481b7fbca4c4a1080ed703401eb25375e087 assets/create/models/item/basin.json
|
||||
1da382e7e58eaa9788f5b1d92221ccac573e068f assets/create/models/item/belt_connector.json
|
||||
9044243882cfd49a2827e1b910a4c9b0e46daa47 assets/create/models/item/birch_window.json
|
||||
6ed49f59ea91068ef68720f43e67a9237594bdf0 assets/create/models/item/birch_window_pane.json
|
||||
|
@ -1481,7 +1481,7 @@ d531f87f425d199aee4777a588c1cd6cab6f5173 data/create/advancements/recipes/create
|
|||
2eef3201017af03f6a2f0f015645e3ff5e25d9c1 data/create/advancements/recipes/create.base/crafting/curiosities/wand_of_symmetry.json
|
||||
d97d96e1b2ddd25df15fe1ef1c3d084f15bb9789 data/create/advancements/recipes/create.base/crafting/kinetics/adjustable_pulley.json
|
||||
92416ced6ede6965fd728e1c7336bb05a3e41ea2 data/create/advancements/recipes/create.base/crafting/kinetics/analog_lever.json
|
||||
2105b4f1fd9a170a100efc083a794fdb9e068924 data/create/advancements/recipes/create.base/crafting/kinetics/attribute_filter.json
|
||||
3e9753006da898d4569bbeabf95997e8c90847c8 data/create/advancements/recipes/create.base/crafting/kinetics/attribute_filter.json
|
||||
bec8c280b717306f87050b08a418feab53be71cb data/create/advancements/recipes/create.base/crafting/kinetics/basin.json
|
||||
5af08853632fb5970fe542b3ecbde0ad16d64714 data/create/advancements/recipes/create.base/crafting/kinetics/belt_connector.json
|
||||
80d87f1dde60adb5334e0cff25a9f0b7f67c1526 data/create/advancements/recipes/create.base/crafting/kinetics/black_seat.json
|
||||
|
@ -2428,6 +2428,8 @@ d9021504be855cd2d4d91503a82b84233052adb0 data/create/recipes/blasting/gold_ingot
|
|||
c323b106e88b7de77fea71ff12494abdbb818d15 data/create/recipes/chiseled_limestone_from_limestone_stonecutting.json
|
||||
da9a919b476954c1de34826aa7706bf6056a8f12 data/create/recipes/chiseled_scoria_from_scoria_stonecutting.json
|
||||
09faa4ddcf9f3907dcdb3ab3e8b68c1deb2486e5 data/create/recipes/chiseled_weathered_limestone_from_weathered_limestone_stonecutting.json
|
||||
c3cfdc9552a23e4749c42e71fbddd153b76ca708 data/create/recipes/compacting/ice.json
|
||||
5758a1804287c261e1c953bda599d8495ba7c40a data/create/recipes/compacting/temp_gabbro.json
|
||||
19526da3a59fc136654ff1bc93c0251581f397a9 data/create/recipes/crafting/appliances/dough.json
|
||||
7b5f863dda3d05a79cb85943a178eba0bd8a7dc7 data/create/recipes/crafting/appliances/slime_ball.json
|
||||
b159ba84428eee6ef6e23df1766f2a18f2c8a63e data/create/recipes/crafting/appliances/tree_fertilizer.json
|
||||
|
@ -2437,7 +2439,7 @@ b159ba84428eee6ef6e23df1766f2a18f2c8a63e data/create/recipes/crafting/appliances
|
|||
fcbc04d0a7eaf820a74bc7e4736a4a581e0a9dff data/create/recipes/crafting/curiosities/wand_of_symmetry.json
|
||||
696df0fe5f8e29220ea15527f8c119c39b418819 data/create/recipes/crafting/kinetics/adjustable_pulley.json
|
||||
88de51b451469698665b7319e5b9cfb9a87ae3e0 data/create/recipes/crafting/kinetics/analog_lever.json
|
||||
6912101930aae627820783c27358dcf2ff4016aa data/create/recipes/crafting/kinetics/attribute_filter.json
|
||||
cf1f3a6306d47025cebe153cf05949ef69ccbe5a data/create/recipes/crafting/kinetics/attribute_filter.json
|
||||
059d12526529b2896ed583555373afa31839a0de data/create/recipes/crafting/kinetics/basin.json
|
||||
dcf98e667d321fb4bd9fa6dfec7927a84cdbd5d6 data/create/recipes/crafting/kinetics/belt_connector.json
|
||||
1123903a11b13448b61cf8f8a5dc2e8013d39ac0 data/create/recipes/crafting/kinetics/black_seat.json
|
||||
|
@ -2675,6 +2677,7 @@ ddda28bb6efc43b7e3149756daf53e1664187283 data/create/recipes/dolomite_cobbleston
|
|||
500ecdfdcf34e9d26256948e206aab4f0b79e659 data/create/recipes/dolomite_cobblestone_wall_from_dolomite_cobblestone_stonecutting.json
|
||||
ff39e629b242ae91e23aec86b0a1f757dd938305 data/create/recipes/dolomite_pillar.json
|
||||
b4a8d14d9a20e812e0acb691b5b511a87e8b0576 data/create/recipes/dolomite_pillar_from_dolomite_stonecutting.json
|
||||
ae6698363e49f7cb5f2ed52c6b8805bebed31fa2 data/create/recipes/emptying/water_bottle.json
|
||||
0e11aa1accb71ed62e212f23a7069b7b7b4e8119 data/create/recipes/fancy_andesite_bricks_from_andesite_stonecutting.json
|
||||
8b86fc9a9416adeaab3f26192a73a481887675c3 data/create/recipes/fancy_andesite_bricks_slab.json
|
||||
c7b762b25c7a6705dba3e922e981be851ac4f36b data/create/recipes/fancy_andesite_bricks_slab_from_fancy_andesite_bricks_stonecutting.json
|
||||
|
@ -2860,6 +2863,7 @@ e7bfaa806d57573d060fac0a5e7a84f345b8bb85 data/create/recipes/mixing/andesite_all
|
|||
76939e4d3e5b615ae21d14c0ff7b917a622bcf80 data/create/recipes/mixing/chromatic_compound.json
|
||||
d9a3dff1288d675ab812eef1eb73cb27dcc71bd2 data/create/recipes/mixing/crushed_brass.json
|
||||
00b165ea38d834c7955440e87062004a8182c3f8 data/create/recipes/mixing/gunpowder.json
|
||||
35c4e8a765479861f307afb9ec650f912f92b998 data/create/recipes/mixing/temp_cobble.json
|
||||
1998c6f84f871d6da58ec29d729401d18f8f1aa1 data/create/recipes/mossy_andesite_from_andesite_stonecutting.json
|
||||
89929d9cb11b5c589b2ecfa821c61add1ef7b62b data/create/recipes/mossy_dark_scoria_from_dark_scoria_stonecutting.json
|
||||
4b8b1191dd3a21294293dc5ad237af89b849df28 data/create/recipes/mossy_diorite_from_diorite_stonecutting.json
|
||||
|
|
|
@ -1,7 +1,22 @@
|
|||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "create:block/basin"
|
||||
"facing=down": {
|
||||
"model": "create:block/basin/block"
|
||||
},
|
||||
"facing=north": {
|
||||
"model": "create:block/basin/block_directional",
|
||||
"y": 180
|
||||
},
|
||||
"facing=south": {
|
||||
"model": "create:block/basin/block_directional"
|
||||
},
|
||||
"facing=west": {
|
||||
"model": "create:block/basin/block_directional",
|
||||
"y": 90
|
||||
},
|
||||
"facing=east": {
|
||||
"model": "create:block/basin/block_directional",
|
||||
"y": 270
|
||||
}
|
||||
}
|
||||
}
|
|
@ -149,8 +149,8 @@
|
|||
},
|
||||
{
|
||||
"when": {
|
||||
"sticky_north": "true",
|
||||
"axis": "x"
|
||||
"axis": "x",
|
||||
"sticky_north": "true"
|
||||
},
|
||||
"apply": {
|
||||
"model": "create:block/radial_chassis_side_x_sticky"
|
||||
|
@ -158,8 +158,8 @@
|
|||
},
|
||||
{
|
||||
"when": {
|
||||
"sticky_north": "true",
|
||||
"axis": "y"
|
||||
"axis": "y",
|
||||
"sticky_north": "true"
|
||||
},
|
||||
"apply": {
|
||||
"model": "create:block/radial_chassis_side_y_sticky",
|
||||
|
@ -168,8 +168,8 @@
|
|||
},
|
||||
{
|
||||
"when": {
|
||||
"sticky_north": "true",
|
||||
"axis": "z"
|
||||
"axis": "z",
|
||||
"sticky_north": "true"
|
||||
},
|
||||
"apply": {
|
||||
"model": "create:block/radial_chassis_side_x_sticky",
|
||||
|
@ -178,8 +178,8 @@
|
|||
},
|
||||
{
|
||||
"when": {
|
||||
"sticky_north": "false",
|
||||
"axis": "x"
|
||||
"axis": "x",
|
||||
"sticky_north": "false"
|
||||
},
|
||||
"apply": {
|
||||
"model": "create:block/radial_chassis_side_x"
|
||||
|
@ -187,8 +187,8 @@
|
|||
},
|
||||
{
|
||||
"when": {
|
||||
"sticky_north": "false",
|
||||
"axis": "y"
|
||||
"axis": "y",
|
||||
"sticky_north": "false"
|
||||
},
|
||||
"apply": {
|
||||
"model": "create:block/radial_chassis_side_y",
|
||||
|
@ -197,8 +197,8 @@
|
|||
},
|
||||
{
|
||||
"when": {
|
||||
"sticky_north": "false",
|
||||
"axis": "z"
|
||||
"axis": "z",
|
||||
"sticky_north": "false"
|
||||
},
|
||||
"apply": {
|
||||
"model": "create:block/radial_chassis_side_x",
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"parent": "create:block/basin"
|
||||
"parent": "create:block/basin/block"
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
"conditions": {
|
||||
"items": [
|
||||
{
|
||||
"item": "create:andesite_alloy"
|
||||
"tag": "forge:ingots/brass"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"type": "create:compacting",
|
||||
"ingredients": [
|
||||
{
|
||||
"item": "minecraft:ice"
|
||||
}
|
||||
],
|
||||
"results": [
|
||||
{
|
||||
"fluid": "minecraft:water",
|
||||
"amount": 250
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"type": "create:compacting",
|
||||
"ingredients": [
|
||||
{
|
||||
"item": "minecraft:cobblestone"
|
||||
},
|
||||
{
|
||||
"fluidTag": "minecraft:lava",
|
||||
"amount": 250
|
||||
}
|
||||
],
|
||||
"results": [
|
||||
{
|
||||
"item": "create:gabbro",
|
||||
"count": 1
|
||||
}
|
||||
]
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
"tag": "minecraft:wool"
|
||||
},
|
||||
"A": {
|
||||
"tag": "forge:nuggets/copper"
|
||||
"tag": "forge:nuggets/brass"
|
||||
}
|
||||
},
|
||||
"result": {
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"type": "create:emptying",
|
||||
"ingredients": [
|
||||
{
|
||||
"item": "minecraft:potion"
|
||||
}
|
||||
],
|
||||
"results": [
|
||||
{
|
||||
"item": "minecraft:glass_bottle",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"fluid": "minecraft:water",
|
||||
"amount": 250
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"type": "create:mixing",
|
||||
"ingredients": [
|
||||
{
|
||||
"fluidTag": "minecraft:water",
|
||||
"amount": 250
|
||||
},
|
||||
{
|
||||
"fluidTag": "minecraft:lava",
|
||||
"amount": 250
|
||||
}
|
||||
],
|
||||
"results": [
|
||||
{
|
||||
"item": "minecraft:cobblestone",
|
||||
"count": 1
|
||||
}
|
||||
]
|
||||
}
|
|
@ -73,6 +73,7 @@ import com.simibubi.create.content.contraptions.fluids.tank.FluidTankGenerator;
|
|||
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankItem;
|
||||
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankModel;
|
||||
import com.simibubi.create.content.contraptions.processing.BasinBlock;
|
||||
import com.simibubi.create.content.contraptions.processing.BasinGenerator;
|
||||
import com.simibubi.create.content.contraptions.processing.BasinMovementBehaviour;
|
||||
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock;
|
||||
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlockItem;
|
||||
|
@ -408,9 +409,10 @@ public class AllBlocks {
|
|||
|
||||
public static final BlockEntry<BasinBlock> BASIN = REGISTRATE.block("basin", BasinBlock::new)
|
||||
.initialProperties(SharedProperties::stone)
|
||||
.blockstate((ctx, prov) -> prov.simpleBlock(ctx.getEntry(), AssetLookup.standardModel(ctx, prov)))
|
||||
.blockstate(new BasinGenerator()::generate)
|
||||
.onRegister(addMovementBehaviour(new BasinMovementBehaviour()))
|
||||
.simpleItem()
|
||||
.item()
|
||||
.transform(customItemModel("_", "block"))
|
||||
.register();
|
||||
|
||||
public static final BlockEntry<BlazeBurnerBlock> BLAZE_BURNER =
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.simibubi.create;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.simibubi.create.compat.jei.ConversionRecipe;
|
||||
|
@ -7,10 +8,13 @@ import com.simibubi.create.content.contraptions.components.crafter.MechanicalCra
|
|||
import com.simibubi.create.content.contraptions.components.crusher.CrushingRecipe;
|
||||
import com.simibubi.create.content.contraptions.components.fan.SplashingRecipe;
|
||||
import com.simibubi.create.content.contraptions.components.millstone.MillingRecipe;
|
||||
import com.simibubi.create.content.contraptions.components.mixer.CompactingRecipe;
|
||||
import com.simibubi.create.content.contraptions.components.mixer.MixingRecipe;
|
||||
import com.simibubi.create.content.contraptions.components.press.PressingRecipe;
|
||||
import com.simibubi.create.content.contraptions.components.saw.CuttingRecipe;
|
||||
import com.simibubi.create.content.contraptions.fluids.actors.FillingRecipe;
|
||||
import com.simibubi.create.content.contraptions.processing.BasinRecipe;
|
||||
import com.simibubi.create.content.contraptions.processing.EmptyingRecipe;
|
||||
import com.simibubi.create.content.contraptions.processing.ProcessingRecipe;
|
||||
import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeFactory;
|
||||
import com.simibubi.create.content.contraptions.processing.ProcessingRecipeSerializer;
|
||||
|
@ -25,22 +29,26 @@ import net.minecraft.item.crafting.IRecipeType;
|
|||
import net.minecraft.item.crafting.ShapedRecipe;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.event.RegistryEvent;
|
||||
|
||||
public enum AllRecipeTypes {
|
||||
|
||||
BLOCKZAPPER_UPGRADE(BlockzapperUpgradeRecipe.Serializer::new, IRecipeType.CRAFTING),
|
||||
MECHANICAL_CRAFTING(MechanicalCraftingRecipe.Serializer::new),
|
||||
|
||||
|
||||
CONVERSION(processingSerializer(ConversionRecipe::new)),
|
||||
CRUSHING(processingSerializer(CrushingRecipe::new)),
|
||||
CUTTING(processingSerializer(CuttingRecipe::new)),
|
||||
MILLING(processingSerializer(MillingRecipe::new)),
|
||||
BASIN(processingSerializer(BasinRecipe::new)),
|
||||
MIXING(processingSerializer(MixingRecipe::new)),
|
||||
COMPACTING(processingSerializer(CompactingRecipe::new)),
|
||||
PRESSING(processingSerializer(PressingRecipe::new)),
|
||||
SANDPAPER_POLISHING(processingSerializer(SandPaperPolishingRecipe::new)),
|
||||
SPLASHING(processingSerializer(SplashingRecipe::new)),
|
||||
FILLING(processingSerializer(FillingRecipe::new)),
|
||||
EMPTYING(processingSerializer(EmptyingRecipe::new)),
|
||||
|
||||
;
|
||||
|
||||
|
@ -89,4 +97,9 @@ public enum AllRecipeTypes {
|
|||
public <T extends IRecipeType<?>> T getType() {
|
||||
return (T) type;
|
||||
}
|
||||
|
||||
public <C extends IInventory, T extends IRecipe<C>> Optional<T> find(C inv, World world) {
|
||||
return world.getRecipeManager()
|
||||
.getRecipe(getType(), inv, world);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,10 +23,12 @@ import com.simibubi.create.compat.jei.category.PressingCategory;
|
|||
import com.simibubi.create.compat.jei.category.SawingCategory;
|
||||
import com.simibubi.create.compat.jei.category.SmokingViaFanCategory;
|
||||
import com.simibubi.create.compat.jei.category.SplashingCategory;
|
||||
import com.simibubi.create.content.contraptions.components.mixer.MixingRecipe;
|
||||
import com.simibubi.create.content.contraptions.components.press.MechanicalPressTileEntity;
|
||||
import com.simibubi.create.content.contraptions.processing.BasinRecipe;
|
||||
import com.simibubi.create.content.logistics.block.inventories.AdjustableCrateScreen;
|
||||
import com.simibubi.create.content.schematics.block.SchematicannonScreen;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.config.CRecipes;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
|
||||
import mezz.jei.api.IModPlugin;
|
||||
|
@ -96,44 +98,62 @@ public class CreateJEI implements IModPlugin {
|
|||
|
||||
@Override
|
||||
public void registerCategories(IRecipeCategoryRegistration registration) {
|
||||
registration
|
||||
.addRecipeCategories(millingCategory, crushingCategory, splashingCategory, pressingCategory,
|
||||
smokingCategory, blastingCategory, blockzapperCategory, mixingCategory, sawingCategory,
|
||||
blockCuttingCategory, packingCategory, polishingCategory, mysteryConversionCategory,
|
||||
mechanicalCraftingCategory);
|
||||
registration.addRecipeCategories(millingCategory, crushingCategory, splashingCategory, pressingCategory,
|
||||
smokingCategory, blastingCategory, blockzapperCategory, mixingCategory, sawingCategory,
|
||||
blockCuttingCategory, packingCategory, polishingCategory, mysteryConversionCategory,
|
||||
mechanicalCraftingCategory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerRecipes(IRecipeRegistration registration) {
|
||||
CRecipes recipeConfig = AllConfigs.SERVER.recipes;
|
||||
|
||||
registration.addRecipes(findRecipes(AllRecipeTypes.MILLING), millingCategory.getUid());
|
||||
registration.addRecipes(findRecipes(AllRecipeTypes.CRUSHING), crushingCategory.getUid());
|
||||
registration.addRecipes(findRecipesByTypeExcluding(AllRecipeTypes.MILLING.getType(), AllRecipeTypes.CRUSHING.getType()),
|
||||
crushingCategory.getUid());
|
||||
registration.addRecipes(
|
||||
findRecipesByTypeExcluding(AllRecipeTypes.MILLING.getType(), AllRecipeTypes.CRUSHING.getType()),
|
||||
crushingCategory.getUid());
|
||||
registration.addRecipes(findRecipes(AllRecipeTypes.SPLASHING), splashingCategory.getUid());
|
||||
registration.addRecipes(findRecipes(AllRecipeTypes.PRESSING), pressingCategory.getUid());
|
||||
registration.addRecipes(findRecipesById(AllRecipeTypes.BLOCKZAPPER_UPGRADE.serializer.getRegistryName()),
|
||||
blockzapperCategory.getUid());
|
||||
blockzapperCategory.getUid());
|
||||
registration.addRecipes(findRecipesByType(IRecipeType.SMOKING), smokingCategory.getUid());
|
||||
registration.addRecipes(findRecipesByTypeExcluding(IRecipeType.SMELTING, IRecipeType.SMOKING),
|
||||
blastingCategory.getUid());
|
||||
blastingCategory.getUid());
|
||||
registration.addRecipes(findRecipes(AllRecipeTypes.MIXING), mixingCategory.getUid());
|
||||
registration.addRecipes(findRecipes(r -> r.getSerializer() == IRecipeSerializer.CRAFTING_SHAPELESS
|
||||
&& !MechanicalPressTileEntity.canCompress(r.getIngredients())).stream().map(MixingRecipe::convertShapeless)
|
||||
.collect(Collectors.toList()),
|
||||
|
||||
if (recipeConfig.allowShapelessInMixer.get())
|
||||
registration.addRecipes(findRecipes(r -> r.getSerializer() == IRecipeSerializer.CRAFTING_SHAPELESS
|
||||
&& !MechanicalPressTileEntity.canCompress(r.getIngredients())).stream()
|
||||
.map(BasinRecipe::convert)
|
||||
.collect(Collectors.toList()),
|
||||
mixingCategory.getUid());
|
||||
|
||||
registration.addRecipes(findRecipes(AllRecipeTypes.CUTTING), sawingCategory.getUid());
|
||||
registration.addRecipes(
|
||||
|
||||
if (recipeConfig.allowStonecuttingOnSaw.get())
|
||||
registration.addRecipes(
|
||||
CondensedBlockCuttingRecipe.condenseRecipes(findRecipesByType(IRecipeType.STONECUTTING)),
|
||||
blockCuttingCategory.getUid());
|
||||
registration.addRecipes(findRecipes(
|
||||
r -> (r instanceof ICraftingRecipe) && MechanicalPressTileEntity.canCompress(r.getIngredients())),
|
||||
|
||||
registration.addRecipes(findRecipes(AllRecipeTypes.COMPACTING), packingCategory.getUid());
|
||||
if (recipeConfig.allowShapedSquareInPress.get())
|
||||
registration.addRecipes(findRecipes(
|
||||
r -> (r instanceof ICraftingRecipe) && MechanicalPressTileEntity.canCompress(r.getIngredients()))
|
||||
.stream()
|
||||
.map(BasinRecipe::convert)
|
||||
.collect(Collectors.toList()),
|
||||
packingCategory.getUid());
|
||||
|
||||
registration.addRecipes(findRecipes(AllRecipeTypes.SANDPAPER_POLISHING), polishingCategory.getUid());
|
||||
registration.addRecipes(MysteriousItemConversionCategory.getRecipes(), mysteryConversionCategory.getUid());
|
||||
registration.addRecipes(findRecipes(r -> (r.getType() == AllRecipeTypes.MECHANICAL_CRAFTING.type)),
|
||||
mechanicalCraftingCategory.getUid());
|
||||
registration.addRecipes(findRecipes(r -> (r.getType() == IRecipeType.CRAFTING
|
||||
&& r.getType() != AllRecipeTypes.MECHANICAL_CRAFTING.type) && (r instanceof ShapedRecipe)),
|
||||
mechanicalCraftingCategory.getUid());
|
||||
|
||||
if (recipeConfig.allowRegularCraftingInCrafter.get())
|
||||
registration.addRecipes(findRecipes(
|
||||
r -> (r.getType() == IRecipeType.CRAFTING && r.getType() != AllRecipeTypes.MECHANICAL_CRAFTING.type)
|
||||
&& (r instanceof ShapedRecipe)),
|
||||
mechanicalCraftingCategory.getUid());
|
||||
}
|
||||
|
||||
|
@ -141,17 +161,13 @@ public class CreateJEI implements IModPlugin {
|
|||
public void registerRecipeCatalysts(IRecipeCatalystRegistration registration) {
|
||||
ItemStack fan = new ItemStack(AllBlocks.ENCASED_FAN.get());
|
||||
|
||||
ItemStack splashingFan = fan
|
||||
.copy()
|
||||
.setDisplayName(new StringTextComponent(TextFormatting.RESET + Lang.translate("recipe.splashing.fan")));
|
||||
ItemStack smokingFan = fan
|
||||
.copy()
|
||||
.setDisplayName(
|
||||
new StringTextComponent(TextFormatting.RESET + Lang.translate("recipe.smokingViaFan.fan")));
|
||||
ItemStack blastingFan = fan
|
||||
.copy()
|
||||
.setDisplayName(
|
||||
new StringTextComponent(TextFormatting.RESET + Lang.translate("recipe.blastingViaFan.fan")));
|
||||
ItemStack splashingFan = fan.copy()
|
||||
.setDisplayName(new StringTextComponent(TextFormatting.RESET + Lang.translate("recipe.splashing.fan")));
|
||||
ItemStack smokingFan = fan.copy()
|
||||
.setDisplayName(new StringTextComponent(TextFormatting.RESET + Lang.translate("recipe.smokingViaFan.fan")));
|
||||
ItemStack blastingFan = fan.copy()
|
||||
.setDisplayName(
|
||||
new StringTextComponent(TextFormatting.RESET + Lang.translate("recipe.blastingViaFan.fan")));
|
||||
|
||||
registration.addRecipeCatalyst(new ItemStack(AllBlocks.MILLSTONE.get()), millingCategory.getUid());
|
||||
registration.addRecipeCatalyst(new ItemStack(AllBlocks.CRUSHING_WHEEL.get()), crushingCategory.getUid());
|
||||
|
@ -170,9 +186,8 @@ public class CreateJEI implements IModPlugin {
|
|||
registration.addRecipeCatalyst(new ItemStack(AllBlocks.BASIN.get()), packingCategory.getUid());
|
||||
registration.addRecipeCatalyst(AllItems.SAND_PAPER.asStack(), polishingCategory.getUid());
|
||||
registration.addRecipeCatalyst(AllItems.RED_SAND_PAPER.asStack(), polishingCategory.getUid());
|
||||
registration
|
||||
.addRecipeCatalyst(new ItemStack(AllBlocks.MECHANICAL_CRAFTER.get()),
|
||||
mechanicalCraftingCategory.getUid());
|
||||
registration.addRecipeCatalyst(new ItemStack(AllBlocks.MECHANICAL_CRAFTER.get()),
|
||||
mechanicalCraftingCategory.getUid());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -186,30 +201,29 @@ public class CreateJEI implements IModPlugin {
|
|||
}
|
||||
|
||||
private static List<IRecipe<?>> findRecipes(Predicate<IRecipe<?>> pred) {
|
||||
return Minecraft.getInstance().world
|
||||
.getRecipeManager()
|
||||
.getRecipes()
|
||||
.stream()
|
||||
.filter(pred)
|
||||
.collect(Collectors.toList());
|
||||
return Minecraft.getInstance().world.getRecipeManager()
|
||||
.getRecipes()
|
||||
.stream()
|
||||
.filter(pred)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static List<IRecipe<?>> findRecipesByType(IRecipeType<?> type) {
|
||||
return Minecraft.getInstance().world
|
||||
.getRecipeManager()
|
||||
.getRecipes()
|
||||
.stream()
|
||||
.filter(r -> r.getType() == type)
|
||||
.collect(Collectors.toList());
|
||||
return Minecraft.getInstance().world.getRecipeManager()
|
||||
.getRecipes()
|
||||
.stream()
|
||||
.filter(r -> r.getType() == type)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static List<IRecipe<?>> findRecipesById(ResourceLocation id) {
|
||||
return Minecraft.getInstance().world
|
||||
.getRecipeManager()
|
||||
.getRecipes()
|
||||
.stream()
|
||||
.filter(r -> r.getSerializer().getRegistryName().equals(id))
|
||||
.collect(Collectors.toList());
|
||||
return Minecraft.getInstance().world.getRecipeManager()
|
||||
.getRecipes()
|
||||
.stream()
|
||||
.filter(r -> r.getSerializer()
|
||||
.getRegistryName()
|
||||
.equals(id))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static List<IRecipe<?>> findRecipesByTypeExcluding(IRecipeType<?> type, IRecipeType<?> excludingType) {
|
||||
|
@ -217,10 +231,14 @@ public class CreateJEI implements IModPlugin {
|
|||
List<IRecipe<?>> byExcludingType = findRecipesByType(excludingType);
|
||||
byType.removeIf(recipe -> {
|
||||
for (IRecipe<?> r : byExcludingType) {
|
||||
ItemStack[] matchingStacks = recipe.getIngredients().get(0).getMatchingStacks();
|
||||
ItemStack[] matchingStacks = recipe.getIngredients()
|
||||
.get(0)
|
||||
.getMatchingStacks();
|
||||
if (matchingStacks.length == 0)
|
||||
return true;
|
||||
if (r.getIngredients().get(0).test(matchingStacks[0]))
|
||||
if (r.getIngredients()
|
||||
.get(0)
|
||||
.test(matchingStacks[0]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
package com.simibubi.create.compat.jei.category;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableInt;
|
||||
|
||||
import com.simibubi.create.content.contraptions.processing.BasinRecipe;
|
||||
import com.simibubi.create.content.contraptions.processing.HeatCondition;
|
||||
import com.simibubi.create.foundation.gui.AllGuiTextures;
|
||||
import com.simibubi.create.foundation.item.ItemHelper;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import mezz.jei.api.constants.VanillaTypes;
|
||||
import mezz.jei.api.gui.IRecipeLayout;
|
||||
import mezz.jei.api.gui.drawable.IDrawable;
|
||||
import mezz.jei.api.gui.ingredient.IGuiItemStackGroup;
|
||||
import mezz.jei.api.ingredients.IIngredients;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.util.NonNullList;
|
||||
|
||||
public class BasinCategory extends CreateRecipeCategory<BasinRecipe> {
|
||||
|
||||
public BasinCategory(String id, IDrawable icon, IDrawable background) {
|
||||
super(id, icon, background);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends BasinRecipe> getRecipeClass() {
|
||||
return BasinRecipe.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIngredients(BasinRecipe recipe, IIngredients ingredients) {
|
||||
ingredients.setInputIngredients(recipe.getIngredients());
|
||||
ingredients.setOutput(VanillaTypes.ITEM, recipe.getRecipeOutput());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRecipe(IRecipeLayout recipeLayout, BasinRecipe recipe, IIngredients ingredients) {
|
||||
IGuiItemStackGroup itemStacks = recipeLayout.getItemStacks();
|
||||
NonNullList<Ingredient> recipeIngredients = recipe.getIngredients();
|
||||
List<Pair<Ingredient, MutableInt>> actualIngredients = ItemHelper.condenseIngredients(recipeIngredients);
|
||||
|
||||
int size = actualIngredients.size();
|
||||
int xOffset = size < 3 ? (3 - size) * 19 / 2 : 0;
|
||||
int yOffset = recipe.getRequiredHeat() != HeatCondition.NONE ? 30 : 10;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < actualIngredients.size(); i++) {
|
||||
itemStacks.init(i, true, 16 + xOffset + (i % 3) * 19, 50 - (i / 3) * 19 + yOffset);
|
||||
List<ItemStack> stacks = new ArrayList<>();
|
||||
Pair<Ingredient, MutableInt> pair = actualIngredients.get(i);
|
||||
Ingredient ingredient = pair.getFirst();
|
||||
MutableInt amount = pair.getSecond();
|
||||
|
||||
for (ItemStack itemStack : ingredient.getMatchingStacks()) {
|
||||
ItemStack stack = itemStack.copy();
|
||||
stack.setCount(amount.getValue());
|
||||
stacks.add(stack);
|
||||
}
|
||||
|
||||
itemStacks.set(i, stacks);
|
||||
}
|
||||
|
||||
itemStacks.init(i, false, 141, 50 + yOffset);
|
||||
itemStacks.set(i, recipe.getRecipeOutput()
|
||||
.getStack());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(BasinRecipe recipe, double mouseX, double mouseY) {
|
||||
List<Pair<Ingredient, MutableInt>> actualIngredients = ItemHelper.condenseIngredients(recipe.getIngredients());
|
||||
|
||||
int size = actualIngredients.size();
|
||||
int xOffset = size < 3 ? (3 - size) * 19 / 2 : 0;
|
||||
HeatCondition requiredHeat = recipe.getRequiredHeat();
|
||||
int yOffset = requiredHeat != HeatCondition.NONE ? 30 : 10;
|
||||
for (int i = 0; i < size; i++)
|
||||
AllGuiTextures.JEI_SLOT.draw(16 + xOffset + (i % 3) * 19, 50 - (i / 3) * 19 + yOffset);
|
||||
|
||||
AllGuiTextures.JEI_SLOT.draw(141, 50 + yOffset);
|
||||
AllGuiTextures.JEI_DOWN_ARROW.draw(136, 32 + yOffset);
|
||||
AllGuiTextures.JEI_SHADOW.draw(81, 57 + yOffset);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,28 +1,12 @@
|
|||
package com.simibubi.create.compat.jei.category;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableInt;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.compat.jei.category.animations.AnimatedBlazeBurner;
|
||||
import com.simibubi.create.compat.jei.category.animations.AnimatedMixer;
|
||||
import com.simibubi.create.content.contraptions.components.mixer.MixingRecipe;
|
||||
import com.simibubi.create.content.contraptions.processing.BasinRecipe;
|
||||
import com.simibubi.create.content.contraptions.processing.HeatCondition;
|
||||
import com.simibubi.create.foundation.gui.AllGuiTextures;
|
||||
import com.simibubi.create.foundation.item.ItemHelper;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import mezz.jei.api.constants.VanillaTypes;
|
||||
import mezz.jei.api.gui.IRecipeLayout;
|
||||
import mezz.jei.api.gui.ingredient.IGuiItemStackGroup;
|
||||
import mezz.jei.api.ingredients.IIngredients;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.util.NonNullList;
|
||||
|
||||
public class MixingCategory extends CreateRecipeCategory<MixingRecipe> {
|
||||
public class MixingCategory extends BasinCategory {
|
||||
|
||||
private AnimatedMixer mixer = new AnimatedMixer();
|
||||
private AnimatedBlazeBurner heater = new AnimatedBlazeBurner();
|
||||
|
@ -33,63 +17,9 @@ public class MixingCategory extends CreateRecipeCategory<MixingRecipe> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends MixingRecipe> getRecipeClass() {
|
||||
return MixingRecipe.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIngredients(MixingRecipe recipe, IIngredients ingredients) {
|
||||
ingredients.setInputIngredients(recipe.getIngredients());
|
||||
ingredients.setOutput(VanillaTypes.ITEM, recipe.getRecipeOutput());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRecipe(IRecipeLayout recipeLayout, MixingRecipe recipe, IIngredients ingredients) {
|
||||
IGuiItemStackGroup itemStacks = recipeLayout.getItemStacks();
|
||||
NonNullList<Ingredient> recipeIngredients = recipe.getIngredients();
|
||||
List<Pair<Ingredient, MutableInt>> actualIngredients = ItemHelper.condenseIngredients(recipeIngredients);
|
||||
|
||||
int size = actualIngredients.size();
|
||||
int xOffset = size < 3 ? (3 - size) * 19 / 2 : 0;
|
||||
int yOffset = recipe.getRequiredHeat() != HeatCondition.NONE ? 30 : 10;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < actualIngredients.size(); i++) {
|
||||
itemStacks.init(i, true, 16 + xOffset + (i % 3) * 19, 50 - (i / 3) * 19 + yOffset);
|
||||
List<ItemStack> stacks = new ArrayList<>();
|
||||
Pair<Ingredient, MutableInt> pair = actualIngredients.get(i);
|
||||
Ingredient ingredient = pair.getFirst();
|
||||
MutableInt amount = pair.getSecond();
|
||||
|
||||
for (ItemStack itemStack : ingredient.getMatchingStacks()) {
|
||||
ItemStack stack = itemStack.copy();
|
||||
stack.setCount(amount.getValue());
|
||||
stacks.add(stack);
|
||||
}
|
||||
|
||||
itemStacks.set(i, stacks);
|
||||
}
|
||||
|
||||
itemStacks.init(i, false, 141, 50 + yOffset);
|
||||
itemStacks.set(i, recipe.getRecipeOutput()
|
||||
.getStack());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(MixingRecipe recipe, double mouseX, double mouseY) {
|
||||
List<Pair<Ingredient, MutableInt>> actualIngredients = ItemHelper.condenseIngredients(recipe.getIngredients());
|
||||
|
||||
int size = actualIngredients.size();
|
||||
int xOffset = size < 3 ? (3 - size) * 19 / 2 : 0;
|
||||
public void draw(BasinRecipe recipe, double mouseX, double mouseY) {
|
||||
super.draw(recipe, mouseX, mouseY);
|
||||
HeatCondition requiredHeat = recipe.getRequiredHeat();
|
||||
int yOffset = requiredHeat != HeatCondition.NONE ? 30 : 10;
|
||||
for (int i = 0; i < size; i++)
|
||||
AllGuiTextures.JEI_SLOT.draw(16 + xOffset + (i % 3) * 19, 50 - (i / 3) * 19 + yOffset);
|
||||
|
||||
AllGuiTextures.JEI_SLOT.draw(141, 50 + yOffset);
|
||||
AllGuiTextures.JEI_DOWN_ARROW.draw(136, 32 + yOffset);
|
||||
AllGuiTextures.JEI_SHADOW.draw(81, 57 + yOffset);
|
||||
|
||||
if (requiredHeat != HeatCondition.NONE)
|
||||
heater.withHeat(requiredHeat.visualizeAsBlazeBurner())
|
||||
.draw(getBackground().getWidth() / 2 + 3, 55);
|
||||
|
|
|
@ -4,18 +4,16 @@ import java.util.Arrays;
|
|||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.compat.jei.category.animations.AnimatedPress;
|
||||
import com.simibubi.create.content.contraptions.processing.BasinRecipe;
|
||||
import com.simibubi.create.foundation.gui.AllGuiTextures;
|
||||
|
||||
import mezz.jei.api.constants.VanillaTypes;
|
||||
import mezz.jei.api.gui.IRecipeLayout;
|
||||
import mezz.jei.api.gui.ingredient.IGuiItemStackGroup;
|
||||
import mezz.jei.api.ingredients.IIngredients;
|
||||
import net.minecraft.item.crafting.ICraftingRecipe;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.util.NonNullList;
|
||||
|
||||
public class PackingCategory extends CreateRecipeCategory<IRecipe<?>> {
|
||||
public class PackingCategory extends BasinCategory {
|
||||
|
||||
private AnimatedPress press = new AnimatedPress(true);
|
||||
|
||||
|
@ -25,18 +23,12 @@ public class PackingCategory extends CreateRecipeCategory<IRecipe<?>> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IRecipe<?>> getRecipeClass() {
|
||||
return ICraftingRecipe.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIngredients(IRecipe<?> recipe, IIngredients ingredients) {
|
||||
ingredients.setInputIngredients(recipe.getIngredients());
|
||||
ingredients.setOutput(VanillaTypes.ITEM, recipe.getRecipeOutput());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRecipe(IRecipeLayout recipeLayout, IRecipe<?> recipe, IIngredients ingredients) {
|
||||
public void setRecipe(IRecipeLayout recipeLayout, BasinRecipe recipe, IIngredients ingredients) {
|
||||
if (!recipe.convertedRecipe) {
|
||||
super.setRecipe(recipeLayout, recipe, ingredients);
|
||||
return;
|
||||
}
|
||||
|
||||
IGuiItemStackGroup itemStacks = recipeLayout.getItemStacks();
|
||||
int i = 0;
|
||||
|
||||
|
@ -55,16 +47,21 @@ public class PackingCategory extends CreateRecipeCategory<IRecipe<?>> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void draw(IRecipe<?> recipe, double mouseX, double mouseY) {
|
||||
NonNullList<Ingredient> ingredients2 = recipe.getIngredients();
|
||||
int size = ingredients2.size();
|
||||
int rows = size == 4 ? 2 : 3;
|
||||
for (int i = 0; i < size; i++) {
|
||||
AllGuiTextures.JEI_SLOT.draw((rows == 2 ? 26 : 17) + (i % rows) * 19, 50 - (i / rows) * 19);
|
||||
public void draw(BasinRecipe recipe, double mouseX, double mouseY) {
|
||||
if (!recipe.convertedRecipe) {
|
||||
super.draw(recipe, mouseX, mouseY);
|
||||
|
||||
} else {
|
||||
NonNullList<Ingredient> ingredients2 = recipe.getIngredients();
|
||||
int size = ingredients2.size();
|
||||
int rows = size == 4 ? 2 : 3;
|
||||
for (int i = 0; i < size; i++)
|
||||
AllGuiTextures.JEI_SLOT.draw((rows == 2 ? 26 : 17) + (i % rows) * 19, 50 - (i / rows) * 19);
|
||||
AllGuiTextures.JEI_SLOT.draw(141, 50);
|
||||
AllGuiTextures.JEI_DOWN_ARROW.draw(136, 32);
|
||||
AllGuiTextures.JEI_SHADOW.draw(81, 57);
|
||||
}
|
||||
AllGuiTextures.JEI_SLOT.draw(141, 50);
|
||||
AllGuiTextures.JEI_DOWN_ARROW.draw(136, 32);
|
||||
AllGuiTextures.JEI_SHADOW.draw(81, 57);
|
||||
|
||||
press.draw(getBackground().getWidth() / 2 + 6, 30);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.apache.commons.lang3.tuple.Pair;
|
|||
import com.google.common.base.Predicates;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllRecipeTypes;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.utility.Pointing;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
|
@ -139,16 +140,16 @@ public class RecipeGridHandler {
|
|||
public static ItemStack tryToApplyRecipe(World world, GroupedItems items) {
|
||||
items.calcStats();
|
||||
CraftingInventory craftinginventory = new MechanicalCraftingInventory(items);
|
||||
ItemStack result = world.getRecipeManager()
|
||||
.getRecipe(IRecipeType.CRAFTING, craftinginventory, world)
|
||||
.map(r -> r.getCraftingResult(craftinginventory))
|
||||
.orElse(null);
|
||||
if (result == null)
|
||||
ItemStack result = null;
|
||||
if (AllConfigs.SERVER.recipes.allowRegularCraftingInCrafter.get())
|
||||
result = world.getRecipeManager()
|
||||
.getRecipe(AllRecipeTypes.MECHANICAL_CRAFTING.getType(), craftinginventory, world)
|
||||
.getRecipe(IRecipeType.CRAFTING, craftinginventory, world)
|
||||
.map(r -> r.getCraftingResult(craftinginventory))
|
||||
.orElse(null);
|
||||
if (result == null)
|
||||
result = AllRecipeTypes.MECHANICAL_CRAFTING.find(craftinginventory, world)
|
||||
.map(r -> r.getCraftingResult(craftinginventory))
|
||||
.orElse(null);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -206,11 +206,9 @@ public class CrushingWheelControllerTileEntity extends SmartTileEntity {
|
|||
}
|
||||
|
||||
public Optional<ProcessingRecipe<RecipeWrapper>> findRecipe() {
|
||||
Optional<ProcessingRecipe<RecipeWrapper>> crushingRecipe = world.getRecipeManager()
|
||||
.getRecipe(AllRecipeTypes.CRUSHING.getType(), wrapper, world);
|
||||
Optional<ProcessingRecipe<RecipeWrapper>> crushingRecipe = AllRecipeTypes.CRUSHING.find(wrapper, world);
|
||||
if (!crushingRecipe.isPresent())
|
||||
crushingRecipe = world.getRecipeManager()
|
||||
.getRecipe(AllRecipeTypes.MILLING.getType(), wrapper, world);
|
||||
crushingRecipe = AllRecipeTypes.MILLING.find(wrapper, world);
|
||||
return crushingRecipe;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,8 +65,7 @@ public class MillstoneTileEntity extends KineticTileEntity {
|
|||
|
||||
RecipeWrapper inventoryIn = new RecipeWrapper(inputInv);
|
||||
if (lastRecipe == null || !lastRecipe.matches(inventoryIn, world)) {
|
||||
Optional<MillingRecipe> recipe = world.getRecipeManager()
|
||||
.getRecipe(AllRecipeTypes.MILLING.getType(), inventoryIn, world);
|
||||
Optional<MillingRecipe> recipe = AllRecipeTypes.MILLING.find(inventoryIn, world);
|
||||
if (!recipe.isPresent()) {
|
||||
timer = 100;
|
||||
sendData();
|
||||
|
@ -86,8 +85,7 @@ public class MillstoneTileEntity extends KineticTileEntity {
|
|||
RecipeWrapper inventoryIn = new RecipeWrapper(inputInv);
|
||||
|
||||
if (lastRecipe == null || !lastRecipe.matches(inventoryIn, world)) {
|
||||
Optional<MillingRecipe> recipe = world.getRecipeManager()
|
||||
.getRecipe(AllRecipeTypes.MILLING.getType(), inventoryIn, world);
|
||||
Optional<MillingRecipe> recipe = AllRecipeTypes.MILLING.find(inventoryIn, world);
|
||||
if (!recipe.isPresent())
|
||||
return;
|
||||
lastRecipe = recipe.get();
|
||||
|
@ -153,8 +151,7 @@ public class MillstoneTileEntity extends KineticTileEntity {
|
|||
|
||||
if (lastRecipe != null && lastRecipe.matches(inventoryIn, world))
|
||||
return true;
|
||||
return world.getRecipeManager()
|
||||
.getRecipe(AllRecipeTypes.MILLING.getType(), inventoryIn, world)
|
||||
return AllRecipeTypes.MILLING.find(inventoryIn, world)
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package com.simibubi.create.content.contraptions.components.mixer;
|
||||
|
||||
import com.simibubi.create.AllRecipeTypes;
|
||||
import com.simibubi.create.content.contraptions.processing.BasinRecipe;
|
||||
import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams;
|
||||
|
||||
public class CompactingRecipe extends BasinRecipe {
|
||||
|
||||
public CompactingRecipe(ProcessingRecipeParams params) {
|
||||
super(AllRecipeTypes.COMPACTING, params);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,37 +1,29 @@
|
|||
package com.simibubi.create.content.contraptions.components.mixer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.simibubi.create.AllRecipeTypes;
|
||||
import com.simibubi.create.AllTags;
|
||||
import com.simibubi.create.content.contraptions.components.press.MechanicalPressTileEntity;
|
||||
import com.simibubi.create.content.contraptions.processing.BasinOperatingTileEntity;
|
||||
import com.simibubi.create.content.contraptions.processing.BasinTileEntity;
|
||||
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock;
|
||||
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel;
|
||||
import com.simibubi.create.foundation.advancement.AllTriggers;
|
||||
import com.simibubi.create.foundation.advancement.ITriggerable;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.item.SmartInventory;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.IRecipeSerializer;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.particles.ItemParticleData;
|
||||
import net.minecraft.particles.ParticleTypes;
|
||||
import net.minecraft.tileentity.TileEntityType;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
|
||||
public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
|
||||
|
||||
|
@ -99,13 +91,6 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
|
|||
super.write(compound, clientPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lazyTick() {
|
||||
super.lazyTick();
|
||||
if (world != null && world.isRemote && running && !basinItemInv.isPresent())
|
||||
updateBasin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
@ -168,45 +153,11 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
|
|||
|
||||
@Override
|
||||
protected <C extends IInventory> boolean matchStaticFilters(IRecipe<C> r) {
|
||||
return (r.getSerializer() == IRecipeSerializer.CRAFTING_SHAPELESS || r.getType() == AllRecipeTypes.MIXING.type)
|
||||
return ((r.getSerializer() == IRecipeSerializer.CRAFTING_SHAPELESS
|
||||
&& AllConfigs.SERVER.recipes.allowShapelessInMixer.get()) || r.getType() == AllRecipeTypes.MIXING.type)
|
||||
&& !MechanicalPressTileEntity.canCompress(r.getIngredients());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <C extends IInventory> boolean matchBasinRecipe(IRecipe<C> recipe) {
|
||||
if (!super.matchBasinRecipe(recipe))
|
||||
return false;
|
||||
|
||||
NonNullList<Ingredient> ingredients = recipe.getIngredients();
|
||||
List<ItemStack> remainingItems = new ArrayList<>();
|
||||
itemInputs.forEach(stack -> remainingItems.add(stack.copy()));
|
||||
List<FluidStack> remainingFluids = new ArrayList<>();
|
||||
fluidInputs.forEach(stack -> remainingFluids.add(stack.copy()));
|
||||
|
||||
// TODO: match fluid inputs
|
||||
|
||||
// Sort by leniency
|
||||
List<Ingredient> sortedIngredients = new LinkedList<>(ingredients);
|
||||
sortedIngredients.sort(Comparator.comparingInt(i -> i.getMatchingStacks().length));
|
||||
|
||||
Ingredients: for (Ingredient ingredient : sortedIngredients) {
|
||||
for (ItemStack stack : remainingItems) {
|
||||
if (stack.isEmpty())
|
||||
continue;
|
||||
if (ingredient.test(stack)) {
|
||||
stack.shrink(1);
|
||||
continue Ingredients;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(recipe instanceof MixingRecipe))
|
||||
return true;
|
||||
return ((MixingRecipe) recipe).getRequiredHeat()
|
||||
.testBlazeBurner(getHeatLevel());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startProcessingBasin() {
|
||||
if (running && runningTicks <= 20)
|
||||
|
@ -239,13 +190,10 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
|
|||
protected boolean isRunning() {
|
||||
return running;
|
||||
}
|
||||
|
||||
private HeatLevel getHeatLevel() {
|
||||
if (world == null)
|
||||
return HeatLevel.NONE;
|
||||
BlockState state = world.getBlockState(pos.down(3));
|
||||
if (state.has(BlazeBurnerBlock.HEAT_LEVEL))
|
||||
return state.get(BlazeBurnerBlock.HEAT_LEVEL);
|
||||
return AllTags.AllBlockTags.FAN_HEATERS.matches(state) ? HeatLevel.SMOULDERING : HeatLevel.NONE;
|
||||
|
||||
@Override
|
||||
protected Optional<ITriggerable> getProcessedRecipeTrigger() {
|
||||
return Optional.of(AllTriggers.MIXER_MIX);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,98 +1,13 @@
|
|||
package com.simibubi.create.content.contraptions.components.mixer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.simibubi.create.AllRecipeTypes;
|
||||
import com.simibubi.create.content.contraptions.processing.ProcessingRecipe;
|
||||
import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder;
|
||||
import com.simibubi.create.content.contraptions.processing.BasinRecipe;
|
||||
import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams;
|
||||
import com.simibubi.create.foundation.item.SmartInventory;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class MixingRecipe extends ProcessingRecipe<SmartInventory> {
|
||||
|
||||
/**
|
||||
* For JEI purposes only
|
||||
*/
|
||||
public static MixingRecipe convertShapeless(IRecipe<?> recipe) {
|
||||
return new ProcessingRecipeBuilder<>(MixingRecipe::new, recipe.getId())
|
||||
.withItemIngredients(recipe.getIngredients())
|
||||
.withSingleItemOutput(recipe.getRecipeOutput())
|
||||
.build();
|
||||
}
|
||||
public class MixingRecipe extends BasinRecipe {
|
||||
|
||||
public MixingRecipe(ProcessingRecipeParams params) {
|
||||
super(AllRecipeTypes.MIXING, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaxInputCount() {
|
||||
return 9;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaxOutputCount() {
|
||||
return 1;// TODO increase
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaxFluidInputCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaxFluidOutputCount() {
|
||||
return 1;// TODO increase?
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canRequireHeat() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(SmartInventory inv, @Nonnull World worldIn) {
|
||||
if (inv.isEmpty())
|
||||
return false;
|
||||
|
||||
NonNullList<Ingredient> ingredients = this.getIngredients();
|
||||
if (!ingredients.stream()
|
||||
.allMatch(Ingredient::isSimple))
|
||||
return false;
|
||||
|
||||
List<ItemStack> remaining = new ArrayList<>();
|
||||
for (int slot = 0; slot < inv.getSizeInventory(); ++slot) {
|
||||
ItemStack itemstack = inv.getStackInSlot(slot);
|
||||
if (!itemstack.isEmpty()) {
|
||||
remaining.add(itemstack.copy());
|
||||
}
|
||||
}
|
||||
|
||||
// sort by leniency
|
||||
List<Ingredient> sortedIngredients = new LinkedList<>(ingredients);
|
||||
sortedIngredients.sort(Comparator.comparingInt(i -> i.getMatchingStacks().length));
|
||||
Ingredients: for (Ingredient ingredient : sortedIngredients) {
|
||||
for (ItemStack stack : remaining) {
|
||||
if (stack.isEmpty())
|
||||
continue;
|
||||
if (ingredient.test(stack)) {
|
||||
stack.shrink(1);
|
||||
continue Ingredients;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ import com.simibubi.create.content.contraptions.processing.BasinOperatingTileEnt
|
|||
import com.simibubi.create.content.contraptions.processing.BasinTileEntity;
|
||||
import com.simibubi.create.content.logistics.InWorldProcessing;
|
||||
import com.simibubi.create.foundation.advancement.AllTriggers;
|
||||
import com.simibubi.create.foundation.advancement.ITriggerable;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.item.ItemHelper;
|
||||
import com.simibubi.create.foundation.item.SmartInventory;
|
||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||
|
@ -41,29 +43,12 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
|
|||
|
||||
private static final Object compressingRecipesKey = new Object();
|
||||
public List<ItemStack> pressedItems = new ArrayList<>();
|
||||
|
||||
public static class PressingInv extends RecipeWrapper {
|
||||
public PressingInv() {
|
||||
super(new ItemStackHandler(1));
|
||||
}
|
||||
}
|
||||
|
||||
enum Mode {
|
||||
WORLD(1), BELT(19f / 16f), BASIN(22f / 16f)
|
||||
|
||||
;
|
||||
|
||||
float headOffset;
|
||||
|
||||
Mode(float headOffset) {
|
||||
this.headOffset = headOffset;
|
||||
}
|
||||
}
|
||||
|
||||
private static final PressingInv pressingInv = new PressingInv();
|
||||
public BeltProcessingBehaviour processingBehaviour;
|
||||
|
||||
public int prevRunningTicks;
|
||||
public int runningTicks;
|
||||
static final int CYCLE = 240;
|
||||
|
||||
public boolean running;
|
||||
public Mode mode;
|
||||
public boolean finished;
|
||||
|
@ -87,7 +72,7 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
|
|||
running = compound.getBoolean("Running");
|
||||
mode = Mode.values()[compound.getInt("Mode")];
|
||||
finished = compound.getBoolean("Finished");
|
||||
runningTicks = compound.getInt("Ticks");
|
||||
prevRunningTicks = runningTicks = compound.getInt("Ticks");
|
||||
super.read(compound, clientPacket);
|
||||
|
||||
if (clientPacket) {
|
||||
|
@ -105,8 +90,10 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
|
|||
compound.putInt("Ticks", runningTicks);
|
||||
super.write(compound, clientPacket);
|
||||
|
||||
if (clientPacket)
|
||||
if (clientPacket) {
|
||||
compound.put("ParticleItems", NBTHelper.writeCompoundList(pressedItems, ItemStack::serializeNBT));
|
||||
pressedItems.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -116,15 +103,12 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
|
|||
}
|
||||
|
||||
public float getRenderedHeadOffset(float partialTicks) {
|
||||
if (running) {
|
||||
if (runningTicks < 40) {
|
||||
float num = (runningTicks - 1 + partialTicks) / 30f;
|
||||
return MathHelper.clamp(num * num * num, 0, mode.headOffset);
|
||||
}
|
||||
return MathHelper.clamp(((60 - runningTicks) + 1 - partialTicks) / 20f * mode.headOffset, 0,
|
||||
mode.headOffset);
|
||||
}
|
||||
return 0;
|
||||
if (!running)
|
||||
return 0;
|
||||
float ticks = MathHelper.lerp(partialTicks, prevRunningTicks, runningTicks);
|
||||
if (runningTicks < (CYCLE * 2) / 3)
|
||||
return (float) MathHelper.clamp(Math.pow(ticks / CYCLE * 2, 3), 0, mode.headOffset);
|
||||
return MathHelper.clamp((CYCLE - ticks) / CYCLE * 3 * mode.headOffset, 0, mode.headOffset);
|
||||
}
|
||||
|
||||
public void start(Mode mode) {
|
||||
|
@ -150,50 +134,11 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
|
|||
if (!running || world == null)
|
||||
return;
|
||||
|
||||
if (runningTicks == 30) {
|
||||
|
||||
if (inWorld()) {
|
||||
AxisAlignedBB bb = new AxisAlignedBB(pos.down(1));
|
||||
pressedItems.clear();
|
||||
for (Entity entity : world.getEntitiesWithinAABBExcludingEntity(null, bb)) {
|
||||
if (!(entity instanceof ItemEntity))
|
||||
continue;
|
||||
|
||||
ItemEntity itemEntity = (ItemEntity) entity;
|
||||
|
||||
if (!world.isRemote) {
|
||||
pressedItems.add(itemEntity.getItem());
|
||||
sendData();
|
||||
Optional<PressingRecipe> recipe = getRecipe(itemEntity.getItem());
|
||||
if (recipe.isPresent()) {
|
||||
InWorldProcessing.applyRecipeOn(itemEntity, recipe.get());
|
||||
AllTriggers.triggerForNearbyPlayers(AllTriggers.BONK, world, pos, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (onBasin()) {
|
||||
if (!world.isRemote) {
|
||||
pressedItems.clear();
|
||||
applyBasinRecipe();
|
||||
|
||||
Optional<BasinTileEntity> basin = getBasin();
|
||||
SmartInventory inputs = basin.get()
|
||||
.getInputInventory();
|
||||
if (basin.isPresent()) {
|
||||
for (int slot = 0; slot < inputs.getSlots(); slot++) {
|
||||
ItemStack stackInSlot = inputs.getStackInSlot(slot);
|
||||
if (stackInSlot.isEmpty())
|
||||
continue;
|
||||
pressedItems.add(stackInSlot);
|
||||
}
|
||||
}
|
||||
sendData();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (runningTicks == CYCLE / 2) {
|
||||
if (inWorld())
|
||||
applyPressingInWorld();
|
||||
if (onBasin())
|
||||
applyCompactingOnBasin();
|
||||
if (!world.isRemote) {
|
||||
world.playSound(null, getPos(), AllSoundEvents.MECHANICAL_PRESS_ITEM_BREAK.get(), SoundCategory.BLOCKS,
|
||||
.5f, 1f);
|
||||
|
@ -202,105 +147,125 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
|
|||
}
|
||||
}
|
||||
|
||||
if (!world.isRemote && runningTicks > 60) {
|
||||
if (!world.isRemote && runningTicks > CYCLE) {
|
||||
finished = true;
|
||||
if (inWorld())
|
||||
finished = world.isBlockPowered(pos);
|
||||
running = false;
|
||||
|
||||
if (onBasin()) {
|
||||
gatherInputs();
|
||||
if (matchBasinRecipe(lastRecipe)) {
|
||||
startProcessingBasin();
|
||||
}
|
||||
}
|
||||
if (onBasin() && matchBasinRecipe(currentRecipe))
|
||||
startProcessingBasin();
|
||||
|
||||
pressedItems.clear();
|
||||
sendData();
|
||||
return;
|
||||
}
|
||||
|
||||
runningTicks++;
|
||||
prevRunningTicks = runningTicks;
|
||||
runningTicks += getRunningTickSpeed();
|
||||
if (prevRunningTicks < CYCLE / 2 && runningTicks >= CYCLE / 2)
|
||||
runningTicks = CYCLE / 2;
|
||||
}
|
||||
|
||||
protected void applyCompactingOnBasin() {
|
||||
if (world.isRemote)
|
||||
return;
|
||||
pressedItems.clear();
|
||||
applyBasinRecipe();
|
||||
Optional<BasinTileEntity> basin = getBasin();
|
||||
SmartInventory inputs = basin.get()
|
||||
.getInputInventory();
|
||||
if (basin.isPresent()) {
|
||||
for (int slot = 0; slot < inputs.getSlots(); slot++) {
|
||||
ItemStack stackInSlot = inputs.getStackInSlot(slot);
|
||||
if (stackInSlot.isEmpty())
|
||||
continue;
|
||||
pressedItems.add(stackInSlot);
|
||||
}
|
||||
}
|
||||
sendData();
|
||||
}
|
||||
|
||||
protected void applyPressingInWorld() {
|
||||
AxisAlignedBB bb = new AxisAlignedBB(pos.down(1));
|
||||
pressedItems.clear();
|
||||
if (world.isRemote)
|
||||
return;
|
||||
for (Entity entity : world.getEntitiesWithinAABBExcludingEntity(null, bb)) {
|
||||
if (!(entity instanceof ItemEntity))
|
||||
continue;
|
||||
ItemEntity itemEntity = (ItemEntity) entity;
|
||||
pressedItems.add(itemEntity.getItem());
|
||||
sendData();
|
||||
Optional<PressingRecipe> recipe = getRecipe(itemEntity.getItem());
|
||||
if (!recipe.isPresent())
|
||||
continue;
|
||||
InWorldProcessing.applyRecipeOn(itemEntity, recipe.get());
|
||||
AllTriggers.triggerForNearbyPlayers(AllTriggers.BONK, world, pos, 4);
|
||||
}
|
||||
}
|
||||
|
||||
public int getRunningTickSpeed() {
|
||||
if (getSpeed() == 0)
|
||||
return 0;
|
||||
return (int) MathHelper.lerp(MathHelper.clamp(Math.abs(getSpeed()) / 512f, 0, 1), 1, 60);
|
||||
}
|
||||
|
||||
protected void spawnParticles() {
|
||||
if (pressedItems.isEmpty())
|
||||
return;
|
||||
|
||||
if (mode == Mode.BASIN) {
|
||||
if (mode == Mode.BASIN)
|
||||
pressedItems.forEach(stack -> makeCompactingParticleEffect(VecHelper.getCenterOf(pos.down(2)), stack));
|
||||
}
|
||||
if (mode == Mode.BELT) {
|
||||
if (mode == Mode.BELT)
|
||||
pressedItems.forEach(stack -> makePressingParticleEffect(VecHelper.getCenterOf(pos.down(2))
|
||||
.add(0, 8 / 16f, 0), stack));
|
||||
}
|
||||
if (mode == Mode.WORLD) {
|
||||
if (mode == Mode.WORLD)
|
||||
pressedItems.forEach(stack -> makePressingParticleEffect(VecHelper.getCenterOf(pos.down(1))
|
||||
.add(0, -1 / 4f, 0), stack));
|
||||
}
|
||||
|
||||
pressedItems.clear();
|
||||
}
|
||||
|
||||
public void makePressingParticleEffect(Vec3d pos, ItemStack stack) {
|
||||
if (world != null && world.isRemote) {
|
||||
for (int i = 0; i < 20; i++) {
|
||||
Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f)
|
||||
.mul(1, 0, 1);
|
||||
world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), pos.x, pos.y - .25f, pos.z, motion.x,
|
||||
motion.y + .125f, motion.z);
|
||||
}
|
||||
if (world == null || !world.isRemote)
|
||||
return;
|
||||
for (int i = 0; i < 20; i++) {
|
||||
Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f)
|
||||
.mul(1, 0, 1);
|
||||
world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), pos.x, pos.y - .25f, pos.z, motion.x,
|
||||
motion.y + .125f, motion.z);
|
||||
}
|
||||
}
|
||||
|
||||
public void makeCompactingParticleEffect(Vec3d pos, ItemStack stack) {
|
||||
if (world != null && world.isRemote) {
|
||||
for (int i = 0; i < 20; i++) {
|
||||
Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .175f)
|
||||
.mul(1, 0, 1);
|
||||
world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), pos.x, pos.y, pos.z, motion.x,
|
||||
motion.y + .25f, motion.z);
|
||||
}
|
||||
if (world == null || !world.isRemote)
|
||||
return;
|
||||
for (int i = 0; i < 20; i++) {
|
||||
Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .175f)
|
||||
.mul(1, 0, 1);
|
||||
world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), pos.x, pos.y, pos.z, motion.x,
|
||||
motion.y + .25f, motion.z);
|
||||
}
|
||||
}
|
||||
|
||||
private static final RecipeWrapper pressingInv = new RecipeWrapper(new ItemStackHandler(1));
|
||||
|
||||
public Optional<PressingRecipe> getRecipe(ItemStack item) {
|
||||
pressingInv.setInventorySlotContents(0, item);
|
||||
return world.getRecipeManager()
|
||||
.getRecipe(AllRecipeTypes.PRESSING.getType(), pressingInv, world);
|
||||
return AllRecipeTypes.PRESSING.find(pressingInv, world);
|
||||
}
|
||||
|
||||
public static boolean canCompress(NonNullList<Ingredient> ingredients) {
|
||||
return (ingredients.size() == 4 || ingredients.size() == 9) && ItemHelper.condenseIngredients(ingredients)
|
||||
.size() == 1;
|
||||
return AllConfigs.SERVER.recipes.allowShapedSquareInPress.get()
|
||||
&& (ingredients.size() == 4 || ingredients.size() == 9) && ItemHelper.condenseIngredients(ingredients)
|
||||
.size() == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <C extends IInventory> boolean matchStaticFilters(IRecipe<C> recipe) {
|
||||
return recipe instanceof ICraftingRecipe && canCompress(recipe.getIngredients());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <C extends IInventory> boolean matchBasinRecipe(IRecipe<C> recipe) {
|
||||
if (!super.matchBasinRecipe(recipe))
|
||||
return false;
|
||||
|
||||
NonNullList<Ingredient> ingredients = recipe.getIngredients();
|
||||
List<ItemStack> remainingItems = new ArrayList<>();
|
||||
itemInputs.forEach(stack -> remainingItems.add(stack.copy()));
|
||||
|
||||
Ingredients: for (Ingredient ingredient : ingredients) {
|
||||
for (ItemStack stack : remainingItems) {
|
||||
if (stack.isEmpty())
|
||||
continue;
|
||||
if (ingredient.test(stack)) {
|
||||
stack.shrink(1);
|
||||
continue Ingredients;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return (recipe instanceof ICraftingRecipe && canCompress(recipe.getIngredients()))
|
||||
|| recipe.getType() == AllRecipeTypes.COMPACTING.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -310,7 +275,7 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
|
|||
|
||||
@Override
|
||||
public void startProcessingBasin() {
|
||||
if (running && runningTicks <= 30)
|
||||
if (running && runningTicks <= CYCLE / 2)
|
||||
return;
|
||||
super.startProcessingBasin();
|
||||
start(Mode.BASIN);
|
||||
|
@ -329,4 +294,21 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
|
|||
return running;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<ITriggerable> getProcessedRecipeTrigger() {
|
||||
return Optional.of(AllTriggers.PRESS_COMPACT);
|
||||
}
|
||||
|
||||
enum Mode {
|
||||
WORLD(1), BELT(19f / 16f), BASIN(22f / 16f)
|
||||
|
||||
;
|
||||
|
||||
float headOffset;
|
||||
|
||||
Mode(float headOffset) {
|
||||
this.headOffset = headOffset;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,21 +3,21 @@ package com.simibubi.create.content.contraptions.components.press;
|
|||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import com.simibubi.create.AllRecipeTypes;
|
||||
import com.simibubi.create.content.contraptions.components.press.MechanicalPressTileEntity.PressingInv;
|
||||
import com.simibubi.create.content.contraptions.processing.ProcessingRecipe;
|
||||
import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams;
|
||||
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.items.wrapper.RecipeWrapper;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
public class PressingRecipe extends ProcessingRecipe<MechanicalPressTileEntity.PressingInv> {
|
||||
public class PressingRecipe extends ProcessingRecipe<RecipeWrapper> {
|
||||
|
||||
public PressingRecipe(ProcessingRecipeParams params) {
|
||||
super(AllRecipeTypes.PRESSING, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(PressingInv inv, World worldIn) {
|
||||
public boolean matches(RecipeWrapper inv, World worldIn) {
|
||||
if (inv.isEmpty())
|
||||
return false;
|
||||
return ingredients.get(0)
|
||||
|
|
|
@ -8,9 +8,11 @@ import java.util.List;
|
|||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.simibubi.create.AllRecipeTypes;
|
||||
import com.simibubi.create.content.contraptions.components.actors.BlockBreakingKineticTileEntity;
|
||||
import com.simibubi.create.content.contraptions.processing.ProcessingInventory;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.item.ItemHelper;
|
||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour;
|
||||
|
@ -264,8 +266,10 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity {
|
|||
}
|
||||
|
||||
private List<? extends IRecipe<?>> getRecipes() {
|
||||
List<IRecipe<?>> startedSearch = RecipeFinder.get(cuttingRecipesKey, world,
|
||||
RecipeConditions.isOfType(IRecipeType.STONECUTTING, AllRecipeTypes.CUTTING.getType()));
|
||||
Predicate<IRecipe<?>> types = AllConfigs.SERVER.recipes.allowStonecuttingOnSaw.get()
|
||||
? RecipeConditions.isOfType(IRecipeType.STONECUTTING, AllRecipeTypes.CUTTING.getType())
|
||||
: RecipeConditions.isOfType(AllRecipeTypes.CUTTING.getType());
|
||||
List<IRecipe<?>> startedSearch = RecipeFinder.get(cuttingRecipesKey, world, types);
|
||||
return startedSearch.stream()
|
||||
.filter(RecipeConditions.outputMatchesFilter(filtering))
|
||||
.filter(RecipeConditions.firstIngredientMatches(inventory.getStackInSlot(0)))
|
||||
|
|
|
@ -9,13 +9,13 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.simibubi.create.AllMovementBehaviours;
|
||||
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||
import org.apache.commons.lang3.mutable.MutableObject;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllMovementBehaviours;
|
||||
import com.simibubi.create.content.contraptions.components.actors.BlockBreakingMovementBehaviour;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.sync.ClientMotionPacket;
|
||||
import com.simibubi.create.foundation.collision.ContinuousOBBCollider.ContinuousSeparationManifold;
|
||||
|
@ -28,6 +28,7 @@ import com.simibubi.create.foundation.utility.VecHelper;
|
|||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.CocoaBlock;
|
||||
import net.minecraft.client.entity.player.ClientPlayerEntity;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
|
@ -37,6 +38,7 @@ import net.minecraft.util.Direction.AxisDirection;
|
|||
import net.minecraft.util.ReuseableStream;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.shapes.IBooleanFunction;
|
||||
import net.minecraft.util.math.shapes.ISelectionContext;
|
||||
|
@ -44,6 +46,9 @@ import net.minecraft.util.math.shapes.VoxelShape;
|
|||
import net.minecraft.util.math.shapes.VoxelShapes;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
|
||||
public class ContraptionCollider {
|
||||
|
||||
|
@ -54,14 +59,20 @@ public class ContraptionCollider {
|
|||
for (Iterator<WeakReference<ContraptionEntity>> iterator = list.iterator(); iterator.hasNext();) {
|
||||
WeakReference<ContraptionEntity> weakReference = iterator.next();
|
||||
ContraptionEntity contraptionEntity = weakReference.get();
|
||||
if (contraptionEntity == null || !contraptionEntity.isAlive()) {
|
||||
if (contraptionEntity == null) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
if (!contraptionEntity.isAlive())
|
||||
continue;
|
||||
collideEntities(contraptionEntity);
|
||||
}
|
||||
}
|
||||
|
||||
enum PlayerType {
|
||||
NONE, CLIENT, REMOTE, SERVER
|
||||
}
|
||||
|
||||
private static void collideEntities(ContraptionEntity contraptionEntity) {
|
||||
World world = contraptionEntity.getEntityWorld();
|
||||
Contraption contraption = contraptionEntity.getContraption();
|
||||
|
@ -87,8 +98,10 @@ public class ContraptionCollider {
|
|||
|
||||
for (Entity entity : world.getEntitiesWithinAABB((EntityType<?>) null, bounds.grow(2)
|
||||
.expand(0, 32, 0), contraptionEntity::canCollideWith)) {
|
||||
boolean player = entity instanceof PlayerEntity;
|
||||
boolean serverPlayer = player && !world.isRemote;
|
||||
|
||||
PlayerType playerType = getPlayerType(entity);
|
||||
if (playerType == PlayerType.REMOTE)
|
||||
continue;
|
||||
|
||||
// Init matrix
|
||||
if (rotation == null) {
|
||||
|
@ -199,7 +212,7 @@ public class ContraptionCollider {
|
|||
totalResponse = rotation.transform(totalResponse);
|
||||
rotation.transpose();
|
||||
|
||||
if (futureCollision.isTrue() && !serverPlayer) {
|
||||
if (futureCollision.isTrue() && playerType != PlayerType.SERVER) {
|
||||
if (motionResponse.y != entityMotion.y) {
|
||||
entity.setMotion(entityMotion.mul(1, 0, 1)
|
||||
.add(0, motionResponse.y, 0));
|
||||
|
@ -212,7 +225,7 @@ public class ContraptionCollider {
|
|||
entity.fallDistance = 0;
|
||||
entity.onGround = true;
|
||||
contraptionEntity.collidingEntities.add(entity);
|
||||
if (!serverPlayer)
|
||||
if (playerType != PlayerType.SERVER)
|
||||
contactPointMotion = contraptionEntity.getContactPointMotion(entityPosition);
|
||||
}
|
||||
|
||||
|
@ -236,7 +249,7 @@ public class ContraptionCollider {
|
|||
if (!hardCollision && surfaceCollision.isFalse())
|
||||
continue;
|
||||
|
||||
if (serverPlayer && entity instanceof ServerPlayerEntity) {
|
||||
if (playerType == PlayerType.SERVER && entity instanceof ServerPlayerEntity) {
|
||||
((ServerPlayerEntity) entity).connection.floatingTickCount = 0;
|
||||
continue;
|
||||
}
|
||||
|
@ -249,8 +262,15 @@ public class ContraptionCollider {
|
|||
entityPosition.z + allowedMovement.z);
|
||||
entity.setMotion(entityMotion);
|
||||
|
||||
if (!serverPlayer && player)
|
||||
AllPackets.channel.sendToServer(new ClientMotionPacket(entityMotion, true));
|
||||
if (playerType != PlayerType.CLIENT)
|
||||
continue;
|
||||
|
||||
double d0 = entity.getX() - entity.prevPosX - contactPointMotion.x;
|
||||
double d1 = entity.getZ() - entity.prevPosZ - contactPointMotion.z;
|
||||
float limbSwing = MathHelper.sqrt(d0 * d0 + d1 * d1) * 4.0F;
|
||||
if (limbSwing > 1.0F)
|
||||
limbSwing = 1.0F;
|
||||
AllPackets.channel.sendToServer(new ClientMotionPacket(entityMotion, true, limbSwing));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -296,6 +316,21 @@ public class ContraptionCollider {
|
|||
return vec3d;
|
||||
}
|
||||
|
||||
private static PlayerType getPlayerType(Entity entity) {
|
||||
if (!(entity instanceof PlayerEntity))
|
||||
return PlayerType.NONE;
|
||||
if (!entity.world.isRemote)
|
||||
return PlayerType.SERVER;
|
||||
MutableBoolean isClient = new MutableBoolean(false);
|
||||
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> isClient.setValue(isClientPlayerEntity(entity)));
|
||||
return isClient.booleanValue() ? PlayerType.CLIENT : PlayerType.REMOTE;
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private static boolean isClientPlayerEntity(Entity entity) {
|
||||
return entity instanceof ClientPlayerEntity;
|
||||
}
|
||||
|
||||
private static ReuseableStream<VoxelShape> getPotentiallyCollidedShapes(World world, Contraption contraption,
|
||||
AxisAlignedBB localBB) {
|
||||
|
||||
|
@ -395,10 +430,10 @@ public class ContraptionCollider {
|
|||
BlockInfo blockInfo = contraption.blocks.get(pos);
|
||||
|
||||
if (AllMovementBehaviours.hasMovementBehaviour(blockInfo.state.getBlock())) {
|
||||
MovementBehaviour movementBehaviour = AllMovementBehaviours.getMovementBehaviour(blockInfo.state.getBlock());
|
||||
MovementBehaviour movementBehaviour =
|
||||
AllMovementBehaviours.getMovementBehaviour(blockInfo.state.getBlock());
|
||||
if (movementBehaviour instanceof BlockBreakingMovementBehaviour) {
|
||||
BlockBreakingMovementBehaviour behaviour =
|
||||
(BlockBreakingMovementBehaviour) movementBehaviour;
|
||||
BlockBreakingMovementBehaviour behaviour = (BlockBreakingMovementBehaviour) movementBehaviour;
|
||||
if (!behaviour.canBreak(world, colliderPos, collidedState)
|
||||
&& !collidedState.getCollisionShape(world, pos)
|
||||
.isEmpty()) {
|
||||
|
|
|
@ -78,6 +78,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
|||
final List<Entity> collidingEntities = new ArrayList<>();
|
||||
private boolean isSerializingFurnaceCart;
|
||||
private boolean attachedExtraInventories;
|
||||
private boolean prevPosInvalid;
|
||||
|
||||
private static final Ingredient FUEL_ITEMS = Ingredient.fromItems(Items.COAL, Items.CHARCOAL);
|
||||
private static final DataParameter<Boolean> STALLED =
|
||||
|
@ -107,6 +108,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
|||
isSerializingFurnaceCart = false;
|
||||
attachedExtraInventories = false;
|
||||
forcedAngle = -1;
|
||||
prevPosInvalid = true;
|
||||
}
|
||||
|
||||
public static ContraptionEntity createMounted(World world, Contraption contraption, float initialAngle) {
|
||||
|
@ -289,26 +291,32 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
|||
remove();
|
||||
return;
|
||||
}
|
||||
|
||||
prevPosX = getX();
|
||||
prevPosY = getY();
|
||||
prevPosZ = getZ();
|
||||
prevPosInvalid = false;
|
||||
|
||||
if (!initialized)
|
||||
contraptionInitialize();
|
||||
|
||||
checkController();
|
||||
|
||||
Entity mountedEntity = getRidingEntity();
|
||||
if (mountedEntity != null) {
|
||||
tickAsPassenger(mountedEntity);
|
||||
super.tick();
|
||||
return;
|
||||
}
|
||||
|
||||
if (getMotion().length() < 1 / 4098f)
|
||||
setMotion(Vec3d.ZERO);
|
||||
|
||||
|
||||
move(getMotion().x, getMotion().y, getMotion().z);
|
||||
if (ContraptionCollider.collideBlocks(this))
|
||||
getController().collided();
|
||||
|
||||
tickActors(getPositionVec().subtract(prevPosX, prevPosY, prevPosZ));
|
||||
Vec3d movement = getPositionVec().subtract(prevPosX, prevPosY, prevPosZ);
|
||||
tickActors(movement);
|
||||
|
||||
prevYaw = yaw;
|
||||
prevPitch = pitch;
|
||||
|
@ -439,8 +447,6 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
|||
furnaceCart.deserializeNBT(nbt);
|
||||
}
|
||||
}
|
||||
|
||||
super.tick();
|
||||
}
|
||||
|
||||
public void tickActors(Vec3d movementVector) {
|
||||
|
@ -846,6 +852,9 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
|||
}
|
||||
|
||||
public Vec3d getContactPointMotion(Vec3d globalContactPoint) {
|
||||
if (prevPosInvalid)
|
||||
return Vec3d.ZERO;
|
||||
|
||||
Vec3d positionVec = getPositionVec();
|
||||
Vec3d conMotion = positionVec.subtract(getPrevPositionVec());
|
||||
Vec3d conAngularMotion = getRotationVec().subtract(getPrevRotationVec());
|
||||
|
@ -906,5 +915,10 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
|||
public void setCoupledCart(UUID id) {
|
||||
dataManager.set(COUPLED_CART, Optional.ofNullable(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnePlayerRiding() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import static java.util.concurrent.TimeUnit.SECONDS;
|
|||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
|
@ -28,7 +29,8 @@ public class ContraptionHandler {
|
|||
if (!(entity instanceof ContraptionEntity))
|
||||
return;
|
||||
try {
|
||||
List<WeakReference<ContraptionEntity>> list = activeContraptions.get(world, ArrayList::new);
|
||||
List<WeakReference<ContraptionEntity>> list =
|
||||
activeContraptions.get(world, () -> Collections.synchronizedList(new ArrayList<>()));
|
||||
ContraptionEntity contraption = (ContraptionEntity) entity;
|
||||
list.add(new WeakReference<>(contraption));
|
||||
} catch (ExecutionException e) {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
package com.simibubi.create.content.contraptions.components.structureMovement;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableObject;
|
||||
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionInteractionPacket;
|
||||
|
@ -9,6 +10,8 @@ import com.simibubi.create.foundation.utility.RaycastHelper.PredicateTraceResult
|
|||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.entity.player.ClientPlayerEntity;
|
||||
import net.minecraft.client.entity.player.RemoteClientPlayerEntity;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
|
@ -20,11 +23,38 @@ import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.client.event.InputEvent.ClickInputEvent;
|
||||
import net.minecraftforge.event.TickEvent.Phase;
|
||||
import net.minecraftforge.event.TickEvent.PlayerTickEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
|
||||
@EventBusSubscriber
|
||||
public class ContraptionInteractionHandler {
|
||||
public class ContraptionHandlerClient {
|
||||
|
||||
@SubscribeEvent
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void preventRemotePlayersWalkingAnimations(PlayerTickEvent event) {
|
||||
if (event.phase == Phase.START)
|
||||
return;
|
||||
if (!(event.player instanceof RemoteClientPlayerEntity))
|
||||
return;
|
||||
RemoteClientPlayerEntity remotePlayer = (RemoteClientPlayerEntity) event.player;
|
||||
CompoundNBT data = remotePlayer.getPersistentData();
|
||||
if (!data.contains("LastOverrideLimbSwingUpdate"))
|
||||
return;
|
||||
|
||||
int lastOverride = data.getInt("LastOverrideLimbSwingUpdate");
|
||||
data.putInt("LastOverrideLimbSwingUpdate", lastOverride + 1);
|
||||
if (lastOverride > 5) {
|
||||
data.remove("LastOverrideLimbSwingUpdate");
|
||||
data.remove("OverrideLimbSwing");
|
||||
return;
|
||||
}
|
||||
|
||||
float limbSwing = data.getFloat("OverrideLimbSwing");
|
||||
remotePlayer.prevPosX = remotePlayer.getX() - (limbSwing / 4);
|
||||
remotePlayer.prevPosZ = remotePlayer.getZ();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
|
@ -38,11 +68,12 @@ public class ContraptionInteractionHandler {
|
|||
if (!event.isUseItem())
|
||||
return;
|
||||
Vec3d origin = RaycastHelper.getTraceOrigin(player);
|
||||
|
||||
|
||||
double reach = mc.playerController.getBlockReachDistance();
|
||||
if (mc.objectMouseOver != null && mc.objectMouseOver.getHitVec() != null)
|
||||
reach = Math.min(mc.objectMouseOver.getHitVec().distanceTo(origin), reach);
|
||||
|
||||
if (mc.objectMouseOver != null && mc.objectMouseOver.getHitVec() != null)
|
||||
reach = Math.min(mc.objectMouseOver.getHitVec()
|
||||
.distanceTo(origin), reach);
|
||||
|
||||
Vec3d target = RaycastHelper.getTraceTarget(player, reach, origin);
|
||||
for (ContraptionEntity contraptionEntity : mc.world.getEntitiesWithinAABB(ContraptionEntity.class,
|
||||
new AxisAlignedBB(origin, target))) {
|
||||
|
@ -75,11 +106,10 @@ public class ContraptionInteractionHandler {
|
|||
Hand hand = event.getHand();
|
||||
Direction face = rayTraceResult.getFace();
|
||||
BlockPos pos = rayTraceResult.getPos();
|
||||
|
||||
|
||||
if (!contraptionEntity.handlePlayerInteraction(player, pos, face, hand))
|
||||
return;
|
||||
AllPackets.channel.sendToServer(new ContraptionInteractionPacket(contraptionEntity, hand,
|
||||
pos, face));
|
||||
AllPackets.channel.sendToServer(new ContraptionInteractionPacket(contraptionEntity, hand, pos, face));
|
||||
event.setCanceled(true);
|
||||
event.setSwingHand(false);
|
||||
}
|
|
@ -2,26 +2,31 @@ package com.simibubi.create.content.contraptions.components.structureMovement.sy
|
|||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
||||
|
||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.fml.network.NetworkEvent.Context;
|
||||
import net.minecraftforge.fml.network.PacketDistributor;
|
||||
|
||||
public class ClientMotionPacket extends SimplePacketBase {
|
||||
|
||||
private Vec3d motion;
|
||||
private boolean onGround;
|
||||
private float limbSwing;
|
||||
|
||||
public ClientMotionPacket(Vec3d motion, boolean onGround) {
|
||||
public ClientMotionPacket(Vec3d motion, boolean onGround, float limbSwing) {
|
||||
this.motion = motion;
|
||||
this.onGround = onGround;
|
||||
this.limbSwing = limbSwing;
|
||||
}
|
||||
|
||||
public ClientMotionPacket(PacketBuffer buffer) {
|
||||
motion = new Vec3d(buffer.readFloat(), buffer.readFloat(), buffer.readFloat());
|
||||
onGround = buffer.readBoolean();
|
||||
limbSwing = buffer.readFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -30,6 +35,7 @@ public class ClientMotionPacket extends SimplePacketBase {
|
|||
buffer.writeFloat((float) motion.y);
|
||||
buffer.writeFloat((float) motion.z);
|
||||
buffer.writeBoolean(onGround);
|
||||
buffer.writeFloat(limbSwing);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -47,6 +53,8 @@ public class ClientMotionPacket extends SimplePacketBase {
|
|||
sender.fallDistance = 0;
|
||||
sender.connection.floatingTickCount = 0;
|
||||
}
|
||||
AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> sender),
|
||||
new LimbSwingUpdatePacket(sender.getEntityId(), sender.getPositionVec(), limbSwing));
|
||||
});
|
||||
context.get()
|
||||
.setPacketHandled(true);
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
package com.simibubi.create.content.contraptions.components.structureMovement.sync;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.fml.network.NetworkEvent.Context;
|
||||
|
||||
public class LimbSwingUpdatePacket extends SimplePacketBase {
|
||||
|
||||
private int entityId;
|
||||
private Vec3d position;
|
||||
private float limbSwing;
|
||||
|
||||
public LimbSwingUpdatePacket(int entityId, Vec3d position, float limbSwing) {
|
||||
this.entityId = entityId;
|
||||
this.position = position;
|
||||
this.limbSwing = limbSwing;
|
||||
}
|
||||
|
||||
public LimbSwingUpdatePacket(PacketBuffer buffer) {
|
||||
entityId = buffer.readInt();
|
||||
position = new Vec3d(buffer.readFloat(), buffer.readFloat(), buffer.readFloat());
|
||||
limbSwing = buffer.readFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(PacketBuffer buffer) {
|
||||
buffer.writeInt(entityId);
|
||||
buffer.writeFloat((float) position.x);
|
||||
buffer.writeFloat((float) position.y);
|
||||
buffer.writeFloat((float) position.z);
|
||||
buffer.writeFloat(limbSwing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Supplier<Context> context) {
|
||||
context.get()
|
||||
.enqueueWork(() -> {
|
||||
ClientWorld world = Minecraft.getInstance().world;
|
||||
if (world == null)
|
||||
return;
|
||||
Entity entity = world.getEntityByID(entityId);
|
||||
if (entity == null)
|
||||
return;
|
||||
CompoundNBT data = entity.getPersistentData();
|
||||
data.putInt("LastOverrideLimbSwingUpdate", 0);
|
||||
data.putFloat("OverrideLimbSwing", limbSwing);
|
||||
entity.setPositionAndRotationDirect(position.x, position.y, position.z, entity.rotationYaw,
|
||||
entity.rotationPitch, 2, false);
|
||||
});
|
||||
context.get()
|
||||
.setPacketHandled(true);
|
||||
}
|
||||
|
||||
}
|
|
@ -24,8 +24,7 @@ public class FillingBySpout {
|
|||
|
||||
public static boolean canItemBeFilled(World world, ItemStack stack) {
|
||||
wrapper.setInventorySlotContents(0, stack);
|
||||
if (world.getRecipeManager()
|
||||
.getRecipe(AllRecipeTypes.FILLING.getType(), wrapper, world)
|
||||
if (AllRecipeTypes.FILLING.find(wrapper, world)
|
||||
.isPresent())
|
||||
return true;
|
||||
|
||||
|
@ -44,8 +43,7 @@ public class FillingBySpout {
|
|||
|
||||
public static int getRequiredAmountForItem(World world, ItemStack stack, FluidStack availableFluid) {
|
||||
wrapper.setInventorySlotContents(0, stack);
|
||||
Optional<IRecipe<RecipeWrapper>> recipe = world.getRecipeManager()
|
||||
.getRecipe(AllRecipeTypes.FILLING.getType(), wrapper, world);
|
||||
Optional<IRecipe<RecipeWrapper>> recipe = AllRecipeTypes.FILLING.find(wrapper, world);
|
||||
if (recipe.isPresent()) {
|
||||
FillingRecipe fillingRecipe = (FillingRecipe) recipe.get();
|
||||
FluidIngredient requiredFluid = fillingRecipe.getRequiredFluid();
|
||||
|
@ -71,8 +69,7 @@ public class FillingBySpout {
|
|||
availableFluid.shrink(requiredAmount);
|
||||
|
||||
wrapper.setInventorySlotContents(0, stack);
|
||||
Optional<IRecipe<RecipeWrapper>> recipe = world.getRecipeManager()
|
||||
.getRecipe(AllRecipeTypes.FILLING.getType(), wrapper, world);
|
||||
Optional<IRecipe<RecipeWrapper>> recipe = AllRecipeTypes.FILLING.find(wrapper, world);
|
||||
if (recipe.isPresent()) {
|
||||
FillingRecipe fillingRecipe = (FillingRecipe) recipe.get();
|
||||
FluidIngredient requiredFluid = fillingRecipe.getRequiredFluid();
|
||||
|
|
|
@ -9,16 +9,23 @@ import com.simibubi.create.foundation.block.ITE;
|
|||
import com.simibubi.create.foundation.item.ItemHelper;
|
||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.item.ItemEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.BlockItemUseContext;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.ItemUseContext;
|
||||
import net.minecraft.state.DirectionProperty;
|
||||
import net.minecraft.state.StateContainer.Builder;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.ActionResultType;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
|
@ -26,14 +33,22 @@ import net.minecraft.util.math.shapes.ISelectionContext;
|
|||
import net.minecraft.util.math.shapes.VoxelShape;
|
||||
import net.minecraft.world.IBlockReader;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
|
||||
import net.minecraftforge.items.IItemHandlerModifiable;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
import net.minecraftforge.items.ItemStackHandler;
|
||||
|
||||
public class BasinBlock extends Block implements ITE<BasinTileEntity>, IWrenchable {
|
||||
|
||||
public static final DirectionProperty FACING = BlockStateProperties.FACING_EXCEPT_UP;
|
||||
|
||||
public BasinBlock(Properties p_i48440_1_) {
|
||||
super(p_i48440_1_);
|
||||
setDefaultState(getDefaultState().with(FACING, Direction.DOWN));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -41,6 +56,11 @@ public class BasinBlock extends Block implements ITE<BasinTileEntity>, IWrenchab
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fillStateContainer(Builder<Block, BlockState> p_206840_1_) {
|
||||
super.fillStateContainer(p_206840_1_.add(FACING));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
|
||||
return AllTileEntities.BASIN.create();
|
||||
|
@ -54,12 +74,16 @@ public class BasinBlock extends Block implements ITE<BasinTileEntity>, IWrenchab
|
|||
@Override
|
||||
public ActionResultType onUse(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn,
|
||||
BlockRayTraceResult hit) {
|
||||
if (!player.getHeldItem(handIn)
|
||||
.isEmpty())
|
||||
return ActionResultType.PASS;
|
||||
ItemStack heldItem = player.getHeldItem(handIn);
|
||||
|
||||
try {
|
||||
BasinTileEntity te = getTileEntity(worldIn, pos);
|
||||
if (!heldItem.isEmpty()) {
|
||||
if (tryEmptyItemIntoBasin(worldIn, player, handIn, heldItem, te))
|
||||
return ActionResultType.SUCCESS;
|
||||
return ActionResultType.PASS;
|
||||
}
|
||||
|
||||
IItemHandlerModifiable inv = te.itemCapability.orElse(new ItemStackHandler(1));
|
||||
for (int slot = 0; slot < inv.getSlots(); slot++) {
|
||||
player.inventory.placeItemBackInInventory(worldIn, inv.getStackInSlot(slot));
|
||||
|
@ -72,6 +96,30 @@ public class BasinBlock extends Block implements ITE<BasinTileEntity>, IWrenchab
|
|||
return ActionResultType.SUCCESS;
|
||||
}
|
||||
|
||||
protected boolean tryEmptyItemIntoBasin(World worldIn, PlayerEntity player, Hand handIn, ItemStack heldItem,
|
||||
BasinTileEntity te) {
|
||||
if (!EmptyingByBasin.canItemBeEmptied(worldIn, heldItem))
|
||||
return false;
|
||||
|
||||
Pair<FluidStack, ItemStack> emptyItem = EmptyingByBasin.emptyItem(worldIn, heldItem, true);
|
||||
LazyOptional<IFluidHandler> capability = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY);
|
||||
IFluidHandler tank = capability.orElse(null);
|
||||
FluidStack fluidStack = emptyItem.getFirst();
|
||||
|
||||
if (tank == null || fluidStack.getAmount() != tank.fill(fluidStack, FluidAction.SIMULATE))
|
||||
return false;
|
||||
if (worldIn.isRemote)
|
||||
return true;
|
||||
|
||||
EmptyingByBasin.emptyItem(worldIn, heldItem, false);
|
||||
tank.fill(fluidStack, FluidAction.EXECUTE);
|
||||
if (heldItem.isEmpty())
|
||||
player.setHeldItem(handIn, emptyItem.getSecond());
|
||||
else
|
||||
player.inventory.placeItemBackInInventory(worldIn, emptyItem.getSecond());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLanded(IBlockReader worldIn, Entity entityIn) {
|
||||
super.onLanded(worldIn, entityIn);
|
||||
|
@ -102,6 +150,11 @@ public class BasinBlock extends Block implements ITE<BasinTileEntity>, IWrenchab
|
|||
return AllShapes.BASIN_BLOCK_SHAPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockAdded(BlockState state, World world, BlockPos pos, BlockState p_220082_4_, boolean p_220082_5_) {
|
||||
updateDiagonalNeighbours(state, world, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getCollisionShape(BlockState state, IBlockReader reader, BlockPos pos, ISelectionContext ctx) {
|
||||
if (ctx.getEntity() instanceof ItemEntity)
|
||||
|
@ -111,6 +164,7 @@ public class BasinBlock extends Block implements ITE<BasinTileEntity>, IWrenchab
|
|||
|
||||
@Override
|
||||
public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) {
|
||||
updateDiagonalNeighbours(state, worldIn, pos);
|
||||
if (!state.hasTileEntity() || state.getBlock() == newState.getBlock())
|
||||
return;
|
||||
TileEntityBehaviour.destroy(worldIn, pos, FilteringBehaviour.TYPE);
|
||||
|
@ -140,4 +194,35 @@ public class BasinBlock extends Block implements ITE<BasinTileEntity>, IWrenchab
|
|||
return BasinTileEntity.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getStateForPlacement(BlockItemUseContext ctx) {
|
||||
BlockState state = super.getStateForPlacement(ctx);
|
||||
World world = ctx.getWorld();
|
||||
BlockPos pos = ctx.getPos();
|
||||
return updateDiagonalState(state, world, pos);
|
||||
}
|
||||
|
||||
protected void updateDiagonalNeighbours(BlockState state, World world, BlockPos pos) {
|
||||
for (Direction direction : Iterate.horizontalDirections) {
|
||||
BlockPos toUpdate = pos.up()
|
||||
.offset(direction);
|
||||
BlockState stateToUpdate = world.getBlockState(toUpdate);
|
||||
BlockState updated = updateDiagonalState(stateToUpdate, world, toUpdate);
|
||||
if (stateToUpdate != updated && !world.isRemote)
|
||||
world.setBlockState(toUpdate, updated);
|
||||
}
|
||||
}
|
||||
|
||||
public static BlockState updateDiagonalState(BlockState state, IBlockReader world, BlockPos pos) {
|
||||
if (!(state.getBlock() instanceof BasinBlock))
|
||||
return state;
|
||||
for (Direction direction : Iterate.horizontalDirections) {
|
||||
BlockState diagonaloutputBasin = world.getBlockState(pos.down()
|
||||
.offset(direction));
|
||||
if (diagonaloutputBasin.getBlock() instanceof BasinBlock)
|
||||
return state.with(FACING, direction);
|
||||
}
|
||||
return state.with(FACING, Direction.DOWN);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package com.simibubi.create.content.contraptions.processing;
|
||||
|
||||
import com.simibubi.create.foundation.data.AssetLookup;
|
||||
import com.simibubi.create.foundation.data.SpecialBlockStateGen;
|
||||
import com.tterrag.registrate.providers.DataGenContext;
|
||||
import com.tterrag.registrate.providers.RegistrateBlockstateProvider;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraftforge.client.model.generators.ModelFile;
|
||||
|
||||
public class BasinGenerator extends SpecialBlockStateGen {
|
||||
|
||||
@Override
|
||||
protected int getXRotation(BlockState state) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getYRotation(BlockState state) {
|
||||
return horizontalAngle(state.get(BasinBlock.FACING));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Block> ModelFile getModel(DataGenContext<Block, T> ctx, RegistrateBlockstateProvider prov,
|
||||
BlockState state) {
|
||||
if (state.get(BasinBlock.FACING).getAxis().isVertical())
|
||||
return AssetLookup.partialBaseModel(ctx, prov);
|
||||
return AssetLookup.partialBaseModel(ctx, prov, "directional");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
package com.simibubi.create.content.contraptions.processing;
|
||||
|
||||
import com.simibubi.create.foundation.item.SmartInventory;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
|
||||
public class BasinInputInventory extends SmartInventory {
|
||||
|
||||
public BasinInputInventory(int slots, BasinTileEntity te) {
|
||||
super(slots, te);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
|
||||
// Only insert if no other slot already has a 'full' stack of this item
|
||||
for (int i = 0; i < getSlots(); i++) {
|
||||
ItemStack stackInSlot = getStackInSlot(i);
|
||||
if (ItemHandlerHelper.canItemStacksStack(stack, stackInSlot)
|
||||
&& stackInSlot.getCount() == getStackLimit(i, stackInSlot))
|
||||
return stack;
|
||||
}
|
||||
|
||||
return super.insertItem(slot, stack, simulate);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.simibubi.create.content.contraptions.processing;
|
||||
|
||||
import com.simibubi.create.foundation.item.SmartInventory;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
|
||||
public class BasinInventory extends SmartInventory {
|
||||
|
||||
public BasinInventory(int slots, BasinTileEntity te) {
|
||||
super(slots, te, 16, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
|
||||
// Only insert if no other slot already has a stack of this item
|
||||
for (int i = 0; i < getSlots(); i++)
|
||||
if (i != slot && ItemHandlerHelper.canItemStacksStack(stack, inv.getStackInSlot(i)))
|
||||
return stack;
|
||||
return super.insertItem(slot, stack, simulate);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,49 +1,29 @@
|
|||
package com.simibubi.create.content.contraptions.processing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.simibubi.create.AllTileEntities;
|
||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.foundation.advancement.AllTriggers;
|
||||
import com.simibubi.create.foundation.advancement.SimpleTrigger;
|
||||
import com.simibubi.create.foundation.item.SmartInventory;
|
||||
import com.simibubi.create.foundation.advancement.ITriggerable;
|
||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.simple.DeferralBehaviour;
|
||||
import com.simibubi.create.foundation.utility.recipe.RecipeFinder;
|
||||
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.tileentity.TileEntityType;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||
import net.minecraftforge.items.CapabilityItemHandler;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
|
||||
public abstract class BasinOperatingTileEntity extends KineticTileEntity {
|
||||
|
||||
public DeferralBehaviour basinChecker;
|
||||
public boolean basinRemoved;
|
||||
protected IRecipe<?> lastRecipe;
|
||||
|
||||
protected LazyOptional<IItemHandler> basinItemInv = LazyOptional.empty();
|
||||
protected List<ItemStack> itemInputs;
|
||||
protected LazyOptional<IFluidHandler> basinFluidInv = LazyOptional.empty();
|
||||
protected List<FluidStack> fluidInputs;
|
||||
protected IRecipe<?> currentRecipe;
|
||||
|
||||
public BasinOperatingTileEntity(TileEntityType<?> typeIn) {
|
||||
super(typeIn);
|
||||
itemInputs = new ArrayList<>();
|
||||
fluidInputs = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -58,29 +38,10 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
|
|||
super.onSpeedChanged(prevSpeed);
|
||||
if (getSpeed() == 0)
|
||||
basinRemoved = true;
|
||||
basinRemoved = false;
|
||||
basinChecker.scheduleUpdate();
|
||||
}
|
||||
|
||||
public void gatherInputs() {
|
||||
itemInputs.clear();
|
||||
basinItemInv.ifPresent(handler -> {
|
||||
for (int slot = 0; slot < handler.getSlots(); ++slot) {
|
||||
ItemStack itemstack = handler.getStackInSlot(slot);
|
||||
if (!itemstack.isEmpty())
|
||||
itemInputs.add(itemstack);
|
||||
}
|
||||
});
|
||||
|
||||
fluidInputs.clear();
|
||||
basinFluidInv.ifPresent(handler -> {
|
||||
for (int tank = 0; tank < handler.getTanks(); tank++) {
|
||||
FluidStack fluidInTank = handler.getFluidInTank(tank);
|
||||
if (!fluidInTank.isEmpty())
|
||||
fluidInputs.add(fluidInTank);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (basinRemoved) {
|
||||
|
@ -100,28 +61,13 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
|
|||
return true;
|
||||
if (isRunning())
|
||||
return false;
|
||||
|
||||
Optional<BasinTileEntity> basinTe = getBasin();
|
||||
if (!basinTe.isPresent())
|
||||
return true;
|
||||
if (!basinItemInv.isPresent())
|
||||
basinItemInv = basinTe.get()
|
||||
.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY);
|
||||
if (!basinFluidInv.isPresent())
|
||||
basinFluidInv = basinTe.get()
|
||||
.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY);
|
||||
if (!basinFluidInv.isPresent() || !basinItemInv.isPresent())
|
||||
return true;
|
||||
|
||||
if (world == null || world.isRemote)
|
||||
return true;
|
||||
|
||||
gatherInputs();
|
||||
List<IRecipe<?>> recipes = getMatchingRecipes();
|
||||
if (recipes.isEmpty())
|
||||
return true;
|
||||
|
||||
lastRecipe = recipes.get(0);
|
||||
currentRecipe = recipes.get(0);
|
||||
startProcessingBasin();
|
||||
sendData();
|
||||
return true;
|
||||
|
@ -135,58 +81,37 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
|
|||
return true;
|
||||
}
|
||||
|
||||
public void applyBasinRecipe() {
|
||||
if (lastRecipe == null)
|
||||
return;
|
||||
if (!basinItemInv.isPresent() || !basinFluidInv.isPresent())
|
||||
return;
|
||||
|
||||
protected <C extends IInventory> boolean matchBasinRecipe(IRecipe<C> recipe) {
|
||||
if (recipe == null)
|
||||
return false;
|
||||
Optional<BasinTileEntity> basin = getBasin();
|
||||
if (!basin.isPresent())
|
||||
return false;
|
||||
return BasinRecipe.match(basin.get(), recipe);
|
||||
}
|
||||
|
||||
protected void applyBasinRecipe() {
|
||||
if (currentRecipe == null)
|
||||
return;
|
||||
SmartInventory inputs = basin.get().getInputInventory();
|
||||
SmartInventory outputs = basin.get().getOutputInventory();
|
||||
List<ItemStack> containers = new ArrayList<>();
|
||||
|
||||
NonNullList<Ingredient> ingredients = lastRecipe.getIngredients();
|
||||
Ingredients: for (int i = 0; i < ingredients.size(); i++) {
|
||||
Ingredient ingredient = ingredients.get(i);
|
||||
|
||||
for (int slot = 0; slot < inputs.getSlots(); slot++) {
|
||||
if (!ingredient.test(inputs.extractItem(slot, 1, true)))
|
||||
continue;
|
||||
ItemStack extracted = inputs.extractItem(slot, 1, false);
|
||||
if (extracted.hasContainerItem())
|
||||
containers.add(extracted.getContainerItem()
|
||||
.copy());
|
||||
continue Ingredients;
|
||||
}
|
||||
|
||||
// something wasn't found
|
||||
|
||||
Optional<BasinTileEntity> optionalBasin = getBasin();
|
||||
if (!optionalBasin.isPresent())
|
||||
return;
|
||||
}
|
||||
|
||||
if (world != null && !world.isRemote) {
|
||||
SimpleTrigger trigger = AllTriggers.MIXER_MIX;
|
||||
if (AllTileEntities.MECHANICAL_PRESS.is(this))
|
||||
trigger = AllTriggers.PRESS_COMPACT;
|
||||
AllTriggers.triggerForNearbyPlayers(trigger, world, pos, 4);
|
||||
}
|
||||
|
||||
outputs.allowInsertion();
|
||||
ItemHandlerHelper.insertItemStacked(outputs, lastRecipe.getRecipeOutput()
|
||||
.copy(), false); // TODO only works for single item output
|
||||
containers.forEach(stack -> ItemHandlerHelper.insertItemStacked(outputs, stack, false));
|
||||
outputs.forbidInsertion();
|
||||
|
||||
BasinTileEntity basin = optionalBasin.get();
|
||||
if (!BasinRecipe.apply(basin, currentRecipe))
|
||||
return;
|
||||
Optional<ITriggerable> processedRecipeTrigger = getProcessedRecipeTrigger();
|
||||
if (world != null && !world.isRemote && processedRecipeTrigger.isPresent())
|
||||
AllTriggers.triggerForNearbyPlayers(processedRecipeTrigger.get(), world, pos, 4);
|
||||
basin.inputTank.sendDataImmediately();
|
||||
|
||||
// Continue mixing
|
||||
gatherInputs();
|
||||
if (matchBasinRecipe(lastRecipe)) {
|
||||
if (matchBasinRecipe(currentRecipe)) {
|
||||
continueWithPreviousRecipe();
|
||||
sendData();
|
||||
}
|
||||
|
||||
getBasin().ifPresent(BasinTileEntity::notifyChangeOfContents);
|
||||
basin.notifyChangeOfContents();
|
||||
}
|
||||
|
||||
protected List<IRecipe<?>> getMatchingRecipes() {
|
||||
|
@ -210,28 +135,13 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
|
|||
return Optional.empty();
|
||||
return Optional.of((BasinTileEntity) basinTE);
|
||||
}
|
||||
|
||||
protected Optional<ITriggerable> getProcessedRecipeTrigger() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
protected abstract <C extends IInventory> boolean matchStaticFilters(IRecipe<C> recipe);
|
||||
|
||||
protected <C extends IInventory> boolean matchBasinRecipe(IRecipe<C> recipe) {
|
||||
if (recipe == null)
|
||||
return false;
|
||||
|
||||
Optional<BasinTileEntity> basin = getBasin();
|
||||
if (!basin.isPresent())
|
||||
return false;
|
||||
BasinTileEntity basinTileEntity = basin.get();
|
||||
if (!basinTileEntity.getFilter()
|
||||
.test(recipe.getRecipeOutput()))
|
||||
return false;
|
||||
|
||||
NonNullList<Ingredient> ingredients = recipe.getIngredients();
|
||||
if (!ingredients.stream()
|
||||
.allMatch(ingredient -> (ingredient.isSimple() || ingredient.getMatchingStacks().length == 1)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract Object getRecipeCacheKey();
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
package com.simibubi.create.content.contraptions.processing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.simibubi.create.AllRecipeTypes;
|
||||
import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams;
|
||||
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel;
|
||||
import com.simibubi.create.foundation.fluid.FluidIngredient;
|
||||
import com.simibubi.create.foundation.item.SmartInventory;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||
import net.minecraftforge.items.CapabilityItemHandler;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
|
||||
public class BasinRecipe extends ProcessingRecipe<SmartInventory> {
|
||||
|
||||
public static boolean match(BasinTileEntity basin, IRecipe<?> recipe) {
|
||||
FilteringBehaviour filter = basin.getFilter();
|
||||
if (filter == null || !filter.test(recipe.getRecipeOutput()))
|
||||
return false;
|
||||
return apply(basin, recipe, true);
|
||||
}
|
||||
|
||||
public static boolean apply(BasinTileEntity basin, IRecipe<?> recipe) {
|
||||
return apply(basin, recipe, false);
|
||||
}
|
||||
|
||||
private static boolean apply(BasinTileEntity basin, IRecipe<?> recipe, boolean test) {
|
||||
boolean isBasinRecipe = recipe instanceof BasinRecipe;
|
||||
IItemHandler availableItems = basin.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
|
||||
.orElse(null);
|
||||
IFluidHandler availableFluids = basin.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)
|
||||
.orElse(null);
|
||||
|
||||
if (availableItems == null || availableFluids == null)
|
||||
return false;
|
||||
|
||||
HeatLevel heat = basin.getHeatLevel();
|
||||
if (isBasinRecipe && !((BasinRecipe) recipe).getRequiredHeat()
|
||||
.testBlazeBurner(heat))
|
||||
return false;
|
||||
|
||||
List<ItemStack> recipeOutputItems = new ArrayList<>();
|
||||
List<FluidStack> recipeOutputFluids = new ArrayList<>();
|
||||
|
||||
List<Ingredient> ingredients = new LinkedList<>(recipe.getIngredients());
|
||||
ingredients.sort(Comparator.comparingInt(i -> i.getMatchingStacks().length));
|
||||
List<FluidIngredient> fluidIngredients =
|
||||
isBasinRecipe ? ((BasinRecipe) recipe).getFluidIngredients() : Collections.emptyList();
|
||||
|
||||
for (boolean simulate : Iterate.trueAndFalse) {
|
||||
|
||||
if (!simulate && test)
|
||||
return true;
|
||||
|
||||
int[] extractedItemsFromSlot = new int[availableItems.getSlots()];
|
||||
int[] extractedFluidsFromTank = new int[availableFluids.getTanks()];
|
||||
|
||||
Ingredients: for (int i = 0; i < ingredients.size(); i++) {
|
||||
Ingredient ingredient = ingredients.get(i);
|
||||
|
||||
for (int slot = 0; slot < availableItems.getSlots(); slot++) {
|
||||
if (simulate && availableItems.getStackInSlot(slot)
|
||||
.getCount() <= extractedItemsFromSlot[slot])
|
||||
continue;
|
||||
ItemStack extracted = availableItems.extractItem(slot, 1, true);
|
||||
if (!ingredient.test(extracted))
|
||||
continue;
|
||||
if (!simulate)
|
||||
availableItems.extractItem(slot, 1, false);
|
||||
else if (extracted.hasContainerItem())
|
||||
recipeOutputItems.add(extracted.getContainerItem()
|
||||
.copy());
|
||||
extractedItemsFromSlot[slot]++;
|
||||
continue Ingredients;
|
||||
}
|
||||
|
||||
// something wasn't found
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean fluidsAffected = false;
|
||||
FluidIngredients: for (int i = 0; i < fluidIngredients.size(); i++) {
|
||||
FluidIngredient fluidIngredient = fluidIngredients.get(i);
|
||||
int amountRequired = fluidIngredient.getRequiredAmount();
|
||||
|
||||
for (int tank = 0; tank < availableFluids.getTanks(); tank++) {
|
||||
FluidStack fluidStack = availableFluids.getFluidInTank(tank);
|
||||
if (simulate && fluidStack.getAmount() <= extractedFluidsFromTank[tank])
|
||||
continue;
|
||||
if (!fluidIngredient.test(fluidStack))
|
||||
continue;
|
||||
int drainedAmount = Math.min(amountRequired, fluidStack.getAmount());
|
||||
if (!simulate) {
|
||||
fluidStack.shrink(drainedAmount);
|
||||
fluidsAffected = true;
|
||||
}
|
||||
amountRequired -= drainedAmount;
|
||||
if (amountRequired != 0)
|
||||
continue;
|
||||
extractedFluidsFromTank[tank] += drainedAmount;
|
||||
continue FluidIngredients;
|
||||
}
|
||||
|
||||
// something wasn't found
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fluidsAffected) {
|
||||
basin.getBehaviour(SmartFluidTankBehaviour.INPUT)
|
||||
.foreach(TankSegment::onFluidStackChanged);
|
||||
basin.getBehaviour(SmartFluidTankBehaviour.OUTPUT)
|
||||
.foreach(TankSegment::onFluidStackChanged);
|
||||
}
|
||||
|
||||
if (simulate) {
|
||||
if (recipe instanceof BasinRecipe) {
|
||||
recipeOutputItems.addAll(((BasinRecipe) recipe).rollResults());
|
||||
recipeOutputFluids.addAll(((BasinRecipe) recipe).getFluidResults());
|
||||
} else
|
||||
recipeOutputItems.add(recipe.getRecipeOutput());
|
||||
}
|
||||
|
||||
if (!basin.acceptOutputs(recipeOutputItems, recipeOutputFluids, simulate))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* For JEI purposes only
|
||||
*/
|
||||
public boolean convertedRecipe;
|
||||
|
||||
public static BasinRecipe convert(IRecipe<?> recipe) {
|
||||
BasinRecipe basinRecipe = new ProcessingRecipeBuilder<>(BasinRecipe::new, recipe.getId())
|
||||
.withItemIngredients(recipe.getIngredients())
|
||||
.withSingleItemOutput(recipe.getRecipeOutput())
|
||||
.build();
|
||||
basinRecipe.convertedRecipe = true;
|
||||
return basinRecipe;
|
||||
}
|
||||
|
||||
protected BasinRecipe(AllRecipeTypes type, ProcessingRecipeParams params) {
|
||||
super(type, params);
|
||||
}
|
||||
|
||||
public BasinRecipe(ProcessingRecipeParams params) {
|
||||
this(AllRecipeTypes.BASIN, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaxInputCount() {
|
||||
return 9;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaxOutputCount() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaxFluidInputCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaxFluidOutputCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canRequireHeat() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(SmartInventory inv, @Nonnull World worldIn) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -79,16 +79,19 @@ public class BasinRenderer extends SmartTileEntityRenderer<BasinTileEntity> {
|
|||
if (tankSegment.getRenderedFluid()
|
||||
.isEmpty())
|
||||
continue;
|
||||
totalUnits += tankSegment.getTotalUnits(partialTicks);
|
||||
float units = tankSegment.getTotalUnits(partialTicks);
|
||||
if (units < 1)
|
||||
continue;
|
||||
totalUnits += units;
|
||||
renderedFluids++;
|
||||
}
|
||||
}
|
||||
|
||||
if (renderedFluids == 0)
|
||||
return 0;
|
||||
if (totalUnits == 0)
|
||||
if (totalUnits < 1)
|
||||
return 0;
|
||||
|
||||
|
||||
float fluidLevel = MathHelper.clamp(totalUnits / 2000, 0, 1);
|
||||
|
||||
float xMin = 2 / 16f;
|
||||
|
@ -105,8 +108,11 @@ public class BasinRenderer extends SmartTileEntityRenderer<BasinTileEntity> {
|
|||
FluidStack renderedFluid = tankSegment.getRenderedFluid();
|
||||
if (renderedFluid.isEmpty())
|
||||
continue;
|
||||
|
||||
float partial = tankSegment.getTotalUnits(partialTicks) / totalUnits;
|
||||
float units = tankSegment.getTotalUnits(partialTicks);
|
||||
if (units < 1)
|
||||
continue;
|
||||
|
||||
float partial = units / totalUnits;
|
||||
xMax += partial * 12 / 16f;
|
||||
FluidRenderer.renderTiledFluidBB(renderedFluid, xMin, yMin, zMin, xMax, yMax, zMax, buffer, ms, light,
|
||||
false);
|
||||
|
@ -114,7 +120,7 @@ public class BasinRenderer extends SmartTileEntityRenderer<BasinTileEntity> {
|
|||
xMin = xMax;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return fluidLevel;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,9 @@ import java.util.Optional;
|
|||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.simibubi.create.AllTags;
|
||||
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock;
|
||||
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel;
|
||||
import com.simibubi.create.foundation.fluid.CombinedTankWrapper;
|
||||
import com.simibubi.create.foundation.item.SmartInventory;
|
||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||
|
@ -13,30 +16,36 @@ import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform;
|
|||
import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.tileentity.ITickableTileEntity;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.tileentity.TileEntityType;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
|
||||
import net.minecraftforge.items.CapabilityItemHandler;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import net.minecraftforge.items.IItemHandlerModifiable;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
import net.minecraftforge.items.wrapper.CombinedInvWrapper;
|
||||
|
||||
public class BasinTileEntity extends SmartTileEntity implements ITickableTileEntity {
|
||||
|
||||
public BasinInputInventory inputInventory;
|
||||
public BasinInventory inputInventory;
|
||||
public SmartFluidTankBehaviour inputTank;
|
||||
|
||||
protected SmartInventory outputInventory;
|
||||
protected SmartFluidTankBehaviour outputTank;
|
||||
|
||||
|
@ -48,12 +57,11 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt
|
|||
|
||||
public BasinTileEntity(TileEntityType<? extends BasinTileEntity> type) {
|
||||
super(type);
|
||||
inputInventory = new BasinInputInventory(9, this);
|
||||
inputInventory.withMaxStackSize(8)
|
||||
.forbidExtraction();
|
||||
outputInventory = new SmartInventory(9, this).forbidInsertion();
|
||||
itemCapability = LazyOptional.of(() -> new CombinedInvWrapper(inputInventory, outputInventory));
|
||||
inputInventory = new BasinInventory(9, this);
|
||||
inputInventory.whenContentsChanged(() -> contentsChanged = true);
|
||||
outputInventory = new BasinInventory(9, this).forbidInsertion();
|
||||
|
||||
itemCapability = LazyOptional.of(() -> new CombinedInvWrapper(inputInventory, outputInventory));
|
||||
contentsChanged = true;
|
||||
}
|
||||
|
||||
|
@ -65,7 +73,8 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt
|
|||
.forRecipes();
|
||||
behaviours.add(filtering);
|
||||
|
||||
inputTank = new SmartFluidTankBehaviour(SmartFluidTankBehaviour.INPUT, this, 2, 1000, true).forbidExtraction();
|
||||
inputTank = new SmartFluidTankBehaviour(SmartFluidTankBehaviour.INPUT, this, 2, 1000, true)
|
||||
.whenFluidUpdates(() -> contentsChanged = true);
|
||||
outputTank = new SmartFluidTankBehaviour(SmartFluidTankBehaviour.OUTPUT, this, 2, 1000, true).forbidInsertion();
|
||||
behaviours.add(inputTank);
|
||||
behaviours.add(outputTank);
|
||||
|
@ -112,6 +121,16 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt
|
|||
return super.getCapability(cap, side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyUpdate() {
|
||||
super.notifyUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lazyTick() {
|
||||
super.lazyTick();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
@ -119,6 +138,17 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt
|
|||
return;
|
||||
contentsChanged = false;
|
||||
getOperator().ifPresent(te -> te.basinChecker.scheduleUpdate());
|
||||
|
||||
for (Direction offset : Iterate.horizontalDirections) {
|
||||
BlockPos toUpdate = pos.up()
|
||||
.offset(offset);
|
||||
BlockState stateToUpdate = world.getBlockState(toUpdate);
|
||||
if (stateToUpdate.getBlock() instanceof BasinBlock && stateToUpdate.get(BasinBlock.FACING) == offset.getOpposite()) {
|
||||
TileEntity te = world.getTileEntity(toUpdate);
|
||||
if (te instanceof BasinTileEntity)
|
||||
((BasinTileEntity) te).contentsChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<BasinOperatingTileEntity> getOperator() {
|
||||
|
@ -152,11 +182,64 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt
|
|||
return 256;
|
||||
}
|
||||
|
||||
public boolean acceptOutputs(List<ItemStack> outputItems, List<FluidStack> outputFluids, boolean simulate) {
|
||||
outputInventory.allowInsertion();
|
||||
outputTank.allowInsertion();
|
||||
boolean acceptOutputsInner = acceptOutputsInner(outputItems, outputFluids, simulate);
|
||||
outputInventory.forbidInsertion();
|
||||
outputTank.forbidInsertion();
|
||||
return acceptOutputsInner;
|
||||
}
|
||||
|
||||
private boolean acceptOutputsInner(List<ItemStack> outputItems, List<FluidStack> outputFluids, boolean simulate) {
|
||||
BlockState blockState = getBlockState();
|
||||
if (!(blockState.getBlock() instanceof BasinBlock))
|
||||
return false;
|
||||
Direction direction = blockState.get(BasinBlock.FACING);
|
||||
|
||||
IItemHandler targetInv = null;
|
||||
IFluidHandler targetTank = null;
|
||||
|
||||
if (direction == Direction.DOWN) {
|
||||
// No output basin, gather locally
|
||||
targetInv = outputInventory;
|
||||
targetTank = outputTank.getCapability()
|
||||
.orElse(null);
|
||||
|
||||
} else {
|
||||
// Output basin, try moving items to it
|
||||
TileEntity te = world.getTileEntity(pos.down()
|
||||
.offset(direction));
|
||||
if (!(te instanceof BasinTileEntity))
|
||||
return false;
|
||||
targetInv = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
|
||||
.orElse(null);
|
||||
targetTank = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
if (targetInv == null)
|
||||
return false;
|
||||
for (ItemStack itemStack : outputItems)
|
||||
if (!ItemHandlerHelper.insertItemStacked(targetInv, itemStack.copy(), simulate)
|
||||
.isEmpty())
|
||||
return false;
|
||||
|
||||
if (targetTank == null)
|
||||
return false;
|
||||
for (FluidStack fluidStack : outputFluids)
|
||||
if (targetTank.fill(fluidStack.copy(), simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE) != fluidStack
|
||||
.getAmount())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class BasinValueBox extends ValueBoxTransform.Sided {
|
||||
|
||||
@Override
|
||||
protected Vec3d getSouthLocation() {
|
||||
return VecHelper.voxelSpace(8, 12, 16);
|
||||
return VecHelper.voxelSpace(8, 12, 15.75);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -171,4 +254,11 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt
|
|||
inputInventory.deserializeNBT(compound.getCompound("InputItems"));
|
||||
outputInventory.deserializeNBT(compound.getCompound("OutputItems"));
|
||||
}
|
||||
|
||||
public HeatLevel getHeatLevel() {
|
||||
BlockState state = world.getBlockState(pos.down(1));
|
||||
if (state.has(BlazeBurnerBlock.HEAT_LEVEL))
|
||||
return state.get(BlazeBurnerBlock.HEAT_LEVEL);
|
||||
return AllTags.AllBlockTags.FAN_HEATERS.matches(state) ? HeatLevel.SMOULDERING : HeatLevel.NONE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package com.simibubi.create.content.contraptions.processing;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.simibubi.create.AllRecipeTypes;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
|
||||
import net.minecraftforge.items.ItemStackHandler;
|
||||
import net.minecraftforge.items.wrapper.RecipeWrapper;
|
||||
|
||||
public class EmptyingByBasin {
|
||||
|
||||
static RecipeWrapper wrapper = new RecipeWrapper(new ItemStackHandler(1));
|
||||
|
||||
public static boolean canItemBeEmptied(World world, ItemStack stack) {
|
||||
wrapper.setInventorySlotContents(0, stack);
|
||||
if (AllRecipeTypes.EMPTYING.find(wrapper, world)
|
||||
.isPresent())
|
||||
return true;
|
||||
|
||||
LazyOptional<IFluidHandlerItem> capability =
|
||||
stack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY);
|
||||
IFluidHandlerItem tank = capability.orElse(null);
|
||||
if (tank == null)
|
||||
return false;
|
||||
for (int i = 0; i < tank.getTanks(); i++) {
|
||||
if (tank.getFluidInTank(i)
|
||||
.getAmount() > 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Pair<FluidStack, ItemStack> emptyItem(World world, ItemStack stack, boolean simulate) {
|
||||
FluidStack resultingFluid = FluidStack.EMPTY;
|
||||
ItemStack resultingItem = ItemStack.EMPTY;
|
||||
|
||||
wrapper.setInventorySlotContents(0, stack);
|
||||
Optional<IRecipe<RecipeWrapper>> recipe = AllRecipeTypes.EMPTYING.find(wrapper, world);
|
||||
if (recipe.isPresent()) {
|
||||
EmptyingRecipe emptyingRecipe = (EmptyingRecipe) recipe.get();
|
||||
List<ItemStack> results = emptyingRecipe.rollResults();
|
||||
if (!simulate)
|
||||
stack.shrink(1);
|
||||
resultingItem = results.isEmpty() ? ItemStack.EMPTY : results.get(0);
|
||||
resultingFluid = emptyingRecipe.getResultingFluid();
|
||||
return Pair.of(resultingFluid, resultingItem);
|
||||
}
|
||||
|
||||
ItemStack split = stack.copy();
|
||||
split.setCount(1);
|
||||
LazyOptional<IFluidHandlerItem> capability =
|
||||
split.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY);
|
||||
IFluidHandlerItem tank = capability.orElse(null);
|
||||
if (tank == null)
|
||||
return Pair.of(resultingFluid, resultingItem);
|
||||
resultingFluid = tank.drain(1000, simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE);
|
||||
resultingItem = tank.getContainer()
|
||||
.copy();
|
||||
if (!simulate)
|
||||
stack.shrink(1);
|
||||
|
||||
return Pair.of(resultingFluid, resultingItem);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package com.simibubi.create.content.contraptions.processing;
|
||||
|
||||
import com.simibubi.create.AllRecipeTypes;
|
||||
import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams;
|
||||
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.items.wrapper.RecipeWrapper;
|
||||
|
||||
public class EmptyingRecipe extends ProcessingRecipe<RecipeWrapper> {
|
||||
|
||||
public EmptyingRecipe(ProcessingRecipeParams params) {
|
||||
super(AllRecipeTypes.EMPTYING, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(RecipeWrapper inv, World p_77569_2_) {
|
||||
return ingredients.get(0).test(inv.getStackInSlot(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaxInputCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaxOutputCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaxFluidOutputCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public FluidStack getResultingFluid() {
|
||||
if (fluidResults.isEmpty())
|
||||
throw new IllegalStateException("Emptying Recipe: " + id.toString() + " has no fluid output!");
|
||||
return fluidResults.get(0);
|
||||
}
|
||||
|
||||
}
|
|
@ -120,8 +120,7 @@ public class InWorldProcessing {
|
|||
|
||||
public static boolean isWashable(ItemStack stack, World world) {
|
||||
splashingInv.setInventorySlotContents(0, stack);
|
||||
Optional<SplashingRecipe> recipe = world.getRecipeManager()
|
||||
.getRecipe(AllRecipeTypes.SPLASHING.getType(), splashingInv, world);
|
||||
Optional<SplashingRecipe> recipe = AllRecipeTypes.SPLASHING.find(splashingInv, world);
|
||||
return recipe.isPresent();
|
||||
}
|
||||
|
||||
|
@ -176,8 +175,7 @@ public class InWorldProcessing {
|
|||
private static List<ItemStack> process(ItemStack stack, Type type, World world) {
|
||||
if (type == Type.SPLASHING) {
|
||||
splashingInv.setInventorySlotContents(0, stack);
|
||||
Optional<SplashingRecipe> recipe = world.getRecipeManager()
|
||||
.getRecipe(AllRecipeTypes.SPLASHING.getType(), splashingInv, world);
|
||||
Optional<SplashingRecipe> recipe = AllRecipeTypes.SPLASHING.find(splashingInv, world);
|
||||
if (recipe.isPresent())
|
||||
return applyRecipeOn(stack, recipe.get());
|
||||
return null;
|
||||
|
|
|
@ -127,10 +127,10 @@ public interface ItemAttribute {
|
|||
this.test = test;
|
||||
}
|
||||
|
||||
private static boolean testRecipe(ItemStack s, World w, IRecipeType<? extends IRecipe<IInventory>> smelting) {
|
||||
private static boolean testRecipe(ItemStack s, World w, IRecipeType<? extends IRecipe<IInventory>> type) {
|
||||
RECIPE_WRAPPER.setInventorySlotContents(0, s.copy());
|
||||
return w.getRecipeManager()
|
||||
.getRecipe(smelting, RECIPE_WRAPPER, w)
|
||||
.getRecipe(type, RECIPE_WRAPPER, w)
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@ public class CKinetics extends ConfigBase {
|
|||
public ConfigInt maxPistonPoles = i(64, 1, "maxPistonPoles", Comments.maxPistonPoles);
|
||||
public ConfigInt maxRopeLength = i(128, 1, "maxRopeLength", Comments.maxRopeLength);
|
||||
public ConfigInt maxCartCouplingLength = i(32, 1, "maxCartCouplingLength", Comments.maxCartCouplingLength);
|
||||
|
||||
public CStress stressValues = nested(0, CStress::new, Comments.stress);
|
||||
|
||||
public ConfigGroup state = group(0, "stats", Comments.stats);
|
||||
public ConfigFloat mediumSpeed = f(30, 0, 4096, "mediumSpeed", Comments.rpm, Comments.mediumSpeed);
|
||||
|
@ -37,8 +39,6 @@ public class CKinetics extends ConfigBase {
|
|||
public ConfigFloat mediumCapacity = f(128, 0, 4096, "mediumCapacity", Comments.su, Comments.mediumCapacity);
|
||||
public ConfigFloat highCapacity = f(512, 0, 65535, "highCapacity", Comments.su, Comments.highCapacity);
|
||||
|
||||
public CStress stressValues = nested(0, CStress::new, Comments.stress);
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "kinetics";
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package com.simibubi.create.foundation.config;
|
||||
|
||||
public class CRecipes extends ConfigBase {
|
||||
|
||||
public ConfigBool allowShapelessInMixer = b(true, "allowShapelessInMixer", Comments.allowShapelessInMixer);
|
||||
public ConfigBool allowShapedSquareInPress = b(true, "allowShapedSquareInPress", Comments.allowShapedSquareInPress);
|
||||
public ConfigBool allowRegularCraftingInCrafter = b(true, "allowRegularCraftingInCrafter", Comments.allowRegularCraftingInCrafter);
|
||||
public ConfigBool allowStonecuttingOnSaw = b(true, "allowStonecuttingOnSaw", Comments.allowStonecuttingOnSaw);
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "recipes";
|
||||
}
|
||||
|
||||
private static class Comments {
|
||||
static String allowShapelessInMixer =
|
||||
"When true, allows any shapeless crafting recipes to be processed by a Mechanical Mixer + Basin.";
|
||||
static String allowShapedSquareInPress =
|
||||
"When true, allows any single-ingredient 2x2 or 3x3 crafting recipes to be processed by a Mechanical Press + Basin.";
|
||||
static String allowRegularCraftingInCrafter =
|
||||
"When true, allows any standard crafting recipes to be processed by Mechanical Crafters.";
|
||||
static String allowStonecuttingOnSaw =
|
||||
"When true, allows any stonecutting recipes to be processed by a Mechanical Saw.";
|
||||
}
|
||||
|
||||
}
|
|
@ -6,6 +6,7 @@ public class CServer extends ConfigBase {
|
|||
public ConfigInt tickrateSyncTimer =
|
||||
i(20, 5, "tickrateSyncTimer", "[in Ticks]", Comments.tickrateSyncTimer, Comments.tickrateSyncTimer2);
|
||||
|
||||
public CRecipes recipes = nested(0, CRecipes::new, Comments.recipes);
|
||||
public CKinetics kinetics = nested(0, CKinetics::new, Comments.kinetics);
|
||||
public CFluids fluids = nested(0, CFluids::new, Comments.fluids);
|
||||
public CLogistics logistics = nested(0, CLogistics::new, Comments.logistics);
|
||||
|
@ -19,6 +20,7 @@ public class CServer extends ConfigBase {
|
|||
}
|
||||
|
||||
private static class Comments {
|
||||
static String recipes = "Packmakers' control panel for internal recipe compat";
|
||||
static String schematics = "Everything related to Schematic tools";
|
||||
static String kinetics = "Parameters and abilities of Create's kinetic mechanisms";
|
||||
static String fluids = "Create's liquid manipulation tools";
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package com.simibubi.create.foundation.data.recipe;
|
||||
|
||||
import com.simibubi.create.AllRecipeTypes;
|
||||
import com.simibubi.create.content.palettes.AllPaletteBlocks;
|
||||
|
||||
import net.minecraft.data.DataGenerator;
|
||||
import net.minecraft.fluid.Fluids;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.tags.FluidTags;
|
||||
|
||||
public class CompactingRecipeGen extends ProcessingRecipeGen {
|
||||
|
||||
GeneratedRecipe
|
||||
|
||||
TEMPGABBRO = create("temp_gabbro", b -> b
|
||||
.require(Items.COBBLESTONE)
|
||||
.require(FluidTags.LAVA, 250)
|
||||
.output(AllPaletteBlocks.GABBRO.get(), 1)),
|
||||
|
||||
ICE = create("ice", b -> b
|
||||
.require(Items.ICE)
|
||||
.output(Fluids.WATER, 250))
|
||||
|
||||
;
|
||||
|
||||
public CompactingRecipeGen(DataGenerator p_i48262_1_) {
|
||||
super(p_i48262_1_);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AllRecipeTypes getRecipeType() {
|
||||
return AllRecipeTypes.COMPACTING;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.simibubi.create.foundation.data.recipe;
|
||||
|
||||
import com.simibubi.create.AllRecipeTypes;
|
||||
|
||||
import net.minecraft.data.DataGenerator;
|
||||
import net.minecraft.fluid.Fluids;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.potion.PotionUtils;
|
||||
import net.minecraft.potion.Potions;
|
||||
import net.minecraftforge.common.crafting.NBTIngredient;
|
||||
|
||||
public class EmptyingRecipeGen extends ProcessingRecipeGen {
|
||||
|
||||
GeneratedRecipe
|
||||
|
||||
WATER_BOTTLE = create("water_bottle", b -> b
|
||||
.require(NBTIngredient.fromStacks(PotionUtils.addPotionToItemStack(new ItemStack(Items.POTION), Potions.WATER)))
|
||||
.output(Fluids.WATER, 250)
|
||||
.output(Items.GLASS_BOTTLE))
|
||||
|
||||
;
|
||||
|
||||
public EmptyingRecipeGen(DataGenerator p_i48262_1_) {
|
||||
super(p_i48262_1_);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AllRecipeTypes getRecipeType() {
|
||||
return AllRecipeTypes.EMPTYING;
|
||||
}
|
||||
|
||||
}
|
|
@ -8,6 +8,7 @@ import com.simibubi.create.content.contraptions.processing.HeatCondition;
|
|||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.data.DataGenerator;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.tags.FluidTags;
|
||||
import net.minecraft.tags.ItemTags;
|
||||
import net.minecraftforge.common.Tags;
|
||||
|
||||
|
@ -15,6 +16,11 @@ public class MixingRecipeGen extends ProcessingRecipeGen {
|
|||
|
||||
GeneratedRecipe
|
||||
|
||||
TEMPCOBBLE = create("temp_cobble", b -> b
|
||||
.require(FluidTags.WATER, 250)
|
||||
.require(FluidTags.LAVA, 250)
|
||||
.output(Blocks.COBBLESTONE, 1)),
|
||||
|
||||
BRASS_INGOT = create("brass_ingot", b -> b.require(I.copper())
|
||||
.require(I.zinc())
|
||||
.output(AllItems.BRASS_INGOT.get(), 2)
|
||||
|
|
|
@ -32,8 +32,10 @@ public abstract class ProcessingRecipeGen extends CreateRecipeProvider {
|
|||
generators.add(new WashingRecipeGen(gen));
|
||||
generators.add(new PolishingRecipeGen(gen));
|
||||
generators.add(new MixingRecipeGen(gen));
|
||||
generators.add(new CompactingRecipeGen(gen));
|
||||
generators.add(new PressingRecipeGen(gen));
|
||||
generators.add(new FillingRecipeGen(gen));
|
||||
generators.add(new EmptyingRecipeGen(gen));
|
||||
|
||||
gen.addProvider(new IDataProvider() {
|
||||
|
||||
|
|
|
@ -201,9 +201,9 @@ public class StandardRecipeGen extends CreateRecipeProvider {
|
|||
.key('A', Tags.Items.NUGGETS_IRON)
|
||||
.patternLine("ASA")),
|
||||
|
||||
ATTRIBUTE_FILTER = create(AllItems.ATTRIBUTE_FILTER).unlockedBy(I::andesite)
|
||||
ATTRIBUTE_FILTER = create(AllItems.ATTRIBUTE_FILTER).unlockedByTag(I::brass)
|
||||
.viaShaped(b -> b.key('S', ItemTags.WOOL)
|
||||
.key('A', I.copperNugget())
|
||||
.key('A', I.brassNugget())
|
||||
.patternLine("ASA")),
|
||||
|
||||
BRASS_HAND = create(AllItems.BRASS_HAND).unlockedByTag(I::brass)
|
||||
|
|
|
@ -62,6 +62,9 @@ public class CombinedTankWrapper implements IFluidHandler {
|
|||
|
||||
@Override
|
||||
public int fill(FluidStack resource, FluidAction action) {
|
||||
if (resource.isEmpty())
|
||||
return 0;
|
||||
|
||||
int filled = 0;
|
||||
resource = resource.copy();
|
||||
|
||||
|
@ -85,6 +88,9 @@ public class CombinedTankWrapper implements IFluidHandler {
|
|||
|
||||
@Override
|
||||
public FluidStack drain(FluidStack resource, FluidAction action) {
|
||||
if (resource.isEmpty())
|
||||
return resource;
|
||||
|
||||
FluidStack drained = FluidStack.EMPTY;
|
||||
resource = resource.copy();
|
||||
|
||||
|
|
|
@ -74,6 +74,9 @@ public class FluidHelper {
|
|||
int amount = JSONUtils.getInt(json, "amount");
|
||||
FluidStack stack = new FluidStack(fluid, amount);
|
||||
|
||||
if (!json.has("nbt"))
|
||||
return stack;
|
||||
|
||||
try {
|
||||
JsonElement element = json.get("nbt");
|
||||
stack.setTag(JsonToNBT.getTagFromJson(
|
||||
|
|
|
@ -10,17 +10,29 @@ import net.minecraftforge.common.util.INBTSerializable;
|
|||
import net.minecraftforge.items.ItemStackHandler;
|
||||
import net.minecraftforge.items.wrapper.RecipeWrapper;
|
||||
|
||||
public class SmartInventory extends RecipeWrapper implements IItemHandlerModifiableIntermediate, INBTSerializable<CompoundNBT> {
|
||||
public class SmartInventory extends RecipeWrapper
|
||||
implements IItemHandlerModifiableIntermediate, INBTSerializable<CompoundNBT> {
|
||||
|
||||
private boolean extractionAllowed;
|
||||
private boolean insertionAllowed;
|
||||
private int stackSize;
|
||||
protected boolean extractionAllowed;
|
||||
protected boolean insertionAllowed;
|
||||
protected boolean stackNonStackables;
|
||||
protected int stackSize;
|
||||
|
||||
public SmartInventory(int slots, SyncedTileEntity te) {
|
||||
super(new SyncedStackHandler(slots, te));
|
||||
this(slots, te, 64, false);
|
||||
}
|
||||
|
||||
public SmartInventory(int slots, SyncedTileEntity te, int stackSize, boolean stackNonStackables) {
|
||||
super(new SyncedStackHandler(slots, te, stackNonStackables, stackSize));
|
||||
this.stackNonStackables = stackNonStackables;
|
||||
insertionAllowed = true;
|
||||
extractionAllowed = true;
|
||||
stackSize = 64;
|
||||
this.stackSize = stackSize;
|
||||
}
|
||||
|
||||
public SmartInventory whenContentsChanged(Runnable updateCallback) {
|
||||
((SyncedStackHandler) inv).whenContentsChange(updateCallback);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SmartInventory allowInsertion() {
|
||||
|
@ -43,11 +55,6 @@ public class SmartInventory extends RecipeWrapper implements IItemHandlerModifia
|
|||
return this;
|
||||
}
|
||||
|
||||
public SmartInventory withMaxStackSize(int stackSize) {
|
||||
this.stackSize = stackSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlots() {
|
||||
return inv.getSlots();
|
||||
|
@ -64,6 +71,11 @@ public class SmartInventory extends RecipeWrapper implements IItemHandlerModifia
|
|||
public ItemStack extractItem(int slot, int amount, boolean simulate) {
|
||||
if (!extractionAllowed)
|
||||
return ItemStack.EMPTY;
|
||||
if (stackNonStackables) {
|
||||
ItemStack extractItem = inv.extractItem(slot, amount, true);
|
||||
if (!extractItem.isEmpty() && extractItem.getMaxStackSize() < extractItem.getCount())
|
||||
amount = extractItem.getMaxStackSize();
|
||||
}
|
||||
return inv.extractItem(slot, amount, simulate);
|
||||
}
|
||||
|
||||
|
@ -86,7 +98,7 @@ public class SmartInventory extends RecipeWrapper implements IItemHandlerModifia
|
|||
public ItemStack getStackInSlot(int slot) {
|
||||
return super.getStackInSlot(slot);
|
||||
}
|
||||
|
||||
|
||||
public int getStackLimit(int slot, @Nonnull ItemStack stack) {
|
||||
return Math.min(getSlotLimit(slot), stack.getMaxStackSize());
|
||||
}
|
||||
|
@ -100,7 +112,7 @@ public class SmartInventory extends RecipeWrapper implements IItemHandlerModifia
|
|||
public void deserializeNBT(CompoundNBT nbt) {
|
||||
getInv().deserializeNBT(nbt);
|
||||
}
|
||||
|
||||
|
||||
private SyncedStackHandler getInv() {
|
||||
return (SyncedStackHandler) inv;
|
||||
}
|
||||
|
@ -108,18 +120,34 @@ public class SmartInventory extends RecipeWrapper implements IItemHandlerModifia
|
|||
private static class SyncedStackHandler extends ItemStackHandler {
|
||||
|
||||
private SyncedTileEntity te;
|
||||
private boolean stackNonStackables;
|
||||
private int stackSize;
|
||||
private Runnable updateCallback;
|
||||
|
||||
public SyncedStackHandler(int slots, SyncedTileEntity te) {
|
||||
public SyncedStackHandler(int slots, SyncedTileEntity te, boolean stackNonStackables, int stackSize) {
|
||||
super(slots);
|
||||
this.te = te;
|
||||
this.stackNonStackables = stackNonStackables;
|
||||
this.stackSize = stackSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onContentsChanged(int slot) {
|
||||
super.onContentsChanged(slot);
|
||||
if (updateCallback != null)
|
||||
updateCallback.run();
|
||||
te.notifyUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlotLimit(int slot) {
|
||||
return Math.min(stackNonStackables ? 64 : super.getSlotLimit(slot), stackSize);
|
||||
}
|
||||
|
||||
public void whenContentsChange(Runnable updateCallback) {
|
||||
this.updateCallback = updateCallback;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.glu
|
|||
import com.simibubi.create.content.contraptions.components.structureMovement.sync.ClientMotionPacket;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionInteractionPacket;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionSeatMappingPacket;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.sync.LimbSwingUpdatePacket;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.MinecartCouplingCreationPacket;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.MinecartCouplingSyncPacket;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.PersistantDataPacket;
|
||||
|
@ -68,6 +69,7 @@ public enum AllPackets {
|
|||
MINECART_COUPLING_SYNC(MinecartCouplingSyncPacket.class, MinecartCouplingSyncPacket::new),
|
||||
CONTRAPTION_SEAT_MAPPING(ContraptionSeatMappingPacket.class, ContraptionSeatMappingPacket::new),
|
||||
PERSISTANT_DATA(PersistantDataPacket.class, PersistantDataPacket::new),
|
||||
LIMBSWING_UPDATE(LimbSwingUpdatePacket.class, LimbSwingUpdatePacket::new),
|
||||
|
||||
;
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour {
|
|||
protected LazyOptional<? extends IFluidHandler> capability;
|
||||
protected boolean extractionAllowed;
|
||||
protected boolean insertionAllowed;
|
||||
protected Runnable fluidUpdateCallback;
|
||||
|
||||
private BehaviourType<SmartFluidTankBehaviour> behaviourType;
|
||||
|
||||
|
@ -55,6 +56,13 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour {
|
|||
handlers[i] = tankSegment.tank;
|
||||
}
|
||||
capability = LazyOptional.of(() -> new InternalFluidHandler(handlers, enforceVariety));
|
||||
fluidUpdateCallback = () -> {
|
||||
};
|
||||
}
|
||||
|
||||
public SmartFluidTankBehaviour whenFluidUpdates(Runnable fluidUpdateCallback) {
|
||||
this.fluidUpdateCallback = fluidUpdateCallback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SmartFluidTankBehaviour allowInsertion() {
|
||||
|
@ -76,7 +84,7 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour {
|
|||
extractionAllowed = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
|
@ -84,7 +92,7 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour {
|
|||
return;
|
||||
foreach(ts -> {
|
||||
ts.fluidLevel.forceNextSync();
|
||||
ts.onFluidStackChanged(ts.tank.getFluid());
|
||||
ts.onFluidStackChanged();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -94,8 +102,8 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour {
|
|||
|
||||
if (syncCooldown > 0) {
|
||||
syncCooldown--;
|
||||
if (syncCooldown == 0 && queuedSync)
|
||||
tileEntity.sendData();
|
||||
if (syncCooldown == 0 && queuedSync)
|
||||
updateFluids();
|
||||
}
|
||||
|
||||
foreach(te -> {
|
||||
|
@ -108,7 +116,7 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour {
|
|||
public void sendDataImmediately() {
|
||||
syncCooldown = 0;
|
||||
queuedSync = false;
|
||||
tileEntity.sendData();
|
||||
updateFluids();
|
||||
}
|
||||
|
||||
public void sendDataLazily() {
|
||||
|
@ -116,11 +124,16 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour {
|
|||
queuedSync = true;
|
||||
return;
|
||||
}
|
||||
tileEntity.sendData();
|
||||
updateFluids();
|
||||
queuedSync = false;
|
||||
syncCooldown = SYNC_RATE;
|
||||
}
|
||||
|
||||
protected void updateFluids() {
|
||||
fluidUpdateCallback.run();
|
||||
tileEntity.sendData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
super.remove();
|
||||
|
@ -174,36 +187,36 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour {
|
|||
index.increment();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
class InternalFluidHandler extends CombinedTankWrapper {
|
||||
|
||||
|
||||
public InternalFluidHandler(IFluidHandler[] handlers, boolean enforceVariety) {
|
||||
super(handlers);
|
||||
if (enforceVariety)
|
||||
enforceVariety();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int fill(FluidStack resource, FluidAction action) {
|
||||
if (!insertionAllowed)
|
||||
return 0;
|
||||
return super.fill(resource, action);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FluidStack drain(FluidStack resource, FluidAction action) {
|
||||
if (!extractionAllowed)
|
||||
return FluidStack.EMPTY;
|
||||
return super.drain(resource, action);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FluidStack drain(int maxDrain, FluidAction action) {
|
||||
if (!extractionAllowed)
|
||||
return FluidStack.EMPTY;
|
||||
return super.drain(maxDrain, action);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class TankSegment {
|
||||
|
@ -213,14 +226,14 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour {
|
|||
protected FluidStack renderedFluid;
|
||||
|
||||
public TankSegment(int capacity) {
|
||||
tank = new SmartFluidTank(1000, f -> onFluidStackChanged(f));
|
||||
tank = new SmartFluidTank(1000, f -> onFluidStackChanged());
|
||||
fluidLevel = LerpedFloat.linear()
|
||||
.startWithValue(0)
|
||||
.chase(0, .25, Chaser.EXP);
|
||||
renderedFluid = FluidStack.EMPTY;
|
||||
}
|
||||
|
||||
protected void onFluidStackChanged(FluidStack newFluidStack) {
|
||||
public void onFluidStackChanged() {
|
||||
if (!tileEntity.hasWorld())
|
||||
return;
|
||||
fluidLevel.chase(tank.getFluidAmount() / (float) tank.getCapacity(), .25, Chaser.EXP);
|
||||
|
@ -235,7 +248,7 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour {
|
|||
public LerpedFloat getFluidLevel() {
|
||||
return fluidLevel;
|
||||
}
|
||||
|
||||
|
||||
public float getTotalUnits(float partialTicks) {
|
||||
return fluidLevel.getValue(partialTicks) * tank.getCapacity();
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,237 @@
|
|||
{
|
||||
"credit": "Made with Blockbench",
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"1": "create:block/basin_side",
|
||||
"2": "create:block/basin_canal",
|
||||
"12": "create:block/basin",
|
||||
"particle": "create:block/basin"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "Side1",
|
||||
"from": [14, 2, 0],
|
||||
"to": [16, 16, 16],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 24, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 2, 14], "texture": "#1"},
|
||||
"east": {"uv": [0, 0, 16, 14], "texture": "#1"},
|
||||
"south": {"uv": [14, 0, 16, 14], "texture": "#1"},
|
||||
"west": {"uv": [0, 0, 16, 14], "texture": "#1"},
|
||||
"up": {"uv": [0, 0, 2, 16], "rotation": 180, "texture": "#12"},
|
||||
"down": {"uv": [0, 0, 2, 16], "rotation": 180, "texture": "#12"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "BasinBottom",
|
||||
"from": [2, 0, 2],
|
||||
"to": [14, 2, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 25, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [2, 14, 14, 16], "texture": "#1"},
|
||||
"east": {"uv": [2, 14, 14, 16], "texture": "#1"},
|
||||
"south": {"uv": [2, 14, 14, 16], "texture": "#1"},
|
||||
"west": {"uv": [2, 14, 14, 16], "texture": "#1"},
|
||||
"up": {"uv": [2, 2, 14, 14], "rotation": 180, "texture": "#12"},
|
||||
"down": {"uv": [2, 2, 14, 14], "rotation": 180, "texture": "#12"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side4",
|
||||
"from": [2, 2, 14],
|
||||
"to": [14, 16, 16],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 24, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [2, 0, 14, 14], "texture": "#1"},
|
||||
"south": {"uv": [2, 0, 14, 14], "texture": "#1"},
|
||||
"up": {"uv": [2, 0, 14, 2], "rotation": 180, "texture": "#12"},
|
||||
"down": {"uv": [2, 14, 14, 16], "rotation": 180, "texture": "#12"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side2",
|
||||
"from": [2, 2, 0],
|
||||
"to": [14, 16, 2],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 24, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [2, 0, 14, 14], "texture": "#1"},
|
||||
"south": {"uv": [2, 0, 14, 14], "texture": "#1"},
|
||||
"up": {"uv": [2, 14, 14, 16], "rotation": 180, "texture": "#12"},
|
||||
"down": {"uv": [2, 0, 14, 2], "rotation": 180, "texture": "#12"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side3",
|
||||
"from": [0, 2, 0],
|
||||
"to": [2, 16, 16],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 40, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [14, 0, 16, 14], "texture": "#1"},
|
||||
"east": {"uv": [0, 0, 16, 14], "texture": "#1"},
|
||||
"south": {"uv": [0, 0, 2, 14], "texture": "#1"},
|
||||
"west": {"uv": [0, 0, 16, 14], "texture": "#1"},
|
||||
"up": {"uv": [14, 0, 16, 16], "rotation": 180, "texture": "#12"},
|
||||
"down": {"uv": [14, 0, 16, 16], "rotation": 180, "texture": "#12"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [12, 0, 14],
|
||||
"to": [13, 2, 16],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [5, 8, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [14, 10, 16, 11], "rotation": 90, "texture": "#2"},
|
||||
"east": {"uv": [14, 10, 16, 12], "rotation": 90, "texture": "#2"},
|
||||
"south": {"uv": [0, 0, 10, 2], "texture": "#2"},
|
||||
"west": {"uv": [14, 10, 16, 12], "texture": "#2"},
|
||||
"up": {"uv": [14, 10, 15, 12], "texture": "#2"},
|
||||
"down": {"uv": [15, 10, 16, 12], "rotation": 180, "texture": "#2"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [3, 0, 14],
|
||||
"to": [4, 2, 16],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [-4, 8, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [14, 10, 16, 11], "rotation": 90, "texture": "#2"},
|
||||
"east": {"uv": [14, 10, 16, 12], "rotation": 90, "texture": "#2"},
|
||||
"south": {"uv": [0, 0, 10, 2], "texture": "#2"},
|
||||
"west": {"uv": [14, 10, 16, 12], "texture": "#2"},
|
||||
"up": {"uv": [14, 10, 15, 12], "texture": "#2"},
|
||||
"down": {"uv": [15, 10, 16, 12], "rotation": 180, "texture": "#2"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [4, 0, 14],
|
||||
"to": [12, 1, 17],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [4, 8, 9]},
|
||||
"faces": {
|
||||
"north": {"uv": [8, 14, 9, 15], "rotation": 90, "texture": "#2"},
|
||||
"east": {"uv": [14, 10, 16, 12], "rotation": 90, "texture": "#2"},
|
||||
"south": {"uv": [7, 15, 15, 16], "texture": "#2"},
|
||||
"west": {"uv": [14, 10, 16, 12], "texture": "#2"},
|
||||
"up": {"uv": [11, 10, 12, 11], "texture": "#2"},
|
||||
"down": {"uv": [7, 13, 15, 16], "rotation": 180, "texture": "#2"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [12, 0, 16],
|
||||
"to": [13, 10, 17],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [5, 8, 9]},
|
||||
"faces": {
|
||||
"north": {"uv": [6, 12, 16, 13], "rotation": 90, "texture": "#2"},
|
||||
"east": {"uv": [6, 12, 16, 13], "rotation": 90, "texture": "#2"},
|
||||
"south": {"uv": [6, 12, 16, 13], "rotation": 90, "texture": "#2"},
|
||||
"west": {"uv": [6, 12, 16, 13], "rotation": 90, "texture": "#2"},
|
||||
"up": {"uv": [6, 12, 7, 13], "rotation": 180, "texture": "#2"},
|
||||
"down": {"uv": [15, 12, 16, 13], "rotation": 180, "texture": "#2"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [4, 9, 16],
|
||||
"to": [12, 10, 17],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [4, 8, 9]},
|
||||
"faces": {
|
||||
"north": {"uv": [8, 9, 16, 10], "texture": "#2"},
|
||||
"south": {"uv": [8, 9, 16, 10], "texture": "#2"},
|
||||
"up": {"uv": [8, 9, 16, 10], "rotation": 180, "texture": "#2"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [3, 0, 16],
|
||||
"to": [4, 10, 17],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [-4, 8, 9]},
|
||||
"faces": {
|
||||
"north": {"uv": [6, 12, 16, 13], "rotation": 90, "texture": "#2"},
|
||||
"east": {"uv": [6, 12, 16, 13], "rotation": 90, "texture": "#2"},
|
||||
"south": {"uv": [6, 12, 16, 13], "rotation": 90, "texture": "#2"},
|
||||
"west": {"uv": [6, 12, 16, 13], "rotation": 90, "texture": "#2"},
|
||||
"up": {"uv": [6, 12, 7, 13], "rotation": 180, "texture": "#2"},
|
||||
"down": {"uv": [15, 12, 16, 13], "rotation": 180, "texture": "#2"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [5, 1, 13],
|
||||
"to": [11, 2, 22],
|
||||
"rotation": {"angle": 22.5, "axis": "x", "origin": [8, 9, 17]},
|
||||
"faces": {
|
||||
"north": {"uv": [9, 7, 15, 8], "texture": "#2"},
|
||||
"east": {"uv": [0, 0, 9, 1], "texture": "#2"},
|
||||
"south": {"uv": [9, 7, 15, 8], "texture": "#2"},
|
||||
"west": {"uv": [0, 0, 9, 1], "texture": "#2"},
|
||||
"up": {"uv": [1, 0, 7, 9], "rotation": 180, "texture": "#2"},
|
||||
"down": {"uv": [1, 0, 7, 9], "texture": "#2"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [5, 8, 13],
|
||||
"to": [11, 9, 22],
|
||||
"rotation": {"angle": 22.5, "axis": "x", "origin": [8, 9, 17]},
|
||||
"faces": {
|
||||
"north": {"uv": [9, 0, 15, 1], "texture": "#2"},
|
||||
"east": {"uv": [0, 0, 9, 1], "texture": "#2"},
|
||||
"south": {"uv": [9, 0, 15, 1], "texture": "#2"},
|
||||
"west": {"uv": [0, 0, 9, 1], "texture": "#2"},
|
||||
"up": {"uv": [1, 0, 7, 9], "texture": "#2"},
|
||||
"down": {"uv": [1, 0, 7, 9], "rotation": 180, "texture": "#2"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [5, 2, 14],
|
||||
"to": [11, 8, 20],
|
||||
"rotation": {"angle": 22.5, "axis": "x", "origin": [8, 9, 17]},
|
||||
"faces": {
|
||||
"north": {"uv": [9, 1, 15, 7], "texture": "#2"},
|
||||
"south": {"uv": [9, 1, 15, 7], "texture": "#2"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [4, 1, 13],
|
||||
"to": [5, 9, 22],
|
||||
"rotation": {"angle": 22.5, "axis": "x", "origin": [1, 9, 17]},
|
||||
"faces": {
|
||||
"north": {"uv": [15, 0, 16, 8], "texture": "#2"},
|
||||
"east": {"uv": [0, 0, 8, 9], "rotation": 90, "texture": "#2"},
|
||||
"south": {"uv": [8, 0, 9, 8], "texture": "#2"},
|
||||
"west": {"uv": [0, 0, 8, 9], "rotation": 270, "texture": "#2"},
|
||||
"up": {"uv": [0, 0, 1, 9], "texture": "#2"},
|
||||
"down": {"uv": [0, 0, 1, 9], "rotation": 180, "texture": "#2"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [11, 1, 13],
|
||||
"to": [12, 9, 22],
|
||||
"rotation": {"angle": 22.5, "axis": "x", "origin": [8, 9, 17]},
|
||||
"faces": {
|
||||
"north": {"uv": [8, 0, 9, 8], "texture": "#2"},
|
||||
"east": {"uv": [0, 0, 8, 9], "rotation": 90, "texture": "#2"},
|
||||
"south": {"uv": [15, 0, 16, 8], "texture": "#2"},
|
||||
"west": {"uv": [0, 0, 8, 9], "rotation": 90, "texture": "#2"},
|
||||
"up": {"uv": [0, 0, 1, 9], "texture": "#2"},
|
||||
"down": {"uv": [0, 0, 1, 9], "rotation": 180, "texture": "#2"}
|
||||
}
|
||||
}
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"name": "Basins",
|
||||
"origin": [8, 8, 8],
|
||||
"children": [
|
||||
{
|
||||
"name": "Basin top",
|
||||
"origin": [8, 8, 8],
|
||||
"children": [0, 1, 2, 3, 4]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canal",
|
||||
"origin": [8, 8, 8],
|
||||
"children": [
|
||||
{
|
||||
"name": "Frame",
|
||||
"origin": [8, 8, 8],
|
||||
"children": [5, 6, 7, 8, 9, 10]
|
||||
}, 11, 12, 13, 14, 15]
|
||||
}
|
||||
]
|
||||
}
|
BIN
src/main/resources/assets/create/textures/block/basin_canal.png
Normal file
BIN
src/main/resources/assets/create/textures/block/basin_canal.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 376 B |
Binary file not shown.
Before Width: | Height: | Size: 329 B After Width: | Height: | Size: 259 B |
Loading…
Reference in a new issue