mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-03-04 06:44:40 +01:00
Merge remote-tracking branch 'upstream/mc1.20.1/dev' into mc1.20.1/feature-dev
# Conflicts: # build.gradle # src/generated/resources/.cache/2d64935085b86659cb7857bad9701dbf9bab6e4c # src/generated/resources/.cache/b256105d8411632b0d585496ea8944a751a08034 # src/main/java/com/simibubi/create/AllBlocks.java # src/main/java/com/simibubi/create/compat/Mods.java # src/main/java/com/simibubi/create/compat/jei/category/CreateRecipeCategory.java # src/main/java/com/simibubi/create/compat/jei/category/ItemDrainCategory.java # src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionControlsBlockEntity.java # src/main/java/com/simibubi/create/content/fluids/spout/SpoutRenderer.java # src/main/java/com/simibubi/create/content/logistics/filter/FilterItemStack.java # src/main/java/com/simibubi/create/foundation/item/ItemHelper.java # src/main/java/com/simibubi/create/foundation/mixin/SmithingMenuMixin.java # src/main/java/com/simibubi/create/foundation/utility/BlockHelper.java # src/main/java/com/simibubi/create/foundation/utility/DyeHelper.java # src/main/java/com/simibubi/create/infrastructure/debugInfo/ServerDebugInfoPacket.java # src/main/resources/META-INF/mods.toml # src/main/resources/create.mixins.json
This commit is contained in:
commit
a7518e0dfe
67 changed files with 755 additions and 304 deletions
|
@ -22,7 +22,7 @@ registrate_version = MC1.20-1.3.3
|
|||
flywheel_minecraft_version = 1.20.1
|
||||
flywheel_version = 1.0.0-beta-4
|
||||
jei_minecraft_version = 1.20.1
|
||||
jei_version = 15.10.0.39
|
||||
jei_version = 15.19.0.85
|
||||
curios_minecraft_version = 1.20.1
|
||||
curios_version = 5.3.1
|
||||
ponder_version = 1.0.24
|
||||
|
|
|
@ -1,14 +1,5 @@
|
|||
{
|
||||
"type": "create:milling",
|
||||
"conditions": [
|
||||
{
|
||||
"type": "forge:not",
|
||||
"value": {
|
||||
"type": "forge:mod_loaded",
|
||||
"modid": "quark"
|
||||
}
|
||||
}
|
||||
],
|
||||
"ingredients": [
|
||||
{
|
||||
"item": "minecraft:cactus"
|
||||
|
|
|
@ -7,6 +7,12 @@
|
|||
},
|
||||
{
|
||||
"item": "minecraft:dirt"
|
||||
},
|
||||
{
|
||||
"item": "minecraft:coarse_dirt"
|
||||
},
|
||||
{
|
||||
"item": "minecraft:rooted_dirt"
|
||||
}
|
||||
]
|
||||
],
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"values": [
|
||||
"minecraft:sugar_cane"
|
||||
]
|
||||
}
|
|
@ -1,5 +1,21 @@
|
|||
{
|
||||
"values": [
|
||||
"create:copper_shingle_slab",
|
||||
"create:exposed_copper_shingle_slab",
|
||||
"create:weathered_copper_shingle_slab",
|
||||
"create:oxidized_copper_shingle_slab",
|
||||
"create:waxed_copper_shingle_slab",
|
||||
"create:waxed_exposed_copper_shingle_slab",
|
||||
"create:waxed_weathered_copper_shingle_slab",
|
||||
"create:waxed_oxidized_copper_shingle_slab",
|
||||
"create:copper_tile_slab",
|
||||
"create:exposed_copper_tile_slab",
|
||||
"create:weathered_copper_tile_slab",
|
||||
"create:oxidized_copper_tile_slab",
|
||||
"create:waxed_copper_tile_slab",
|
||||
"create:waxed_exposed_copper_tile_slab",
|
||||
"create:waxed_weathered_copper_tile_slab",
|
||||
"create:waxed_oxidized_copper_tile_slab",
|
||||
"create:cut_granite_slab",
|
||||
"create:polished_cut_granite_slab",
|
||||
"create:cut_granite_brick_slab",
|
||||
|
|
|
@ -1,5 +1,21 @@
|
|||
{
|
||||
"values": [
|
||||
"create:copper_shingle_stairs",
|
||||
"create:exposed_copper_shingle_stairs",
|
||||
"create:weathered_copper_shingle_stairs",
|
||||
"create:oxidized_copper_shingle_stairs",
|
||||
"create:waxed_copper_shingle_stairs",
|
||||
"create:waxed_exposed_copper_shingle_stairs",
|
||||
"create:waxed_weathered_copper_shingle_stairs",
|
||||
"create:waxed_oxidized_copper_shingle_stairs",
|
||||
"create:copper_tile_stairs",
|
||||
"create:exposed_copper_tile_stairs",
|
||||
"create:weathered_copper_tile_stairs",
|
||||
"create:oxidized_copper_tile_stairs",
|
||||
"create:waxed_copper_tile_stairs",
|
||||
"create:waxed_exposed_copper_tile_stairs",
|
||||
"create:waxed_weathered_copper_tile_stairs",
|
||||
"create:waxed_oxidized_copper_tile_stairs",
|
||||
"create:cut_granite_stairs",
|
||||
"create:polished_cut_granite_stairs",
|
||||
"create:cut_granite_brick_stairs",
|
||||
|
|
|
@ -17,6 +17,7 @@ import static com.simibubi.create.foundation.data.TagGen.tagBlockAndItem;
|
|||
|
||||
import com.simibubi.create.AllTags.AllBlockTags;
|
||||
import com.simibubi.create.AllTags.AllItemTags;
|
||||
import com.simibubi.create.api.contraption.train.TrainConductorHandler;
|
||||
import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsBlock;
|
||||
import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement;
|
||||
import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovingInteraction;
|
||||
|
@ -209,7 +210,6 @@ import com.simibubi.create.content.processing.basin.BasinGenerator;
|
|||
import com.simibubi.create.content.processing.basin.BasinMovementBehaviour;
|
||||
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock;
|
||||
import com.simibubi.create.content.processing.burner.BlazeBurnerBlockItem;
|
||||
import com.simibubi.create.content.processing.burner.BlazeBurnerInteractionBehaviour;
|
||||
import com.simibubi.create.content.processing.burner.BlazeBurnerMovementBehaviour;
|
||||
import com.simibubi.create.content.processing.burner.LitBlazeBurnerBlock;
|
||||
import com.simibubi.create.content.redstone.RoseQuartzLampBlock;
|
||||
|
@ -338,6 +338,7 @@ import net.minecraftforge.client.model.generators.ModelFile;
|
|||
import net.minecraftforge.common.Tags;
|
||||
import net.minecraftforge.common.util.ForgeSoundType;
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
public class AllBlocks {
|
||||
|
||||
static {
|
||||
|
@ -359,7 +360,7 @@ public class AllBlocks {
|
|||
.when(survivesExplosion)
|
||||
.setRolls(ConstantValue.exactly(1))
|
||||
.add(LootItem.lootTableItem(AllBlocks.SCHEMATICANNON.get()
|
||||
.asItem())
|
||||
.asItem())
|
||||
.apply(CopyNbtFunction.copyData(ContextNbtProvider.BLOCK_ENTITY)
|
||||
.copy("Options", "BlockEntityTag.Options")))));
|
||||
})
|
||||
|
@ -767,7 +768,7 @@ public class AllBlocks {
|
|||
.loot((lt, block) -> lt.add(block, BlazeBurnerBlock.buildLootTable()))
|
||||
.blockstate((c, p) -> p.simpleBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p)))
|
||||
.onRegister(movementBehaviour(new BlazeBurnerMovementBehaviour()))
|
||||
.onRegister(interactionBehaviour(new BlazeBurnerInteractionBehaviour()))
|
||||
.onRegister(block -> TrainConductorHandler.registerBlazeBurner())
|
||||
.item(BlazeBurnerBlockItem::withBlaze)
|
||||
.model(AssetLookup.customBlockItemModel("blaze_burner", "block_with_blaze"))
|
||||
.build()
|
||||
|
@ -788,8 +789,8 @@ public class AllBlocks {
|
|||
.modelFile(p.models()
|
||||
.getExistingFile(p.modLoc("block/blaze_burner/"
|
||||
+ (state.getValue(LitBlazeBurnerBlock.FLAME_TYPE) == LitBlazeBurnerBlock.FlameType.SOUL
|
||||
? "block_with_soul_fire"
|
||||
: "block_with_fire"))))
|
||||
? "block_with_soul_fire"
|
||||
: "block_with_fire"))))
|
||||
.build()))
|
||||
.register();
|
||||
|
||||
|
@ -2681,10 +2682,10 @@ public class AllBlocks {
|
|||
|
||||
public static final CopperBlockSet COPPER_SHINGLES = new CopperBlockSet(REGISTRATE, "copper_shingles",
|
||||
"copper_roof_top", CopperBlockSet.DEFAULT_VARIANTS, (c, p) -> {
|
||||
p.stonecutting(DataIngredient.tag(AllTags.forgeItemTag("ingots/copper")), RecipeCategory.BUILDING_BLOCKS,
|
||||
c::get, 2);
|
||||
}, (ws, block) -> connectedTextures(() -> new RoofBlockCTBehaviour(AllSpriteShifts.COPPER_SHINGLES.get(ws)))
|
||||
.accept(block));
|
||||
p.stonecutting(DataIngredient.tag(AllTags.forgeItemTag("ingots/copper")), RecipeCategory.BUILDING_BLOCKS,
|
||||
c::get, 2);
|
||||
}, (ws, block) -> connectedTextures(() -> new RoofBlockCTBehaviour(AllSpriteShifts.COPPER_SHINGLES.get(ws)))
|
||||
.accept(block));
|
||||
|
||||
public static final CopperBlockSet COPPER_TILES =
|
||||
new CopperBlockSet(REGISTRATE, "copper_tiles", "copper_roof_top", CopperBlockSet.DEFAULT_VARIANTS, (c, p) -> {
|
||||
|
@ -2695,6 +2696,7 @@ public class AllBlocks {
|
|||
|
||||
// Load this class
|
||||
|
||||
public static void register() {}
|
||||
public static void register() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ import java.util.function.Supplier;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.simibubi.create.content.fluids.VirtualFluid;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
|
@ -14,7 +16,6 @@ import com.mojang.blaze3d.shaders.FogShape;
|
|||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.simibubi.create.AllTags.AllFluidTags;
|
||||
import com.simibubi.create.content.decoration.palettes.AllPaletteStoneTypes;
|
||||
import com.simibubi.create.content.fluids.VirtualFluid;
|
||||
import com.simibubi.create.content.fluids.potion.PotionFluid;
|
||||
import com.simibubi.create.content.fluids.potion.PotionFluid.PotionFluidType;
|
||||
import com.simibubi.create.infrastructure.config.AllConfigs;
|
||||
|
@ -46,7 +47,7 @@ public class AllFluids {
|
|||
}
|
||||
|
||||
public static final FluidEntry<PotionFluid> POTION =
|
||||
REGISTRATE.virtualFluid("potion", PotionFluidType::new, PotionFluid::new)
|
||||
REGISTRATE.virtualFluid("potion", PotionFluidType::new, PotionFluid::createSource, PotionFluid::createFlowing)
|
||||
.lang("Potion")
|
||||
.register();
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ public class AllTags {
|
|||
SIMPLE_MOUNTED_STORAGE,
|
||||
FALLBACK_MOUNTED_STORAGE_BLACKLIST,
|
||||
ROOTS,
|
||||
SUGAR_CANE_VARIANTS,
|
||||
|
||||
CORALS,
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
package com.simibubi.create.api.contraption.train;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllInteractionBehaviours;
|
||||
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock;
|
||||
|
||||
import com.simibubi.create.content.processing.burner.BlockBasedTrainConductorInteractionBehaviour;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
|
||||
/**
|
||||
* All required methods to make your block a train conductor similar to the blaze burner
|
||||
*/
|
||||
public interface TrainConductorHandler {
|
||||
|
||||
@ApiStatus.Internal
|
||||
List<TrainConductorHandler> CONDUCTOR_HANDLERS = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
boolean isValidConductor(BlockState state);
|
||||
|
||||
private static void registerHandler(TrainConductorHandler handler) {
|
||||
CONDUCTOR_HANDLERS.add(handler);
|
||||
}
|
||||
|
||||
static void registerConductor(ResourceLocation blockRl, Predicate<BlockState> isValidConductor, UpdateScheduleCallback updateScheduleCallback) {
|
||||
AllInteractionBehaviours.registerBehaviour(blockRl, new BlockBasedTrainConductorInteractionBehaviour(isValidConductor, updateScheduleCallback));
|
||||
registerHandler(isValidConductor::test);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
static void registerBlazeBurner() {
|
||||
registerConductor(AllBlocks.BLAZE_BURNER.getId(), blockState -> AllBlocks.BLAZE_BURNER.has(blockState)
|
||||
&& blockState.getValue(BlazeBurnerBlock.HEAT_LEVEL) != BlazeBurnerBlock.HeatLevel.NONE, UpdateScheduleCallback.EMPTY);
|
||||
}
|
||||
|
||||
interface UpdateScheduleCallback {
|
||||
|
||||
UpdateScheduleCallback EMPTY = (hasSchedule, blockState, blockStateSetter) -> {};
|
||||
|
||||
void update(boolean hasSchedule, BlockState currentBlockState, Consumer<BlockState> blockStateSetter);
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ import net.minecraftforge.registries.ForgeRegistries;
|
|||
*/
|
||||
public enum Mods {
|
||||
AETHER,
|
||||
BETTEREND,
|
||||
COMPUTERCRAFT,
|
||||
CONNECTIVITY,
|
||||
CURIOS,
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
package com.simibubi.create.compat.betterend;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.VarHandle;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.portal.PortalInfo;
|
||||
|
||||
public class BetterEndPortalCompat {
|
||||
private static final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
|
||||
private static MethodHandle constructorHandle;
|
||||
private static VarHandle portalEntrancePosHandle;
|
||||
private static MethodHandle findDimensionEntryPointHandle;
|
||||
|
||||
private static boolean hasErrored = false;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> travelerStateClass = Class.forName("org.betterx.betterend.portal.TravelerState");
|
||||
MethodHandles.Lookup privateLookup = MethodHandles.privateLookupIn(travelerStateClass, lookup);
|
||||
|
||||
MethodType travelerStateConstructorTypes = MethodType.methodType(void.class, Entity.class);
|
||||
constructorHandle = lookup.findConstructor(travelerStateClass, travelerStateConstructorTypes);
|
||||
|
||||
portalEntrancePosHandle = privateLookup.findVarHandle(travelerStateClass, "portalEntrancePos", BlockPos.class);
|
||||
|
||||
MethodType findDimensionEntryPointTypes = MethodType.methodType(PortalInfo.class, ServerLevel.class);
|
||||
findDimensionEntryPointHandle = privateLookup.findVirtual(travelerStateClass, "findDimensionEntryPoint", findDimensionEntryPointTypes);
|
||||
} catch (Exception e) {
|
||||
Create.LOGGER.error("Create's Better End Portal compat failed to initialize: ", e);
|
||||
hasErrored = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the adjusted {@link PortalInfo} for the Better End portal using reflection.
|
||||
*
|
||||
* @param targetLevel The target {@link ServerLevel} (dimension).
|
||||
* @param entity The probe {@link Entity} used for portal traversal calculations.
|
||||
* @return The adjusted {@link PortalInfo} for the target dimension, or {@code null} if an error occurs.
|
||||
*/
|
||||
public static PortalInfo getBetterEndPortalInfo(ServerLevel targetLevel, Entity entity) {
|
||||
if (!hasErrored) {
|
||||
try {
|
||||
Object travelerState = constructorHandle.invoke(entity);
|
||||
|
||||
// Set the private portalEntrancePos field to the entity's block position
|
||||
// as assumed in TravelerState#findDimensionEntryPoint
|
||||
portalEntrancePosHandle.set(travelerState, entity.blockPosition().immutable());
|
||||
|
||||
return (PortalInfo) findDimensionEntryPointHandle.invoke(travelerState, targetLevel);
|
||||
} catch (Throwable e) {
|
||||
Create.LOGGER.error("Create's Better End Portal compat failed to initialize: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@ public class DisplayLinkPeripheral extends SyncedPeripheral<DisplayLinkBlockEnti
|
|||
|
||||
@LuaFunction(mainThread = true)
|
||||
public final Object[] getSize() {
|
||||
blockEntity.updateGatheredData();
|
||||
DisplayTargetStats stats = blockEntity.activeTarget.provideStats(new DisplayLinkContext(blockEntity.getLevel(), blockEntity));
|
||||
return new Object[]{stats.maxRows(), stats.maxColumns()};
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ import mezz.jei.api.forge.ForgeTypes;
|
|||
import mezz.jei.api.gui.drawable.IDrawable;
|
||||
import mezz.jei.api.helpers.IPlatformFluidHelper;
|
||||
import mezz.jei.api.recipe.category.IRecipeCategory;
|
||||
import mezz.jei.api.registration.IExtraIngredientRegistration;
|
||||
import mezz.jei.api.registration.IGuiHandlerRegistration;
|
||||
import mezz.jei.api.registration.IRecipeCatalystRegistration;
|
||||
import mezz.jei.api.registration.IRecipeCategoryRegistration;
|
||||
|
@ -91,6 +92,7 @@ import net.minecraft.core.RegistryAccess;
|
|||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.alchemy.Potion;
|
||||
import net.minecraft.world.item.crafting.AbstractCookingRecipe;
|
||||
import net.minecraft.world.item.crafting.CraftingRecipe;
|
||||
import net.minecraft.world.item.crafting.Recipe;
|
||||
|
@ -99,7 +101,9 @@ import net.minecraft.world.item.crafting.SmokingRecipe;
|
|||
import net.minecraft.world.level.ItemLike;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraftforge.common.crafting.IShapedRecipe;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
@JeiPlugin
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -356,6 +360,22 @@ public class CreateJEI implements IModPlugin {
|
|||
registration.registerSubtypeInterpreter(ForgeTypes.FLUID_STACK, potionFluid.getFlowing(), interpreter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerExtraIngredients(IExtraIngredientRegistration registration) {
|
||||
Collection<Potion> potions = ForgeRegistries.POTIONS.getValues();
|
||||
Collection<FluidStack> potionFluids = new ArrayList<>(potions.size() * 3);
|
||||
for (Potion potion : potions) {
|
||||
// @goshante: Ingame potion fluids always have Bottle tag that specifies
|
||||
// to what bottle type this potion belongs
|
||||
// Potion fluid without this tag wouldn't be recognized by other mods
|
||||
for (PotionFluid.BottleType bottleType : PotionFluid.BottleType.values()) {
|
||||
FluidStack potionFluid = PotionFluid.of(1000, potion, bottleType);
|
||||
potionFluids.add(potionFluid);
|
||||
}
|
||||
}
|
||||
registration.addExtraIngredients(ForgeTypes.FLUID_STACK, potionFluids);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Override
|
||||
public void registerGuiHandlers(IGuiHandlerRegistration registration) {
|
||||
|
|
|
@ -68,7 +68,7 @@ public class BasinCategory extends CreateRecipeCategory<BasinRecipe> {
|
|||
.addSlot(RecipeIngredientRole.INPUT, 17 + xOffset + (i % 3) * 19, 51 - (i / 3) * 19)
|
||||
.setBackground(getRenderedSlot(), -1, -1)
|
||||
.addIngredients(ForgeTypes.FLUID_STACK, withImprovedVisibility(fluidIngredient.getMatchingFluidStacks()))
|
||||
.addTooltipCallback(addFluidTooltip(fluidIngredient.getRequiredAmount()));
|
||||
.addRichTooltipCallback(addFluidTooltip(fluidIngredient.getRequiredAmount()));
|
||||
i++;
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ public class BasinCategory extends CreateRecipeCategory<BasinRecipe> {
|
|||
.addSlot(RecipeIngredientRole.OUTPUT, xPosition, yPosition)
|
||||
.setBackground(getRenderedSlot(result), -1, -1)
|
||||
.addItemStack(result.getStack())
|
||||
.addTooltipCallback(addStochasticTooltip(result));
|
||||
.addRichTooltipCallback(addStochasticTooltip(result));
|
||||
i++;
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,7 @@ public class BasinCategory extends CreateRecipeCategory<BasinRecipe> {
|
|||
.addSlot(RecipeIngredientRole.OUTPUT, xPosition, yPosition)
|
||||
.setBackground(getRenderedSlot(), -1, -1)
|
||||
.addIngredient(ForgeTypes.FLUID_STACK, withImprovedVisibility(fluidResult))
|
||||
.addTooltipCallback(addFluidTooltip(fluidResult.getAmount()));
|
||||
.addRichTooltipCallback(addFluidTooltip(fluidResult.getAmount()));
|
||||
i++;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import java.util.stream.Collectors;
|
|||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.simibubi.create.AllFluids;
|
||||
|
@ -19,7 +18,7 @@ import com.simibubi.create.foundation.utility.CreateLang;
|
|||
|
||||
import mezz.jei.api.forge.ForgeTypes;
|
||||
import mezz.jei.api.gui.drawable.IDrawable;
|
||||
import mezz.jei.api.gui.ingredient.IRecipeSlotTooltipCallback;
|
||||
import mezz.jei.api.gui.ingredient.IRecipeSlotRichTooltipCallback;
|
||||
import mezz.jei.api.recipe.RecipeType;
|
||||
import mezz.jei.api.recipe.category.IRecipeCategory;
|
||||
import mezz.jei.api.registration.IRecipeCatalystRegistration;
|
||||
|
@ -109,11 +108,11 @@ public abstract class CreateRecipeCategory<T extends Recipe<?>> implements IReci
|
|||
return recipe.getResultItem(level.registryAccess());
|
||||
}
|
||||
|
||||
public static IRecipeSlotTooltipCallback addStochasticTooltip(ProcessingOutput output) {
|
||||
public static IRecipeSlotRichTooltipCallback addStochasticTooltip(ProcessingOutput output) {
|
||||
return (view, tooltip) -> {
|
||||
float chance = output.getChance();
|
||||
if (chance != 1)
|
||||
tooltip.add(1, CreateLang.translateDirect("recipe.processing.chance", chance < 0.01 ? "<1" : (int) (chance * 100))
|
||||
tooltip.add(CreateLang.translateDirect("recipe.processing.chance", chance < 0.01 ? "<1" : (int) (chance * 100))
|
||||
.withStyle(ChatFormatting.GOLD));
|
||||
};
|
||||
}
|
||||
|
@ -131,11 +130,11 @@ public abstract class CreateRecipeCategory<T extends Recipe<?>> implements IReci
|
|||
return display;
|
||||
}
|
||||
|
||||
public static IRecipeSlotTooltipCallback addFluidTooltip() {
|
||||
public static IRecipeSlotRichTooltipCallback addFluidTooltip() {
|
||||
return addFluidTooltip(-1);
|
||||
}
|
||||
|
||||
public static IRecipeSlotTooltipCallback addFluidTooltip(int mbAmount) {
|
||||
public static IRecipeSlotRichTooltipCallback addFluidTooltip(int mbAmount) {
|
||||
return (view, tooltip) -> {
|
||||
Optional<FluidStack> displayed = view.getDisplayedIngredient(ForgeTypes.FLUID_STACK);
|
||||
if (displayed.isEmpty())
|
||||
|
@ -144,26 +143,14 @@ public abstract class CreateRecipeCategory<T extends Recipe<?>> implements IReci
|
|||
FluidStack fluidStack = displayed.get();
|
||||
|
||||
if (fluidStack.getFluid().isSame(AllFluids.POTION.get())) {
|
||||
Component name = fluidStack.getDisplayName();
|
||||
if (tooltip.isEmpty())
|
||||
tooltip.add(0, name);
|
||||
else
|
||||
tooltip.set(0, name);
|
||||
|
||||
ArrayList<Component> potionTooltip = new ArrayList<>();
|
||||
PotionFluidHandler.addPotionTooltip(fluidStack, potionTooltip, 1);
|
||||
tooltip.addAll(1, potionTooltip.stream().toList());
|
||||
tooltip.addAll(potionTooltip.stream().toList());
|
||||
}
|
||||
|
||||
int amount = mbAmount == -1 ? fluidStack.getAmount() : mbAmount;
|
||||
Component text = Component.literal(String.valueOf(amount)).append(CreateLang.translateDirect("generic.unit.millibuckets")).withStyle(ChatFormatting.GOLD);
|
||||
if (tooltip.isEmpty())
|
||||
tooltip.add(0, text);
|
||||
else {
|
||||
List<Component> siblings = tooltip.get(0).getSiblings();
|
||||
siblings.add(Component.literal(" "));
|
||||
siblings.add(text);
|
||||
}
|
||||
Component text = Component.literal(String.valueOf(amount)).append(CreateLang.translateDirect("generic.unit.millibuckets")).withStyle(ChatFormatting.GOLD);
|
||||
tooltip.add(text);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -186,7 +173,9 @@ public abstract class CreateRecipeCategory<T extends Recipe<?>> implements IReci
|
|||
};
|
||||
}
|
||||
|
||||
public record Info<T extends Recipe<?>>(RecipeType<T> recipeType, Component title, IDrawable background, IDrawable icon, Supplier<List<T>> recipes, List<Supplier<? extends ItemStack>> catalysts) {
|
||||
public record Info<T extends Recipe<?>>(RecipeType<T> recipeType, Component title, IDrawable background,
|
||||
IDrawable icon, Supplier<List<T>> recipes,
|
||||
List<Supplier<? extends ItemStack>> catalysts) {
|
||||
}
|
||||
|
||||
public interface Factory<T extends Recipe<?>> {
|
||||
|
|
|
@ -41,7 +41,7 @@ public class CrushingCategory extends CreateRecipeCategory<AbstractCrushingRecip
|
|||
.addSlot(RecipeIngredientRole.OUTPUT, (xOffset) + layoutEntry.posX() + 1, yOffset + layoutEntry.posY() + 1)
|
||||
.setBackground(getRenderedSlot(layoutEntry.output()), -1, -1)
|
||||
.addItemStack(layoutEntry.output().getStack())
|
||||
.addTooltipCallback(addStochasticTooltip(layoutEntry.output()))
|
||||
.addRichTooltipCallback(addStochasticTooltip(layoutEntry.output()))
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ public class DeployingCategory extends CreateRecipeCategory<DeployerApplicationR
|
|||
builder.addSlot(RecipeIngredientRole.OUTPUT, single ? 132 : 132 + xOffset, 51 + yOffset)
|
||||
.setBackground(getRenderedSlot(output), -1, -1)
|
||||
.addItemStack(output.getStack())
|
||||
.addTooltipCallback(addStochasticTooltip(output));
|
||||
.addRichTooltipCallback(addStochasticTooltip(output));
|
||||
}
|
||||
|
||||
if (recipe.shouldKeepHeldItem())
|
||||
|
|
|
@ -56,7 +56,7 @@ public class ItemApplicationCategory extends CreateRecipeCategory<ItemApplicatio
|
|||
builder.addSlot(RecipeIngredientRole.OUTPUT, single ? 132 : 132 + xOffset, 38 + yOffset)
|
||||
.setBackground(getRenderedSlot(output), -1, -1)
|
||||
.addItemStack(output.getStack())
|
||||
.addTooltipCallback(addStochasticTooltip(output));
|
||||
.addRichTooltipCallback(addStochasticTooltip(output));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,9 @@ import com.simibubi.create.content.fluids.transfer.EmptyingRecipe;
|
|||
import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder;
|
||||
import com.simibubi.create.foundation.gui.AllGuiTextures;
|
||||
|
||||
import com.simibubi.create.foundation.item.ItemHelper;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
|
||||
import mezz.jei.api.constants.VanillaTypes;
|
||||
import mezz.jei.api.forge.ForgeTypes;
|
||||
import mezz.jei.api.gui.builder.IRecipeLayoutBuilder;
|
||||
|
@ -22,6 +25,7 @@ import net.createmod.catnip.platform.CatnipServices;
|
|||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.ItemStackLinkedSet;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
|
@ -40,6 +44,7 @@ public class ItemDrainCategory extends CreateRecipeCategory<EmptyingRecipe> {
|
|||
}
|
||||
|
||||
public static void consumeRecipes(Consumer<EmptyingRecipe> consumer, IIngredientManager ingredientManager) {
|
||||
ObjectOpenCustomHashSet<ItemStack> emptiedItems = new ObjectOpenCustomHashSet<>(ItemStackLinkedSet.TYPE_AND_TAG);
|
||||
for (ItemStack stack : ingredientManager.getAllIngredients(VanillaTypes.ITEM_STACK)) {
|
||||
if (PotionFluidHandler.isPotionItem(stack)) {
|
||||
FluidStack fluidFromPotionItem = PotionFluidHandler.getFluidFromPotionItem(stack);
|
||||
|
@ -67,6 +72,11 @@ public class ItemDrainCategory extends CreateRecipeCategory<EmptyingRecipe> {
|
|||
if (result.isEmpty())
|
||||
continue;
|
||||
|
||||
// There can be a lot of duplicate empty tanks (e.g. from emptying tanks with different fluids). Merge
|
||||
// them to reduce memory usage. If the item is exactly the same as the input, just use the input stack
|
||||
// instead of the copy.
|
||||
result = ItemHelper.sameItem(stack, result) ? stack : emptiedItems.addOrGet(result);
|
||||
|
||||
Ingredient ingredient = Ingredient.of(stack);
|
||||
ResourceLocation itemName = CatnipServices.REGISTRIES.getKeyOrThrow(stack.getItem());
|
||||
ResourceLocation fluidName = CatnipServices.REGISTRIES.getKeyOrThrow(extracted.getFluid());
|
||||
|
@ -90,7 +100,7 @@ public class ItemDrainCategory extends CreateRecipeCategory<EmptyingRecipe> {
|
|||
.addSlot(RecipeIngredientRole.OUTPUT, 132, 8)
|
||||
.setBackground(getRenderedSlot(), -1, -1)
|
||||
.addIngredient(ForgeTypes.FLUID_STACK, withImprovedVisibility(recipe.getResultingFluid()))
|
||||
.addTooltipCallback(addFluidTooltip(recipe.getResultingFluid().getAmount()));
|
||||
.addRichTooltipCallback(addFluidTooltip(recipe.getResultingFluid().getAmount()));
|
||||
builder
|
||||
.addSlot(RecipeIngredientRole.OUTPUT, 132, 27)
|
||||
.setBackground(getRenderedSlot(), -1, -1)
|
||||
|
|
|
@ -40,7 +40,7 @@ public class MillingCategory extends CreateRecipeCategory<AbstractCrushingRecipe
|
|||
.addSlot(RecipeIngredientRole.OUTPUT, single ? 139 : 133 + xOffset, 27 + yOffset)
|
||||
.setBackground(getRenderedSlot(output), -1, -1)
|
||||
.addItemStack(output.getStack())
|
||||
.addTooltipCallback(addStochasticTooltip(output));
|
||||
.addRichTooltipCallback(addStochasticTooltip(output));
|
||||
|
||||
i++;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ public class PolishingCategory extends CreateRecipeCategory<SandPaperPolishingRe
|
|||
.addSlot(RecipeIngredientRole.OUTPUT, 132, 29)
|
||||
.setBackground(getRenderedSlot(output), -1, -1)
|
||||
.addItemStack(output.getStack())
|
||||
.addTooltipCallback(addStochasticTooltip(output));
|
||||
.addRichTooltipCallback(addStochasticTooltip(output));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -35,7 +35,7 @@ public class PressingCategory extends CreateRecipeCategory<PressingRecipe> {
|
|||
builder.addSlot(RecipeIngredientRole.OUTPUT, 131 + 19 * i, 50)
|
||||
.setBackground(getRenderedSlot(output), -1, -1)
|
||||
.addItemStack(output.getStack())
|
||||
.addTooltipCallback(addStochasticTooltip(output));
|
||||
.addRichTooltipCallback(addStochasticTooltip(output));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ public abstract class ProcessingViaFanCategory<T extends Recipe<?>> extends Crea
|
|||
.addSlot(RecipeIngredientRole.OUTPUT, 141 + xOffset, 48 + yOffset)
|
||||
.setBackground(getRenderedSlot(output), -1, -1)
|
||||
.addItemStack(output.getStack())
|
||||
.addTooltipCallback(addStochasticTooltip(output));
|
||||
.addRichTooltipCallback(addStochasticTooltip(output));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public class SawingCategory extends CreateRecipeCategory<CuttingRecipe> {
|
|||
.addSlot(RecipeIngredientRole.OUTPUT, 118 + xOffset, 48 + yOffset)
|
||||
.setBackground(getRenderedSlot(output), -1, -1)
|
||||
.addItemStack(output.getStack())
|
||||
.addTooltipCallback(addStochasticTooltip(output));
|
||||
.addRichTooltipCallback(addStochasticTooltip(output));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,16 @@ public class SpoutCategory extends CreateRecipeCategory<FillingRecipe> {
|
|||
if (!capability.isPresent())
|
||||
continue;
|
||||
|
||||
var existingFluidHandler = capability.orElse(null);
|
||||
int numTanks = existingFluidHandler.getTanks();
|
||||
FluidStack existingFluid = numTanks == 1 ? existingFluidHandler.getFluidInTank(0) : FluidStack.EMPTY;
|
||||
|
||||
for (FluidStack fluidStack : fluidStacks) {
|
||||
// Hoist the fluid equality check to avoid the work of copying the stack + populating capabilities
|
||||
// when most fluids will not match
|
||||
if (numTanks == 1 && (!existingFluid.isEmpty() && !existingFluid.isFluidEqual(fluidStack))) {
|
||||
continue;
|
||||
}
|
||||
ItemStack copy = stack.copy();
|
||||
copy.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM)
|
||||
.ifPresent(fhi -> {
|
||||
|
@ -102,7 +111,7 @@ public class SpoutCategory extends CreateRecipeCategory<FillingRecipe> {
|
|||
.addSlot(RecipeIngredientRole.INPUT, 27, 32)
|
||||
.setBackground(getRenderedSlot(), -1, -1)
|
||||
.addIngredients(ForgeTypes.FLUID_STACK, withImprovedVisibility(recipe.getRequiredFluid().getMatchingFluidStacks()))
|
||||
.addTooltipCallback(addFluidTooltip(recipe.getRequiredFluid().getRequiredAmount()));
|
||||
.addRichTooltipCallback(addFluidTooltip(recipe.getRequiredFluid().getRequiredAmount()));
|
||||
builder
|
||||
.addSlot(RecipeIngredientRole.OUTPUT, 132, 51)
|
||||
.setBackground(getRenderedSlot(), -1, -1)
|
||||
|
|
|
@ -75,7 +75,7 @@ public abstract class SequencedAssemblySubCategory {
|
|||
.addSlot(RecipeIngredientRole.INPUT, x + 4, 15)
|
||||
.setBackground(CreateRecipeCategory.getRenderedSlot(), -1, -1)
|
||||
.addIngredients(ForgeTypes.FLUID_STACK, CreateRecipeCategory.withImprovedVisibility(fluidIngredient.getMatchingFluidStacks()))
|
||||
.addTooltipCallback(CreateRecipeCategory.addFluidTooltip(fluidIngredient.getRequiredAmount()));
|
||||
.addRichTooltipCallback(CreateRecipeCategory.addFluidTooltip(fluidIngredient.getRequiredAmount()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -14,7 +14,6 @@ import org.apache.commons.lang3.mutable.MutableFloat;
|
|||
import org.apache.commons.lang3.mutable.MutableObject;
|
||||
import org.apache.commons.lang3.tuple.MutablePair;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllMovementBehaviours;
|
||||
import com.simibubi.create.AllPackets;
|
||||
|
@ -162,8 +161,7 @@ public class ContraptionCollider {
|
|||
List<AABB> bbs = new ArrayList<>();
|
||||
List<VoxelShape> potentialHits =
|
||||
getPotentiallyCollidedShapes(world, contraption, localBB.expandTowards(motionCopy));
|
||||
potentialHits.forEach(shape -> shape.toAabbs()
|
||||
.forEach(bbs::add));
|
||||
potentialHits.forEach(shape -> bbs.addAll(shape.toAabbs()));
|
||||
return bbs;
|
||||
|
||||
});
|
||||
|
@ -670,19 +668,23 @@ public class ContraptionCollider {
|
|||
BlockPos min = BlockPos.containing(blockScanBB.minX, blockScanBB.minY, blockScanBB.minZ);
|
||||
BlockPos max = BlockPos.containing(blockScanBB.maxX, blockScanBB.maxY, blockScanBB.maxZ);
|
||||
|
||||
List<VoxelShape> potentialHits = BlockPos.betweenClosedStream(min, max)
|
||||
.filter(contraption.getBlocks()::containsKey)
|
||||
.filter(Predicates.not(contraption::isHiddenInPortal))
|
||||
.map(p -> {
|
||||
BlockState blockState = contraption.getBlocks()
|
||||
.get(p).state();
|
||||
BlockPos pos = contraption.getBlocks()
|
||||
.get(p).pos();
|
||||
VoxelShape collisionShape = blockState.getCollisionShape(world, p);
|
||||
return collisionShape.move(pos.getX(), pos.getY(), pos.getZ());
|
||||
})
|
||||
.filter(Predicates.not(VoxelShape::isEmpty))
|
||||
.toList();
|
||||
List<VoxelShape> potentialHits = new ArrayList<>();
|
||||
|
||||
for (BlockPos p : BlockPos.betweenClosed(min, max)) {
|
||||
if (contraption.blocks.containsKey(p) && !contraption.isHiddenInPortal(p)) {
|
||||
StructureBlockInfo info = contraption.getBlocks().get(p);
|
||||
|
||||
BlockState blockState = info.state();
|
||||
BlockPos pos = info.pos();
|
||||
|
||||
VoxelShape collisionShape = blockState.getCollisionShape(world, p)
|
||||
.move(pos.getX(), pos.getY(), pos.getZ());
|
||||
|
||||
if (!collisionShape.isEmpty()) {
|
||||
potentialHits.add(collisionShape);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return potentialHits;
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ public class ContraptionControlsBlockEntity extends SmartBlockEntity {
|
|||
|
||||
public static void sendStatus(Player player, ItemStack filter, boolean enabled) {
|
||||
MutableComponent state = CreateLang.translate("contraption.controls.actor_toggle." + (enabled ? "on" : "off"))
|
||||
.color(DyeHelper.DYE_TABLE.get(enabled ? DyeColor.LIME : DyeColor.ORANGE)
|
||||
.color(DyeHelper.getDyeColors(enabled ? DyeColor.LIME : DyeColor.ORANGE)
|
||||
.getFirst())
|
||||
.component();
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ public class ContraptionControlsRenderer extends SmartBlockEntityRenderer<Contra
|
|||
: ctx.position.distanceToSqr(cameraEntity.getEyePosition()));
|
||||
|
||||
float flicker = r.nextFloat();
|
||||
Couple<Integer> couple = DyeHelper.DYE_TABLE.get(efs.targetYEqualsSelection ? DyeColor.WHITE : DyeColor.ORANGE);
|
||||
Couple<Integer> couple = DyeHelper.getDyeColors(efs.targetYEqualsSelection ? DyeColor.WHITE : DyeColor.ORANGE);
|
||||
int brightColor = couple.getFirst();
|
||||
int darkColor = couple.getSecond();
|
||||
int flickeringBrightColor = Color.mixColors(brightColor, darkColor, flicker / 4);
|
||||
|
|
|
@ -4,6 +4,7 @@ import javax.annotation.Nullable;
|
|||
|
||||
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||
|
||||
import com.simibubi.create.AllTags;
|
||||
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour;
|
||||
import com.simibubi.create.content.contraptions.behaviour.MovementContext;
|
||||
import com.simibubi.create.content.contraptions.render.ActorVisual;
|
||||
|
@ -174,7 +175,7 @@ public class HarvesterMovementBehaviour implements MovementBehaviour {
|
|||
if (block == Blocks.SWEET_BERRY_BUSH) {
|
||||
return state.setValue(BlockStateProperties.AGE_3, Integer.valueOf(1));
|
||||
}
|
||||
if (block == Blocks.SUGAR_CANE || block instanceof GrowingPlantBlock) {
|
||||
if (state.is(AllTags.AllBlockTags.SUGAR_CANE_VARIANTS.tag) || block instanceof GrowingPlantBlock) {
|
||||
if (state.getFluidState()
|
||||
.isEmpty())
|
||||
return Blocks.AIR.defaultBlockState();
|
||||
|
|
|
@ -164,6 +164,11 @@ public class CopycatPanelBlock extends WaterloggedCopycatBlock {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean skipRendering(BlockState state, BlockState adjacentState, Direction direction) {
|
||||
return state.equals(adjacentState) && direction.getAxis().isHorizontal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsExternalFaceHiding(BlockState state) {
|
||||
return true;
|
||||
|
|
|
@ -184,8 +184,10 @@ public class BacktankBlock extends HorizontalKineticBlock implements IBE<Backtan
|
|||
Optional<BacktankBlockEntity> blockEntityOptional = getBlockEntityOptional(blockGetter, pos);
|
||||
|
||||
CompoundTag forgeCapsTag = blockEntityOptional.map(BacktankBlockEntity::getForgeCapsTag)
|
||||
.map(CompoundTag::copy)
|
||||
.orElse(null);
|
||||
CompoundTag vanillaTag = blockEntityOptional.map(BacktankBlockEntity::getVanillaTag)
|
||||
.map(CompoundTag::copy)
|
||||
.orElse(new CompoundTag());
|
||||
int air = blockEntityOptional.map(BacktankBlockEntity::getAirLevel)
|
||||
.orElse(0);
|
||||
|
|
|
@ -183,8 +183,10 @@ public class BacktankBlockEntity extends KineticBlockEntity implements Nameable
|
|||
}
|
||||
|
||||
public void setTags(CompoundTag vanillaTag, @Nullable CompoundTag forgeCapsTag) {
|
||||
this.vanillaTag = vanillaTag;
|
||||
this.forgeCapsTag = forgeCapsTag;
|
||||
this.vanillaTag = vanillaTag.copy();
|
||||
this.forgeCapsTag = forgeCapsTag == null ? null : forgeCapsTag.copy();
|
||||
// Prevent nesting of the ctrl+pick block added tag
|
||||
vanillaTag.remove("BlockEntityTag");
|
||||
}
|
||||
|
||||
public CompoundTag getVanillaTag() {
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.simibubi.create.AllBlockEntityTypes;
|
|||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllShapes;
|
||||
import com.simibubi.create.foundation.block.IBE;
|
||||
import com.simibubi.create.foundation.item.ItemHelper;
|
||||
import com.simibubi.create.foundation.utility.BlockHelper;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
@ -22,7 +23,6 @@ import net.minecraft.world.entity.player.Player;
|
|||
import net.minecraft.world.item.DyeColor;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
|
@ -38,6 +38,7 @@ import net.minecraft.world.level.material.Fluids;
|
|||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
import net.minecraftforge.network.NetworkHooks;
|
||||
|
||||
|
@ -171,7 +172,7 @@ public class ToolboxBlock extends HorizontalDirectionalBlock implements SimpleWa
|
|||
public Class<ToolboxBlockEntity> getBlockEntityClass() {
|
||||
return ToolboxBlockEntity.class;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BlockEntityType<? extends ToolboxBlockEntity> getBlockEntityType() {
|
||||
return AllBlockEntityTypes.TOOLBOX.get();
|
||||
|
@ -181,9 +182,14 @@ public class ToolboxBlock extends HorizontalDirectionalBlock implements SimpleWa
|
|||
return color;
|
||||
}
|
||||
|
||||
public static Ingredient getMainBox() {
|
||||
return Ingredient.of(AllBlocks.TOOLBOXES.get(DyeColor.BROWN)
|
||||
.get());
|
||||
@Override
|
||||
public boolean hasAnalogOutputSignal(BlockState pState) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAnalogOutputSignal(BlockState pState, Level pLevel, BlockPos pPos) {
|
||||
return ItemHelper.calcRedstoneFromBlockEntity(this, pLevel, pPos);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -208,7 +208,7 @@ public class OpenEndedPipe extends FlowSource {
|
|||
if (!FluidHelper.hasBlockState(fluid.getFluid()))
|
||||
return true;
|
||||
|
||||
if (!fluidState.isEmpty() && fluidState.getType() != fluid.getFluid()) {
|
||||
if (!fluidState.isEmpty() && FluidHelper.convertToStill(fluidState.getType()) != fluid.getFluid()) {
|
||||
FluidReactions.handlePipeSpillCollision(world, outputPos, fluid.getFluid(), fluidState);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.simibubi.create.content.fluids;
|
||||
|
||||
import com.simibubi.create.content.fluids.potion.PotionFluid;
|
||||
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
|
@ -10,17 +12,35 @@ import net.minecraftforge.fluids.ForgeFlowingFluid;
|
|||
|
||||
public class VirtualFluid extends ForgeFlowingFluid {
|
||||
|
||||
public VirtualFluid(Properties properties) {
|
||||
public static VirtualFluid createSource(Properties properties) {
|
||||
return new VirtualFluid(properties, true);
|
||||
}
|
||||
|
||||
public static VirtualFluid createFlowing(Properties properties) {
|
||||
return new VirtualFluid(properties, false);
|
||||
}
|
||||
|
||||
|
||||
private final boolean source;
|
||||
|
||||
public VirtualFluid(Properties properties, boolean source) {
|
||||
super(properties);
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fluid getSource() {
|
||||
if (source) {
|
||||
return this;
|
||||
}
|
||||
return super.getSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fluid getFlowing() {
|
||||
if (source) {
|
||||
return super.getFlowing();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -36,7 +56,7 @@ public class VirtualFluid extends ForgeFlowingFluid {
|
|||
|
||||
@Override
|
||||
public boolean isSource(FluidState p_207193_1_) {
|
||||
return false;
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -24,19 +24,29 @@ import net.minecraftforge.fluids.FluidStack;
|
|||
|
||||
public class PotionFluid extends VirtualFluid {
|
||||
|
||||
public PotionFluid(Properties properties) {
|
||||
super(properties);
|
||||
public static PotionFluid createSource(Properties properties) {
|
||||
return new PotionFluid(properties, true);
|
||||
}
|
||||
|
||||
public static FluidStack of(int amount, Potion potion) {
|
||||
FluidStack fluidStack = new FluidStack(AllFluids.POTION.get()
|
||||
.getSource(), amount);
|
||||
public static PotionFluid createFlowing(Properties properties) {
|
||||
return new PotionFluid(properties, false);
|
||||
}
|
||||
|
||||
public PotionFluid(Properties properties, boolean source) {
|
||||
super(properties, source);
|
||||
}
|
||||
|
||||
public static FluidStack of(int amount, Potion potion, BottleType bottleType) {
|
||||
|
||||
FluidStack fluidStack;
|
||||
fluidStack = new FluidStack(AllFluids.POTION.get().getSource(), amount);
|
||||
addPotionToFluidStack(fluidStack, potion);
|
||||
NBTHelper.writeEnum(fluidStack.getOrCreateTag(), "Bottle", bottleType);
|
||||
return fluidStack;
|
||||
}
|
||||
|
||||
public static FluidStack withEffects(int amount, Potion potion, List<MobEffectInstance> customEffects) {
|
||||
FluidStack fluidStack = of(amount, potion);
|
||||
FluidStack fluidStack = of(amount, potion, BottleType.REGULAR);
|
||||
appendEffects(fluidStack, customEffects);
|
||||
return fluidStack;
|
||||
}
|
||||
|
|
|
@ -69,8 +69,7 @@ public class PotionFluidHandler {
|
|||
public static FluidStack getFluidFromPotion(Potion potion, BottleType bottleType, int amount) {
|
||||
if (potion == Potions.WATER && bottleType == BottleType.REGULAR)
|
||||
return new FluidStack(Fluids.WATER, amount);
|
||||
FluidStack fluid = PotionFluid.of(amount, potion);
|
||||
NBTHelper.writeEnum(fluid.getOrCreateTag(), "Bottle", bottleType);
|
||||
FluidStack fluid = PotionFluid.of(amount, potion, bottleType);
|
||||
return fluid;
|
||||
}
|
||||
|
||||
|
|
|
@ -234,6 +234,8 @@ public class SpoutBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
|
|||
protected void spawnProcessingParticles(FluidStack fluid) {
|
||||
if (isVirtual())
|
||||
return;
|
||||
if (fluid.isEmpty())
|
||||
return;
|
||||
Vec3 vec = VecHelper.getCenterOf(worldPosition);
|
||||
vec = vec.subtract(0, 8 / 16f, 0);
|
||||
ParticleOptions particle = FluidFX.getFluidParticle(fluid);
|
||||
|
|
|
@ -65,9 +65,9 @@ public class SpoutRenderer extends SafeBlockEntityRenderer<SpoutBlockEntity> {
|
|||
processingProgress = Mth.clamp(processingProgress, 0, 1);
|
||||
float radius = 0;
|
||||
|
||||
if (processingTicks != -1) {
|
||||
if (!fluidStack.isEmpty() && processingTicks != -1) {
|
||||
radius = (float) (Math.pow(((2 * processingProgress) - 1), 2) - 1);
|
||||
AABB bb = new AABB(0.5, .5, 0.5, 0.5, -1.2, 0.5).inflate(radius / 32f);
|
||||
AABB bb = new AABB(0.5, 0.0, 0.5, 0.5, -1.2, 0.5).inflate(radius / 32f);
|
||||
FluidRenderer.renderFluidBox(fluidStack.getFluid(), fluidStack.getAmount(), (float) bb.minX, (float) bb.minY, (float) bb.minZ,
|
||||
(float) bb.maxX, (float) bb.maxY, (float) bb.maxZ, buffer, ms, light, true, true, fluidStack.getTag());
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ public abstract class BlockBreakingKineticBlockEntity extends KineticBlockEntity
|
|||
float breakSpeed = getBreakSpeed();
|
||||
destroyProgress += Mth.clamp((int) (breakSpeed / blockHardness), 1, 10 - destroyProgress);
|
||||
level.playSound(null, worldPosition, stateToBreak.getSoundType()
|
||||
.getHitSound(), SoundSource.NEUTRAL, .25f, 1);
|
||||
.getHitSound(), SoundSource.BLOCKS, .25f, 1);
|
||||
|
||||
if (destroyProgress >= 10) {
|
||||
onBlockBroken(stateToBreak);
|
||||
|
|
|
@ -555,7 +555,10 @@ public class DeployerBlockEntity extends KineticBlockEntity {
|
|||
ItemStack heldItemMainhand = player.getMainHandItem();
|
||||
if (heldItemMainhand.getItem() instanceof SandPaperItem) {
|
||||
sandpaperInv.setItem(0, stack);
|
||||
return checkRecipe(AllRecipeTypes.SANDPAPER_POLISHING, sandpaperInv, level).orElse(null);
|
||||
Optional<? extends Recipe<? extends Container>> polishingRecipe = checkRecipe(AllRecipeTypes.SANDPAPER_POLISHING, sandpaperInv, level);
|
||||
if (polishingRecipe.isPresent()){
|
||||
return polishingRecipe.get();
|
||||
}
|
||||
}
|
||||
|
||||
recipeInv.setItem(0, stack);
|
||||
|
|
|
@ -186,8 +186,9 @@ public class DeployerHandler {
|
|||
if (stack.isEdible()) {
|
||||
FoodProperties foodProperties = item.getFoodProperties(stack, player);
|
||||
if (playerEntity.canEat(foodProperties.canAlwaysEat())) {
|
||||
playerEntity.eat(world, stack);
|
||||
player.spawnedItemEffects = stack.copy();
|
||||
ItemStack copy = stack.copy();
|
||||
player.setItemInHand(hand, stack.finishUsingItem(world, playerEntity));
|
||||
player.spawnedItemEffects = copy;
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -605,45 +605,30 @@ public class AllArmInteractionPointTypes {
|
|||
|
||||
@Override
|
||||
public ItemStack insert(ItemStack stack, boolean simulate) {
|
||||
Item item = stack.getItem();
|
||||
if (!(item instanceof RecordItem))
|
||||
if (!(stack.getItem() instanceof RecordItem))
|
||||
return stack;
|
||||
if (cachedState.getOptionalValue(JukeboxBlock.HAS_RECORD)
|
||||
.orElse(true))
|
||||
if (cachedState.getOptionalValue(JukeboxBlock.HAS_RECORD).orElse(true))
|
||||
return stack;
|
||||
BlockEntity blockEntity = level.getBlockEntity(pos);
|
||||
if (!(blockEntity instanceof JukeboxBlockEntity jukeboxBE))
|
||||
if (!(level.getBlockEntity(pos) instanceof JukeboxBlockEntity jukeboxBE))
|
||||
return stack;
|
||||
if (!jukeboxBE.getFirstItem()
|
||||
.isEmpty())
|
||||
if (!jukeboxBE.getFirstItem().isEmpty())
|
||||
return stack;
|
||||
ItemStack remainder = stack.copy();
|
||||
ItemStack toInsert = remainder.split(1);
|
||||
if (!simulate) {
|
||||
jukeboxBE.setFirstItem(toInsert);
|
||||
level.setBlock(pos, cachedState.setValue(JukeboxBlock.HAS_RECORD, true), 2);
|
||||
level.levelEvent(null, 1010, pos, Item.getId(item));
|
||||
}
|
||||
if (!simulate)
|
||||
jukeboxBE.setItem(0, toInsert);
|
||||
return remainder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack extract(int slot, int amount, boolean simulate) {
|
||||
if (!cachedState.getOptionalValue(JukeboxBlock.HAS_RECORD)
|
||||
.orElse(false))
|
||||
if (!cachedState.getOptionalValue(JukeboxBlock.HAS_RECORD).orElse(false))
|
||||
return ItemStack.EMPTY;
|
||||
BlockEntity blockEntity = level.getBlockEntity(pos);
|
||||
if (!(blockEntity instanceof JukeboxBlockEntity jukeboxBE))
|
||||
if (!(level.getBlockEntity(pos) instanceof JukeboxBlockEntity jukeboxBE))
|
||||
return ItemStack.EMPTY;
|
||||
ItemStack record = jukeboxBE.getFirstItem();
|
||||
if (record.isEmpty())
|
||||
return ItemStack.EMPTY;
|
||||
if (!simulate) {
|
||||
level.levelEvent(1010, pos, 0);
|
||||
jukeboxBE.clearContent();
|
||||
level.setBlock(pos, cachedState.setValue(JukeboxBlock.HAS_RECORD, false), 2);
|
||||
}
|
||||
return record;
|
||||
if (!simulate)
|
||||
return jukeboxBE.removeItem(slot, amount);
|
||||
return jukeboxBE.getFirstItem();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,10 @@ public abstract class AbstractSimpleShaftBlock extends AbstractShaftBlock implem
|
|||
|
||||
@Override
|
||||
public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) {
|
||||
if (state != newState && !isMoving)
|
||||
boolean wasWaterLogged = state.hasProperty(WATERLOGGED) &&
|
||||
newState.hasProperty(WATERLOGGED) &&
|
||||
(state.getValue(WATERLOGGED) != newState.getValue(WATERLOGGED));
|
||||
if (state != newState && !isMoving && !wasWaterLogged)
|
||||
removeBracket(world, pos, true).ifPresent(stack -> Block.popResource(world, pos, stack));
|
||||
super.onRemove(state, world, pos, newState, isMoving);
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ import java.util.List;
|
|||
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.content.fluids.transfer.GenericItemEmptying;
|
||||
import com.simibubi.create.content.logistics.item.filter.attribute.ItemAttribute;
|
||||
import com.simibubi.create.content.logistics.box.PackageItem;
|
||||
import com.simibubi.create.content.logistics.item.filter.attribute.ItemAttribute;
|
||||
|
||||
import net.createmod.catnip.data.Pair;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
@ -14,6 +14,7 @@ import net.minecraft.nbt.ListTag;
|
|||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.items.ItemStackHandler;
|
||||
|
||||
|
@ -25,16 +26,18 @@ public class FilterItemStack {
|
|||
|
||||
public static FilterItemStack of(ItemStack filter) {
|
||||
if (filter.hasTag()) {
|
||||
CompoundTag stackTag = filter.getTag();
|
||||
stackTag.remove("Enchantments");
|
||||
stackTag.remove("AttributeModifiers");
|
||||
|
||||
if (AllItems.FILTER.isIn(filter))
|
||||
if (AllItems.FILTER.isIn(filter)) {
|
||||
trimFilterTag(filter);
|
||||
return new ListFilterItemStack(filter);
|
||||
if (AllItems.ATTRIBUTE_FILTER.isIn(filter))
|
||||
}
|
||||
if (AllItems.ATTRIBUTE_FILTER.isIn(filter)) {
|
||||
trimFilterTag(filter);
|
||||
return new AttributeFilterItemStack(filter);
|
||||
if (AllItems.PACKAGE_FILTER.isIn(filter))
|
||||
}
|
||||
if (AllItems.PACKAGE_FILTER.isIn(filter)) {
|
||||
trimFilterTag(filter);
|
||||
return new PackageFilterItemStack(filter);
|
||||
}
|
||||
}
|
||||
|
||||
return new FilterItemStack(filter);
|
||||
|
@ -48,6 +51,12 @@ public class FilterItemStack {
|
|||
return of(ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
private static void trimFilterTag(ItemStack filter) {
|
||||
CompoundTag stackTag = filter.getTag();
|
||||
stackTag.remove("Enchantments");
|
||||
stackTag.remove("AttributeModifiers");
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return filterItemStack.isEmpty();
|
||||
}
|
||||
|
@ -138,10 +147,10 @@ public class FilterItemStack {
|
|||
|
||||
shouldRespectNBT = defaults ? false
|
||||
: filter.getTag()
|
||||
.getBoolean("RespectNBT");
|
||||
.getBoolean("RespectNBT");
|
||||
isBlacklist = defaults ? false
|
||||
: filter.getTag()
|
||||
.getBoolean("Blacklist");
|
||||
.getBoolean("Blacklist");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -180,11 +189,11 @@ public class FilterItemStack {
|
|||
attributeTests = new ArrayList<>();
|
||||
whitelistMode = WhitelistMode.values()[defaults ? 0
|
||||
: filter.getTag()
|
||||
.getInt("WhitelistMode")];
|
||||
.getInt("WhitelistMode")];
|
||||
|
||||
ListTag attributes = defaults ? new ListTag()
|
||||
: filter.getTag()
|
||||
.getList("MatchedAttributes", Tag.TAG_COMPOUND);
|
||||
.getList("MatchedAttributes", Tag.TAG_COMPOUND);
|
||||
for (Tag inbt : attributes) {
|
||||
CompoundTag compound = (CompoundTag) inbt;
|
||||
ItemAttribute attribute = ItemAttribute.loadStatic(compound);
|
||||
|
@ -208,35 +217,35 @@ public class FilterItemStack {
|
|||
boolean matches = attribute.appliesTo(stack, world) != inverted;
|
||||
|
||||
if (matches) {
|
||||
switch (whitelistMode) {
|
||||
case BLACKLIST -> {
|
||||
return false;
|
||||
}
|
||||
case WHITELIST_CONJ -> {
|
||||
switch (whitelistMode) {
|
||||
case BLACKLIST -> {
|
||||
return false;
|
||||
}
|
||||
case WHITELIST_CONJ -> {
|
||||
continue;
|
||||
}
|
||||
case WHITELIST_DISJ -> {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
case WHITELIST_DISJ -> {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (whitelistMode) {
|
||||
case BLACKLIST, WHITELIST_DISJ -> {
|
||||
switch (whitelistMode) {
|
||||
case BLACKLIST, WHITELIST_DISJ -> {
|
||||
continue;
|
||||
}
|
||||
case WHITELIST_CONJ -> {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
case WHITELIST_CONJ -> {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return switch (whitelistMode) {
|
||||
case BLACKLIST, WHITELIST_CONJ -> true;
|
||||
case WHITELIST_DISJ -> false;
|
||||
};
|
||||
return switch (whitelistMode) {
|
||||
case BLACKLIST, WHITELIST_CONJ -> true;
|
||||
case WHITELIST_DISJ -> false;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -159,11 +159,7 @@ public class ItemVaultBlock extends Block implements IWrenchable, IBE<ItemVaultB
|
|||
|
||||
@Override
|
||||
public int getAnalogOutputSignal(BlockState pState, Level pLevel, BlockPos pPos) {
|
||||
return getBlockEntityOptional(pLevel, pPos)
|
||||
.map(vte -> vte.getCapability(ForgeCapabilities.ITEM_HANDLER))
|
||||
.map(lo -> lo.map(ItemHelper::calcRedstoneFromInventory)
|
||||
.orElse(0))
|
||||
.orElse(0);
|
||||
return ItemHelper.calcRedstoneFromBlockEntity(this, pLevel, pPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,10 +2,10 @@ package com.simibubi.create.content.processing.burner;
|
|||
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.AllSoundEvents;
|
||||
import com.simibubi.create.api.contraption.train.TrainConductorHandler;
|
||||
import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
|
||||
import com.simibubi.create.content.contraptions.Contraption;
|
||||
import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour;
|
||||
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel;
|
||||
import com.simibubi.create.content.trains.entity.CarriageContraption;
|
||||
import com.simibubi.create.content.trains.entity.CarriageContraptionEntity;
|
||||
import com.simibubi.create.content.trains.entity.Train;
|
||||
|
@ -21,9 +21,21 @@ import net.minecraft.core.Direction;
|
|||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
|
||||
|
||||
public class BlazeBurnerInteractionBehaviour extends MovingInteractionBehaviour {
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class BlockBasedTrainConductorInteractionBehaviour extends MovingInteractionBehaviour {
|
||||
|
||||
private final Predicate<BlockState> isValidConductor;
|
||||
private final TrainConductorHandler.UpdateScheduleCallback callback;
|
||||
|
||||
public BlockBasedTrainConductorInteractionBehaviour(Predicate<BlockState> isValidConductor, TrainConductorHandler.UpdateScheduleCallback callback) {
|
||||
this.isValidConductor = isValidConductor;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos,
|
||||
|
@ -40,8 +52,7 @@ public class BlazeBurnerInteractionBehaviour extends MovingInteractionBehaviour
|
|||
|
||||
StructureBlockInfo info = carriageContraption.getBlocks()
|
||||
.get(localPos);
|
||||
if (info == null || !info.state().hasProperty(BlazeBurnerBlock.HEAT_LEVEL)
|
||||
|| info.state().getValue(BlazeBurnerBlock.HEAT_LEVEL) == HeatLevel.NONE)
|
||||
if (info == null || !isValidConductor.test(info.state()))
|
||||
return false;
|
||||
|
||||
Direction assemblyDirection = carriageContraption.getAssemblyDirection();
|
||||
|
@ -74,6 +85,7 @@ public class BlazeBurnerInteractionBehaviour extends MovingInteractionBehaviour
|
|||
train.runtime.isAutoSchedule ? "schedule.auto_removed_from_train" : "schedule.removed_from_train"),
|
||||
true);
|
||||
player.setItemInHand(activeHand, train.runtime.returnSchedule());
|
||||
callback.update(false, info.state(), newBlockState -> setBlockState(localPos, contraptionEntity, newBlockState));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -89,7 +101,7 @@ public class BlazeBurnerInteractionBehaviour extends MovingInteractionBehaviour
|
|||
player.displayClientMessage(CreateLang.translateDirect("schedule.no_stops"), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
callback.update(true, info.state(), newBlockState -> setBlockState(localPos, contraptionEntity, newBlockState));
|
||||
train.runtime.setSchedule(schedule, false);
|
||||
AllAdvancements.CONDUCTOR.awardTo(player);
|
||||
AllSoundEvents.CONFIRM.playOnServer(player.level(), player.blockPosition(), 1, 1);
|
||||
|
@ -105,4 +117,10 @@ public class BlazeBurnerInteractionBehaviour extends MovingInteractionBehaviour
|
|||
return true;
|
||||
}
|
||||
|
||||
private void setBlockState(BlockPos localPos, AbstractContraptionEntity contraption, BlockState newState) {
|
||||
StructureTemplate.StructureBlockInfo info = contraption.getContraption().getBlocks().get(localPos);
|
||||
if (info != null) {
|
||||
setContraptionBlockData(contraption, localPos, new StructureTemplate.StructureBlockInfo(info.pos(), newState, info.nbt()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ package com.simibubi.create.content.redstone.link.controller;
|
|||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.AllSoundEvents;
|
||||
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
|
||||
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
|
||||
|
@ -28,7 +29,7 @@ import net.minecraftforge.fml.DistExecutor;
|
|||
|
||||
public class LecternControllerBlockEntity extends SmartBlockEntity {
|
||||
|
||||
private ItemStack controller = ItemStack.EMPTY;
|
||||
private CompoundTag controllerNbt = new CompoundTag();
|
||||
private UUID user;
|
||||
private UUID prevUser; // used only on client
|
||||
private boolean deactivatedThisTick; // used only on server
|
||||
|
@ -43,7 +44,7 @@ public class LecternControllerBlockEntity extends SmartBlockEntity {
|
|||
@Override
|
||||
protected void write(CompoundTag compound, boolean clientPacket) {
|
||||
super.write(compound, clientPacket);
|
||||
compound.put("Controller", controller.save(new CompoundTag()));
|
||||
compound.put("ControllerData", controllerNbt);
|
||||
if (user != null)
|
||||
compound.putUUID("User", user);
|
||||
}
|
||||
|
@ -51,18 +52,25 @@ public class LecternControllerBlockEntity extends SmartBlockEntity {
|
|||
@Override
|
||||
public void writeSafe(CompoundTag compound) {
|
||||
super.writeSafe(compound);
|
||||
compound.put("Controller", controller.save(new CompoundTag()));
|
||||
compound.put("ControllerData", controllerNbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void read(CompoundTag compound, boolean clientPacket) {
|
||||
super.read(compound, clientPacket);
|
||||
controller = ItemStack.of(compound.getCompound("Controller"));
|
||||
|
||||
// Migrate old data if that is found
|
||||
if (compound.contains("Controller")) {
|
||||
controllerNbt = ItemStack.of(compound.getCompound("Controller")).getTag();
|
||||
} else {
|
||||
controllerNbt = compound.getCompound("ControllerData");
|
||||
}
|
||||
|
||||
user = compound.hasUUID("User") ? compound.getUUID("User") : null;
|
||||
}
|
||||
|
||||
public ItemStack getController() {
|
||||
return controller;
|
||||
return getController();
|
||||
}
|
||||
|
||||
public boolean hasUser() { return user != null; }
|
||||
|
@ -138,8 +146,8 @@ public class LecternControllerBlockEntity extends SmartBlockEntity {
|
|||
}
|
||||
|
||||
public void setController(ItemStack newController) {
|
||||
controller = newController;
|
||||
if (newController != null) {
|
||||
controllerNbt = newController.getTag();
|
||||
AllSoundEvents.CONTROLLER_PUT.playOnServer(level, worldPosition);
|
||||
}
|
||||
}
|
||||
|
@ -148,7 +156,7 @@ public class LecternControllerBlockEntity extends SmartBlockEntity {
|
|||
ItemStack newController = stack.copy();
|
||||
stack.setCount(0);
|
||||
if (player.getItemInHand(hand).isEmpty()) {
|
||||
player.setItemInHand(hand, controller);
|
||||
player.setItemInHand(hand, createLinkedController());
|
||||
} else {
|
||||
dropController(state);
|
||||
}
|
||||
|
@ -164,10 +172,10 @@ public class LecternControllerBlockEntity extends SmartBlockEntity {
|
|||
double x = worldPosition.getX() + 0.5 + 0.25 * dir.getStepX();
|
||||
double y = worldPosition.getY() + 1;
|
||||
double z = worldPosition.getZ() + 0.5 + 0.25 * dir.getStepZ();
|
||||
ItemEntity itementity = new ItemEntity(level, x, y, z, controller.copy());
|
||||
ItemEntity itementity = new ItemEntity(level, x, y, z, createLinkedController());
|
||||
itementity.setDefaultPickUpDelay();
|
||||
level.addFreshEntity(itementity);
|
||||
controller = null;
|
||||
controllerNbt = new CompoundTag();
|
||||
}
|
||||
|
||||
public static boolean playerInRange(Player player, Level world, BlockPos pos) {
|
||||
|
@ -176,4 +184,10 @@ public class LecternControllerBlockEntity extends SmartBlockEntity {
|
|||
return player.distanceToSqr(Vec3.atCenterOf(pos)) < reach * reach;
|
||||
}
|
||||
|
||||
private ItemStack createLinkedController() {
|
||||
ItemStack stack = AllItems.LINKED_CONTROLLER.asStack();
|
||||
stack.setTag(controllerNbt);
|
||||
return stack;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ public class NixieTubeRenderer extends SafeBlockEntityRenderer<NixieTubeBlockEnt
|
|||
float charWidth = fontRenderer.width(c);
|
||||
float shadowOffset = .5f;
|
||||
float flicker = r.nextFloat();
|
||||
Couple<Integer> couple = DyeHelper.DYE_TABLE.get(color);
|
||||
Couple<Integer> couple = DyeHelper.getDyeColors(color);
|
||||
int brightColor = couple.getFirst();
|
||||
int darkColor = couple.getSecond();
|
||||
int flickeringBrightColor = Color.mixColors(brightColor, darkColor, flicker / 4);
|
||||
|
|
|
@ -323,7 +323,7 @@ public class FlapDisplayBlockEntity extends KineticBlockEntity {
|
|||
public int getLineColor(int line) {
|
||||
DyeColor color = colour[line];
|
||||
return color == null ? 0xFF_D3C6BA
|
||||
: DyeHelper.DYE_TABLE.get(color)
|
||||
: DyeHelper.getDyeColors(color)
|
||||
.getFirst() | 0xFF_000000;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.simibubi.create.api.contraption.train.TrainConductorHandler;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
|
@ -16,8 +18,6 @@ import com.simibubi.create.content.contraptions.ContraptionType;
|
|||
import com.simibubi.create.content.contraptions.MountedStorageManager;
|
||||
import com.simibubi.create.content.contraptions.actors.trainControls.ControlsBlock;
|
||||
import com.simibubi.create.content.contraptions.minecart.TrainCargoManager;
|
||||
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock;
|
||||
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel;
|
||||
import com.simibubi.create.content.trains.bogey.AbstractBogeyBlock;
|
||||
import com.simibubi.create.foundation.utility.CreateLang;
|
||||
|
||||
|
@ -45,7 +45,7 @@ public class CarriageContraption extends Contraption {
|
|||
private boolean forwardControls;
|
||||
private boolean backwardControls;
|
||||
|
||||
public Couple<Boolean> blazeBurnerConductors;
|
||||
public Couple<Boolean> blockConductors;
|
||||
public Map<BlockPos, Couple<Boolean>> conductorSeats;
|
||||
public ArrivalSoundQueue soundQueue;
|
||||
|
||||
|
@ -55,7 +55,7 @@ public class CarriageContraption extends Contraption {
|
|||
private int bogeys;
|
||||
private boolean sidewaysControls;
|
||||
private BlockPos secondBogeyPos;
|
||||
private List<BlockPos> assembledBlazeBurners;
|
||||
private List<BlockPos> assembledBlockConductors;
|
||||
|
||||
// render
|
||||
public int portalCutoffMin;
|
||||
|
@ -70,8 +70,8 @@ public class CarriageContraption extends Contraption {
|
|||
|
||||
public CarriageContraption() {
|
||||
conductorSeats = new HashMap<>();
|
||||
assembledBlazeBurners = new ArrayList<>();
|
||||
blazeBurnerConductors = Couple.create(false, false);
|
||||
assembledBlockConductors = new ArrayList<>();
|
||||
blockConductors = Couple.create(false, false);
|
||||
soundQueue = new ArrivalSoundQueue();
|
||||
portalCutoffMin = Integer.MIN_VALUE;
|
||||
portalCutoffMax = Integer.MAX_VALUE;
|
||||
|
@ -101,10 +101,10 @@ public class CarriageContraption extends Contraption {
|
|||
if (sidewaysControls)
|
||||
throw new AssemblyException(CreateLang.translateDirect("train_assembly.sideways_controls"));
|
||||
|
||||
for (BlockPos blazePos : assembledBlazeBurners)
|
||||
for (BlockPos blazePos : assembledBlockConductors)
|
||||
for (Direction direction : Iterate.directionsInAxis(assemblyDirection.getAxis()))
|
||||
if (inControl(blazePos, direction))
|
||||
blazeBurnerConductors.set(direction != assemblyDirection, true);
|
||||
blockConductors.set(direction != assemblyDirection, true);
|
||||
for (BlockPos seatPos : getSeats())
|
||||
for (Direction direction : Iterate.directionsInAxis(assemblyDirection.getAxis()))
|
||||
if (inControl(seatPos, direction))
|
||||
|
@ -165,9 +165,8 @@ public class CarriageContraption extends Contraption {
|
|||
captureBE ? world.getBlockEntity(pos) : null);
|
||||
}
|
||||
|
||||
if (AllBlocks.BLAZE_BURNER.has(blockState)
|
||||
&& blockState.getValue(BlazeBurnerBlock.HEAT_LEVEL) != HeatLevel.NONE)
|
||||
assembledBlazeBurners.add(toLocalPos(pos));
|
||||
if (TrainConductorHandler.CONDUCTOR_HANDLERS.stream().anyMatch(handler -> handler.isValidConductor(blockState)))
|
||||
assembledBlockConductors.add(toLocalPos(pos));
|
||||
|
||||
if (AllBlocks.TRAIN_CONTROLS.has(blockState)) {
|
||||
Direction facing = blockState.getValue(ControlsBlock.FACING);
|
||||
|
@ -191,8 +190,8 @@ public class CarriageContraption extends Contraption {
|
|||
NBTHelper.writeEnum(tag, "AssemblyDirection", getAssemblyDirection());
|
||||
tag.putBoolean("FrontControls", forwardControls);
|
||||
tag.putBoolean("BackControls", backwardControls);
|
||||
tag.putBoolean("FrontBlazeConductor", blazeBurnerConductors.getFirst());
|
||||
tag.putBoolean("BackBlazeConductor", blazeBurnerConductors.getSecond());
|
||||
tag.putBoolean("FrontBlazeConductor", blockConductors.getFirst());
|
||||
tag.putBoolean("BackBlazeConductor", blockConductors.getSecond());
|
||||
ListTag list = NBTHelper.writeCompoundList(conductorSeats.entrySet(), e -> {
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
compoundTag.put("Pos", NbtUtils.writeBlockPos(e.getKey()));
|
||||
|
@ -212,7 +211,7 @@ public class CarriageContraption extends Contraption {
|
|||
assemblyDirection = NBTHelper.readEnum(nbt, "AssemblyDirection", Direction.class);
|
||||
forwardControls = nbt.getBoolean("FrontControls");
|
||||
backwardControls = nbt.getBoolean("BackControls");
|
||||
blazeBurnerConductors =
|
||||
blockConductors =
|
||||
Couple.create(nbt.getBoolean("FrontBlazeConductor"), nbt.getBoolean("BackBlazeConductor"));
|
||||
conductorSeats.clear();
|
||||
NBTHelper.iterateCompoundList(nbt.getList("ConductorSeats", Tag.TAG_COMPOUND),
|
||||
|
|
|
@ -492,8 +492,8 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
if (!(contraption instanceof CarriageContraption cc))
|
||||
return sides;
|
||||
|
||||
sides.setFirst(cc.blazeBurnerConductors.getFirst());
|
||||
sides.setSecond(cc.blazeBurnerConductors.getSecond());
|
||||
sides.setFirst(cc.blockConductors.getFirst());
|
||||
sides.setSecond(cc.blockConductors.getSecond());
|
||||
|
||||
for (Entity entity : getPassengers()) {
|
||||
if (entity instanceof Player)
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
package com.simibubi.create.content.trains.track;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.compat.Mods;
|
||||
import com.simibubi.create.compat.betterend.BetterEndPortalCompat;
|
||||
import com.simibubi.create.content.contraptions.glue.SuperGlueEntity;
|
||||
import com.simibubi.create.foundation.utility.AttachedRegistry;
|
||||
|
||||
|
@ -26,30 +29,66 @@ import net.minecraft.world.phys.AABB;
|
|||
import net.minecraftforge.common.util.ITeleporter;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
/**
|
||||
* Manages portal track integrations for various dimensions and mods within the Create mod.
|
||||
* <p>
|
||||
* Portals must be entered from the side and must lead to a different dimension than the one entered from.
|
||||
* This class handles the registration and functionality of portal tracks for standard and modded portals.
|
||||
* </p>
|
||||
*/
|
||||
public class AllPortalTracks {
|
||||
|
||||
// Portals must be entered from the side and must lead to a different dimension
|
||||
// than the one entered from
|
||||
|
||||
/**
|
||||
* Functional interface representing a provider for portal track connections.
|
||||
* It takes a pair of {@link ServerLevel} and {@link BlockFace} representing the inbound track
|
||||
* and returns a similar pair for the outbound track.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface PortalTrackProvider extends UnaryOperator<Pair<ServerLevel, BlockFace>> {
|
||||
};
|
||||
public interface PortalTrackProvider extends UnaryOperator<Pair<ServerLevel, BlockFace>> {}
|
||||
|
||||
/**
|
||||
* Registry mapping portal blocks to their respective {@link PortalTrackProvider}s.
|
||||
*/
|
||||
private static final AttachedRegistry<Block, PortalTrackProvider> PORTAL_BEHAVIOURS =
|
||||
new AttachedRegistry<>(ForgeRegistries.BLOCKS);
|
||||
new AttachedRegistry<>(ForgeRegistries.BLOCKS);
|
||||
|
||||
/**
|
||||
* Registers a portal track integration for a given block identified by its {@link ResourceLocation}.
|
||||
*
|
||||
* @param block The resource location of the portal block.
|
||||
* @param provider The portal track provider for the block.
|
||||
*/
|
||||
public static void registerIntegration(ResourceLocation block, PortalTrackProvider provider) {
|
||||
PORTAL_BEHAVIOURS.register(block, provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a portal track integration for a given {@link Block}.
|
||||
*
|
||||
* @param block The portal block.
|
||||
* @param provider The portal track provider for the block.
|
||||
*/
|
||||
public static void registerIntegration(Block block, PortalTrackProvider provider) {
|
||||
PORTAL_BEHAVIOURS.register(block, provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given {@link BlockState} represents a supported portal block.
|
||||
*
|
||||
* @param state The block state to check.
|
||||
* @return {@code true} if the block state represents a supported portal; {@code false} otherwise.
|
||||
*/
|
||||
public static boolean isSupportedPortal(BlockState state) {
|
||||
return PORTAL_BEHAVIOURS.get(state.getBlock()) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the corresponding outbound track on the other side of a portal.
|
||||
*
|
||||
* @param level The current {@link ServerLevel}.
|
||||
* @param inboundTrack The inbound track {@link BlockFace}.
|
||||
* @return A pair containing the target {@link ServerLevel} and outbound {@link BlockFace},
|
||||
* or {@code null} if no corresponding portal is found.
|
||||
*/
|
||||
public static Pair<ServerLevel, BlockFace> getOtherSide(ServerLevel level, BlockFace inboundTrack) {
|
||||
BlockPos portalPos = inboundTrack.getConnectedPos();
|
||||
BlockState portalState = level.getBlockState(portalPos);
|
||||
|
@ -57,61 +96,132 @@ public class AllPortalTracks {
|
|||
return provider == null ? null : provider.apply(Pair.of(level, inboundTrack));
|
||||
}
|
||||
|
||||
// Builtin handlers
|
||||
// Built-in handlers
|
||||
|
||||
/**
|
||||
* Registers default portal track integrations for built-in dimensions and mods.
|
||||
* This includes the Nether and the Aether (if loaded).
|
||||
*/
|
||||
public static void registerDefaults() {
|
||||
registerIntegration(Blocks.NETHER_PORTAL, AllPortalTracks::nether);
|
||||
if (Mods.AETHER.isLoaded())
|
||||
registerIntegration(new ResourceLocation("aether", "aether_portal"), AllPortalTracks::aether);
|
||||
registerIntegration(Mods.AETHER.rl("aether_portal"), AllPortalTracks::aether);
|
||||
if (Mods.BETTEREND.isLoaded())
|
||||
registerIntegration(Mods.BETTEREND.rl("end_portal_block"), AllPortalTracks::betterend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Portal track provider for the Nether portal.
|
||||
*
|
||||
* @param inbound A pair containing the current {@link ServerLevel} and inbound {@link BlockFace}.
|
||||
* @return A pair with the target {@link ServerLevel} and outbound {@link BlockFace}, or {@code null} if not applicable.
|
||||
*/
|
||||
private static Pair<ServerLevel, BlockFace> nether(Pair<ServerLevel, BlockFace> inbound) {
|
||||
ServerLevel level = inbound.getFirst();
|
||||
MinecraftServer minecraftServer = level.getServer();
|
||||
|
||||
if (!minecraftServer.isNetherEnabled())
|
||||
return null;
|
||||
|
||||
return standardPortalProvider(inbound, Level.OVERWORLD, Level.NETHER, ServerLevel::getPortalForcer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Portal track provider for the Aether mod's portal.
|
||||
*
|
||||
* @param inbound A pair containing the current {@link ServerLevel} and inbound {@link BlockFace}.
|
||||
* @return A pair with the target {@link ServerLevel} and outbound {@link BlockFace}, or {@code null} if not applicable.
|
||||
*/
|
||||
private static Pair<ServerLevel, BlockFace> aether(Pair<ServerLevel, BlockFace> inbound) {
|
||||
ResourceKey<Level> aetherLevelKey =
|
||||
ResourceKey.create(Registries.DIMENSION, new ResourceLocation("aether", "the_aether"));
|
||||
ResourceKey.create(Registries.DIMENSION, Mods.AETHER.rl("the_aether"));
|
||||
return standardPortalProvider(inbound, Level.OVERWORLD, aetherLevelKey, level -> {
|
||||
try {
|
||||
return (ITeleporter) Class.forName("com.aetherteam.aether.block.portal.AetherPortalForcer")
|
||||
.getDeclaredConstructor(ServerLevel.class, boolean.class)
|
||||
.newInstance(level, true);
|
||||
.getDeclaredConstructor(ServerLevel.class, boolean.class)
|
||||
.newInstance(level, true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Create.LOGGER.error("Failed to create Aether teleporter: ", e);
|
||||
}
|
||||
return level.getPortalForcer();
|
||||
});
|
||||
}
|
||||
|
||||
public static Pair<ServerLevel, BlockFace> standardPortalProvider(Pair<ServerLevel, BlockFace> inbound,
|
||||
ResourceKey<Level> firstDimension, ResourceKey<Level> secondDimension,
|
||||
Function<ServerLevel, ITeleporter> customPortalForcer) {
|
||||
ServerLevel level = inbound.getFirst();
|
||||
ResourceKey<Level> resourcekey = level.dimension() == secondDimension ? firstDimension : secondDimension;
|
||||
MinecraftServer minecraftserver = level.getServer();
|
||||
ServerLevel otherLevel = minecraftserver.getLevel(resourcekey);
|
||||
/**
|
||||
* Portal track provider for the Better End mod's portal.
|
||||
*
|
||||
* @param inbound A pair containing the current {@link ServerLevel} and inbound {@link BlockFace}.
|
||||
* @return A pair with the target {@link ServerLevel} and outbound {@link BlockFace}, or {@code null} if not applicable.
|
||||
*/
|
||||
private static Pair<ServerLevel, BlockFace> betterend(Pair<ServerLevel, BlockFace> inbound) {
|
||||
return portalProvider(inbound, Level.OVERWORLD, Level.END, BetterEndPortalCompat::getBetterEndPortalInfo);
|
||||
}
|
||||
|
||||
if (otherLevel == null || !minecraftserver.isNetherEnabled())
|
||||
/**
|
||||
* Provides a standard portal track provider that handles portal traversal between two dimensions.
|
||||
*
|
||||
* @param inbound A pair containing the current {@link ServerLevel} and inbound {@link BlockFace}.
|
||||
* @param firstDimension The first dimension (typically the Overworld).
|
||||
* @param secondDimension The second dimension (e.g., Nether, Aether).
|
||||
* @param customPortalForcer A function to obtain the {@link ITeleporter} for the target level.
|
||||
* @return A pair with the target {@link ServerLevel} and outbound {@link BlockFace}, or {@code null} if not applicable.
|
||||
*/
|
||||
public static Pair<ServerLevel, BlockFace> standardPortalProvider(
|
||||
Pair<ServerLevel, BlockFace> inbound,
|
||||
ResourceKey<Level> firstDimension,
|
||||
ResourceKey<Level> secondDimension,
|
||||
Function<ServerLevel, ITeleporter> customPortalForcer
|
||||
) {
|
||||
return portalProvider(
|
||||
inbound,
|
||||
firstDimension,
|
||||
secondDimension,
|
||||
(otherLevel, probe) -> {
|
||||
ITeleporter teleporter = customPortalForcer.apply(otherLevel);
|
||||
return teleporter.getPortalInfo(probe, otherLevel, probe::findDimensionEntryPoint);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generalized portal provider method that calculates the corresponding outbound track across a portal.
|
||||
*
|
||||
* @param inbound A pair containing the current {@link ServerLevel} and inbound {@link BlockFace}.
|
||||
* @param firstDimension The first dimension.
|
||||
* @param secondDimension The second dimension.
|
||||
* @param portalInfoProvider A function that provides the {@link PortalInfo} given the target level and probe entity.
|
||||
* @return A pair with the target {@link ServerLevel} and outbound {@link BlockFace}, or {@code null} if not applicable.
|
||||
*/
|
||||
public static Pair<ServerLevel, BlockFace> portalProvider(
|
||||
Pair<ServerLevel, BlockFace> inbound,
|
||||
ResourceKey<Level> firstDimension,
|
||||
ResourceKey<Level> secondDimension,
|
||||
BiFunction<ServerLevel, SuperGlueEntity, PortalInfo> portalInfoProvider
|
||||
) {
|
||||
ServerLevel level = inbound.getFirst();
|
||||
ResourceKey<Level> resourceKey = level.dimension() == secondDimension ? firstDimension : secondDimension;
|
||||
|
||||
MinecraftServer minecraftServer = level.getServer();
|
||||
ServerLevel otherLevel = minecraftServer.getLevel(resourceKey);
|
||||
|
||||
if (otherLevel == null)
|
||||
return null;
|
||||
|
||||
BlockFace inboundTrack = inbound.getSecond();
|
||||
BlockPos portalPos = inboundTrack.getConnectedPos();
|
||||
BlockState portalState = level.getBlockState(portalPos);
|
||||
ITeleporter teleporter = customPortalForcer.apply(otherLevel);
|
||||
|
||||
SuperGlueEntity probe = new SuperGlueEntity(level, new AABB(portalPos));
|
||||
probe.setYRot(inboundTrack.getFace()
|
||||
.toYRot());
|
||||
probe.setYRot(inboundTrack.getFace().toYRot());
|
||||
probe.setPortalEntrancePos();
|
||||
|
||||
PortalInfo portalinfo = teleporter.getPortalInfo(probe, otherLevel, probe::findDimensionEntryPoint);
|
||||
if (portalinfo == null)
|
||||
PortalInfo portalInfo = portalInfoProvider.apply(otherLevel, probe);
|
||||
if (portalInfo == null)
|
||||
return null;
|
||||
|
||||
BlockPos otherPortalPos = BlockPos.containing(portalinfo.pos);
|
||||
BlockPos otherPortalPos = BlockPos.containing(portalInfo.pos);
|
||||
BlockState otherPortalState = otherLevel.getBlockState(otherPortalPos);
|
||||
if (otherPortalState.getBlock() != portalState.getBlock())
|
||||
if (!otherPortalState.is(portalState.getBlock()))
|
||||
return null;
|
||||
|
||||
Direction targetDirection = inboundTrack.getFace();
|
||||
|
@ -120,5 +230,4 @@ public class AllPortalTracks {
|
|||
BlockPos otherPos = otherPortalPos.relative(targetDirection);
|
||||
return Pair.of(otherLevel, new BlockFace(otherPos, targetDirection.getOpposite()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ import java.util.Map;
|
|||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import net.minecraft.tags.ItemTags;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import com.simibubi.create.foundation.data.TagGen;
|
||||
|
@ -140,7 +142,13 @@ public class CopperBlockSet {
|
|||
.simpleItem();
|
||||
|
||||
if (variant == BlockVariant.INSTANCE && state == WeatherState.UNAFFECTED)
|
||||
builder.recipe((c, p) -> mainBlockRecipe.accept(c, p));
|
||||
builder.recipe(mainBlockRecipe::accept);
|
||||
|
||||
if (variant == StairVariant.INSTANCE)
|
||||
builder.tag(BlockTags.STAIRS);
|
||||
|
||||
if (variant == SlabVariant.INSTANCE)
|
||||
builder.tag(BlockTags.SLABS);
|
||||
|
||||
if (waxed) {
|
||||
builder.recipe((ctx, prov) -> {
|
||||
|
|
|
@ -184,29 +184,30 @@ public class CreateRegistrate extends AbstractRegistrate<CreateRegistrate> {
|
|||
/* Fluids */
|
||||
|
||||
public <T extends ForgeFlowingFluid> FluidBuilder<T, CreateRegistrate> virtualFluid(String name,
|
||||
FluidBuilder.FluidTypeFactory typeFactory, NonNullFunction<ForgeFlowingFluid.Properties, T> factory) {
|
||||
FluidBuilder.FluidTypeFactory typeFactory, NonNullFunction<ForgeFlowingFluid.Properties, T> sourceFactory,
|
||||
NonNullFunction<ForgeFlowingFluid.Properties, T> flowingFactory) {
|
||||
return entry(name,
|
||||
c -> new VirtualFluidBuilder<>(self(), self(), name, c, new ResourceLocation(getModid(), "fluid/" + name + "_still"),
|
||||
new ResourceLocation(getModid(), "fluid/" + name + "_flow"), typeFactory, factory));
|
||||
new ResourceLocation(getModid(), "fluid/" + name + "_flow"), typeFactory, sourceFactory, flowingFactory));
|
||||
}
|
||||
|
||||
public <T extends ForgeFlowingFluid> FluidBuilder<T, CreateRegistrate> virtualFluid(String name,
|
||||
ResourceLocation still, ResourceLocation flow, FluidBuilder.FluidTypeFactory typeFactory,
|
||||
NonNullFunction<ForgeFlowingFluid.Properties, T> factory) {
|
||||
return entry(name, c -> new VirtualFluidBuilder<>(self(), self(), name, c, still, flow, typeFactory, factory));
|
||||
NonNullFunction<ForgeFlowingFluid.Properties, T> sourceFactory, NonNullFunction<ForgeFlowingFluid.Properties, T> flowingFactory) {
|
||||
return entry(name, c -> new VirtualFluidBuilder<>(self(), self(), name, c, still, flow, typeFactory, sourceFactory, flowingFactory));
|
||||
}
|
||||
|
||||
public FluidBuilder<VirtualFluid, CreateRegistrate> virtualFluid(String name) {
|
||||
return entry(name,
|
||||
c -> new VirtualFluidBuilder<VirtualFluid, CreateRegistrate>(self(), self(), name, c,
|
||||
new ResourceLocation(getModid(), "fluid/" + name + "_still"), new ResourceLocation(getModid(), "fluid/" + name + "_flow"),
|
||||
CreateRegistrate::defaultFluidType, VirtualFluid::new));
|
||||
CreateRegistrate::defaultFluidType, VirtualFluid::createSource, VirtualFluid::createFlowing));
|
||||
}
|
||||
|
||||
public FluidBuilder<VirtualFluid, CreateRegistrate> virtualFluid(String name, ResourceLocation still,
|
||||
ResourceLocation flow) {
|
||||
return entry(name, c -> new VirtualFluidBuilder<>(self(), self(), name, c, still, flow,
|
||||
CreateRegistrate::defaultFluidType, VirtualFluid::new));
|
||||
CreateRegistrate::defaultFluidType, VirtualFluid::createSource, VirtualFluid::createFlowing));
|
||||
}
|
||||
|
||||
public FluidBuilder<ForgeFlowingFluid.Flowing, CreateRegistrate> standardFluid(String name) {
|
||||
|
|
|
@ -17,9 +17,11 @@ public class VirtualFluidBuilder<T extends ForgeFlowingFluid, P> extends FluidBu
|
|||
|
||||
public VirtualFluidBuilder(AbstractRegistrate<?> owner, P parent, String name, BuilderCallback callback,
|
||||
ResourceLocation stillTexture, ResourceLocation flowingTexture, FluidBuilder.FluidTypeFactory typeFactory,
|
||||
NonNullFunction<Properties, T> factory) {
|
||||
super(owner, parent, name, callback, stillTexture, flowingTexture, typeFactory, factory);
|
||||
source(factory);
|
||||
NonNullFunction<Properties, T> sourceFactory,
|
||||
NonNullFunction<Properties, T> flowingFactory
|
||||
) {
|
||||
super(owner, parent, name, callback, stillTexture, flowingTexture, typeFactory, flowingFactory);
|
||||
source(sourceFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -62,8 +62,7 @@ public class MillingRecipeGen extends ProcessingRecipeGen {
|
|||
|
||||
CACTUS = create(() -> Blocks.CACTUS, b -> b.duration(50)
|
||||
.output(Items.GREEN_DYE, 2)
|
||||
.output(.1f, Items.GREEN_DYE, 1)
|
||||
.whenModMissing("quark")),
|
||||
.output(.1f, Items.GREEN_DYE, 1)),
|
||||
|
||||
SEA_PICKLE = create(() -> Blocks.SEA_PICKLE, b -> b.duration(50)
|
||||
.output(Items.LIME_DYE, 2)
|
||||
|
|
|
@ -14,7 +14,7 @@ public class PressingRecipeGen extends ProcessingRecipeGen {
|
|||
|
||||
SUGAR_CANE = create(() -> Items.SUGAR_CANE, b -> b.output(Items.PAPER)),
|
||||
|
||||
PATH = create("path", b -> b.require(Ingredient.of(Items.GRASS_BLOCK, Items.DIRT))
|
||||
PATH = create("path", b -> b.require(Ingredient.of(Items.GRASS_BLOCK, Items.DIRT, Items.COARSE_DIRT, Items.ROOTED_DIRT))
|
||||
.output(Items.DIRT_PATH)),
|
||||
|
||||
IRON = create("iron_ingot", b -> b.require(I.iron())
|
||||
|
|
|
@ -7,6 +7,11 @@ import java.util.function.Predicate;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.simibubi.create.foundation.block.IBE;
|
||||
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
|
||||
import net.minecraftforge.items.IItemHandlerModifiable;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableInt;
|
||||
|
@ -78,6 +83,13 @@ public class ItemHelper {
|
|||
return true;
|
||||
}
|
||||
|
||||
public static <T extends IBE<? extends BlockEntity>> int calcRedstoneFromBlockEntity(T ibe, Level level, BlockPos pos) {
|
||||
return ibe.getBlockEntityOptional(level, pos)
|
||||
.map(be -> be.getCapability(ForgeCapabilities.ITEM_HANDLER))
|
||||
.map(lo -> lo.map(ItemHelper::calcRedstoneFromInventory).orElse(0))
|
||||
.orElse(0);
|
||||
}
|
||||
|
||||
public static int calcRedstoneFromInventory(@Nullable IItemHandler inv) {
|
||||
if (inv == null)
|
||||
return 0;
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
package com.simibubi.create.foundation.mixin;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.foundation.advancement.AllAdvancements;
|
||||
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.SmithingMenu;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.enchantment.Enchantment;
|
||||
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||
|
||||
@Mixin(SmithingMenu.class)
|
||||
public class SmithingMenuMixin {
|
||||
|
@ -23,4 +29,27 @@ public class SmithingMenuMixin {
|
|||
AllAdvancements.CARDBOARD_ARMOR_TRIM.awardTo(player);
|
||||
}
|
||||
}
|
||||
|
||||
// Only add enchantments to the backtank if it supports them
|
||||
@ModifyExpressionValue(
|
||||
method = "createResult",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/item/crafting/SmithingRecipe;assemble(Lnet/minecraft/world/Container;Lnet/minecraft/core/RegistryAccess;)Lnet/minecraft/world/item/ItemStack;"
|
||||
)
|
||||
)
|
||||
private ItemStack create$preventUnbreakingOnBacktanks(ItemStack original) {
|
||||
if (AllItems.COPPER_BACKTANK.is(original) || AllItems.NETHERITE_BACKTANK.is(original)) {
|
||||
Map<Enchantment, Integer> enchantments = new HashMap<>();
|
||||
|
||||
EnchantmentHelper.getEnchantments(original).forEach((enchantment, level) -> {
|
||||
if (enchantment.canEnchant(original))
|
||||
enchantments.put(enchantment, level);
|
||||
});
|
||||
|
||||
EnchantmentHelper.setEnchantments(enchantments, original);
|
||||
}
|
||||
|
||||
return original;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.simibubi.create.foundation.utility;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -49,6 +50,8 @@ import net.minecraft.world.level.block.SlimeBlock;
|
|||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||
import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import net.minecraft.world.level.block.state.properties.SlabType;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
|
@ -59,6 +62,24 @@ import net.minecraftforge.common.MinecraftForge;
|
|||
import net.minecraftforge.event.level.BlockEvent;
|
||||
|
||||
public class BlockHelper {
|
||||
private static final List<IntegerProperty> COUNT_STATES = List.of(
|
||||
BlockStateProperties.EGGS,
|
||||
BlockStateProperties.PICKLES,
|
||||
BlockStateProperties.CANDLES
|
||||
);
|
||||
|
||||
private static final List<Block> VINELIKE_BLOCKS = List.of(
|
||||
Blocks.VINE, Blocks.GLOW_LICHEN
|
||||
);
|
||||
|
||||
private static final List<BooleanProperty> VINELIKE_STATES = List.of(
|
||||
BlockStateProperties.UP,
|
||||
BlockStateProperties.NORTH,
|
||||
BlockStateProperties.EAST,
|
||||
BlockStateProperties.SOUTH,
|
||||
BlockStateProperties.WEST,
|
||||
BlockStateProperties.DOWN
|
||||
);
|
||||
|
||||
public static BlockState setZeroAge(BlockState blockState) {
|
||||
if (blockState.hasProperty(BlockStateProperties.AGE_1))
|
||||
|
@ -100,11 +121,21 @@ public class BlockHelper {
|
|||
if (needsTwo)
|
||||
amount *= 2;
|
||||
|
||||
if (block.hasProperty(BlockStateProperties.EGGS))
|
||||
amount *= block.getValue(BlockStateProperties.EGGS);
|
||||
for (IntegerProperty property : COUNT_STATES)
|
||||
if (block.hasProperty(property))
|
||||
amount *= block.getValue(property);
|
||||
|
||||
if (block.hasProperty(BlockStateProperties.PICKLES))
|
||||
amount *= block.getValue(BlockStateProperties.PICKLES);
|
||||
if (VINELIKE_BLOCKS.contains(block.getBlock())) {
|
||||
int vineCount = 0;
|
||||
|
||||
for (BooleanProperty vineState : VINELIKE_STATES) {
|
||||
if (block.hasProperty(vineState) && block.getValue(vineState)) {
|
||||
vineCount++;
|
||||
}
|
||||
}
|
||||
|
||||
amount += vineCount - 1;
|
||||
}
|
||||
|
||||
{
|
||||
// Try held Item first
|
||||
|
@ -259,8 +290,7 @@ public class BlockHelper {
|
|||
safeNbtBE.writeSafe(data);
|
||||
} else if (Mods.FRAMEDBLOCKS.contains(blockState.getBlock())) {
|
||||
data = FramedBlocksInSchematics.prepareBlockEntityData(blockState, blockEntity);
|
||||
}
|
||||
|
||||
}
|
||||
return NBTProcessors.process(blockState, blockEntity, data, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package com.simibubi.create.foundation.utility;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import net.createmod.catnip.data.Couple;
|
||||
import net.minecraft.world.item.DyeColor;
|
||||
|
@ -12,66 +12,52 @@ import net.minecraft.world.level.block.Blocks;
|
|||
public class DyeHelper {
|
||||
|
||||
public static ItemLike getWoolOfDye(DyeColor color) {
|
||||
switch (color) {
|
||||
case BLACK:
|
||||
return Blocks.BLACK_WOOL;
|
||||
case BLUE:
|
||||
return Blocks.BLUE_WOOL;
|
||||
case BROWN:
|
||||
return Blocks.BROWN_WOOL;
|
||||
case CYAN:
|
||||
return Blocks.CYAN_WOOL;
|
||||
case GRAY:
|
||||
return Blocks.GRAY_WOOL;
|
||||
case GREEN:
|
||||
return Blocks.GREEN_WOOL;
|
||||
case LIGHT_BLUE:
|
||||
return Blocks.LIGHT_BLUE_WOOL;
|
||||
case LIGHT_GRAY:
|
||||
return Blocks.LIGHT_GRAY_WOOL;
|
||||
case LIME:
|
||||
return Blocks.LIME_WOOL;
|
||||
case MAGENTA:
|
||||
return Blocks.MAGENTA_WOOL;
|
||||
case ORANGE:
|
||||
return Blocks.ORANGE_WOOL;
|
||||
case PINK:
|
||||
return Blocks.PINK_WOOL;
|
||||
case PURPLE:
|
||||
return Blocks.PURPLE_WOOL;
|
||||
case RED:
|
||||
return Blocks.RED_WOOL;
|
||||
case YELLOW:
|
||||
return Blocks.YELLOW_WOOL;
|
||||
case WHITE:
|
||||
default:
|
||||
return Blocks.WHITE_WOOL;
|
||||
}
|
||||
return WOOL_TABLE.getOrDefault(color, () -> Blocks.WHITE_WOOL).get();
|
||||
}
|
||||
|
||||
public static final Map<DyeColor, Couple<Integer>> DYE_TABLE = new ImmutableMap.Builder<DyeColor, Couple<Integer>>()
|
||||
public static Couple<Integer> getDyeColors(DyeColor color){
|
||||
return DYE_TABLE.getOrDefault(color, DYE_TABLE.get(DyeColor.WHITE));
|
||||
}
|
||||
|
||||
// DyeColor, ( Front RGB, Back RGB )
|
||||
.put(DyeColor.BLACK, Couple.create(0x45403B, 0x21201F))
|
||||
.put(DyeColor.RED, Couple.create(0xB13937, 0x632737))
|
||||
.put(DyeColor.GREEN, Couple.create(0x208A46, 0x1D6045))
|
||||
.put(DyeColor.BROWN, Couple.create(0xAC855C, 0x68533E))
|
||||
/**
|
||||
* Adds a dye color s.t. Create's blocks can use it instead of defaulting to white.
|
||||
* @param color Dye color to add
|
||||
* @param brightColor Front (bright) RGB color
|
||||
* @param darkColor Back (dark) RGB color
|
||||
* @param wool Supplier of wool item/block corresponding to the color
|
||||
*/
|
||||
public static void addDye(DyeColor color, Integer brightColor, Integer darkColor, Supplier<ItemLike> wool){
|
||||
DYE_TABLE.put(color, Couple.create(brightColor, darkColor));
|
||||
WOOL_TABLE.put(color, wool);
|
||||
}
|
||||
|
||||
.put(DyeColor.BLUE, Couple.create(0x5391E1, 0x504B90))
|
||||
.put(DyeColor.GRAY, Couple.create(0x5D666F, 0x313538))
|
||||
.put(DyeColor.LIGHT_GRAY, Couple.create(0x95969B, 0x707070))
|
||||
.put(DyeColor.PURPLE, Couple.create(0x9F54AE, 0x63366C))
|
||||
private static void addDye(DyeColor color, Integer brightColor, Integer darkColor, ItemLike wool){
|
||||
addDye(color, brightColor, darkColor, () -> wool);
|
||||
}
|
||||
|
||||
.put(DyeColor.CYAN, Couple.create(0x3EABB4, 0x3C7872))
|
||||
.put(DyeColor.PINK, Couple.create(0xD5A8CB, 0xB86B95))
|
||||
.put(DyeColor.LIME, Couple.create(0xA3DF55, 0x4FB16F))
|
||||
.put(DyeColor.YELLOW, Couple.create(0xE6D756, 0xE9AC29))
|
||||
private static final Map<DyeColor, Supplier<ItemLike>> WOOL_TABLE = new HashMap<>();
|
||||
|
||||
.put(DyeColor.LIGHT_BLUE, Couple.create(0x69CED2, 0x508AA5))
|
||||
.put(DyeColor.ORANGE, Couple.create(0xEE9246, 0xD94927))
|
||||
.put(DyeColor.MAGENTA, Couple.create(0xF062B0, 0xC04488))
|
||||
.put(DyeColor.WHITE, Couple.create(0xEDEAE5, 0xBBB6B0))
|
||||
private static final Map<DyeColor, Couple<Integer>> DYE_TABLE = new HashMap<>();
|
||||
static {
|
||||
// DyeColor, ( Front RGB, Back RGB )
|
||||
addDye(DyeColor.BLACK, 0x45403B, 0x21201F, Blocks.BLACK_WOOL);
|
||||
addDye(DyeColor.RED, 0xB13937, 0x632737, Blocks.RED_WOOL);
|
||||
addDye(DyeColor.GREEN, 0x208A46, 0x1D6045, Blocks.GREEN_WOOL);
|
||||
addDye(DyeColor.BROWN, 0xAC855C, 0x68533E, Blocks.BROWN_WOOL);
|
||||
|
||||
.build();
|
||||
addDye(DyeColor.BLUE, 0x5391E1, 0x504B90, Blocks.BLUE_WOOL);
|
||||
addDye(DyeColor.GRAY, 0x5D666F, 0x313538, Blocks.GRAY_WOOL);
|
||||
addDye(DyeColor.LIGHT_GRAY, 0x95969B, 0x707070, Blocks.LIGHT_GRAY_WOOL);
|
||||
addDye(DyeColor.PURPLE, 0x9F54AE, 0x63366C, Blocks.PURPLE_WOOL);
|
||||
|
||||
addDye(DyeColor.CYAN, 0x3EABB4, 0x3C7872, Blocks.CYAN_WOOL);
|
||||
addDye(DyeColor.PINK, 0xD5A8CB, 0xB86B95, Blocks.PINK_WOOL);
|
||||
addDye(DyeColor.LIME, 0xA3DF55, 0x4FB16F, Blocks.LIME_WOOL);
|
||||
addDye(DyeColor.YELLOW, 0xE6D756, 0xE9AC29, Blocks.YELLOW_WOOL);
|
||||
|
||||
addDye(DyeColor.LIGHT_BLUE, 0x69CED2, 0x508AA5, Blocks.LIGHT_BLUE_WOOL);
|
||||
addDye(DyeColor.ORANGE, 0xEE9246, 0xD94927, Blocks.ORANGE_WOOL);
|
||||
addDye(DyeColor.MAGENTA, 0xF062B0, 0xC04488, Blocks.MAGENTA_WOOL);
|
||||
addDye(DyeColor.WHITE, 0xEDEAE5, 0xBBB6B0, Blocks.WHITE_WOOL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,6 +124,9 @@ public class CreateRegistrateTags {
|
|||
prov.tag(AllBlockTags.ROOTS.tag)
|
||||
.add(Blocks.MANGROVE_ROOTS);
|
||||
|
||||
prov.tag(AllBlockTags.SUGAR_CANE_VARIANTS.tag)
|
||||
.add(Blocks.SUGAR_CANE);
|
||||
|
||||
prov.tag(AllBlockTags.CORALS.tag)
|
||||
.add(Blocks.DEAD_TUBE_CORAL, Blocks.DEAD_BRAIN_CORAL, Blocks.DEAD_BUBBLE_CORAL, Blocks.DEAD_FIRE_CORAL,
|
||||
Blocks.DEAD_HORN_CORAL, Blocks.TUBE_CORAL, Blocks.BRAIN_CORAL, Blocks.BUBBLE_CORAL,
|
||||
|
|
|
@ -84,7 +84,7 @@ public class ServerDebugInfoPacket extends SimplePacketBase {
|
|||
String text = output.toString();
|
||||
Minecraft.getInstance().keyboardHandler.setClipboard(text);
|
||||
Create.lang().translate("command.debuginfo.saved_to_clipboard")
|
||||
.color(DyeHelper.DYE_TABLE.get(DyeColor.LIME)
|
||||
.color(DyeHelper.getDyeColors(DyeColor.LIME)
|
||||
.getFirst())
|
||||
.sendChat(player);
|
||||
}
|
||||
|
|
|
@ -43,3 +43,10 @@ ${mod_description}
|
|||
versionRange="[0.8,)"
|
||||
ordering="AFTER"
|
||||
side="BOTH"
|
||||
|
||||
[[dependencies.create]]
|
||||
modId="jei"
|
||||
mandatory=false
|
||||
versionRange="[15.19.0,)"
|
||||
ordering="NONE"
|
||||
side="CLIENT"
|
||||
|
|
Loading…
Add table
Reference in a new issue