This commit is contained in:
DrMangoTea
2025-01-12 22:23:29 +01:00
commit ff51803fd1
5412 changed files with 249348 additions and 0 deletions

View File

@@ -0,0 +1,113 @@
package com.drmangotea.tfmg;
import com.drmangotea.tfmg.base.TFMGContraptions;
import com.drmangotea.tfmg.base.TFMGCreativeTabs;
import com.drmangotea.tfmg.base.TFMGRegistrate;
import com.drmangotea.tfmg.content.electricity.base.ElectricNetworkManager;
import com.drmangotea.tfmg.content.items.weapons.explosives.thermite_grenades.fire.TFMGColoredFires;
import com.drmangotea.tfmg.datagen.TFMGDatagen;
import com.drmangotea.tfmg.base.fluid.TFMGFluidInteractions;
import com.drmangotea.tfmg.config.TFMGConfigs;
import com.drmangotea.tfmg.content.decoration.pipes.TFMGPipes;
import com.drmangotea.tfmg.registry.*;
import com.mojang.logging.LogUtils;
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock;
import net.minecraft.client.renderer.ItemBlockRenderTypes;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.slf4j.Logger;
import static com.simibubi.create.content.fluids.tank.BoilerHeaters.registerHeater;
@SuppressWarnings("removal")
@Mod(TFMG.MOD_ID)
public class TFMG {
public static final String MOD_ID = "tfmg";
public static final ElectricNetworkManager NETWORK_MANAGER = new ElectricNetworkManager();
public static final Logger LOGGER = LogUtils.getLogger();
public static final TFMGRegistrate REGISTRATE = TFMGRegistrate.create();
public TFMG() {
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
REGISTRATE.registerEventListeners(modEventBus);
TFMGBlocks.init();
TFMGBlockEntities.init();
TFMGItems.init();
TFMGEntityTypes.init();
TFMGPartialModels.init();
TFMGPipes.init();
TFMGFluids.init();
TFMGEncasedBlocks.init();
TFMGPaletteBlocks.init();
TFMGParticleTypes.register(modEventBus);
TFMGCreativeTabs.register(modEventBus);
TFMGMobEffects.register(modEventBus);
TFMGRecipeTypes.register(modEventBus);
TFMGColoredFires.register(modEventBus);
TFMGContraptions.prepare();
TFMGPackets.registerPackets();
TFMGConfigs.register(ModLoadingContext.get());
modEventBus.addListener(EventPriority.LOWEST, TFMGDatagen::gatherData);
modEventBus.addListener(TFMG::commonSetup);
modEventBus.addListener(this::clientSetup);
MinecraftForge.EVENT_BUS.register(this);
DistExecutor.safeRunWhenOn(Dist.CLIENT, () -> TFMGClient::new);
modEventBus.addListener(TFMGCreativeTabs::addCreative);
}
@SuppressWarnings("removal")
private void clientSetup(final FMLClientSetupEvent event) {
ItemBlockRenderTypes.setRenderLayer(TFMGColoredFires.GREEN_FIRE.get(), RenderType.cutout());
ItemBlockRenderTypes.setRenderLayer(TFMGColoredFires.BLUE_FIRE.get(), RenderType.cutout());
}
/**
* fluid interaction & firebox heating
*/
public static void commonSetup(final FMLCommonSetupEvent event) {
TFMGFluidInteractions.registerFluidInteractions();
event.enqueueWork(() -> {
registerHeater(TFMGBlocks.FIREBOX.get(), (level, pos, state) -> {
BlazeBurnerBlock.HeatLevel value = state.getValue(BlazeBurnerBlock.HEAT_LEVEL);
if (value == BlazeBurnerBlock.HeatLevel.NONE) {
return -1;
}
if (value.isAtLeast(BlazeBurnerBlock.HeatLevel.FADING)) {
return 1;
}
return -1;
});
});
}
public static ResourceLocation asResource(String path) {
return new ResourceLocation(MOD_ID, path);
}
}

View File

@@ -0,0 +1,42 @@
package com.drmangotea.tfmg;
import com.drmangotea.tfmg.content.items.weapons.advanced_potato_cannon.AdvancedPotatoCannonRenderHandler;
import com.drmangotea.tfmg.content.items.weapons.flamethrover.FlamethrowerRenderHandler;
import com.drmangotea.tfmg.content.items.weapons.quad_potato_cannon.QuadPotatoCannonRenderHandler;
import com.drmangotea.tfmg.registry.TFMGParticleTypes;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
public class TFMGClient {
/**
* does not work, too bad!
*/
public static final QuadPotatoCannonRenderHandler QUAD_POTATO_CANNON_RENDER_HANDLER = new QuadPotatoCannonRenderHandler();
public static final AdvancedPotatoCannonRenderHandler ADVANCED_POTATO_CANNON_RENDER_HANDLER = new AdvancedPotatoCannonRenderHandler();
public static final FlamethrowerRenderHandler FLAMETHROWER_RENDER_HANDLER = new FlamethrowerRenderHandler();
public TFMGClient() {
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
IEventBus forgeEventBus = MinecraftForge.EVENT_BUS;
modEventBus.addListener(TFMGParticleTypes::registerFactories);
modEventBus.register(this);
ADVANCED_POTATO_CANNON_RENDER_HANDLER.registerListeners(forgeEventBus);
QUAD_POTATO_CANNON_RENDER_HANDLER.registerListeners(forgeEventBus);
FLAMETHROWER_RENDER_HANDLER.registerListeners(forgeEventBus);
}
@SubscribeEvent
public void setup(final FMLClientSetupEvent event) {
// TFMGPonderIndex.register();
// TFMGPonderIndex.registerTags();
}
}

View File

@@ -0,0 +1,24 @@
package com.drmangotea.tfmg.base;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock;
import com.simibubi.create.content.kinetics.base.KineticBlockEntity;
import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer;
import com.simibubi.create.foundation.render.CachedBufferer;
import com.simibubi.create.foundation.render.SuperByteBuffer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.world.level.block.state.BlockState;
public class HalfShaftRenderer<T extends KineticBlockEntity> extends KineticBlockEntityRenderer<T> {
public HalfShaftRenderer(BlockEntityRendererProvider.Context context) {
super(context);
}
@Override
protected SuperByteBuffer getRotatedModel(T be, BlockState state) {
return CachedBufferer.partialFacing(AllPartialModels.SHAFT_HALF, state, state
.getValue(DirectionalKineticBlock.FACING));
}
}

View File

@@ -0,0 +1,21 @@
package com.drmangotea.tfmg.base;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectCategory;
import net.minecraft.world.entity.LivingEntity;
public class HellFireEffect extends MobEffect {
public HellFireEffect(MobEffectCategory pCategory, int pColor) {
super(pCategory, pColor);
}
@Override
public void applyEffectTick(LivingEntity pLivingEntity, int pAmplifier) {
pLivingEntity.setSecondsOnFire(1);
}
@Override
public boolean isDurationEffectTick(int pDuration, int pAmplifier) {
return true;
}
}

View File

@@ -0,0 +1,14 @@
package com.drmangotea.tfmg.base;
import com.tterrag.registrate.util.entry.BlockEntry;
public class MaterialSet {
public BlockEntry<?> block;
public BlockEntry<?> slab;
public BlockEntry<?> stairs;
public BlockEntry<?> wall;
public MaterialSet(){}
}

View File

@@ -0,0 +1,87 @@
package com.drmangotea.tfmg.base;
import com.drmangotea.tfmg.TFMG;
import com.drmangotea.tfmg.registry.TFMGItems;
import com.google.common.base.Suppliers;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.item.ArmorItem;
import net.minecraft.world.item.ArmorMaterial;
import net.minecraft.world.item.crafting.Ingredient;
import java.util.function.Supplier;
public enum TFMGArmorMaterials implements ArmorMaterial {
STEEL(TFMG.asResource("steel").toString(), 30, new int[]{3, 6, 8, 3}, 18, () -> SoundEvents.ARMOR_EQUIP_NETHERITE, 2.0F, 0.1F,
() -> Ingredient.of(TFMGItems.STEEL_INGOT.get()))
;
private static final int[] MAX_DAMAGE_ARRAY = new int[] { 13, 15, 16, 11 };
private final String name;
private final int maxDamageFactor;
private final int[] damageReductionAmountArray;
private final int enchantability;
private final Supplier<SoundEvent> soundEvent;
private final float toughness;
private final float knockbackResistance;
private final Supplier<Ingredient> repairMaterial;
private TFMGArmorMaterials(String name, int maxDamageFactor, int[] damageReductionAmountArray, int enchantability,
Supplier<SoundEvent> soundEvent, float toughness, float knockbackResistance, Supplier<Ingredient> repairMaterial) {
this.name = name;
this.maxDamageFactor = maxDamageFactor;
this.damageReductionAmountArray = damageReductionAmountArray;
this.enchantability = enchantability;
this.soundEvent = soundEvent;
this.toughness = toughness;
this.knockbackResistance = knockbackResistance;
this.repairMaterial = Suppliers.memoize(repairMaterial::get);
}
@Override
public int getDurabilityForType(ArmorItem.Type type) {
return switch (type){
case HELMET -> MAX_DAMAGE_ARRAY[3] * this.maxDamageFactor;
case CHESTPLATE -> MAX_DAMAGE_ARRAY[2] * this.maxDamageFactor;
case LEGGINGS -> MAX_DAMAGE_ARRAY[1] * this.maxDamageFactor;
case BOOTS -> MAX_DAMAGE_ARRAY[0] * this.maxDamageFactor;
};
}
@Override
public int getDefenseForType(ArmorItem.Type type) {
return switch (type){
case HELMET -> damageReductionAmountArray[3];
case CHESTPLATE -> damageReductionAmountArray[2];
case LEGGINGS -> damageReductionAmountArray[1];
case BOOTS -> damageReductionAmountArray[0];
};
}
@Override
public int getEnchantmentValue() {
return this.enchantability;
}
@Override
public SoundEvent getEquipSound() {
return this.soundEvent.get();
}
@Override
public Ingredient getRepairIngredient() {
return this.repairMaterial.get();
}
@Override
public String getName() {
return this.name;
}
@Override
public float getToughness() {
return this.toughness;
}
@Override
public float getKnockbackResistance() {
return this.knockbackResistance;
}
}

View File

@@ -0,0 +1,405 @@
package com.drmangotea.tfmg.base;
import com.drmangotea.tfmg.TFMG;
import com.drmangotea.tfmg.content.decoration.FrameBlock;
import com.drmangotea.tfmg.content.decoration.TrussBlock;
import com.drmangotea.tfmg.content.decoration.doors.TFMGSlidingDoorBlock;
import com.drmangotea.tfmg.content.decoration.encased.TFMGEncasedCogwheelBlock;
import com.drmangotea.tfmg.content.decoration.encased.TFMGEncasedShaftBlock;
import com.drmangotea.tfmg.content.decoration.flywheels.TFMGFlywheelBlock;
import com.drmangotea.tfmg.registry.TFMGBlocks;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTags;
import com.simibubi.create.content.contraptions.behaviour.DoorMovingInteraction;
import com.simibubi.create.content.decoration.encasing.EncasedCTBehaviour;
import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorMovementBehaviour;
import com.simibubi.create.content.kinetics.BlockStressDefaults;
import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock;
import com.simibubi.create.content.kinetics.simpleRelays.encased.EncasedCogCTBehaviour;
import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry;
import com.simibubi.create.foundation.data.*;
import com.tterrag.registrate.builders.BlockBuilder;
import com.tterrag.registrate.util.DataIngredient;
import com.tterrag.registrate.util.entry.BlockEntry;
import com.tterrag.registrate.util.nullness.NonNullUnaryOperator;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.Direction;
import net.minecraft.data.recipes.RecipeCategory;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.ItemTags;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraftforge.client.model.generators.ModelFile;
import java.util.function.Supplier;
import static com.drmangotea.tfmg.TFMG.REGISTRATE;
import static com.simibubi.create.AllInteractionBehaviours.interactionBehaviour;
import static com.simibubi.create.AllMovementBehaviours.movementBehaviour;
import static com.simibubi.create.foundation.data.BlockStateGen.axisBlock;
import static com.simibubi.create.foundation.data.BlockStateGen.simpleCubeAll;
import static com.simibubi.create.foundation.data.ModelGen.customItemModel;
import static com.simibubi.create.foundation.data.TagGen.*;
@SuppressWarnings("removal")
public class TFMGBuilderTransformers {
public static <B extends TFMGSlidingDoorBlock, P> NonNullUnaryOperator<BlockBuilder<B, P>> slidingDoor(String type) {
return b -> b.initialProperties(() -> Blocks.IRON_DOOR)
.properties(p -> p.requiresCorrectToolForDrops()
.strength(3.0F, 6.0F))
.blockstate((c, p) -> {
ModelFile bottom = AssetLookup.partialBaseModel(c, p, "bottom");
ModelFile top = AssetLookup.partialBaseModel(c, p, "top");
p.doorBlock(c.get(), bottom, bottom, bottom, bottom, top, top, top, top);
})
.addLayer(() -> RenderType::cutoutMipped)
.transform(pickaxeOnly())
.onRegister(interactionBehaviour(new DoorMovingInteraction()))
.onRegister(movementBehaviour(new SlidingDoorMovementBehaviour()))
.tag(BlockTags.DOORS)
.tag(BlockTags.WOODEN_DOORS) // for villager AI
.tag(AllTags.AllBlockTags.NON_DOUBLE_DOOR.tag)
.loot((lr, block) -> lr.add(block, lr.createDoorTable(block)))
.item()
.tag(ItemTags.DOORS)
.tag(AllTags.AllItemTags.CONTRAPTION_CONTROLLED.tag)
.model((c, p) -> p.blockSprite(c, p.modLoc("item/" + type + "_door")))
.build();
}
public static <B extends Block, P> NonNullUnaryOperator<BlockBuilder<B, P>> surfaceScanner() {
return b -> b.initialProperties(SharedProperties::softMetal)
.blockstate((c, p) -> p.horizontalBlock(c.get(), p.models()
.getExistingFile(p.modLoc("block/surface_scanner/block"))))
.addLayer(() -> RenderType::cutoutMipped)
.item()
.transform(ModelGen.customItemModel("surface_scanner", "item"));
}
public static <B extends TFMGEncasedShaftBlock, P> NonNullUnaryOperator<BlockBuilder<B, P>> encasedShaft(String casing,
Supplier<CTSpriteShiftEntry> casingShift) {
return builder -> encasedBase(builder, AllBlocks.SHAFT::get)
.onRegister(CreateRegistrate.connectedTextures(() -> new EncasedCTBehaviour(casingShift.get())))
.onRegister(CreateRegistrate.casingConnectivity((block, cc) -> cc.make(block, casingShift.get(),
(s, f) -> f.getAxis() != s.getValue(TFMGEncasedShaftBlock.AXIS))))
.blockstate((c, p) -> axisBlock(c, p, blockState -> p.models()
.getExistingFile(p.modLoc("block/encased_shaft/block_" + casing)), true))
.item()
.model(AssetLookup.customBlockItemModel("encased_shaft", "item_" + casing))
.build();
}
public static <B extends TFMGEncasedCogwheelBlock, P> NonNullUnaryOperator<BlockBuilder<B, P>> encasedCogwheel(
String casing, Supplier<CTSpriteShiftEntry> casingShift) {
return b -> encasedCogwheelBase(b, casing, casingShift, AllBlocks.COGWHEEL::get, false);
}
public static <B extends TFMGEncasedCogwheelBlock, P> NonNullUnaryOperator<BlockBuilder<B, P>> encasedLargeCogwheel(
String casing, Supplier<CTSpriteShiftEntry> casingShift) {
return b -> encasedCogwheelBase(b, casing, casingShift, AllBlocks.LARGE_COGWHEEL::get, true)
.onRegister(CreateRegistrate.connectedTextures(() -> new EncasedCogCTBehaviour(casingShift.get())));
}
private static <B extends TFMGEncasedCogwheelBlock, P> BlockBuilder<B, P> encasedCogwheelBase(BlockBuilder<B, P> b,
String casing, Supplier<CTSpriteShiftEntry> casingShift, Supplier<ItemLike> drop, boolean large) {
String encasedSuffix;
if (!large) {
encasedSuffix = "_encased_cogwheel_side" + (large ? "_connected" : "");
} else encasedSuffix = "_encased_cogwheel_side_large";
String blockFolder = large ? "encased_large_cogwheel" : "encased_cogwheel";
String wood = casing.equals("steel") ? "steel_casing" : "heavy_machinery_casing";
String gearbox = casing.equals("steel") ? "steel_gearbox" : "heavy_gearbox";
String casing1 = casing.equals("heavy_casing") ? "heavy_machinery" : casing;
return encasedBase(b, drop).addLayer(() -> RenderType::cutoutMipped)
.onRegister(CreateRegistrate.casingConnectivity((block, cc) -> cc.make(block, casingShift.get(),
(s, f) -> f.getAxis() == s.getValue(TFMGEncasedCogwheelBlock.AXIS)
&& !s.getValue(f.getAxisDirection() == Direction.AxisDirection.POSITIVE ? TFMGEncasedCogwheelBlock.TOP_SHAFT
: TFMGEncasedCogwheelBlock.BOTTOM_SHAFT))))
.blockstate((c, p) -> axisBlock(c, p, blockState -> {
String suffix = (blockState.getValue(TFMGEncasedCogwheelBlock.TOP_SHAFT) ? "_top" : "")
+ (blockState.getValue(TFMGEncasedCogwheelBlock.BOTTOM_SHAFT) ? "_bottom" : "");
String modelName = c.getName() + suffix;
return p.models()
.withExistingParent(modelName, p.modLoc("block/" + blockFolder + "/block" + suffix))
.texture("casing", TFMG.asResource("block/" + casing1 + "_casing"))
.texture("particle", TFMG.asResource("block/" + casing1 + "_casing"))
.texture("4", TFMG.asResource("block/" + gearbox))
.texture("1", TFMG.asResource("block/" + wood))
.texture("side", TFMG.asResource("block/" + casing1 + encasedSuffix));
}, false))
.item()
.model((c, p) -> p.withExistingParent(c.getName(), p.modLoc("block/" + blockFolder + "/item"))
.texture("casing", TFMG.asResource("block/" + casing1 + "_casing"))
.texture("particle", TFMG.asResource("block/" + casing1 + "_casing"))
.texture("1", TFMG.asResource("block/" + wood))
.texture("side", TFMG.asResource("block/" + casing1 + encasedSuffix)))
.build();
}
private static <B extends RotatedPillarKineticBlock, P> BlockBuilder<B, P> encasedBase(BlockBuilder<B, P> b,
Supplier<ItemLike> drop) {
return b.initialProperties(SharedProperties::stone)
.properties(BlockBehaviour.Properties::noOcclusion)
.transform(BlockStressDefaults.setNoImpact())
.loot((p, lb) -> p.dropOther(lb, drop.get()));
}
//public static <B extends CopycatCableBlock, P> NonNullUnaryOperator<BlockBuilder<B, P>> copycatCable() {
// return b -> b.initialProperties(SharedProperties::softMetal)
// .blockstate((c, p) -> p.simpleBlock(c.get(), p.models()
// .getExistingFile(p.mcLoc("air"))))
// .initialProperties(SharedProperties::softMetal)
// .properties(BlockBehaviour.Properties::noOcclusion)
// .addLayer(() -> RenderType::solid)
// .addLayer(() -> RenderType::cutout)
// .addLayer(() -> RenderType::cutoutMipped)
// // .addLayer(() -> RenderType::translucent)
// .color(() -> CopycatCableBlock::wrappedColor)
// .transform(TagGen.axeOrPickaxe());
//}
///////////////
public static BlockEntry<TFMGFlywheelBlock> flywheel(String name) {
return REGISTRATE.block(name + "_flywheel", TFMGFlywheelBlock::new)
.initialProperties(SharedProperties::softMetal)
.properties(BlockBehaviour.Properties::noOcclusion)
.transform(axeOrPickaxe())
.transform(BlockStressDefaults.setNoImpact())
.blockstate(BlockStateGen.axisBlockProvider(true))
.item()
.transform(customItemModel())
.register();
}
public static BlockEntry<TrussBlock> truss(String name) {
return REGISTRATE.block(name+"_truss", TrussBlock::new)
.initialProperties(() -> Blocks.IRON_BLOCK)
.properties(p -> p.noOcclusion())
.properties(p -> p.sound(SoundType.NETHERITE_BLOCK))
.transform(pickaxeOnly())
.addLayer(() -> RenderType::cutoutMipped)
.blockstate(BlockStateGen.axisBlockProvider(false))
.item()
.build()
.register();
}
public static BlockEntry<FrameBlock> frame(String name) {
return REGISTRATE.block(name+"_frame", FrameBlock::new)
.initialProperties(() -> Blocks.IRON_BLOCK)
.properties(p -> p.sound(SoundType.NETHERITE_BLOCK))
.properties(p -> p.strength(3))
.transform(pickaxeOnly())
.addLayer(() -> RenderType::cutoutMipped)
.properties(BlockBehaviour.Properties::noOcclusion)
.blockstate((ctx, prov) -> prov.simpleBlock(ctx.getEntry(), AssetLookup.partialBaseModel(ctx, prov)))
.simpleItem()
.register();
}
public static final String[] COLORS = {"white", "blue", "light_blue", "red", "green", "lime", "pink", "magenta", "yellow", "gray", "light_gray", "brown", "cyan", "purple", "orange"};
public static void generateCautionBlocks() {
for (String color : COLORS) {
String firstLetter = color.substring(0, 1).toUpperCase();
String colorWithoutC = color.substring(1);
String upperCaseColor = firstLetter + colorWithoutC;
String light = "Light";
if (upperCaseColor.contains(light)) {
String nameWithoutLight = upperCaseColor.substring(6);
String firstLetter2 = nameWithoutLight.substring(0, 1).toUpperCase();
String colorWithoutC2 = nameWithoutLight.substring(1);
upperCaseColor = light + " " + firstLetter2 + colorWithoutC2;
}
REGISTRATE.block(color + "_caution_block", TFMGHorizontalDirectionalBlock::new)
.initialProperties(() -> Blocks.COPPER_BLOCK)
.properties(p -> p.requiresCorrectToolForDrops())
.properties(p -> p.sound(SoundType.NETHERITE_BLOCK))
.transform(pickaxeOnly())
.blockstate((c, p) -> p.horizontalBlock(c.get(), p.models()
.withExistingParent(c.getName(), p.modLoc("block/caution_block"))
.texture("0", p.modLoc("block/caution_block/" + color))
.texture("particle", p.modLoc("block/caution_block/" + color))
))
.tag(BlockTags.NEEDS_STONE_TOOL)
.item()
.build()
.lang(upperCaseColor + " Caution Block")
.register();
}
}
public static MaterialSet generateConcrete(boolean rebar) {
String name = rebar ? "rebar_concrete" : "concrete";
MaterialSet concrete = new MaterialSet();
generateColoredConcrete(rebar);
concrete.wall = REGISTRATE.block(name+"_wall", WallBlock::new)
.initialProperties(() -> Blocks.STONE)
.properties(p -> p.requiresCorrectToolForDrops())
.properties(p ->p.strength(rebar ? 12f : 3.5f,rebar ? 1200f : 3.5f))
.transform(pickaxeOnly())
.blockstate((c, p) -> TFMGVanillaBlockStates.generateWallBlockState(c, p, "concrete"))
.tag(BlockTags.NEEDS_STONE_TOOL)
.tag(BlockTags.WALLS)
.recipe((c, p) -> p.stonecutting(DataIngredient.items(concrete.block.get()), RecipeCategory.BUILDING_BLOCKS, c::get, 1))
.item()
.transform(b -> TFMGVanillaBlockStates.transformWallItem(b, "concrete"))
.build()
.register();
concrete.stairs = REGISTRATE.block(name+"_stairs", p -> new StairBlock(() -> concrete.block.get().defaultBlockState(), p))
.initialProperties(() -> Blocks.STONE)
.properties(p -> p.requiresCorrectToolForDrops())
.properties(p ->p.strength(rebar ? 12f : 3.5f,rebar ? 1200f : 3.5f))
.transform(pickaxeOnly())
.blockstate((c, p) -> TFMGVanillaBlockStates.generateStairBlockState(c, p, "concrete"))
.tag(BlockTags.NEEDS_STONE_TOOL)
.tag(BlockTags.STAIRS)
.recipe((c, p) -> p.stonecutting(DataIngredient.items(concrete.block.get()),RecipeCategory.BUILDING_BLOCKS, c::get, 1))
.item()
//.transform(b -> TFMGVanillaBlockStates.transformStairItem(b, "concrete"))
.transform(customItemModel("concrete_stairs"))
.register();
concrete.block = REGISTRATE.block(name, Block::new)
.initialProperties(() -> Blocks.STONE)
.properties(p ->p.strength(rebar ? 12f : 3.5f,rebar ? 1200f : 3.5f))
.properties(p -> p.requiresCorrectToolForDrops())
.transform(pickaxeOnly())
.blockstate(simpleCubeAll("concrete"))
.tag(BlockTags.NEEDS_STONE_TOOL)
.transform(tagBlockAndItem("concrete"))
.build()
.register();
concrete.slab = REGISTRATE.block(name+"_slab", SlabBlock::new)
.initialProperties(() -> Blocks.STONE)
.properties(p ->p.strength(rebar ? 12f : 3.5f,rebar ? 1200f : 3.5f))
.properties(p -> p.requiresCorrectToolForDrops())
.transform(pickaxeOnly())
.blockstate((c, p) -> TFMGVanillaBlockStates.generateSlabBlockState(c, p, "concrete"))
.tag(BlockTags.NEEDS_STONE_TOOL)
.tag(BlockTags.SLABS)
.recipe((c, p) -> p.stonecutting(DataIngredient.items(concrete.block.get()),RecipeCategory.BUILDING_BLOCKS, c::get, 2))
.item()
.transform(customItemModel("concrete_bottom"))
.register();
return concrete;
}
public static void generateColoredConcrete(boolean rebar) {
String name = rebar ? "_rebar_concrete" : "_concrete";
for (String color : COLORS) {
REGISTRATE.block(color +name, Block::new)
.initialProperties(() -> Blocks.STONE)
.properties(p ->p.strength(rebar ? 12f : 3.5f,rebar ? 1200f : 3.5f))
.properties(p -> p.requiresCorrectToolForDrops())
.transform(pickaxeOnly())
.blockstate(simpleCubeAll(color + "_concrete"))
.tag(BlockTags.NEEDS_STONE_TOOL)
.item()
.build()
.register();
REGISTRATE.block(color + name+"_wall", WallBlock::new)
.initialProperties(() -> Blocks.STONE)
.properties(p ->p.strength(rebar ? 12f : 3.5f,rebar ? 1200f : 3.5f))
.properties(p -> p.requiresCorrectToolForDrops())
.transform(pickaxeOnly())
.blockstate((c, p) -> TFMGVanillaBlockStates.generateWallBlockState(c, p, color + "_concrete"))
.tag(BlockTags.NEEDS_STONE_TOOL)
.tag(BlockTags.WALLS)
.item()
.transform(b -> TFMGVanillaBlockStates.transformWallItem(b, color + "_concrete"))
.build()
.register();
REGISTRATE.block(color + name+"_stairs", p -> new StairBlock(() -> TFMGBlocks.CONCRETE.block.get().defaultBlockState(), p))
.initialProperties(() -> Blocks.STONE)
.properties(p ->p.strength(rebar ? 12f : 3.5f,rebar ? 1200f : 3.5f))
.properties(p -> p.requiresCorrectToolForDrops())
.transform(pickaxeOnly())
.blockstate((c, p) -> TFMGVanillaBlockStates.generateStairBlockState(c, p, color + "_concrete"))
.tag(BlockTags.NEEDS_STONE_TOOL)
.tag(BlockTags.STAIRS)
.item()
// .transform(b -> TFMGVanillaBlockStates.transformStairItem(b, color + "_concrete"))
.transform(customItemModel(color+"_concrete_stairs"))
.register();
REGISTRATE.block(color + name+"_slab", SlabBlock::new)
.initialProperties(() -> Blocks.STONE)
.properties(p ->p.strength(rebar ? 12f : 3.5f,rebar ? 1200f : 3.5f))
.properties(p -> p.requiresCorrectToolForDrops())
.transform(pickaxeOnly())
.blockstate((c, p) -> TFMGVanillaBlockStates.generateSlabBlockState(c, p, color + "_concrete"))
.tag(BlockTags.NEEDS_STONE_TOOL)
.tag(BlockTags.SLABS)
.item()
.transform(customItemModel(color + "_concrete_bottom"))
.register();
}
}
public static MaterialSet makeVariants(BlockEntry<?> blockEntry){
MaterialSet materialSet = new MaterialSet();
materialSet.block = blockEntry;
String name = blockEntry.getId().toString().replace("tfmg:","");
REGISTRATE.block(name+"_wall", WallBlock::new)
.initialProperties(() -> blockEntry.get())
.transform(pickaxeOnly())
.blockstate((c, p) -> TFMGVanillaBlockStates.generateWallBlockState(c, p, name))
.tag(BlockTags.NEEDS_STONE_TOOL)
.tag(BlockTags.WALLS)
.item()
.transform(b -> TFMGVanillaBlockStates.transformWallItem(b, name))
.build()
.register();
REGISTRATE.block(name+"_slab", SlabBlock::new)
.initialProperties(() -> blockEntry.get())
.properties(p -> p.requiresCorrectToolForDrops())
.transform(pickaxeOnly())
.blockstate((c, p) -> TFMGVanillaBlockStates.generateSlabBlockState(c, p, name))
.tag(BlockTags.NEEDS_STONE_TOOL)
.tag(BlockTags.SLABS)
.item()
.transform(customItemModel(name + "_bottom"))
.register();
REGISTRATE.block(name+"_stairs", p -> new StairBlock(() -> TFMGBlocks.CONCRETE.block.get().defaultBlockState(), p))
.initialProperties(() -> Blocks.STONE)
.transform(pickaxeOnly())
.blockstate((c, p) -> TFMGVanillaBlockStates.generateStairBlockState(c, p, name))
.tag(BlockTags.NEEDS_STONE_TOOL)
.tag(BlockTags.STAIRS)
.item()
.transform(customItemModel(name+"_stairs"))
.register();
return materialSet;
}
}

View File

@@ -0,0 +1,23 @@
package com.drmangotea.tfmg.base;
import com.drmangotea.tfmg.TFMG;
import com.simibubi.create.Create;
import com.simibubi.create.foundation.utility.WorldAttached;
import net.minecraft.world.level.LevelAccessor;
import net.minecraftforge.event.level.LevelEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber
public class TFMGCommonEvents {
@SubscribeEvent
public static void onLoadWorld(LevelEvent.Load event) {
LevelAccessor world = event.getLevel();
TFMG.NETWORK_MANAGER.onLoadWorld(world);
}
@SubscribeEvent
public static void onUnloadWorld(LevelEvent.Unload event) {
LevelAccessor world = event.getLevel();
TFMG.NETWORK_MANAGER.onUnloadWorld(world);
}
}

View File

@@ -0,0 +1,15 @@
package com.drmangotea.tfmg.base;
import com.drmangotea.tfmg.TFMG;
import com.drmangotea.tfmg.content.machinery.oil_processing.pumpjack.pumpjack.hammer.PumpjackContraption;
import com.simibubi.create.content.contraptions.ContraptionType;
public class TFMGContraptions {
public static final ContraptionType
PUMPJACK_CONTRAPTION = ContraptionType.register(TFMG.asResource("pumpjack").toString(), PumpjackContraption::new);
public static void prepare() {}
}

View File

@@ -0,0 +1,87 @@
package com.drmangotea.tfmg.base;
import com.drmangotea.tfmg.content.machinery.misc.winding_machine.SpoolItem;
import com.drmangotea.tfmg.registry.TFMGBlocks;
import com.drmangotea.tfmg.registry.TFMGItems;
import com.drmangotea.tfmg.registry.TFMGPaletteStoneTypes;
import com.simibubi.create.AllCreativeModeTabs;
import com.simibubi.create.content.processing.sequenced.SequencedAssemblyItem;
import com.simibubi.create.foundation.data.CreateRegistrate;
import com.tterrag.registrate.util.entry.RegistryEntry;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.event.BuildCreativeModeTabContentsEvent;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.RegistryObject;
import java.util.ArrayList;
import java.util.List;
import static com.drmangotea.tfmg.TFMG.MOD_ID;
import static com.drmangotea.tfmg.TFMG.REGISTRATE;
public class TFMGCreativeTabs {
public static final DeferredRegister<CreativeModeTab> CREATIVE_MODE_TABS = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, MOD_ID);
public static final RegistryObject<CreativeModeTab> TFMG_MAIN = CREATIVE_MODE_TABS.register("tfmg_main", () -> CreativeModeTab.builder()
.withTabsBefore(AllCreativeModeTabs.BASE_CREATIVE_TAB.getId())
.title(Component.translatable("creative_tab.tfmg_main"))
.icon(()-> TFMGItems.STEEL_INGOT.get().asItem().getDefaultInstance())
.build());
public static final RegistryObject<CreativeModeTab> TFMG_DECORATION = CREATIVE_MODE_TABS.register("tfmg_decoration", () -> CreativeModeTab.builder()
.withTabsBefore(TFMG_MAIN.getId())
.title(Component.translatable("creative_tab.tfmg_decoration"))
.icon(()-> TFMGBlocks.CONCRETE.block.get().asItem().getDefaultInstance())
.build());
public static void addCreative(BuildCreativeModeTabContentsEvent event) {
if (event.getTab() == TFMG_MAIN.get()){
for(RegistryEntry<Item> item : REGISTRATE.getAll(Registries.ITEM)){
if(!CreateRegistrate.isInCreativeTab(item,TFMG_MAIN))
continue;
if(blacklist().contains(item))
continue;
if(item.get() instanceof SequencedAssemblyItem)
continue;
if(item.get() instanceof SpoolItem&&!item.is(TFMGItems.EMPTY_SPOOL.get())){
ItemStack spool = item.get().getDefaultInstance();
spool.getOrCreateTag().putInt("Amount", 1000);
event.accept(spool);
continue;
}
event.accept(item);
}
}
if (event.getTab() == TFMG_DECORATION.get()){
for(RegistryEntry<Item> item : REGISTRATE.getAll(Registries.ITEM)){
if(!CreateRegistrate.isInCreativeTab(item, TFMG_DECORATION))
continue;
if(blacklist().contains(item))
continue;
if(item.get() instanceof SequencedAssemblyItem)
continue;
event.accept(item);
}
}
}
public static void register(IEventBus modEventBus){
CREATIVE_MODE_TABS.register(modEventBus);
}
public static List<RegistryEntry<Item>> blacklist(){
List<RegistryEntry<Item>> list = new ArrayList<>();
return list;
}
}

View File

@@ -0,0 +1,25 @@
package com.drmangotea.tfmg.base;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.DirectionalBlock;
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
public class TFMGDirectionalBlock extends DirectionalBlock {
public TFMGDirectionalBlock(Properties p_54120_) {
super(p_54120_);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FACING);
super.createBlockStateDefinition(builder);
}
public BlockState getStateForPlacement(BlockPlaceContext pContext) {
return this.defaultBlockState().setValue(FACING, pContext.getNearestLookingDirection().getOpposite());
}
}

View File

@@ -0,0 +1,22 @@
package com.drmangotea.tfmg.base;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
public class TFMGHorizontalDirectionalBlock extends HorizontalDirectionalBlock {
public TFMGHorizontalDirectionalBlock(Properties p_54120_) {
super(p_54120_);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FACING);
super.createBlockStateDefinition(builder);
}
public BlockState getStateForPlacement(BlockPlaceContext pContext) {
return this.defaultBlockState().setValue(FACING, pContext.getHorizontalDirection().getOpposite());
}
}

View File

@@ -0,0 +1,143 @@
package com.drmangotea.tfmg.base;
import com.drmangotea.tfmg.TFMG;
import com.simibubi.create.AllTags.AllBlockTags;
import com.simibubi.create.foundation.data.TagGen;
import com.tterrag.registrate.providers.DataGenContext;
import com.tterrag.registrate.providers.RegistrateBlockstateProvider;
import com.tterrag.registrate.util.DataIngredient;
import com.tterrag.registrate.util.entry.BlockEntry;
import com.tterrag.registrate.util.nullness.NonNullBiConsumer;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.data.recipes.RecipeCategory;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.IronBarsBlock;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.material.MapColor;
import net.minecraftforge.client.model.generators.ModelFile;
import java.util.function.Supplier;
import static net.minecraft.world.level.block.state.properties.BlockStateProperties.*;
public class TFMGMetalBarsGen {
public static <P extends IronBarsBlock> NonNullBiConsumer<DataGenContext<Block, P>, RegistrateBlockstateProvider> barsBlockState(
String name, boolean specialEdge) {
return (c, p) -> {
ModelFile post_ends = barsSubModel(p, name, "post_ends", specialEdge);
ModelFile post = barsSubModel(p, name, "post", specialEdge);
ModelFile cap = barsSubModel(p, name, "cap", specialEdge);
ModelFile cap_alt = barsSubModel(p, name, "cap_alt", specialEdge);
ModelFile side = barsSubModel(p, name, "side", specialEdge);
ModelFile side_alt = barsSubModel(p, name, "side_alt", specialEdge);
p.getMultipartBuilder(c.get())
.part()
.modelFile(post_ends)
.addModel()
.end()
.part()
.modelFile(post)
.addModel()
.condition(NORTH, false)
.condition(EAST, false)
.condition(SOUTH, false)
.condition(WEST, false)
.end()
.part()
.modelFile(cap)
.addModel()
.condition(NORTH, true)
.condition(EAST, false)
.condition(SOUTH, false)
.condition(WEST, false)
.end()
.part()
.modelFile(cap)
.rotationY(90)
.addModel()
.condition(NORTH, false)
.condition(EAST, true)
.condition(SOUTH, false)
.condition(WEST, false)
.end()
.part()
.modelFile(cap_alt)
.addModel()
.condition(NORTH, false)
.condition(EAST, false)
.condition(SOUTH, true)
.condition(WEST, false)
.end()
.part()
.modelFile(cap_alt)
.rotationY(90)
.addModel()
.condition(NORTH, false)
.condition(EAST, false)
.condition(SOUTH, false)
.condition(WEST, true)
.end()
.part()
.modelFile(side)
.addModel()
.condition(NORTH, true)
.end()
.part()
.modelFile(side)
.rotationY(90)
.addModel()
.condition(EAST, true)
.end()
.part()
.modelFile(side_alt)
.addModel()
.condition(SOUTH, true)
.end()
.part()
.modelFile(side_alt)
.rotationY(90)
.addModel()
.condition(WEST, true)
.end();
};
}
private static ModelFile barsSubModel(RegistrateBlockstateProvider p, String name, String suffix,
boolean specialEdge) {
ResourceLocation barsTexture = p.modLoc("block/bars/" + name + "_bars");
ResourceLocation edgeTexture = specialEdge ? p.modLoc("block/bars/" + name + "_bars_edge") : barsTexture;
return p.models()
.withExistingParent(name + "_" + suffix, p.modLoc("block/bars/" + suffix))
.texture("bars", barsTexture)
.texture("particle", barsTexture)
.texture("edge", edgeTexture);
}
@SuppressWarnings("removal")
public static BlockEntry<IronBarsBlock> createBars(String name, boolean specialEdge,
Supplier<DataIngredient> ingredient, MapColor color) {
return TFMG.REGISTRATE.block(name + "_bars", IronBarsBlock::new)
.addLayer(() -> RenderType::cutoutMipped)
.initialProperties(() -> Blocks.IRON_BARS)
.properties(p -> p.sound(SoundType.COPPER)
.mapColor(color))
.tag(AllBlockTags.WRENCH_PICKUP.tag)
.tag(AllBlockTags.FAN_TRANSPARENT.tag)
.transform(TagGen.pickaxeOnly())
.blockstate(barsBlockState(name, specialEdge))
.item()
.model((c, p) -> {
ResourceLocation barsTexture = p.modLoc("block/bars/" + name + "_bars");
p.withExistingParent(c.getName(), TFMG.asResource("item/bars"))
.texture("bars", barsTexture)
.texture("edge", specialEdge ? p.modLoc("block/bars/" + name + "_bars_edge") : barsTexture);
})
.recipe((c, p) -> p.stonecutting(ingredient.get(), RecipeCategory.DECORATIONS, c::get, 4))
.build()
.register();
}
}

View File

@@ -0,0 +1,52 @@
package com.drmangotea.tfmg.base;
import com.drmangotea.tfmg.TFMG;
import com.drmangotea.tfmg.registry.TFMGBlocks;
import com.simibubi.create.foundation.data.CreateRegistrate;
import com.tterrag.registrate.util.DataIngredient;
import com.tterrag.registrate.util.entry.BlockEntry;
import net.minecraft.data.recipes.RecipeCategory;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraftforge.registries.ForgeRegistries;
import static com.simibubi.create.foundation.data.BlockStateGen.simpleCubeAll;
import static com.simibubi.create.foundation.data.ModelGen.customItemModel;
import static com.simibubi.create.foundation.data.TagGen.pickaxeOnly;
public class TFMGRegistrate extends CreateRegistrate {
public static String autoLang(String id) {
StringBuilder builder = new StringBuilder();
boolean b = true;
for (char c: id.toCharArray()) {
if(c == '_') {
builder.append(' ');
b = true;
} else {
builder.append(b ? String.valueOf(c).toUpperCase() : c);
b = false;
}
}
return builder.toString();
}
protected TFMGRegistrate() {
super(TFMG.MOD_ID);
}
public static TFMGRegistrate create() {
return new TFMGRegistrate();
}
public static Block getBlock(String name) {
return TFMG.REGISTRATE.get(name, ForgeRegistries.BLOCKS.getRegistryKey()).get();
}
public static Item getItem(String name) {
return TFMG.REGISTRATE.get(name, ForgeRegistries.ITEMS.getRegistryKey()).get();
}
public static Item getBucket(String name) {
return TFMG.REGISTRATE.get(name+"_bucket", ForgeRegistries.ITEMS.getRegistryKey()).get();
}
}

View File

@@ -0,0 +1,55 @@
package com.drmangotea.tfmg.base;
import com.drmangotea.tfmg.TFMG;
import com.drmangotea.tfmg.registry.TFMGTags;
import com.simibubi.create.AllItems;
import com.simibubi.create.AllTags;
import com.simibubi.create.foundation.data.TagGen;
import com.simibubi.create.foundation.data.recipe.Mods;
import com.tterrag.registrate.providers.ProviderType;
import com.tterrag.registrate.providers.RegistrateTagsProvider;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.ItemTags;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraftforge.common.Tags;
import java.util.List;
public class TFMGRegistrateTags {
public static void addGenerators() {
TFMG.REGISTRATE.addDataGenerator(ProviderType.BLOCK_TAGS, TFMGRegistrateTags::genBlockTags);
TFMG.REGISTRATE.addDataGenerator(ProviderType.ITEM_TAGS, TFMGRegistrateTags::genItemTags);
// TFMG.REGISTRATE.addDataGenerator(ProviderType.FLUID_TAGS, TFMGRegistrateTags::genFluidTags);
// TFMG.REGISTRATE.addDataGenerator(ProviderType.ENTITY_TAGS, TFMGRegistrateTags::genEntityTags);
}
private static void genItemTags(RegistrateTagsProvider<Item> provIn) {
TagGen.CreateTagsProvider<Item> prov = new TagGen.CreateTagsProvider<>(provIn, Item::builtInRegistryHolder);
prov.tag(TFMGTags.TFMGItemTags.RODS.tag)
.add(Items.STICK);
for (TFMGTags.TFMGItemTags tag : TFMGTags.TFMGItemTags.values()) {
if (tag.alwaysDatagen) {
prov.getOrCreateRawBuilder(tag.tag);
}
}
}
private static void genBlockTags(RegistrateTagsProvider<Block> provIn) {
TagGen.CreateTagsProvider<Block> prov = new TagGen.CreateTagsProvider<>(provIn, Block::builtInRegistryHolder);
prov.tag(TFMGTags.TFMGBlockTags.PUMPJACK_HEAD.tag)
.add(Blocks.IRON_BLOCK);
prov.tag(TFMGTags.TFMGBlockTags.PUMPJACK_PART.tag)
.addTag(TFMGTags.TFMGBlockTags.PUMPJACK_SMALL_PART.tag);
for (TFMGTags.TFMGBlockTags tag : TFMGTags.TFMGBlockTags.values()) {
if (tag.alwaysDatagen) {
prov.getOrCreateRawBuilder(tag.tag);
}
}
}
}

View File

@@ -0,0 +1,174 @@
package com.drmangotea.tfmg.base;
import com.simibubi.create.foundation.utility.VoxelShaper;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.phys.shapes.BooleanOp;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import java.util.function.BiFunction;
import static net.minecraft.core.Direction.*;
public class TFMGShapes {
public static final VoxelShaper
ENGINE_BACK = shape(3, 0, 3, 13, 16, 16)
.forDirectional(),
ENGINE_BACK_VERTICAL = shape(3, 0, 3, 16, 16, 13)
.forDirectional(),
ENGINE_VERTICAL = shape(3, 0, 3, 13, 14, 16)
.forDirectional(),
ENGINE = shape(3, 0, 3, 13, 14, 16)
.forDirectional(),
PUMPJACK_HAMMER_PART = shape(0, 2, 0, 16, 14, 16)
.forDirectional(),
RADIAL_ENGINE = shape(1, 4, 1, 15, 12, 15)
.forDirectional(),
LARGE_RADIAL_ENGINE = shape(-3, 4, -3, 19, 12, 19)
.forDirectional(),
PUMPJACK_HEAD = shape(1, 0, -4, 15, 14, 24)
.forDirectional(),
COMPACT_ENGINE_VERTICAL = shape(3, 0, 3, 13, 14, 14)
.forDirectional(),
COMPACT_ENGINE = shape(3, 0, 3, 13, 14, 14)
.forDirectional(),
CABLE_CONNECTOR = shape(6, 0, 6, 10, 9, 10)
.forDirectional(),
CABLE_CONNECTOR_MIDDLE = shape(6, 0, 6, 10, 16, 10)
.forDirectional(),
GALVANIC_CELL = shape(5, 10, 5, 11, 16, 16).add(1, 4, 6, 15, 10, 16)
.forDirectional(),
GENERATOR = shape(3, 0, 3, 13, 14, 13).add(0, 4, 0, 16, 10, 16)
.forDirectional(),
LIGHT_BULB = shape(5, 0, 5, 11, 9, 11)
.forDirectional(),
MODERN_LIGHT = shape(0, 0, 0, 16, 3, 16)
.forDirectional(),
CIRCULAR_LIGHT = shape(3, 0, 3, 13, 10, 13)
.forDirectional(),
ALUMINUM_LAMP = shape(3, 0, 3, 13, 2, 13).add(4, 2, 4, 12, 3, 12)
.forDirectional(),
RESISTOR = shape(3, 0, 3, 13, 16, 13).add(1, 1, 13, 15, 15, 16)
.forDirectional(),
RESISTOR_VERTICAL = shape(3, 0, 3, 13, 16, 13)
.forDirectional(),
BLAST_FURNACE_REINFORCEMENT_WALL = shape(00, 0, 0, 16, 6, 16)
.forDirectional(),
ROTOR = shape(3, 3, 2, 13, 13, 14)
.forAxis(),
VOLTMETER = shape(0, 0, 2, 16, 3, 14)
.forDirectional(),
DIAGONAL_CABLE_BLOCK_DOWN = shape(3, 3, 11, 13, 13, 16)
.add(3, 11, 3, 13, 16, 13)
.add(4, 4, 5, 12, 11, 12)
.forDirectional(),
DIAGONAL_CABLE_BLOCK_UP = shape(3, 3, 0, 13, 13, 5)
.add(3, 11, 3, 13, 16, 13)
.add(4, 4, 5, 12, 11, 12)
.forDirectional(),
CABLE_TUBE = shape(6, 0, 6, 10, 16, 10)
.forDirectional(),
REBAR_PILLAR = shape(3, 0, 3, 13, 16, 13)
.forDirectional(),
ELECTRICAL_SWITCH = shape(5, 0, 3, 11, 3, 13)
.forHorizontalAxis(),
ELECTRICAL_SWITCH_CEILING = shape(5, 13, 3, 11, 16, 13)
.forHorizontalAxis(),
ELECTRICAL_SWITCH_WALL = shape(5, 3, 0, 11, 13, 3)
.forHorizontal(SOUTH),
POLARIZER = shape(4, 8, 0, 12, 12, 2)
.add(5, 8, 14, 11, 11, 16)
.add(11, 8, 4, 15, 12, 11)
.add(1, 8, 4, 5, 12, 11)
.add(0, 0, 0, 16, 8, 16)
.forHorizontal(NORTH)
;
public static final VoxelShape
EMPTY = shape(0, 0, 0, 0, 0, 0).build(),
PUMPJACK_CRANK = shape(0, 0, 0, 16, 8, 16).build(),
INDUSTRIAL_PIPE = shape(4, 0, 4, 12, 16, 12).build(),
FLARESTACK = shape(3, 0, 3, 13, 14, 14).build(),
PUMPJACK_BASE = shape(3, 0, 3, 13, 16, 13).build(),
TRAFFIC_LIGHT = shape(3, 0, 3, 13, 16, 13).build(),
CASTING_SPOUT = shape(1, 2, 1, 15, 14, 15)
.build(),
REBAR_FLOOR = shape(0, 4, 0, 16, 12, 16)
.build(),
SURFACE_SCANNER = shape(2, 0, 2, 14, 14, 14).build(),
FULL = shape(0, 0, 0, 16, 16, 16).build(),
ELECTRIC_POST = shape(4, 0, 4, 12, 16, 12).build(),
SLAB = shape(0, 0, 0, 16, 8, 16).build();
;
private static Builder shape(VoxelShape shape) {
return new Builder(shape);
}
private static Builder shape(double x1, double y1, double z1, double x2, double y2, double z2) {
return shape(cuboid(x1, y1, z1, x2, y2, z2));
}
private static VoxelShape cuboid(double x1, double y1, double z1, double x2, double y2, double z2) {
return Block.box(x1, y1, z1, x2, y2, z2);
}
public static class Builder {
private VoxelShape shape;
public Builder(VoxelShape shape) {
this.shape = shape;
}
public Builder add(VoxelShape shape) {
this.shape = Shapes.or(this.shape, shape);
return this;
}
public Builder add(double x1, double y1, double z1, double x2, double y2, double z2) {
return add(cuboid(x1, y1, z1, x2, y2, z2));
}
public Builder erase(double x1, double y1, double z1, double x2, double y2, double z2) {
this.shape = Shapes.join(shape, cuboid(x1, y1, z1, x2, y2, z2), BooleanOp.ONLY_FIRST);
return this;
}
public VoxelShape build() {
return shape;
}
public VoxelShaper build(BiFunction<VoxelShape, Direction, VoxelShaper> factory, Direction direction) {
return factory.apply(shape, direction);
}
public VoxelShaper build(BiFunction<VoxelShape, Axis, VoxelShaper> factory, Axis axis) {
return factory.apply(shape, axis);
}
public VoxelShaper forDirectional(Direction direction) {
return build(VoxelShaper::forDirectional, direction);
}
public VoxelShaper forAxis() {
return build(VoxelShaper::forAxis, Axis.Y);
}
public VoxelShaper forHorizontalAxis() {
return build(VoxelShaper::forHorizontalAxis, Axis.Z);
}
public VoxelShaper forHorizontal(Direction direction) {
return build(VoxelShaper::forHorizontal, direction);
}
public VoxelShaper forDirectional() {
return forDirectional(UP);
}
}
}

View File

@@ -0,0 +1,5 @@
package com.drmangotea.tfmg.base;
public class TFMGSharedProperties {}

View File

@@ -0,0 +1,63 @@
package com.drmangotea.tfmg.base;
import com.drmangotea.tfmg.TFMG;
import com.simibubi.create.Create;
import com.simibubi.create.foundation.block.connected.AllCTTypes;
import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry;
import com.simibubi.create.foundation.block.connected.CTSpriteShifter;
import com.simibubi.create.foundation.block.connected.CTType;
import com.simibubi.create.foundation.block.render.SpriteShiftEntry;
import com.simibubi.create.foundation.block.render.SpriteShifter;
public class TFMGSpriteShifts {
public static final CTSpriteShiftEntry CAST_IRON_BLOCK = omni("cast_iron_block"), LEAD_BLOCK = omni("lead_block"), STEEL_BLOCK = omni("steel_block");
public static final CTSpriteShiftEntry STEEL_FLUID_TANK = getCT(AllCTTypes.RECTANGLE, "steel_fluid_tank"), STEEL_FLUID_TANK_TOP = getCT(AllCTTypes.RECTANGLE, "steel_fluid_tank_top"), STEEL_FLUID_TANK_INNER = getCT(AllCTTypes.RECTANGLE, "steel_fluid_tank_inner");
public static final CTSpriteShiftEntry HEAVY_MACHINERY_CASING = omni("heavy_machinery_casing"), ELECTRIC_CASING = omni("electric_casing"), STEEL_CASING = omni("steel_casing"), INDUSTRIAL_ALUMINUM_CASING = omni("industrial_aluminum_casing");
public static final CTSpriteShiftEntry CAPACITOR = getCT(AllCTTypes.RECTANGLE, "capacitor_side"), ACCUMULATOR = getCT(AllCTTypes.RECTANGLE, "accumulator_side");
public static final CTSpriteShiftEntry STEEL_SCAFFOLD = horizontal("scaffold/steel_scaffold"), ALUMINUM_SCAFFOLD = horizontal("scaffold/aluminum_scaffold");
public static final CTSpriteShiftEntry ALUMINUM_SCAFFOLD_TOP = omni("aluminum_casing");
public static final CTSpriteShiftEntry STEEL_SCAFFOLD_INSIDE = horizontal("scaffold/steel_scaffold_inside"), ALUMINUM_SCAFFOLD_INSIDE = horizontal("scaffold/aluminum_scaffold_inside");
public static final CTSpriteShiftEntry STEEL_ENCASED_COGWHEEL_SIDE = vertical("steel_encased_cogwheel_side"), STEEL_ENCASED_COGWHEEL_OTHERSIDE = horizontal("steel_encased_cogwheel_side"), HEAVY_CASING_ENCASED_COGWHEEL_SIDE = vertical("heavy_machinery_encased_cogwheel_side"), HEAVY_CASING_ENCASED_COGWHEEL_OTHERSIDE = horizontal("heavy_machinery_encased_cogwheel_side");
public static final CTSpriteShiftEntry COKE_OVEN_TOP = getCT(AllCTTypes.RECTANGLE, "coke_oven/top"), COKE_OVEN_BOTTOM = getCT(AllCTTypes.RECTANGLE, "coke_oven/bottom"), COKE_OVEN_BACK = getCT(AllCTTypes.RECTANGLE, "coke_oven/side"), COKE_OVEN_SIDE = getCT(AllCTTypes.RECTANGLE, "coke_oven/side");
public static final CTSpriteShiftEntry BLAST_FURNACE_REINFORCEMENT = vertical("blast_furnace_reinforcement");
public static final CTSpriteShiftEntry RUSTED_BLAST_FURNACE_REINFORCEMENT = vertical("rusted_blast_furnace_reinforcement");
public static final CTSpriteShiftEntry SEGMENTED_DISPLAY_SCREEN = horizontal("segmented_display_screen");
public static final CTSpriteShiftEntry BLAST_STOVE_SIDE = getCT(AllCTTypes.RECTANGLE, "blast_stove_side"), BLAST_STOVE_TOP = getCT(AllCTTypes.RECTANGLE, "blast_stove_top");
public static final CTSpriteShiftEntry
REGULAR_ENGINE_TOP = vertical("engines/engine_top"),
REGULAR_ENGINE_BOTTOM = vertical("engines/engine_bottom"),
REGULAR_ENGINE_SIDE = horizontal("engines/engine_side");
public static final SpriteShiftEntry WINDING_MACHINE_COPPER_WIRE = get("block/winding_machine_copper_wire", "block/winding_machine_copper_wire_scroll");
///////////////////////
public static CTSpriteShiftEntry omni(String name) {
return getCT(AllCTTypes.OMNIDIRECTIONAL, name);
}
public static CTSpriteShiftEntry horizontal(String name) {
return getCT(AllCTTypes.HORIZONTAL_KRYPPERS, name);
}
private static CTSpriteShiftEntry vertical(String name) {
return getCT(AllCTTypes.VERTICAL, name);
}
/////
private static CTSpriteShiftEntry getCT(CTType type, String blockTextureName, String connectedTextureName) {
return CTSpriteShifter.getCT(type, TFMG.asResource("block/" + blockTextureName), TFMG.asResource("block/" + connectedTextureName + "_connected"));
}
private static CTSpriteShiftEntry getCT(CTType type, String blockTextureName) {
return getCT(type, blockTextureName, blockTextureName);
}
private static SpriteShiftEntry get(String originalLocation, String targetLocation) {
return SpriteShifter.get(TFMG.asResource(originalLocation), TFMG.asResource(targetLocation));
}
}

View File

@@ -0,0 +1,62 @@
package com.drmangotea.tfmg.base;
import com.drmangotea.tfmg.registry.TFMGItems;
import net.minecraft.util.LazyLoadedValue;
import net.minecraft.world.item.Tier;
import net.minecraft.world.item.crafting.Ingredient;
import java.util.function.Supplier;
public enum TFMGTiers implements Tier {
STEEL(3, 1000, 7.5f, 3f, 12, () -> {
return Ingredient.of(TFMGItems.STEEL_INGOT.get());
}),
ALUMINUM(2, 220, 6, 2f, 22, () -> {
return Ingredient.of(TFMGItems.ALUMINUM_INGOT.get());
}),
LEAD(1, 32, 2, 0.5f, 5, () -> {
return Ingredient.of(TFMGItems.LEAD_INGOT.get());
});
private final int level;
private final int uses;
private final float speed;
private final float damage;
private final int enchantmentValue;
private final LazyLoadedValue<Ingredient> repairIngredient;
private TFMGTiers(int pLevel, int pUses, float pSpeed, float pDamage, int pEnchantmentValue, Supplier<Ingredient> pRepairIngredient) {
this.level = pLevel;
this.uses = pUses;
this.speed = pSpeed;
this.damage = pDamage;
this.enchantmentValue = pEnchantmentValue;
this.repairIngredient = new LazyLoadedValue<>(pRepairIngredient);
}
public int getUses() {
return this.uses;
}
public float getSpeed() {
return this.speed;
}
public float getAttackDamageBonus() {
return this.damage;
}
public int getLevel() {
return this.level;
}
public int getEnchantmentValue() {
return this.enchantmentValue;
}
public Ingredient getRepairIngredient() {
return this.repairIngredient.get();
}
}

View File

@@ -0,0 +1,257 @@
package com.drmangotea.tfmg.base;
import com.drmangotea.tfmg.base.spark.ElectricSparkParticle;
import com.drmangotea.tfmg.base.spark.Spark;
import com.drmangotea.tfmg.registry.TFMGEntityTypes;
import com.simibubi.create.Create;
import com.simibubi.create.content.fluids.tank.FluidTankBlockEntity;
import com.simibubi.create.foundation.fluid.SmartFluidTank;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.LangBuilder;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.phys.AABB;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.IItemHandlerModifiable;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;
public class TFMGUtils {
public static void createFireExplosion(Level level, Entity entity, BlockPos pos, int sparkAmount, float radius) {
if (level.isClientSide && entity != null) level.broadcastEntityEvent(entity, (byte) 3);
for (int i = 0; i < sparkAmount; i++) {
float x = Create.RANDOM.nextFloat(360);
float y = Create.RANDOM.nextFloat(360);
float z = Create.RANDOM.nextFloat(360);
Spark spark = TFMGEntityTypes.SPARK.create(level);
spark.moveTo(pos.getX(), pos.getY() + 1, pos.getZ());
float f = -Mth.sin(y * ((float) Math.PI / 180F)) * Mth.cos(x * ((float) Math.PI / 180F));
float f1 = -Mth.sin((x + z) * ((float) Math.PI / 180F));
float f2 = Mth.cos(y * ((float) Math.PI / 180F)) * Mth.cos(x * ((float) Math.PI / 180F));
spark.shoot(f, f1, f2, 0.3f, 1);
level.addFreshEntity(spark);
}
level.explode(null, pos.getX(), pos.getY(), pos.getZ(), radius, Level.ExplosionInteraction.BLOCK);
}
public static void blowUpTank(FluidTankBlockEntity tank, int power) {
if (tank == null || tank.getControllerBE() == null) return;
FluidTankBlockEntity be = tank.getControllerBE();
for (int xOffset = 0; xOffset < be.getWidth(); xOffset++) {
for (int zOffset = 0; zOffset < be.getWidth(); zOffset++) {
for (int yOffset = 0; yOffset < be.getHeight(); yOffset++) {
BlockPos pos = be.getBlockPos().offset(xOffset, yOffset, zOffset);
be.getLevel().destroyBlock(pos, false);
}
}
}
createFireExplosion(be.getLevel(), null, new BlockPos(be.getBlockPos().getX() + (be.getWidth() / 2), be.getBlockPos().getY() + (be.getHeight() / 2), be.getBlockPos().getZ() + (be.getWidth() / 2)), power * 15, (float) power);
}
public static String fromId(String key) {
String s = key.replaceAll("_", " ");
s = Arrays.stream(StringUtils.splitByCharacterTypeCamelCase(s)).map(StringUtils::capitalize).collect(Collectors.joining(" "));
s = StringUtils.normalizeSpace(s);
return s;
}
public static String toHumanReadable(String key) {
String s = key.replaceAll("_", " ");
s = Arrays.stream(StringUtils.splitByCharacterTypeCamelCase(s)).map(StringUtils::capitalize).collect(Collectors.joining(" "));
s = StringUtils.normalizeSpace(s);
return s;
}
public static void spawnElectricParticles(Level level, BlockPos pos) {
if (level == null) return;
RandomSource r = level.getRandom();
for (int i = 0; i < r.nextInt(40); i++) {
float x = Create.RANDOM.nextFloat(2) - 1;
float y = Create.RANDOM.nextFloat(2) - 1;
float z = Create.RANDOM.nextFloat(2) - 1;
level.addParticle(new ElectricSparkParticle.Data(), pos.getX() + 0.5f + x, pos.getY() + 0.5f + y, pos.getZ() + 0.5f + z, x, y, z);
}
}
public static float getDistance(BlockPos pos1, BlockPos pos2, boolean _2D) {
float x = Math.abs(pos1.getX() - pos2.getX());
float y = Math.abs(pos1.getY() - pos2.getY());
float z = Math.abs(pos1.getZ() - pos2.getZ());
float distance2D = (float) Math.sqrt(x * x + z * z);
if (_2D) return distance2D;
return (float) Math.sqrt(distance2D * distance2D + y * y);
}
public static void createStorageTooltip(BlockEntity be, List<Component> tooltip) {
createFluidTooltip(be, tooltip);
createItemTooltip(be, tooltip);
}
public static boolean createFluidTooltip(BlockEntity be, List<Component> tooltip) {
LangBuilder mb = Lang.translate("generic.unit.millibuckets");
/////////
LazyOptional<IFluidHandler> handler = be.getCapability(ForgeCapabilities.FLUID_HANDLER);
Optional<IFluidHandler> resolve = handler.resolve();
if (!resolve.isPresent()) return false;
IFluidHandler tank = resolve.get();
if (tank.getTanks() == 0) return false;
Lang.translate("goggles.fluid_storage").style(ChatFormatting.GRAY).forGoggles(tooltip);
boolean isEmpty = true;
for (int i = 0; i < tank.getTanks(); i++) {
FluidStack fluidStack = tank.getFluidInTank(i);
if (fluidStack.isEmpty()) continue;
Lang.fluidName(fluidStack).style(ChatFormatting.GRAY).forGoggles(tooltip, 1);
Lang.builder().add(Lang.number(fluidStack.getAmount()).add(mb).style(ChatFormatting.DARK_GREEN)).text(ChatFormatting.GRAY, " / ").add(Lang.number(tank.getTankCapacity(i)).add(mb).style(ChatFormatting.DARK_GRAY)).forGoggles(tooltip, 1);
isEmpty = false;
}
if (tank.getTanks() > 1) {
if (isEmpty) tooltip.remove(tooltip.size() - 1);
return true;
}
if (!isEmpty) return true;
Lang.translate("gui.goggles.fluid_container.capacity").add(Lang.number(tank.getTankCapacity(0)).add(mb).style(ChatFormatting.DARK_GREEN)).style(ChatFormatting.DARK_GRAY).forGoggles(tooltip, 1);
return true;
}
public static boolean createItemTooltip(BlockEntity be, List<Component> tooltip) {
@NotNull LazyOptional<IItemHandler> handler = be.getCapability(ForgeCapabilities.ITEM_HANDLER);
Optional<IItemHandler> resolve = handler.resolve();
if (!resolve.isPresent()) return false;
IItemHandlerModifiable inventory = (IItemHandlerModifiable) resolve.get();
if (inventory.getSlots() == 0) return false;
Lang.translate("goggles.item_storage").style(ChatFormatting.GRAY).forGoggles(tooltip);
boolean isEmpty = true;
for (int i = 0; i < inventory.getSlots(); i++) {
ItemStack itemStack = inventory.getStackInSlot(i);
if (itemStack.isEmpty()) continue;
Lang.itemName(itemStack).style(ChatFormatting.DARK_GREEN).add(Component.literal(" x " + itemStack.getCount())).style(ChatFormatting.DARK_GREEN).forGoggles(tooltip, 1);
isEmpty = false;
}
if (inventory.getSlots() > 1) {
if (isEmpty) tooltip.remove(tooltip.size() - 1);
return true;
}
if (!isEmpty) return true;
Lang.translate("gui.goggles.item_storage_empty").style(ChatFormatting.DARK_GRAY).forGoggles(tooltip, 1);
return true;
}
public static String formatUnits(double n, String unit) {
if(n == 0)
return Math.round(n) + unit;
double var10000;
if (n >= 1000000000) {
var10000 = (double) Math.round((double) n / 1.0E8);
return var10000 / 10.0 + "G" + unit;
} else if (n >= 1000000) {
var10000 = (double) Math.round((double) n / 100000.0);
return var10000 / 10.0 + "M" + unit;
} else if (n >= 1000) {
var10000 = (double) Math.round((double) n / 100.0);
return var10000 / 10.0 + "k" + unit;
}
// else if (n < 0.001) {
// var10000 = (double) Math.round((double) n * 10000000.0);
// return var10000 / 10.0 + "μ" + unit;
// }
else if (n < 1) {
var10000 = (double) Math.round((double) n * 10000.0);
return var10000 / 10.0 + "m" + unit;
}
else {
return Math.round(n) + unit;
}
}
public static void drainFilteredTank(SmartFluidTank tank, int amount){
tank.setFluid(new FluidStack(tank.getFluid(),Math.max(tank.getFluidAmount()-amount,0)));
}
public static void fillFilteredTank(SmartFluidTank tank, FluidStack resource){
if(tank.getFluid().getFluid().isSame(resource.getFluid())||tank.isEmpty())
tank.setFluid(new FluidStack(resource.getFluid(),Math.min(tank.getFluidAmount()+resource.getAmount(),tank.getCapacity())));
}
public static Iterable<BlockPos> AABBtoBlockPos(AABB aabb) {
return BlockPos.betweenClosed(new BlockPos((int) aabb.minX, (int) aabb.minY, (int) aabb.minZ), new BlockPos((int) aabb.maxX, (int) aabb.maxY, (int) aabb.maxZ));
}
public static SmartFluidTank createTank(int capacity, boolean extractionAllowed, Consumer<FluidStack> updateCallback) {
return createTank(capacity, extractionAllowed, true, updateCallback, null);
}
public static SmartFluidTank createTank(int capacity, boolean extractionAllowed, boolean insertionAllowed, Consumer<FluidStack> updateCallback) {
return createTank(capacity, extractionAllowed, insertionAllowed, updateCallback, null);
}
public static SmartFluidTank createTank(int capacity, boolean extractionAllowed, boolean insertionAllowed, Consumer<FluidStack> updateCallback, Fluid validFluid) {
return new SmartFluidTank(capacity, updateCallback) {
@Override
public boolean isFluidValid(FluidStack stack) {
if (validFluid == null) return true;
return stack.getFluid().isSame(validFluid);
}
@Override
public FluidStack drain(FluidStack resource, FluidAction action) {
if (!extractionAllowed) return FluidStack.EMPTY;
return super.drain(resource, action);
}
@Override
public FluidStack drain(int maxDrain, FluidAction action) {
if (!extractionAllowed) return FluidStack.EMPTY;
return super.drain(maxDrain, action);
}
@Override
public int fill(FluidStack resource, FluidAction action) {
if (!insertionAllowed) return 0;
return super.fill(resource, action);
}
};
}
}

View File

@@ -0,0 +1,65 @@
package com.drmangotea.tfmg.base;
import com.drmangotea.tfmg.TFMG;
import com.drmangotea.tfmg.content.decoration.concrete.RebarStairsBlock;
import com.simibubi.create.foundation.data.CreateRegistrate;
import com.tterrag.registrate.builders.BlockBuilder;
import com.tterrag.registrate.builders.ItemBuilder;
import com.tterrag.registrate.providers.DataGenContext;
import com.tterrag.registrate.providers.RegistrateBlockstateProvider;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.SlabBlock;
import net.minecraft.world.level.block.StairBlock;
import net.minecraft.world.level.block.WallBlock;
import net.minecraftforge.client.model.generators.ModelFile;
public class TFMGVanillaBlockStates {
//WALL
public static void generateWallBlockState(DataGenContext<Block, WallBlock> ctx, RegistrateBlockstateProvider prov,
String name) {
prov.wallBlock(ctx.get(), name, TFMG.asResource("block/" + name));
}
public static ItemBuilder<BlockItem, BlockBuilder<WallBlock, CreateRegistrate>> transformWallItem(
ItemBuilder<BlockItem, BlockBuilder<WallBlock, CreateRegistrate>> builder, String name) {
builder.model((c, p) -> p.wallInventory(c.getName(), TFMG.asResource("block/" + name)));
return builder;
}
//STAIR
public static void generateStairBlockState(DataGenContext<Block, StairBlock> ctx, RegistrateBlockstateProvider prov,
String name) {
prov.stairsBlock(ctx.get(), name, TFMG.asResource("block/" + name));
}
public static ItemBuilder<BlockItem, BlockBuilder<StairBlock, CreateRegistrate>> transformStairItem(
ItemBuilder<BlockItem, BlockBuilder<StairBlock, CreateRegistrate>> builder, String variantName) {
return builder;
}
//SLAB
public static void generateSlabBlockState(DataGenContext<Block, SlabBlock> ctx, RegistrateBlockstateProvider prov,
String variantName) {
String name = variantName;
ResourceLocation texture = TFMG.asResource("block/" + name);
ModelFile bottom = prov.models()
.slab(name + "_bottom", texture, texture, texture);
ModelFile top = prov.models()
.slabTop(name + "_top", texture, texture, texture);
ModelFile doubleSlab = prov.models()
.getExistingFile(prov.modLoc("block/" + name));
prov.slabBlock(ctx.get(), bottom, top, doubleSlab);
}
public static ItemBuilder<BlockItem, BlockBuilder<SlabBlock, CreateRegistrate>> transformSlabItem(
ItemBuilder<BlockItem, BlockBuilder<SlabBlock, CreateRegistrate>> builder, String variantName) {
return builder;
}
}

View File

@@ -0,0 +1,43 @@
package com.drmangotea.tfmg.base;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import javax.annotation.Nullable;
public class WallMountBlock extends Block {
public static final DirectionProperty FACING = BlockStateProperties.FACING;
public WallMountBlock(Properties p_49795_) {
super(p_49795_);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder.add(FACING));
}
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext p_58126_) {
BlockState blockstate = this.defaultBlockState();
LevelReader levelreader = p_58126_.getLevel();
BlockPos blockpos = p_58126_.getClickedPos();
Direction[] adirection = p_58126_.getNearestLookingDirections();
for (Direction direction : adirection) {
Direction direction1 = direction.getOpposite();
blockstate = blockstate.setValue(FACING, direction1);
if (blockstate.canSurvive(levelreader, blockpos)) {
return blockstate;
}
}
return null;
}
}

View File

@@ -0,0 +1,70 @@
package com.drmangotea.tfmg.base.fluid;
import com.simibubi.create.AllFluids;
import com.simibubi.create.Create;
import com.simibubi.create.foundation.utility.Color;
import com.tterrag.registrate.builders.FluidBuilder;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.fluids.FluidStack;
import org.joml.Vector3f;
import java.util.function.Supplier;
public class AcidFluidType extends AllFluids.TintedFluidType {
// public static DamageSource damageSourceAcid = new DamageSource("tfmg.acid");
public AcidFluidType(Properties properties, ResourceLocation stillTexture, ResourceLocation flowingTexture) {
super(properties, stillTexture, flowingTexture);
}
private Vector3f fogColor;
private Supplier<Float> fogDistance;
public static FluidBuilder.FluidTypeFactory create(int fogColor, Supplier<Float> fogDistance) {
return (p, s, f) -> {
AcidFluidType fluidType = new AcidFluidType(p, s, f);
fluidType.fogColor = new Color(fogColor, false).asVectorF();
fluidType.fogDistance = fogDistance;
return fluidType;
};
}
@Override
protected Vector3f getCustomFogColor() {
return fogColor;
}
@Override
protected float getFogDistanceModifier() {
return fogDistance.get();
}
@Override
protected int getTintColor(FluidStack stack) {
return NO_TINT;
}
@Override
public int getTintColor(FluidState state, BlockAndTintGetter world, BlockPos pos) {
return 0x00ffffff;
}
@Override
public boolean move(FluidState state, LivingEntity entity, Vec3 movementVector, double gravity)
{
// if(Create.RANDOM.nextInt(2)==0)
// entity.hurt(damageSourceAcid,2);
return false;
}
}

View File

@@ -0,0 +1,76 @@
package com.drmangotea.tfmg.base.fluid;
import com.drmangotea.tfmg.registry.TFMGBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.FluidState;
import net.minecraftforge.fluids.ForgeFlowingFluid;
public class AsphaltFluid extends ForgeFlowingFluid {
protected AsphaltFluid(Properties properties) {
super(properties);
}
@Override
public boolean isSource(FluidState p_76140_) {
return true;
}
@Override
public int getAmount(FluidState p_164509_) {
return 8;
}
@Override
public void randomTick(Level level, BlockPos pos, FluidState p_230574_, RandomSource randomSource) {
int random = randomSource.nextInt(7) ;
if(random==2) {
level.setBlock(pos, TFMGBlocks.ASPHALT.get().defaultBlockState(), 3);
}
}
protected boolean isRandomlyTicking() {
return true;
}
//
public static class Flowing extends AsphaltFluid {
public Flowing(Properties properties) {
super(properties);
}
protected void createFluidStateDefinition(StateDefinition.Builder<Fluid, FluidState> p_76260_) {
super.createFluidStateDefinition(p_76260_);
p_76260_.add(LEVEL);
}
public int getAmount(FluidState p_76264_) {
return p_76264_.getValue(LEVEL);
}
public boolean isSource(FluidState p_76262_) {
return false;
}
}
public static class Source extends AsphaltFluid {
public Source(Properties properties) {
super(properties);
}
public int getAmount(FluidState p_76269_) {
return 8;
}
public boolean isSource(FluidState p_76267_) {
return true;
}
}
}

View File

@@ -0,0 +1,75 @@
package com.drmangotea.tfmg.base.fluid;
import com.drmangotea.tfmg.registry.TFMGBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.LiquidBlock;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.FluidState;
import net.minecraftforge.fluids.ForgeFlowingFluid;
import static com.drmangotea.tfmg.content.decoration.concrete.ConcreteloggedBlock.CONCRETELOGGED;
public class ConcreteFluid extends ForgeFlowingFluid {
protected ConcreteFluid(Properties properties) {
super(properties);
}
@Override
public boolean isSource(FluidState p_76140_) {
return true;
}
@Override
public int getAmount(FluidState p_164509_) {
return 8;
}
@Override
public void randomTick(Level level, BlockPos pos, FluidState p_230574_, RandomSource randomSource) {
if(!(level.getBlockState(pos).getBlock() instanceof LiquidBlock))
return;
int random = randomSource.nextInt(7) ;
if(random==2) {
level.setBlock(pos, TFMGBlocks.CONCRETE.block.get().defaultBlockState(), 3);
}
}
protected boolean isRandomlyTicking() {
return true;
}
public static class Flowing extends ConcreteFluid {
public Flowing(Properties properties) {
super(properties);
}
protected void createFluidStateDefinition(StateDefinition.Builder<Fluid, FluidState> p_76260_) {
super.createFluidStateDefinition(p_76260_);
p_76260_.add(LEVEL);
}
public int getAmount(FluidState p_76264_) {
return p_76264_.getValue(LEVEL);
}
public boolean isSource(FluidState p_76262_) {
return false;
}
}
public static class Source extends ConcreteFluid {
public Source(Properties properties) {
super(properties);
}
public int getAmount(FluidState p_76269_) {
return 8;
}
public boolean isSource(FluidState p_76267_) {
return true;
}
}
}

View File

@@ -0,0 +1,87 @@
package com.drmangotea.tfmg.base.fluid;
import com.drmangotea.tfmg.registry.TFMGFluids;
import com.simibubi.create.AllFluids;
import com.simibubi.create.Create;
import com.simibubi.create.foundation.utility.Color;
import com.tterrag.registrate.builders.FluidBuilder;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.damagesource.DamageSources;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.fluids.FluidStack;
import org.joml.Vector3f;
import java.util.function.Supplier;
public class HotFluidType extends TFMGFluids.SolidRenderedPlaceableFluidType {
public HotFluidType(Properties properties, ResourceLocation stillTexture, ResourceLocation flowingTexture) {
super(properties, stillTexture, flowingTexture);
}
private Vector3f fogColor;
private Supplier<Float> fogDistance;
public static FluidBuilder.FluidTypeFactory create(int fogColor, Supplier<Float> fogDistance) {
return (p, s, f) -> {
HotFluidType fluidType = new HotFluidType(p, s, f);
fluidType.fogColor = new Color(fogColor, false).asVectorF();
fluidType.fogDistance = fogDistance;
return fluidType;
};
}
@Override
protected Vector3f getCustomFogColor() {
return fogColor;
}
@Override
protected float getFogDistanceModifier() {
return fogDistance.get();
}
@Override
protected int getTintColor(FluidStack stack) {
return NO_TINT;
}
@Override
public int getTintColor(FluidState state, BlockAndTintGetter world, BlockPos pos) {
return 0x00ffffff;
}
@Override
public int getLightLevel() {
return 15;
}
@Override
public int getTemperature()
{
return 1270;
}
@Override
public int getViscosity()
{
return 50;
}
@Override
public boolean move(FluidState state, LivingEntity entity, Vec3 movementVector, double gravity)
{
entity.setDeltaMovement(entity.getDeltaMovement().scale(0.6d));
entity.setSecondsOnFire(10);
if(Create.RANDOM.nextInt(30)==27)
entity.lavaHurt();
return false;
}
public boolean canExtinguish(Entity entity)
{
return false;
}
}

View File

@@ -0,0 +1,98 @@
package com.drmangotea.tfmg.base.fluid;
import com.drmangotea.tfmg.TFMG;
import com.drmangotea.tfmg.registry.TFMGBlocks;
import com.simibubi.create.content.decoration.palettes.AllPaletteBlocks;
import com.simibubi.create.content.decoration.palettes.AllPaletteStoneTypes;
import net.minecraft.world.level.block.Blocks;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.fluids.FluidInteractionRegistry;
import net.minecraftforge.registries.ForgeRegistries;
import static com.drmangotea.tfmg.registry.TFMGFluids.*;
public class TFMGFluidInteractions {
public static void registerFluidInteractions() {
FluidInteractionRegistry.addInteraction(ForgeMod.LAVA_TYPE.get(), new FluidInteractionRegistry.InteractionInformation(
CRUDE_OIL.get().getFluidType(),
fluidState -> {
if (fluidState.isSource()) {
return TFMGBlocks.FOSSILSTONE.get().defaultBlockState();
} else {
return Blocks.SMOOTH_BASALT.defaultBlockState();
}
}
));
FluidInteractionRegistry.addInteraction(ForgeMod.LAVA_TYPE.get(), new FluidInteractionRegistry.InteractionInformation(
HEAVY_OIL.get().getFluidType(),
fluidState -> {
if (fluidState.isSource()) {
return TFMGBlocks.FOSSILSTONE.get().defaultBlockState();
} else {
return Blocks.SMOOTH_BASALT.defaultBlockState();
}
}
));
//
FluidInteractionRegistry.addInteraction(ForgeMod.LAVA_TYPE.get(), new FluidInteractionRegistry.InteractionInformation(
GASOLINE.get().getFluidType(),
fluidState -> {
if (fluidState.isSource()) {
return TFMGBlocks.FOSSILSTONE.get().defaultBlockState();
} else {
return Blocks.SMOOTH_BASALT.defaultBlockState();
}
}
));
FluidInteractionRegistry.addInteraction(ForgeMod.LAVA_TYPE.get(), new FluidInteractionRegistry.InteractionInformation(
DIESEL.get().getFluidType(),
fluidState -> {
if (fluidState.isSource()) {
return TFMGBlocks.FOSSILSTONE.get().defaultBlockState();
} else {
return Blocks.SMOOTH_BASALT.defaultBlockState();
}
}
));
FluidInteractionRegistry.addInteraction(ForgeMod.LAVA_TYPE.get(), new FluidInteractionRegistry.InteractionInformation(
NAPHTHA.get().getFluidType(),
fluidState -> {
if (fluidState.isSource()) {
return TFMGBlocks.FOSSILSTONE.get().defaultBlockState();
} else {
return Blocks.SMOOTH_BASALT.defaultBlockState();
}
}
));
FluidInteractionRegistry.addInteraction(ForgeMod.LAVA_TYPE.get(), new FluidInteractionRegistry.InteractionInformation(
KEROSENE.get().getFluidType(),
fluidState -> {
if (fluidState.isSource()) {
return TFMGBlocks.FOSSILSTONE.get().defaultBlockState();
} else {
return Blocks.SMOOTH_BASALT.defaultBlockState();
}
}
));
FluidInteractionRegistry.addInteraction(ForgeMod.LAVA_TYPE.get(), new FluidInteractionRegistry.InteractionInformation(
LUBRICATION_OIL.get().getFluidType(),
fluidState -> {
if (fluidState.isSource()) {
return TFMGBlocks.FOSSILSTONE.get().defaultBlockState();
} else {
return Blocks.SMOOTH_BASALT.defaultBlockState();
}
}
));
FluidInteractionRegistry.addInteraction(ForgeMod.LAVA_TYPE.get(), new FluidInteractionRegistry.InteractionInformation(
COOLING_FLUID.get().getFluidType(),
fluidState -> {
if (fluidState.isSource()) {
return Blocks.BASALT.defaultBlockState();
} else {
return Blocks.SMOOTH_BASALT.defaultBlockState();
}
}
));
}
}

View File

@@ -0,0 +1,262 @@
package com.drmangotea.tfmg.base.palettes;
import com.drmangotea.tfmg.base.TFMGCreativeTabs;
import com.drmangotea.tfmg.registry.TFMGPaletteStoneTypes;
import com.simibubi.create.Create;
import com.simibubi.create.foundation.data.CreateRegistrate;
import com.simibubi.create.foundation.utility.Lang;
import com.tterrag.registrate.builders.BlockBuilder;
import com.tterrag.registrate.builders.ItemBuilder;
import com.tterrag.registrate.providers.DataGenContext;
import com.tterrag.registrate.providers.RegistrateBlockstateProvider;
import com.tterrag.registrate.providers.RegistrateRecipeProvider;
import com.tterrag.registrate.util.DataIngredient;
import com.tterrag.registrate.util.entry.BlockEntry;
import com.tterrag.registrate.util.nullness.NonnullType;
import net.minecraft.data.recipes.RecipeCategory;
import net.minecraft.data.recipes.ShapedRecipeBuilder;
import net.minecraft.data.recipes.ShapelessRecipeBuilder;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.ItemTags;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.SlabBlock;
import net.minecraft.world.level.block.StairBlock;
import net.minecraft.world.level.block.WallBlock;
import net.minecraft.world.level.block.state.BlockBehaviour.Properties;
import net.minecraftforge.client.model.generators.ModelFile;
import java.util.Arrays;
import java.util.function.Supplier;
import static com.drmangotea.tfmg.TFMG.REGISTRATE;
import static com.simibubi.create.foundation.data.TagGen.pickaxeOnly;
public abstract class TFMGPaletteBlockPartial<B extends Block> {
public static final TFMGPaletteBlockPartial<StairBlock> STAIR = new Stairs();
public static final TFMGPaletteBlockPartial<SlabBlock> SLAB = new Slab(false);
public static final TFMGPaletteBlockPartial<SlabBlock> UNIQUE_SLAB = new Slab(true);
public static final TFMGPaletteBlockPartial<WallBlock> WALL = new Wall();
public static final TFMGPaletteBlockPartial<?>[] ALL_PARTIALS = { STAIR, SLAB, WALL };
public static final TFMGPaletteBlockPartial<?>[] FOR_POLISHED = { STAIR, UNIQUE_SLAB, WALL };
private String name;
protected TFMGPaletteBlockPartial(String name) {
this.name = name;
}
static {
REGISTRATE.setCreativeTab(TFMGCreativeTabs.TFMG_DECORATION);
}
public @NonnullType BlockBuilder<B, CreateRegistrate> create(String variantName, TFMGPaletteBlockPattern pattern,
BlockEntry<? extends Block> block, TFMGPaletteStoneTypes variant) {
String patternName = Lang.nonPluralId(pattern.createName(variantName));
String blockName = patternName + "_" + this.name;
BlockBuilder<B, CreateRegistrate> blockBuilder = REGISTRATE
.block(blockName, p -> createBlock(block))
.blockstate((c, p) -> generateBlockState(c, p, variantName, pattern, block))
.recipe((c, p) -> createRecipes(variant, block, c, p))
.transform(b -> transformBlock(b, variantName, pattern));
ItemBuilder<BlockItem, BlockBuilder<B, CreateRegistrate>> itemBuilder = blockBuilder.item()
.transform(b -> transformItem(b, variantName, pattern));
if (canRecycle())
itemBuilder.tag(variant.materialTag);
return itemBuilder.build();
}
protected ResourceLocation getTexture(String variantName, TFMGPaletteBlockPattern pattern, int index) {
return TFMGPaletteBlockPattern.toLocation(variantName, pattern.getTexture(index));
}
protected BlockBuilder<B, CreateRegistrate> transformBlock(BlockBuilder<B, CreateRegistrate> builder,
String variantName, TFMGPaletteBlockPattern pattern) {
getBlockTags().forEach(builder::tag);
return builder.transform(pickaxeOnly());
}
protected ItemBuilder<BlockItem, BlockBuilder<B, CreateRegistrate>> transformItem(
ItemBuilder<BlockItem, BlockBuilder<B, CreateRegistrate>> builder, String variantName,
TFMGPaletteBlockPattern pattern) {
getItemTags().forEach(builder::tag);
return builder;
}
protected boolean canRecycle() {
return true;
}
protected abstract Iterable<TagKey<Block>> getBlockTags();
protected abstract Iterable<TagKey<Item>> getItemTags();
protected abstract B createBlock(Supplier<? extends Block> block);
protected abstract void createRecipes(TFMGPaletteStoneTypes type, BlockEntry<? extends Block> patternBlock,
DataGenContext<Block, ? extends Block> c, RegistrateRecipeProvider p);
protected abstract void generateBlockState(DataGenContext<Block, B> ctx, RegistrateBlockstateProvider prov, String variantName, TFMGPaletteBlockPattern pattern, Supplier<? extends Block> block);
private static class Stairs extends TFMGPaletteBlockPartial<StairBlock> {
public Stairs() {
super("stairs");
}
@Override
protected StairBlock createBlock(Supplier<? extends Block> block) {
return new StairBlock(() -> block.get()
.defaultBlockState(), Properties.copy(block.get()));
}
@Override
protected void generateBlockState(DataGenContext<Block, StairBlock> ctx, RegistrateBlockstateProvider prov,
String variantName, TFMGPaletteBlockPattern pattern, Supplier<? extends Block> block) {
prov.stairsBlock(ctx.get(), getTexture(variantName, pattern, 0));
}
@Override
protected Iterable<TagKey<Block>> getBlockTags() {
return Arrays.asList(BlockTags.STAIRS);
}
@Override
protected Iterable<TagKey<Item>> getItemTags() {
return Arrays.asList(ItemTags.STAIRS);
}
@Override
protected void createRecipes(TFMGPaletteStoneTypes type, BlockEntry<? extends Block> patternBlock,
DataGenContext<Block, ? extends Block> c, RegistrateRecipeProvider p) {
RecipeCategory category = RecipeCategory.BUILDING_BLOCKS;
p.stairs(DataIngredient.items(patternBlock.get()), category, c::get, c.getName(), false);
p.stonecutting(DataIngredient.tag(type.materialTag), category, c::get, 1);
}
}
private static class Slab extends TFMGPaletteBlockPartial<SlabBlock> {
private boolean customSide;
public Slab(boolean customSide) {
super("slab");
this.customSide = customSide;
}
@Override
protected SlabBlock createBlock(Supplier<? extends Block> block) {
return new SlabBlock(Properties.copy(block.get()));
}
@Override
protected boolean canRecycle() {
return false;
}
@Override
protected void generateBlockState(DataGenContext<Block, SlabBlock> ctx, RegistrateBlockstateProvider prov,
String variantName, TFMGPaletteBlockPattern pattern, Supplier<? extends Block> block) {
String name = ctx.getName();
ResourceLocation mainTexture = getTexture(variantName, pattern, 0);
ResourceLocation sideTexture = customSide ? getTexture(variantName, pattern, 1) : mainTexture;
ModelFile bottom = prov.models()
.slab(name, sideTexture, mainTexture, mainTexture);
ModelFile top = prov.models()
.slabTop(name + "_top", sideTexture, mainTexture, mainTexture);
ModelFile doubleSlab;
if (customSide) {
doubleSlab = prov.models()
.cubeColumn(name + "_double", sideTexture, mainTexture);
} else {
doubleSlab = prov.models()
.getExistingFile(prov.modLoc(pattern.createName(variantName)));
}
prov.slabBlock(ctx.get(), bottom, top, doubleSlab);
}
@Override
protected Iterable<TagKey<Block>> getBlockTags() {
return Arrays.asList(BlockTags.SLABS);
}
@Override
protected Iterable<TagKey<Item>> getItemTags() {
return Arrays.asList(ItemTags.SLABS);
}
@Override
protected void createRecipes(TFMGPaletteStoneTypes type, BlockEntry<? extends Block> patternBlock,
DataGenContext<Block, ? extends Block> c, RegistrateRecipeProvider p) {
RecipeCategory category = RecipeCategory.BUILDING_BLOCKS;
p.slab(DataIngredient.items(patternBlock.get()), category, c::get, c.getName(), false);
p.stonecutting(DataIngredient.tag(type.materialTag), category, c::get, 2);
DataIngredient ingredient = DataIngredient.items(c.get());
ShapelessRecipeBuilder.shapeless(category, patternBlock.get())
.requires(ingredient)
.requires(ingredient)
.unlockedBy("has_" + c.getName(), ingredient.getCritereon(p))
.save(p, Create.ID + ":" + c.getName() + "_recycling");
}
@Override
protected BlockBuilder<SlabBlock, CreateRegistrate> transformBlock(
BlockBuilder<SlabBlock, CreateRegistrate> builder, String variantName, TFMGPaletteBlockPattern pattern) {
builder.loot((lt, block) -> lt.add(block, lt.createSlabItemTable(block)));
return super.transformBlock(builder, variantName, pattern);
}
}
public static class Wall extends TFMGPaletteBlockPartial<WallBlock> {
public Wall() {
super("wall");
}
@Override
protected WallBlock createBlock(Supplier<? extends Block> block) {
return new WallBlock(Properties.copy(block.get()));
}
@Override
protected ItemBuilder<BlockItem, BlockBuilder<WallBlock, CreateRegistrate>> transformItem(
ItemBuilder<BlockItem, BlockBuilder<WallBlock, CreateRegistrate>> builder, String variantName,
TFMGPaletteBlockPattern pattern) {
builder.model((c, p) -> p.wallInventory(c.getName(), getTexture(variantName, pattern, 0)));
return super.transformItem(builder, variantName, pattern);
}
@Override
protected void generateBlockState(DataGenContext<Block, WallBlock> ctx, RegistrateBlockstateProvider prov,
String variantName, TFMGPaletteBlockPattern pattern, Supplier<? extends Block> block) {
prov.wallBlock(ctx.get(), pattern.createName(variantName), getTexture(variantName, pattern, 0));
}
@Override
protected Iterable<TagKey<Block>> getBlockTags() {
return Arrays.asList(BlockTags.WALLS);
}
@Override
protected Iterable<TagKey<Item>> getItemTags() {
return Arrays.asList(ItemTags.WALLS);
}
@Override
protected void createRecipes(TFMGPaletteStoneTypes type, BlockEntry<? extends Block> patternBlock,
DataGenContext<Block, ? extends Block> c, RegistrateRecipeProvider p) {
RecipeCategory category = RecipeCategory.BUILDING_BLOCKS;
p.stonecutting(DataIngredient.tag(type.materialTag), category, c::get, 1);
DataIngredient ingredient = DataIngredient.items(patternBlock.get());
ShapedRecipeBuilder.shaped(category, c.get(), 6)
.pattern("XXX")
.pattern("XXX")
.define('X', ingredient)
.unlockedBy("has_" + p.safeName(ingredient), ingredient.getCritereon(p))
.save(p, p.safeId(c.get()));
}
}
}

View File

@@ -0,0 +1,263 @@
package com.drmangotea.tfmg.base.palettes;
import com.drmangotea.tfmg.TFMG;
import com.simibubi.create.content.decoration.palettes.ConnectedPillarBlock;
import com.simibubi.create.foundation.block.connected.*;
import com.tterrag.registrate.providers.DataGenContext;
import com.tterrag.registrate.providers.RegistrateBlockstateProvider;
import com.tterrag.registrate.providers.RegistrateRecipeProvider;
import com.tterrag.registrate.util.nullness.NonNullBiConsumer;
import com.tterrag.registrate.util.nullness.NonNullFunction;
import com.tterrag.registrate.util.nullness.NonNullSupplier;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.model.generators.ConfiguredModel;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
import static com.drmangotea.tfmg.base.palettes.TFMGPaletteBlockPartial.ALL_PARTIALS;
import static com.drmangotea.tfmg.base.palettes.TFMGPaletteBlockPartial.FOR_POLISHED;
import static com.drmangotea.tfmg.base.palettes.TFMGPaletteBlockPattern.PatternNameType.*;
public class TFMGPaletteBlockPattern {
public static final TFMGPaletteBlockPattern
CUT =
create("cut", PREFIX, ALL_PARTIALS),
BRICKS = create("cut_bricks", WRAP, ALL_PARTIALS).textures("brick"),
SMALL_BRICKS = create("small_bricks", WRAP, ALL_PARTIALS).textures("small_brick"),
POLISHED = create("polished_cut", PREFIX, FOR_POLISHED).textures("polished", "slab"),
LAYERED = create("layered", PREFIX).blockStateFactory(p -> p::cubeColumn)
.textures("layered", "cap")
.connectedTextures(v -> new HorizontalCTBehaviour(ct(v, CTs.LAYERED), ct(v, CTs.CAP))),
PILLAR = create("pillar", SUFFIX).blockStateFactory(p -> p::pillar)
.block(ConnectedPillarBlock::new)
.textures("pillar", "cap")
.connectedTextures(v -> new RotatedPillarCTBehaviour(ct(v, CTs.PILLAR), ct(v, CTs.CAP)))
;
public static final TFMGPaletteBlockPattern[] VANILLA_RANGE = { CUT, POLISHED, BRICKS, SMALL_BRICKS, LAYERED, PILLAR };
public static final TFMGPaletteBlockPattern[] STANDARD_RANGE = { CUT, POLISHED, BRICKS, SMALL_BRICKS, LAYERED, PILLAR };
static final String TEXTURE_LOCATION = "block/palettes/stone_types/%s/%s";
private PatternNameType nameType;
private String[] textures;
private String id;
private boolean isTranslucent;
private TagKey<Block>[] blockTags;
private TagKey<Item>[] itemTags;
private Optional<Function<String, ConnectedTextureBehaviour>> ctFactory;
private IPatternBlockStateGenerator blockStateGenerator;
private NonNullFunction<BlockBehaviour.Properties, ? extends Block> blockFactory;
private NonNullFunction<NonNullSupplier<Block>, NonNullBiConsumer<DataGenContext<Block, ? extends Block>, RegistrateRecipeProvider>> additionalRecipes;
private TFMGPaletteBlockPartial<? extends Block>[] partials;
@OnlyIn(Dist.CLIENT)
private RenderType renderType;
private static TFMGPaletteBlockPattern create(String name, PatternNameType nameType,
TFMGPaletteBlockPartial<?>... partials) {
TFMGPaletteBlockPattern pattern = new TFMGPaletteBlockPattern();
pattern.id = name;
pattern.ctFactory = Optional.empty();
pattern.nameType = nameType;
pattern.partials = partials;
pattern.additionalRecipes = $ -> NonNullBiConsumer.noop();
pattern.isTranslucent = false;
pattern.blockFactory = Block::new;
pattern.textures = new String[] { name };
pattern.blockStateGenerator = p -> p::cubeAll;
return pattern;
}
public IPatternBlockStateGenerator getBlockStateGenerator() {
return blockStateGenerator;
}
public boolean isTranslucent() {
return isTranslucent;
}
public TagKey<Block>[] getBlockTags() {
return blockTags;
}
public TagKey<Item>[] getItemTags() {
return itemTags;
}
public NonNullFunction<BlockBehaviour.Properties, ? extends Block> getBlockFactory() {
return blockFactory;
}
public TFMGPaletteBlockPartial<? extends Block>[] getPartials() {
return partials;
}
public String getTexture(int index) {
return textures[index];
}
public void addRecipes(NonNullSupplier<Block> baseBlock, DataGenContext<Block, ? extends Block> c,
RegistrateRecipeProvider p) {
additionalRecipes.apply(baseBlock)
.accept(c, p);
}
public Optional<Supplier<ConnectedTextureBehaviour>> createCTBehaviour(String variant) {
return ctFactory.map(d -> () -> d.apply(variant));
}
// Builder
private TFMGPaletteBlockPattern blockStateFactory(IPatternBlockStateGenerator factory) {
blockStateGenerator = factory;
return this;
}
private TFMGPaletteBlockPattern textures(String... textures) {
this.textures = textures;
return this;
}
private TFMGPaletteBlockPattern block(NonNullFunction<BlockBehaviour.Properties, ? extends Block> blockFactory) {
this.blockFactory = blockFactory;
return this;
}
private TFMGPaletteBlockPattern connectedTextures(Function<String, ConnectedTextureBehaviour> factory) {
this.ctFactory = Optional.of(factory);
return this;
}
// Model generators
public IBlockStateProvider cubeAll(String variant) {
ResourceLocation all = toLocation(variant, textures[0]);
return (ctx, prov) -> prov.simpleBlock(ctx.get(), prov.models()
.cubeAll(createName(variant), all));
}
public IBlockStateProvider cubeBottomTop(String variant) {
ResourceLocation side = toLocation(variant, textures[0]);
ResourceLocation bottom = toLocation(variant, textures[1]);
ResourceLocation top = toLocation(variant, textures[2]);
return (ctx, prov) -> prov.simpleBlock(ctx.get(), prov.models()
.cubeBottomTop(createName(variant), side, bottom, top));
}
public IBlockStateProvider pillar(String variant) {
ResourceLocation side = toLocation(variant, textures[0]);
ResourceLocation end = toLocation(variant, textures[1]);
return (ctx, prov) -> prov.getVariantBuilder(ctx.getEntry())
.forAllStatesExcept(state -> {
Direction.Axis axis = state.getValue(BlockStateProperties.AXIS);
if (axis == Direction.Axis.Y)
return ConfiguredModel.builder()
.modelFile(prov.models()
.cubeColumn(createName(variant), side, end))
.uvLock(false)
.build();
return ConfiguredModel.builder()
.modelFile(prov.models()
.cubeColumnHorizontal(createName(variant) + "_horizontal", side, end))
.uvLock(false)
.rotationX(90)
.rotationY(axis == Direction.Axis.X ? 90 : 0)
.build();
}, BlockStateProperties.WATERLOGGED, ConnectedPillarBlock.NORTH, ConnectedPillarBlock.SOUTH,
ConnectedPillarBlock.EAST, ConnectedPillarBlock.WEST);
}
public IBlockStateProvider cubeColumn(String variant) {
ResourceLocation side = toLocation(variant, textures[0]);
ResourceLocation end = toLocation(variant, textures[1]);
return (ctx, prov) -> prov.simpleBlock(ctx.get(), prov.models()
.cubeColumn(createName(variant), side, end));
}
// Utility
public String createName(String variant) {
if (nameType == WRAP) {
String[] split = id.split("_");
if (split.length == 2) {
String formatString = "%s_%s_%s";
return String.format(formatString, split[0], variant, split[1]);
}
}
String formatString = "%s_%s";
return nameType == SUFFIX ? String.format(formatString, variant, id) : String.format(formatString, id, variant);
}
protected static ResourceLocation toLocation(String variant, String texture) {
return TFMG.asResource(
String.format(TEXTURE_LOCATION, texture, variant + (texture.equals("cut") ? "_" : "_cut_") + texture));
}
protected static CTSpriteShiftEntry ct(String variant, CTs texture) {
ResourceLocation resLoc = texture.srcFactory.apply(variant);
ResourceLocation resLocTarget = texture.targetFactory.apply(variant);
return CTSpriteShifter.getCT(texture.type, resLoc,
new ResourceLocation(resLocTarget.getNamespace(), resLocTarget.getPath() + "_connected"));
}
@FunctionalInterface
static interface IPatternBlockStateGenerator
extends Function<TFMGPaletteBlockPattern, Function<String, IBlockStateProvider>> {
}
@FunctionalInterface
static interface IBlockStateProvider
extends NonNullBiConsumer<DataGenContext<Block, ? extends Block>, RegistrateBlockstateProvider> {
}
enum PatternNameType {
PREFIX, SUFFIX, WRAP
}
// Textures with connectability, used by Spriteshifter
public enum CTs {
PILLAR(AllCTTypes.RECTANGLE, s -> toLocation(s, "pillar")),
CAP(AllCTTypes.OMNIDIRECTIONAL, s -> toLocation(s, "cap")),
LAYERED(AllCTTypes.HORIZONTAL_KRYPPERS, s -> toLocation(s, "layered"))
;
public CTType type;
private Function<String, ResourceLocation> srcFactory;
private Function<String, ResourceLocation> targetFactory;
private CTs(CTType type, Function<String, ResourceLocation> factory) {
this(type, factory, factory);
}
private CTs(CTType type, Function<String, ResourceLocation> srcFactory,
Function<String, ResourceLocation> targetFactory) {
this.type = type;
this.srcFactory = srcFactory;
this.targetFactory = targetFactory;
}
}
}

View File

@@ -0,0 +1,93 @@
package com.drmangotea.tfmg.base.palettes;
import com.drmangotea.tfmg.base.TFMGCreativeTabs;
import com.drmangotea.tfmg.registry.TFMGPaletteStoneTypes;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.foundation.data.CreateRegistrate;
import com.tterrag.registrate.builders.BlockBuilder;
import com.tterrag.registrate.builders.ItemBuilder;
import com.tterrag.registrate.providers.ProviderType;
import com.tterrag.registrate.util.DataIngredient;
import com.tterrag.registrate.util.entry.BlockEntry;
import com.tterrag.registrate.util.nullness.NonNullSupplier;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.data.recipes.RecipeCategory;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import static com.drmangotea.tfmg.TFMG.REGISTRATE;
import static com.simibubi.create.foundation.data.CreateRegistrate.connectedTextures;
import static com.simibubi.create.foundation.data.TagGen.pickaxeOnly;
@SuppressWarnings("'onRegister(com.tterrag.registrate.util.nullness.NonNullConsumer<? super capture<? extends net.minecraft.world.level.block.Block>>)' in 'com.tterrag.registrate.builders.Builder' cannot be applied to '(com.tterrag.registrate.util.nullness.NonNullConsumer<capture<? super capture<? extends net.minecraft.world.level.block.Block>>>)'")
public class TFMGPalettesVariantEntry {
public final ImmutableList<BlockEntry<? extends Block>> registeredBlocks;
public final ImmutableList<BlockEntry<? extends Block>> registeredPartials;
static {
REGISTRATE.setCreativeTab(TFMGCreativeTabs.TFMG_DECORATION);
}
@SuppressWarnings("'onRegister(com.tterrag.registrate.util.nullness.NonNullConsumer<? super capture<? extends net.minecraft.world.level.block.Block>>)' in 'com.tterrag.registrate.builders.Builder' cannot be applied to '(com.tterrag.registrate.util.nullness.NonNullConsumer<capture<? super capture<? extends net.minecraft.world.level.block.Block>>>)'")
public TFMGPalettesVariantEntry(String name, TFMGPaletteStoneTypes paletteStoneVariants) {
ImmutableList.Builder<BlockEntry<? extends Block>> registeredBlocks = ImmutableList.builder();
ImmutableList.Builder<BlockEntry<? extends Block>> registeredPartials = ImmutableList.builder();
NonNullSupplier<Block> baseBlock = paletteStoneVariants.baseBlock;
for (TFMGPaletteBlockPattern pattern : paletteStoneVariants.variantTypes) {
BlockBuilder<? extends Block, CreateRegistrate> builder =
REGISTRATE.block(pattern.createName(name), pattern.getBlockFactory())
.initialProperties(baseBlock)
.transform(pickaxeOnly())
.blockstate(pattern.getBlockStateGenerator()
.apply(pattern)
.apply(name)::accept);
ItemBuilder<BlockItem, ? extends BlockBuilder<? extends Block, CreateRegistrate>> itemBuilder =
builder.item();
TagKey<Block>[] blockTags = pattern.getBlockTags();
if (blockTags != null)
builder.tag(blockTags);
TagKey<Item>[] itemTags = pattern.getItemTags();
if (itemTags != null)
itemBuilder.tag(itemTags);
itemBuilder.tag(paletteStoneVariants.materialTag);
if (pattern.isTranslucent())
builder.addLayer(() -> RenderType::translucent);
pattern.createCTBehaviour(name)
.ifPresent(b -> builder.onRegister(connectedTextures(b)));
builder.recipe((c, p) -> {
p.stonecutting(DataIngredient.tag(paletteStoneVariants.materialTag), RecipeCategory.BUILDING_BLOCKS, c);
pattern.addRecipes(baseBlock, c, p);
});
itemBuilder.register();
BlockEntry<? extends Block> block = builder.register();
registeredBlocks.add(block);
for (TFMGPaletteBlockPartial<? extends Block> partialBlock : pattern.getPartials())
registeredPartials.add(partialBlock.create(name, pattern, block, paletteStoneVariants)
.register());
}
REGISTRATE.addDataGenerator(ProviderType.RECIPE,
p -> p.stonecutting(DataIngredient.tag(paletteStoneVariants.materialTag), RecipeCategory.BUILDING_BLOCKS,
baseBlock));
REGISTRATE.addDataGenerator(ProviderType.ITEM_TAGS, p -> p.addTag(paletteStoneVariants.materialTag)
.add(baseBlock.get()
.asItem()));
this.registeredBlocks = registeredBlocks.build();
this.registeredPartials = registeredPartials.build();
}
}

View File

@@ -0,0 +1,117 @@
package com.drmangotea.tfmg.base.spark;
import com.drmangotea.tfmg.content.items.weapons.explosives.thermite_grenades.fire.BlueFireBlock;
import com.drmangotea.tfmg.registry.TFMGEntityTypes;
import com.drmangotea.tfmg.registry.TFMGItems;
import com.simibubi.create.content.trains.CubeParticleData;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.projectile.ThrowableProjectile;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.HitResult;
public class BlueSpark extends ThrowableProjectile {
public BlueSpark(EntityType<? extends BlueSpark> p_37391_, Level p_37392_) {
super(p_37391_, p_37392_);
}
public BlueSpark(Level p_37399_, LivingEntity p_37400_) {
super(TFMGEntityTypes.SPARK.get(), p_37400_, p_37399_);
}
public BlueSpark(Level p_37394_, double p_37395_, double p_37396_, double p_37397_) {
super(TFMGEntityTypes.BLUE_SPARK.get(), p_37395_, p_37396_, p_37397_, p_37394_);
}
@Override
protected float getGravity(){
return 0.02f;
}
@Override
protected void defineSynchedData() {}
public void tick(){
super.tick();
if (this.isInWaterOrRain()) {
this.discard();
}
if(this.level().isClientSide) {
CubeParticleData data =
new CubeParticleData(4.1f, 60.2f, 100.3f, .0125f + .0625f * random.nextFloat(), 30, false);
level().addParticle(data, this.getX(), this.getY(), this.getZ(), this.random.nextGaussian() * 0.05D, -this.getDeltaMovement().y * 0.5D, this.random.nextGaussian() * 0.05D);
}
}
private ParticleOptions getParticle() {
return ParticleTypes.FLAME;
}
public void handleEntityEvent(byte p_37402_) {
if (p_37402_ == 3) {
ParticleOptions particleoptions = this.getParticle();
for(int i = 0; i < 8; ++i) {
this.level().addParticle(particleoptions, this.getX(), this.getY(), this.getZ(), 0.0D, 0.0D, 0.0D);
}
}
}
protected void onHitBlock(BlockHitResult p_37384_) {
super.onHitBlock(p_37384_);
if (!this.level().isClientSide) {
Entity entity = this.getOwner();
if (!(entity instanceof Mob) || net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.level(), this)) {
BlockPos blockpos = p_37384_.getBlockPos().relative(p_37384_.getDirection());
if (this.level().isEmptyBlock(blockpos)) {
this.level().setBlockAndUpdate(blockpos, BlueFireBlock.getState(this.level(), blockpos));
}
}
}
}
protected void onHitEntity(EntityHitResult p_37386_) {
super.onHitEntity(p_37386_);
if (!this.level().isClientSide) {
Entity entity = p_37386_.getEntity();
Entity entity1 = this.getOwner();
int i = entity.getRemainingFireTicks();
entity.setSecondsOnFire(10);
}
}
protected void onHit(HitResult p_37406_) {
super.onHit(p_37406_);
if (!this.level().isClientSide) {
this.level().broadcastEntityEvent(this, (byte)3);
//this.level.explode(this, this.getX(), this.getY(0.0625D), this.getZ(), 2.0F, Explosion.BlockInteraction.NONE);
this.discard();
}
}
@SuppressWarnings("unchecked")
public static EntityType.Builder<?> build(EntityType.Builder<?> builder) {
EntityType.Builder<BlueSpark> entityBuilder = (EntityType.Builder<BlueSpark>) builder;
return entityBuilder.sized(.25f, .25f);
}
}

View File

@@ -0,0 +1,56 @@
package com.drmangotea.tfmg.base.spark;
import com.drmangotea.tfmg.TFMG;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Axis;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
@OnlyIn(Dist.CLIENT)
public class BlueSparkRenderer extends EntityRenderer<BlueSpark> {
private static final ResourceLocation TEXTURE_LOCATION = TFMG.asResource("textures/entity/blue_spark.png");
private static final RenderType RENDER_TYPE = RenderType.entityCutoutNoCull(TEXTURE_LOCATION);
public BlueSparkRenderer(EntityRendererProvider.Context p_173962_) {
super(p_173962_);
}
protected int getBlockLightLevel(BlueSpark p_114087_, BlockPos p_114088_) {
return 15;
}
public void render(BlueSpark p_114080_, float p_114081_, float p_114082_, PoseStack p_114083_, MultiBufferSource p_114084_, int p_114085_) {
p_114083_.pushPose();
p_114083_.scale(0.5F, 0.5F, 0.5F);
p_114083_.mulPose(this.entityRenderDispatcher.cameraOrientation());
p_114083_.mulPose(Axis.YP.rotationDegrees(180.0F));
PoseStack.Pose posestack$pose = p_114083_.last();
Matrix4f matrix4f = posestack$pose.pose();
Matrix3f matrix3f = posestack$pose.normal();
VertexConsumer vertexconsumer = p_114084_.getBuffer(RENDER_TYPE);
vertex(vertexconsumer, matrix4f, matrix3f, p_114085_, 0.0F, 0, 0, 1);
vertex(vertexconsumer, matrix4f, matrix3f, p_114085_, 1.0F, 0, 1, 1);
vertex(vertexconsumer, matrix4f, matrix3f, p_114085_, 1.0F, 1, 1, 0);
vertex(vertexconsumer, matrix4f, matrix3f, p_114085_, 0.0F, 1, 0, 0);
p_114083_.popPose();
super.render(p_114080_, p_114081_, p_114082_, p_114083_, p_114084_, p_114085_);
}
private static void vertex(VertexConsumer p_114090_, Matrix4f p_114091_, Matrix3f p_114092_, int p_114093_, float p_114094_, int p_114095_, int p_114096_, int p_114097_) {
p_114090_.vertex(p_114091_, p_114094_ - 0.5F, (float)p_114095_ - 0.25F, 0.0F).color(255, 255, 255, 255).uv((float)p_114096_, (float)p_114097_).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(p_114093_).normal(p_114092_, 0.0F, 1.0F, 0.0F).endVertex();
}
public ResourceLocation getTextureLocation(BlueSpark p_114078_) {
return TEXTURE_LOCATION;
}
}

View File

@@ -0,0 +1,56 @@
package com.drmangotea.tfmg.base.spark;
import com.drmangotea.tfmg.registry.TFMGParticleTypes;
import com.simibubi.create.content.equipment.bell.BasicParticleData;
import com.simibubi.create.content.equipment.bell.CustomRotationParticle;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.particle.SpriteSet;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleType;
public class ElectricSparkParticle extends CustomRotationParticle {
private final SpriteSet animatedSprite;
protected int startTicks;
protected int endTicks;
protected int numLoops;
protected int startFrames = 17;
protected int loopFrames = 16;
protected int endFrames = 20;
protected int totalFrames = 53;
public ElectricSparkParticle(ClientLevel worldIn, double x, double y, double z, double vx, double vy, double vz,
SpriteSet spriteSet, ParticleOptions data) {
super(worldIn, x, y, z, spriteSet, 0);
this.animatedSprite = spriteSet;
this.quadSize = 0.5f;
this.setSize(this.quadSize, this.quadSize);
this.loopLength = loopFrames + (int) (this.random.nextFloat() * 5f - 4f);
this.startTicks = startFrames + (int) (this.random.nextFloat() * 5f - 4f);
this.endTicks = endFrames + (int) (this.random.nextFloat() * 5f - 4f);
this.numLoops = (int) (1f + this.random.nextFloat() * 2f);
this.setFrame(0);
this.mirror = this.random.nextBoolean();
}
public void setFrame(int frame) {
if (frame >= 0 && frame < totalFrames)
setSprite(animatedSprite.get(frame, totalFrames));
}
public static class Data extends BasicParticleData<ElectricSparkParticle> {
@Override
public IBasicParticleFactory<ElectricSparkParticle> getBasicFactory() {
return (worldIn, x, y, z, vx, vy, vz, spriteSet) -> new ElectricSparkParticle(worldIn, x, y, z, vx, vy, vz,
spriteSet, this);
}
@Override
public ParticleType<?> getType() {
return TFMGParticleTypes.ELECTRIC_SPARK.get();
}
}
}

View File

@@ -0,0 +1,103 @@
package com.drmangotea.tfmg.base.spark;
import com.drmangotea.tfmg.content.items.weapons.explosives.thermite_grenades.fire.GreenFireBlock;
import com.drmangotea.tfmg.registry.TFMGEntityTypes;
import com.drmangotea.tfmg.registry.TFMGItems;
import com.simibubi.create.content.trains.CubeParticleData;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.projectile.ThrowableProjectile;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.HitResult;
public class GreenSpark extends ThrowableProjectile {
public GreenSpark(EntityType<? extends GreenSpark> p_37391_, Level p_37392_) {
super(p_37391_, p_37392_);
}
public GreenSpark(Level p_37399_, LivingEntity p_37400_) {
super(TFMGEntityTypes.SPARK.get(), p_37400_, p_37399_);
}
public GreenSpark(Level level, double p_37395_, double p_37396_, double p_37397_) {
super(TFMGEntityTypes.SPARK.get(), p_37395_, p_37396_, p_37397_, level);
}
@Override
protected float getGravity(){
return 0.02f;
}
@Override
protected void defineSynchedData() {}
public void tick(){
super.tick();
if (this.isInWaterOrRain()) {
this.discard();
}
if(this.level().isClientSide) {
CubeParticleData data =
new CubeParticleData(0.01f, 100.25f, 20.1f, .0125f + .0625f * random.nextFloat(), 30, true);
level().addParticle(data, this.getX(), this.getY(), this.getZ(), this.random.nextGaussian() * 0.05D, -this.getDeltaMovement().y * 0.5D, this.random.nextGaussian() * 0.05D);
}
}
private ParticleOptions getParticle() {
return ParticleTypes.FLAME;
}
public void handleEntityEvent(byte p_37402_) {
if (p_37402_ == 3) {
ParticleOptions particleoptions = this.getParticle();
for(int i = 0; i < 8; ++i) {
this.level().addParticle(particleoptions, this.getX(), this.getY(), this.getZ(), 0.0D, 0.0D, 0.0D);
}
}
}
protected void onHitBlock(BlockHitResult p_37384_) {
super.onHitBlock(p_37384_);
if (!this.level().isClientSide) {
Entity entity = this.getOwner();
if (!(entity instanceof Mob) || net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.level(), this)) {
BlockPos blockpos = p_37384_.getBlockPos().relative(p_37384_.getDirection());
if (this.level().isEmptyBlock(blockpos)) {
this.level().setBlockAndUpdate(blockpos, GreenFireBlock.getState(this.level(), blockpos));
}
}
}
}
protected void onHitEntity(EntityHitResult p_37386_) {
super.onHitEntity(p_37386_);
if (!this.level().isClientSide) {
Entity entity = p_37386_.getEntity();
entity.setSecondsOnFire(10);
}
}
protected void onHit(HitResult p_37406_) {
super.onHit(p_37406_);
if (!this.level().isClientSide) {
this.level().broadcastEntityEvent(this, (byte)3);
this.discard();
}
}
@SuppressWarnings("unchecked")
public static EntityType.Builder<?> build(EntityType.Builder<?> builder) {
EntityType.Builder<GreenSpark> entityBuilder = (EntityType.Builder<GreenSpark>) builder;
return entityBuilder.sized(.25f, .25f);
}
}

View File

@@ -0,0 +1,56 @@
package com.drmangotea.tfmg.base.spark;
import com.drmangotea.tfmg.TFMG;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Axis;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
@OnlyIn(Dist.CLIENT)
public class GreenSparkRenderer extends EntityRenderer<GreenSpark> {
private static final ResourceLocation TEXTURE_LOCATION = TFMG.asResource("textures/entity/green_spark.png");
private static final RenderType RENDER_TYPE = RenderType.entityCutoutNoCull(TEXTURE_LOCATION);
public GreenSparkRenderer(EntityRendererProvider.Context p_173962_) {
super(p_173962_);
}
protected int getBlockLightLevel(GreenSpark p_114087_, BlockPos p_114088_) {
return 15;
}
public void render(GreenSpark p_114080_, float p_114081_, float p_114082_, PoseStack p_114083_, MultiBufferSource p_114084_, int p_114085_) {
p_114083_.pushPose();
p_114083_.scale(0.5F, 0.5F, 0.5F);
p_114083_.mulPose(this.entityRenderDispatcher.cameraOrientation());
p_114083_.mulPose(Axis.YP.rotationDegrees(180.0F));
PoseStack.Pose posestack$pose = p_114083_.last();
Matrix4f matrix4f = posestack$pose.pose();
Matrix3f matrix3f = posestack$pose.normal();
VertexConsumer vertexconsumer = p_114084_.getBuffer(RENDER_TYPE);
vertex(vertexconsumer, matrix4f, matrix3f, p_114085_, 0.0F, 0, 0, 1);
vertex(vertexconsumer, matrix4f, matrix3f, p_114085_, 1.0F, 0, 1, 1);
vertex(vertexconsumer, matrix4f, matrix3f, p_114085_, 1.0F, 1, 1, 0);
vertex(vertexconsumer, matrix4f, matrix3f, p_114085_, 0.0F, 1, 0, 0);
p_114083_.popPose();
super.render(p_114080_, p_114081_, p_114082_, p_114083_, p_114084_, p_114085_);
}
private static void vertex(VertexConsumer p_114090_, Matrix4f p_114091_, Matrix3f p_114092_, int p_114093_, float p_114094_, int p_114095_, int p_114096_, int p_114097_) {
p_114090_.vertex(p_114091_, p_114094_ - 0.5F, (float)p_114095_ - 0.25F, 0.0F).color(255, 255, 255, 255).uv((float)p_114096_, (float)p_114097_).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(p_114093_).normal(p_114092_, 0.0F, 1.0F, 0.0F).endVertex();
}
public ResourceLocation getTextureLocation(GreenSpark p_114078_) {
return TEXTURE_LOCATION;
}
}

View File

@@ -0,0 +1,100 @@
package com.drmangotea.tfmg.base.spark;
import com.drmangotea.tfmg.registry.TFMGEntityTypes;
import com.drmangotea.tfmg.registry.TFMGItems;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.projectile.ThrowableProjectile;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BaseFireBlock;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.HitResult;
public class Spark extends ThrowableProjectile {
public Spark(EntityType<? extends Spark> p_37391_, Level p_37392_) {
super(p_37391_, p_37392_);
}
public Spark(Level p_37399_, LivingEntity p_37400_) {
super(TFMGEntityTypes.SPARK.get(), p_37400_, p_37399_);
}
public Spark(Level p_37394_, double p_37395_, double p_37396_, double p_37397_) {
super(TFMGEntityTypes.SPARK.get(), p_37395_, p_37396_, p_37397_, p_37394_);
}
@Override
protected float getGravity(){
return 0.02f;
}
@Override
protected void defineSynchedData() {}
public void tick(){
super.tick();
if (this.isInWaterOrRain()) {
this.discard();
}
if(this.level().isClientSide) {
this.level().addParticle(ParticleTypes.FLAME, this.getX(), this.getY(), this.getZ(), this.random.nextGaussian() * 0.05D, -this.getDeltaMovement().y * 0.5D, this.random.nextGaussian() * 0.05D);
}
}
protected Item getDefaultItem() {
return TFMGItems.THERMITE_GRENADE.get();
}
private ParticleOptions getParticle() {
return ParticleTypes.FLAME;
}
public void handleEntityEvent(byte p_37402_) {
if (p_37402_ == 3) {
ParticleOptions particleoptions = this.getParticle();
for(int i = 0; i < 8; ++i) {
this.level().addParticle(particleoptions, this.getX(), this.getY(), this.getZ(), 0.0D, 0.0D, 0.0D);
}
}
}
protected void onHitBlock(BlockHitResult p_37384_) {
super.onHitBlock(p_37384_);
if (!this.level().isClientSide) {
Entity entity = this.getOwner();
if (!(entity instanceof Mob) || net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.level(), this)) {
BlockPos blockpos = p_37384_.getBlockPos().relative(p_37384_.getDirection());
if (this.level().isEmptyBlock(blockpos)) {
this.level().setBlockAndUpdate(blockpos, BaseFireBlock.getState(this.level(), blockpos));
}
}
}
}
protected void onHitEntity(EntityHitResult p_37386_) {
super.onHitEntity(p_37386_);
if (!this.level().isClientSide) {
Entity entity = p_37386_.getEntity();
entity.setSecondsOnFire(10);
}
}
protected void onHit(HitResult p_37406_) {
super.onHit(p_37406_);
if (!this.level().isClientSide) {
this.level().broadcastEntityEvent(this, (byte)3);
this.discard();
}
}
@SuppressWarnings("unchecked")
public static EntityType.Builder<?> build(EntityType.Builder<?> builder) {
EntityType.Builder<Spark> entityBuilder = (EntityType.Builder<Spark>) builder;
return entityBuilder.sized(.25f, .25f);
}
}

View File

@@ -0,0 +1,52 @@
package com.drmangotea.tfmg.base.spark;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Axis;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
@OnlyIn(Dist.CLIENT)
public class SparkRenderer extends EntityRenderer<Spark> {
private static final ResourceLocation TEXTURE_LOCATION = new ResourceLocation("textures/particle/lava.png");
private static final RenderType RENDER_TYPE = RenderType.entityCutoutNoCull(TEXTURE_LOCATION);
public SparkRenderer(EntityRendererProvider.Context p_173962_) {
super(p_173962_);
}
protected int getBlockLightLevel(Spark p_114087_, BlockPos p_114088_) {
return 15;
}
public void render(Spark p_114080_, float p_114081_, float p_114082_, PoseStack p_114083_, MultiBufferSource p_114084_, int p_114085_) {
p_114083_.pushPose();
p_114083_.scale(0.5F, 0.5F, 0.5F);
p_114083_.mulPose(this.entityRenderDispatcher.cameraOrientation());
p_114083_.mulPose(Axis.YP.rotationDegrees(180.0F));
PoseStack.Pose posestack$pose = p_114083_.last();
Matrix4f matrix4f = posestack$pose.pose();
Matrix3f matrix3f = posestack$pose.normal();
VertexConsumer vertexconsumer = p_114084_.getBuffer(RENDER_TYPE);
vertex(vertexconsumer, matrix4f, matrix3f, p_114085_, 0.0F, 0, 0, 1);
vertex(vertexconsumer, matrix4f, matrix3f, p_114085_, 1.0F, 0, 1, 1);
vertex(vertexconsumer, matrix4f, matrix3f, p_114085_, 1.0F, 1, 1, 0);
vertex(vertexconsumer, matrix4f, matrix3f, p_114085_, 0.0F, 1, 0, 0);
p_114083_.popPose();
super.render(p_114080_, p_114081_, p_114082_, p_114083_, p_114084_, p_114085_);
}
private static void vertex(VertexConsumer p_114090_, Matrix4f p_114091_, Matrix3f p_114092_, int p_114093_, float p_114094_, int p_114095_, int p_114096_, int p_114097_) {
p_114090_.vertex(p_114091_, p_114094_ - 0.5F, (float)p_114095_ - 0.25F, 0.0F).color(255, 255, 255, 255).uv((float)p_114096_, (float)p_114097_).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(p_114093_).normal(p_114092_, 0.0F, 1.0F, 0.0F).endVertex();
}
public ResourceLocation getTextureLocation(Spark p_114078_) {
return TEXTURE_LOCATION;
}
}

View File

@@ -0,0 +1,18 @@
package com.drmangotea.tfmg.config;
import com.simibubi.create.foundation.config.ConfigBase;
public class DepositConfig extends ConfigBase {
public final ConfigInt depositMaxReserves = i(10000, 1000, "depositMaxReserves", Comments.depositMaxReserves);
public final ConfigBool infiniteDeposits = b(false, "infiniteDeposits", Comments.infiniteDeposits);
@Override
public String getName() {
return "deposits";
}
private static class Comments {
static String depositMaxReserves = "Sets the maximum oil reserves a deposit can have.";
static String infiniteDeposits = "Makes deposits bottomless.";
}
}

View File

@@ -0,0 +1,59 @@
package com.drmangotea.tfmg.config;
import com.simibubi.create.foundation.config.ConfigBase;
public class MachineConfig extends ConfigBase {
public final ConfigFloat largeGeneratorFeModifier = f(4, 0, "largeGeneratorFEModifier", Comments.largeGenerator);
public final ConfigFloat smallGeneratorFeModifier = f(0.4f, 0, "smallGeneratorFEModifier", Comments.generator);
public final ConfigInt blastFurnaceMaxHeight = i(10, 3, "blastFurnaceMaxHeight", Comments.blastFurnaceHeight);
public final ConfigFloat blastFurnaceHeightSpeedModifier = f(1f, 0.1f, "blastFurnaceHeightSpeedModifier", Comments.blastFurnaceHeightSpeedModifier);
public final ConfigInt blastFurnaceFuelConsumption = i(600, 1, "blastFurnaceFuelConsumption", Comments.blastFurnaceFuelConsumption);
public final ConfigInt electricMotorMinimumPower = i(3000, 1, "electricMotorMinimumPower", Comments.electricMotorMinimumPower);
public final ConfigInt electricMotorMinimumVoltage = i(150, 1, "electricMotorMinimumVoltage", Comments.electricMotorMinimumVoltage);
public final ConfigFloat electricMotorPowerUsageModifier = f(1, 0, "electricMotorPowerUsageModifier", Comments.electricMotorPowerUsageModifier);
public final ConfigInt cokeOvenMaxSize = i(5, 1, "cokeOvenMaxSize", Comments.cokeOvenMaxSize);
public final ConfigInt accumulatorStorage = i(100000, 1, "accumulatorStorage", Comments.accumulatorStorage);
public final ConfigInt accumulatorVoltage = i(12, 1, "accumulatorVoltage", Comments.accumulatorVoltage);
public final ConfigInt accumulatorMaxAmpOutput = i(20, 1, "accumulatorMaxAmpOutput", Comments.accumulatorMaxAmpOutput);
public final ConfigInt accumulatorChargingRate = i(100, 1, "accumulatorChargingRate", Comments.accumulatorChargingRate);
public final ConfigFloat FEtoWattTickConversionRate = f(1, 0, "FEtoWattTickConversionRate", Comments.FEtoWattTickConversionRate);
public final ConfigBool fireboxExhaustRequirement = b(true, "fireboxExhaustRequirement", Comments.fireboxExhaustRequirement);
public final ConfigInt fireboxFuelConsumption = i(100, 1, "fireboxFuelConsumption", Comments.fireboxFuelConsumption);
public final ConfigInt graphiteElectrodeCurrent = i(10, 1, "graphiteElectrodeCurrent", Comments.graphiteElectrodeCurrent);
public final ConfigInt electrolysisMinimumCurrent = i(5, 1, "electrolysisMinimumCurrent", Comments.electrolysisMinimumCurrent);
public final ConfigInt engineMaxLength = i(5, 1, "engineMaxLength", Comments.engineMaxLength);
public final ConfigInt surfaceScannerScanDepth = i(-64, -512, "surfaceScannerScanDepth", Comments.surfaceScannerScanDepth);
public final ConfigInt polarizerItemChargingRate = i(1000, 1, "polarizerItemChargingRate", Comments.polarizerItemChargingRate);
@Override
public String getName() {
return "machines";
}
private static class Comments {
static String largeGenerator = "Changes the FE production of large generators.";
static String generator = "Changes the FE production of small generators.";
static String blastFurnaceHeight = "Changes the maximum height of the blast furnace.";
static String blastFurnaceHeightSpeedModifier = "Sets the maximum time that can be saved by increasing blast furnace height.";
static String blastFurnaceFuelConsumption = "Determines how many ticks does it take to consume one fuel.";
static String electricMotorMinimumPower = "Determines the minimum power an electric motor can run on.";
static String electricMotorMinimumVoltage = "Determines the minimum voltage an electric motor can run on.";
static String electricMotorPowerUsageModifier = "Changes the power usage of electric motors.";
static String cokeOvenMaxSize = "Determines the maximum size of coke ovens.";
static String accumulatorStorage = "Determines the storage space of accumulators.";
static String accumulatorVoltage = "Determines the voltage accumulators output.";
static String accumulatorMaxAmpOutput = "Sets the maximum amperage an accumulator can provide.";
static String accumulatorChargingRate = "Sets the maximum charging rate of accumulators.";
static String fireboxExhaustRequirement = "If set to true,fireboxes will require exhaust management.";
static String fireboxFuelConsumption = "Determines the amount of fuel a firebox needs to run for 3 seconds.";
static String graphiteElectrodeCurrent = "The minimum electric current that will make graphite electrodes superheated.";
static String electrolysisMinimumCurrent = "The minimum electric current that will make electrolyzers operational.";
static String engineMaxLength = "The maximum length of engines.";
static String surfaceScannerScanDepth = "Y level surface scanner scan at.";
static String FEtoWattTickConversionRate = "How much Forge Energy is in one watt-tick.";
static String polarizerItemChargingRate = "How much FE can polarizer charge per tick.";
}
}

View File

@@ -0,0 +1,110 @@
package com.drmangotea.tfmg.config;
import com.drmangotea.tfmg.TFMG;
import com.simibubi.create.content.kinetics.BlockStressDefaults;
import com.simibubi.create.content.kinetics.BlockStressValues.IStressValueProvider;
import com.simibubi.create.foundation.config.ConfigBase;
import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.RegisteredObjects;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
import net.minecraftforge.common.ForgeConfigSpec.Builder;
import net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
public class StressConfig extends ConfigBase implements IStressValueProvider {
private final Map<ResourceLocation, ConfigValue<Double>> capacities = new HashMap<>();
private final Map<ResourceLocation, ConfigValue<Double>> impacts = new HashMap<>();
@Override
public void registerAll(Builder builder) {
builder.comment(".", Comments.su, Comments.impact)
.push("impact");
BlockStressDefaults.DEFAULT_IMPACTS.forEach((r, i) -> {
if (r.getNamespace()
.equals(TFMG.MOD_ID))
getImpacts().put(r, builder.define(r.getPath(), i));
});
builder.pop();
builder.comment(".", Comments.su, Comments.capacity)
.push("capacity");
BlockStressDefaults.DEFAULT_CAPACITIES.forEach((r, i) -> {
if (r.getNamespace()
.equals(TFMG.MOD_ID))
getCapacities().put(r, builder.define(r.getPath(), i));
});
builder.pop();
}
@Override
public String getName() {
return "stressValues";
}
@Override
public double getImpact(Block block) {
block = redirectValues(block);
ResourceLocation key = RegisteredObjects.getKeyOrThrow(block);
ConfigValue<Double> value = getImpacts().get(key);
if (value != null) return value.get();
return 0;
}
@Override
public double getCapacity(Block block) {
block = redirectValues(block);
ResourceLocation key = RegisteredObjects.getKeyOrThrow(block);
ConfigValue<Double> value = getCapacities().get(key);
if (value != null) return value.get();
return 0;
}
@Override
public boolean hasImpact(Block block) {
block = redirectValues(block);
ResourceLocation key = RegisteredObjects.getKeyOrThrow(block);
return getImpacts().containsKey(key);
}
@Override
public boolean hasCapacity(Block block) {
block = redirectValues(block);
ResourceLocation key = RegisteredObjects.getKeyOrThrow(block);
return getCapacities().containsKey(key);
}
@Nullable
@Override
public Couple<Integer> getGeneratedRPM(Block block) {
block = redirectValues(block);
ResourceLocation key = RegisteredObjects.getKeyOrThrow(block);
Supplier<Couple<Integer>> supplier = BlockStressDefaults.GENERATOR_SPEEDS.get(key);
if (supplier == null) return null;
return supplier.get();
}
protected Block redirectValues(Block block) {
return block;
}
public Map<ResourceLocation, ConfigValue<Double>> getImpacts() {
return impacts;
}
public Map<ResourceLocation, ConfigValue<Double>> getCapacities() {
return capacities;
}
private static class Comments {
static String su = "[in Stress Units]";
static String impact = "Configure the individual stress impact of mechanical blocks. Note that this cost is doubled for every speed increase it receives";
static String capacity = "Configure how much stress a source can accommodate for.";
}
}

View File

@@ -0,0 +1,16 @@
package com.drmangotea.tfmg.config;
import com.simibubi.create.foundation.config.ConfigBase;
public class TFMGCommonConfig extends ConfigBase {
public final MachineConfig machines = nested(0, MachineConfig::new, "Config options for TFMG's machinery");
public final DepositConfig deposits = nested(1, DepositConfig::new, "Oil Deposit Config");
@Override
public String getName() {
return "common";
}
}

View File

@@ -0,0 +1,78 @@
package com.drmangotea.tfmg.config;
import com.simibubi.create.content.kinetics.BlockStressValues;
import com.simibubi.create.foundation.config.ConfigBase;
import com.simibubi.create.infrastructure.config.CCommon;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.config.ModConfigEvent;
import org.apache.commons.lang3.tuple.Pair;
import java.util.EnumMap;
import java.util.Map;
import java.util.function.Supplier;
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
public class TFMGConfigs {
private static final Map<ModConfig.Type, ConfigBase> CONFIGS = new EnumMap<>(ModConfig.Type.class);
private static TFMGServerConfig server;
private static TFMGCommonConfig common;
public static TFMGServerConfig server() {
return server;
}
public static TFMGCommonConfig common() {
return common;
}
public static ConfigBase byType(ModConfig.Type type) {
return CONFIGS.get(type);
}
private static <T extends ConfigBase> T register(Supplier<T> factory, ModConfig.Type side) {
Pair<T, ForgeConfigSpec> specPair = new ForgeConfigSpec.Builder().configure(builder -> {
T config = factory.get();
config.registerAll(builder);
return config;
});
T config = specPair.getLeft();
config.specification = specPair.getRight();
CONFIGS.put(side, config);
return config;
}
@SuppressWarnings("removal")
public static void register(ModLoadingContext context) {
server = register(TFMGServerConfig::new, ModConfig.Type.SERVER);
common = register(TFMGCommonConfig::new, ModConfig.Type.COMMON);
for (Map.Entry<ModConfig.Type, ConfigBase> pair : CONFIGS.entrySet())
context.registerConfig(pair.getKey(), pair.getValue().specification);
BlockStressValues.registerProvider(context.getActiveNamespace(), server().stressValues);
}
@SubscribeEvent
public static void onLoad(ModConfigEvent.Loading event) {
for (ConfigBase config : CONFIGS.values())
if (config.specification == event.getConfig()
.getSpec())
config.onLoad();
}
@SubscribeEvent
public static void onReload(ModConfigEvent.Reloading event) {
for (ConfigBase config : CONFIGS.values())
if (config.specification == event.getConfig()
.getSpec())
config.onReload();
}
}

View File

@@ -0,0 +1,15 @@
package com.drmangotea.tfmg.config;
import com.simibubi.create.foundation.config.ConfigBase;
public class TFMGServerConfig extends ConfigBase {
public final StressConfig stressValues = nested(0, StressConfig::new, "Fine tune the kinetic stats of individual components");
@Override
public String getName() {
return "server";
}
}

View File

@@ -0,0 +1,46 @@
package com.drmangotea.tfmg.content.decoration;
import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.RotatedPillarBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.material.FluidState;
public class FrameBlock extends Block implements ProperWaterloggedBlock {
public FrameBlock(Properties p_55926_) {
super(p_55926_);
this.registerDefaultState(this.defaultBlockState().setValue(WATERLOGGED, false));
}
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> p_55933_) {
p_55933_.add(WATERLOGGED);
}
@Override
public FluidState getFluidState(BlockState pState) {
return fluidState(pState);
}
@Override
public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState,
LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) {
updateWater(pLevel, pState, pCurrentPos);
return pState;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext pContext) {
return withWater(super.getStateForPlacement(pContext), pContext);
}
}

View File

@@ -0,0 +1,101 @@
package com.drmangotea.tfmg.content.decoration;
import com.drmangotea.tfmg.base.WallMountBlock;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.SimpleWaterloggedBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import java.util.Map;
import java.util.Properties;
public class LithiumTorchBlock extends WallMountBlock implements SimpleWaterloggedBlock {
public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
private static final Map<Direction, VoxelShape> SHAPE = Maps.newEnumMap(ImmutableMap.of(Direction.NORTH, Block.box(5.5D, 3.0D, 11.0D, 10.5D, 13.0D, 16.0D), Direction.SOUTH, Block.box(5.5D, 3.0D, 0.0D, 10.5D, 13.0D, 5.0D), Direction.WEST, Block.box(11.0D, 3.0D, 5.5D, 16.0D, 13.0D, 10.5D), Direction.EAST, Block.box(0.0D, 3.0D, 5.5D, 5.0D, 13.0D, 10.5D),Direction.UP,Block.box(6.0D, 0.0D, 6.0D, 10.0D, 10.0D, 10.0D),Direction.DOWN,Block.box(6.0D, 6.0D, 6.0D, 10.0D, 16.0D, 10.0D)));
public LithiumTorchBlock(Properties pProperties) {
super(pProperties);
}
public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) {
return SHAPE.get(pState.getValue(FACING));
}
@Override
public FluidState getFluidState(BlockState p_51475_) {
return p_51475_.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(p_51475_);
}
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> p_55125_) {
p_55125_.add(WATERLOGGED,FACING);
}
public void animateTick(BlockState pState, Level pLevel, BlockPos pPos, RandomSource pRandom) {
Direction direction = pState.getValue(FACING);
double d0 = (double)pPos.getX() + 0.5D;
double d1 = (double)pPos.getY() + 0.7D;
double d2 = (double)pPos.getZ() + 0.5D;
double d3 = 0.22D;
double d4 = 0.27D;
Direction direction1 = direction.getOpposite();
double y;
if(direction == Direction.DOWN) {
y = d1 - 0.22D * (double) direction1.getStepY();
}else {
y = d1 + 0.11D;
}
pLevel.addParticle(ParticleTypes.SMOKE, d0 + 0.27D * (double)direction1.getStepX(), y, d2 + 0.27D * (double)direction1.getStepZ(), 0.0D, 0.0D, 0.0D);
pLevel.addParticle(ParticleTypes.FLAME, d0 + 0.27D * (double)direction1.getStepX(), y, d2 + 0.27D * (double)direction1.getStepZ(), 0.0D, 0.0D, 0.0D);
}
public BlockState updateShape(BlockState pState, Direction pFacing, BlockState pFacingState, LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pFacingPos) {
if (pState.getValue(WATERLOGGED)) {
pLevel.scheduleTick(pCurrentPos, Fluids.WATER, Fluids.WATER.getTickDelay(pLevel));
}
return !this.canSurvive(pState, pLevel, pCurrentPos) ? Blocks.AIR.defaultBlockState() : pState;
}
public boolean canSurvive(BlockState pState, LevelReader pLevel, BlockPos pPos) {
Direction direction = pState.getValue(FACING);
BlockPos blockpos = pPos.relative(direction.getOpposite());
BlockState blockstate = pLevel.getBlockState(blockpos);
return blockstate.isFaceSturdy(pLevel, blockpos, direction);
}
public BlockState getStateForPlacement(BlockPlaceContext pContext) {
FluidState fluidstate = pContext.getLevel().getFluidState(pContext.getClickedPos());
boolean flag = fluidstate.getType() == Fluids.WATER;
return this.defaultBlockState().setValue(FACING, pContext.getClickedFace()).setValue(WATERLOGGED,flag);
}
}

View File

@@ -0,0 +1,42 @@
package com.drmangotea.tfmg.content.decoration;
import com.drmangotea.tfmg.base.WallMountBlock;
import com.simibubi.create.foundation.data.SpecialBlockStateGen;
import com.tterrag.registrate.providers.DataGenContext;
import com.tterrag.registrate.providers.RegistrateBlockstateProvider;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.generators.ModelFile;
import static com.simibubi.create.foundation.data.AssetLookup.partialBaseModel;
public class LithiumTorchGenerator extends SpecialBlockStateGen {
@Override
protected int getXRotation(BlockState state) {
return state.getValue(LithiumTorchBlock.FACING)== Direction.DOWN ? 180 : 0;
}
@Override
protected int getYRotation(BlockState state) {
return switch (state.getValue(WallMountBlock.FACING)) {
case NORTH -> 270;
case SOUTH -> 90;
case WEST -> 180;
case EAST -> 0;
case DOWN -> 0;
case UP -> 0;
};
}
@Override
public <T extends Block> ModelFile getModel(DataGenContext<Block, T> ctx, RegistrateBlockstateProvider prov,
BlockState state) {
return state.getValue(WallMountBlock.FACING).getAxis().isHorizontal() ? partialBaseModel(ctx, prov, "wall")
: partialBaseModel(ctx, prov);
}
}

View File

@@ -0,0 +1,53 @@
package com.drmangotea.tfmg.content.decoration;
import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.RotatedPillarBlock;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.SimpleWaterloggedBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
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.EnumProperty;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
public class TrussBlock extends RotatedPillarBlock implements ProperWaterloggedBlock {
public TrussBlock(Properties p_55926_) {
super(p_55926_);
this.registerDefaultState(this.defaultBlockState().setValue(AXIS, Direction.Axis.Y).setValue(WATERLOGGED, false));
}
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> p_55933_) {
p_55933_.add(WATERLOGGED, AXIS);
}
@Override
public FluidState getFluidState(BlockState pState) {
return fluidState(pState);
}
@Override
public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState,
LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) {
updateWater(pLevel, pState, pCurrentPos);
return pState;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext pContext) {
return withWater(super.getStateForPlacement(pContext), pContext);
}
}

View File

@@ -0,0 +1,116 @@
package com.drmangotea.tfmg.content.decoration.cogs;
import com.drmangotea.tfmg.registry.TFMGPartialModels;
import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.Instancer;
import com.jozufozu.flywheel.api.Material;
import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.core.PartialModel;
import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.content.kinetics.base.IRotate;
import com.simibubi.create.content.kinetics.base.KineticBlockEntity;
import com.simibubi.create.content.kinetics.base.KineticBlockEntityInstance;
import com.simibubi.create.content.kinetics.base.flwdata.RotatingData;
import com.simibubi.create.content.kinetics.simpleRelays.BracketedKineticBlockEntityRenderer;
import com.simibubi.create.foundation.render.AllMaterialSpecs;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import java.util.Optional;
public class EncasedAluminumCogInstance extends KineticBlockEntityInstance<KineticBlockEntity> {
private boolean large;
protected RotatingData rotatingModel;
protected Optional<RotatingData> rotatingTopShaft;
protected Optional<RotatingData> rotatingBottomShaft;
public static EncasedAluminumCogInstance small(MaterialManager modelManager, KineticBlockEntity blockEntity) {
return new EncasedAluminumCogInstance(modelManager, blockEntity, false);
}
public static EncasedAluminumCogInstance large(MaterialManager modelManager, KineticBlockEntity blockEntity) {
return new EncasedAluminumCogInstance(modelManager, blockEntity, true);
}
public EncasedAluminumCogInstance(MaterialManager modelManager, KineticBlockEntity blockEntity, boolean large) {
super(modelManager, blockEntity);
this.large = large;
}
@Override
public void init() {
rotatingModel = setup(getCogModel().createInstance());
Block block = blockState.getBlock();
if (!(block instanceof IRotate))
return;
IRotate def = (IRotate) block;
rotatingTopShaft = Optional.empty();
rotatingBottomShaft = Optional.empty();
for (Direction d : Iterate.directionsInAxis(axis)) {
if (!def.hasShaftTowards(blockEntity.getLevel(), blockEntity.getBlockPos(), blockState, d))
continue;
RotatingData data = setup(getRotatingMaterial().getModel(AllPartialModels.SHAFT_HALF, blockState, d)
.createInstance());
if (large)
data.setRotationOffset(BracketedKineticBlockEntityRenderer.getShaftAngleOffset(axis, pos));
if (d.getAxisDirection() == Direction.AxisDirection.POSITIVE)
rotatingTopShaft = Optional.of(data);
else
rotatingBottomShaft = Optional.of(data);
}
}
@Override
public void update() {
updateRotation(rotatingModel);
rotatingTopShaft.ifPresent(this::updateRotation);
rotatingBottomShaft.ifPresent(this::updateRotation);
}
@Override
public void updateLight() {
relight(pos, rotatingModel);
rotatingTopShaft.ifPresent(d -> relight(pos, d));
rotatingBottomShaft.ifPresent(d -> relight(pos, d));
}
@Override
public void remove() {
rotatingModel.delete();
rotatingTopShaft.ifPresent(InstanceData::delete);
rotatingBottomShaft.ifPresent(InstanceData::delete);
}
protected Instancer<RotatingData> getCogModel() {
BlockState referenceState = blockEntity.getBlockState();
Direction facing =
Direction.fromAxisAndDirection(referenceState.getValue(BlockStateProperties.AXIS), Direction.AxisDirection.POSITIVE);
PartialModel partial = large ? TFMGPartialModels.LARGE_ALUMINUM_COGHWEEL : TFMGPartialModels.ALUMINUM_COGHWEEL;
return getCutoutRotatingMaterial().getModel(partial, referenceState, facing, () -> {
PoseStack poseStack = new PoseStack();
TransformStack.cast(poseStack)
.centre()
.rotateToFace(facing)
.multiply(Axis.XN.rotationDegrees(90))
.unCentre();
return poseStack;
});
}
protected Material<RotatingData> getCutoutRotatingMaterial() {
return materialManager.defaultCutout()
.material(AllMaterialSpecs.ROTATING);
}
}

View File

@@ -0,0 +1,74 @@
package com.drmangotea.tfmg.content.decoration.cogs;
import com.drmangotea.tfmg.registry.TFMGPartialModels;
import com.jozufozu.flywheel.backend.Backend;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.content.kinetics.base.IRotate;
import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer;
import com.simibubi.create.content.kinetics.simpleRelays.BracketedKineticBlockEntityRenderer;
import com.simibubi.create.content.kinetics.simpleRelays.SimpleKineticBlockEntity;
import com.simibubi.create.content.kinetics.simpleRelays.encased.EncasedCogwheelBlock;
import com.simibubi.create.foundation.render.CachedBufferer;
import com.simibubi.create.foundation.render.SuperByteBuffer;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
public class EncasedAluminumCogRenderer extends KineticBlockEntityRenderer<SimpleKineticBlockEntity> {
private boolean large;
public static EncasedAluminumCogRenderer small(BlockEntityRendererProvider.Context context) {
return new EncasedAluminumCogRenderer(context, false);
}
public static EncasedAluminumCogRenderer large(BlockEntityRendererProvider.Context context) {
return new EncasedAluminumCogRenderer(context, true);
}
public EncasedAluminumCogRenderer(BlockEntityRendererProvider.Context context, boolean large) {
super(context);
this.large = large;
}
@Override
protected void renderSafe(SimpleKineticBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer,
int light, int overlay) {
super.renderSafe(be, partialTicks, ms, buffer, light, overlay);
if (Backend.canUseInstancing(be.getLevel()))
return;
BlockState blockState = be.getBlockState();
Block block = blockState.getBlock();
if (!(block instanceof IRotate))
return;
IRotate def = (IRotate) block;
Direction.Axis axis = getRotationAxisOf(be);
BlockPos pos = be.getBlockPos();
float angle = large ? BracketedKineticBlockEntityRenderer.getAngleForLargeCogShaft(be, axis)
: getAngleForTe(be, pos, axis);
for (Direction d : Iterate.directionsInAxis(getRotationAxisOf(be))) {
if (!def.hasShaftTowards(be.getLevel(), be.getBlockPos(), blockState, d))
continue;
SuperByteBuffer shaft = CachedBufferer.partialFacing(AllPartialModels.SHAFT_HALF, be.getBlockState(), d);
kineticRotationTransform(shaft, be, axis, angle, light);
shaft.renderInto(ms, buffer.getBuffer(RenderType.cutoutMipped()));
}
}
@Override
protected SuperByteBuffer getRotatedModel(SimpleKineticBlockEntity be, BlockState state) {
return CachedBufferer.partialFacingVertical(
large ? TFMGPartialModels.LARGE_ALUMINUM_COGHWEEL : TFMGPartialModels.ALUMINUM_COGHWEEL, state,
Direction.fromAxisAndDirection(state.getValue(EncasedCogwheelBlock.AXIS), Direction.AxisDirection.POSITIVE));
}
}

View File

@@ -0,0 +1,109 @@
package com.drmangotea.tfmg.content.decoration.cogs;
import com.drmangotea.tfmg.registry.TFMGPartialModels;
import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.Instancer;
import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.core.PartialModel;
import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.content.kinetics.base.IRotate;
import com.simibubi.create.content.kinetics.base.KineticBlockEntity;
import com.simibubi.create.content.kinetics.base.KineticBlockEntityInstance;
import com.simibubi.create.content.kinetics.base.flwdata.RotatingData;
import com.simibubi.create.content.kinetics.simpleRelays.BracketedKineticBlockEntityRenderer;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import java.util.Optional;
public class EncasedSteelCogInstance extends KineticBlockEntityInstance<KineticBlockEntity> {
private boolean large;
protected RotatingData rotatingModel;
protected Optional<RotatingData> rotatingTopShaft;
protected Optional<RotatingData> rotatingBottomShaft;
public static EncasedSteelCogInstance small(MaterialManager modelManager, KineticBlockEntity blockEntity) {
return new EncasedSteelCogInstance(modelManager, blockEntity, false);
}
public static EncasedSteelCogInstance large(MaterialManager modelManager, KineticBlockEntity blockEntity) {
return new EncasedSteelCogInstance(modelManager, blockEntity, true);
}
public EncasedSteelCogInstance(MaterialManager modelManager, KineticBlockEntity blockEntity, boolean large) {
super(modelManager, blockEntity);
this.large = large;
}
@Override
public void init() {
rotatingModel = setup(getCogModel().createInstance());
Block block = blockState.getBlock();
if (!(block instanceof IRotate))
return;
IRotate def = (IRotate) block;
rotatingTopShaft = Optional.empty();
rotatingBottomShaft = Optional.empty();
for (Direction d : Iterate.directionsInAxis(axis)) {
if (!def.hasShaftTowards(blockEntity.getLevel(), blockEntity.getBlockPos(), blockState, d))
continue;
RotatingData data = setup(getRotatingMaterial().getModel(AllPartialModels.SHAFT_HALF, blockState, d)
.createInstance());
if (large)
data.setRotationOffset(BracketedKineticBlockEntityRenderer.getShaftAngleOffset(axis, pos));
if (d.getAxisDirection() == Direction.AxisDirection.POSITIVE)
rotatingTopShaft = Optional.of(data);
else
rotatingBottomShaft = Optional.of(data);
}
}
@Override
public void update() {
updateRotation(rotatingModel);
rotatingTopShaft.ifPresent(this::updateRotation);
rotatingBottomShaft.ifPresent(this::updateRotation);
}
@Override
public void updateLight() {
relight(pos, rotatingModel);
rotatingTopShaft.ifPresent(d -> relight(pos, d));
rotatingBottomShaft.ifPresent(d -> relight(pos, d));
}
@Override
public void remove() {
rotatingModel.delete();
rotatingTopShaft.ifPresent(InstanceData::delete);
rotatingBottomShaft.ifPresent(InstanceData::delete);
}
protected Instancer<RotatingData> getCogModel() {
BlockState referenceState = blockEntity.getBlockState();
Direction facing =
Direction.fromAxisAndDirection(referenceState.getValue(BlockStateProperties.AXIS), Direction.AxisDirection.POSITIVE);
PartialModel partial = large ? TFMGPartialModels.LARGE_STEEL_COGHWEEL : TFMGPartialModels.STEEL_COGHWEEL;
return getRotatingMaterial().getModel(partial, referenceState, facing, () -> {
PoseStack poseStack = new PoseStack();
TransformStack.cast(poseStack)
.centre()
.rotateToFace(facing)
.multiply(Axis.XN.rotationDegrees(90))
.unCentre();
return poseStack;
});
}
}

View File

@@ -0,0 +1,72 @@
package com.drmangotea.tfmg.content.decoration.cogs;
import com.drmangotea.tfmg.registry.TFMGPartialModels;
import com.jozufozu.flywheel.backend.Backend;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.content.kinetics.base.IRotate;
import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer;
import com.simibubi.create.content.kinetics.simpleRelays.BracketedKineticBlockEntityRenderer;
import com.simibubi.create.content.kinetics.simpleRelays.SimpleKineticBlockEntity;
import com.simibubi.create.content.kinetics.simpleRelays.encased.EncasedCogwheelBlock;
import com.simibubi.create.foundation.render.CachedBufferer;
import com.simibubi.create.foundation.render.SuperByteBuffer;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
public class EncasedSteelCogRenderer extends KineticBlockEntityRenderer<SimpleKineticBlockEntity> {
private boolean large;
public static EncasedSteelCogRenderer small(BlockEntityRendererProvider.Context context) {
return new EncasedSteelCogRenderer(context, false);
}
public static EncasedSteelCogRenderer large(BlockEntityRendererProvider.Context context) {
return new EncasedSteelCogRenderer(context, true);
}
public EncasedSteelCogRenderer(BlockEntityRendererProvider.Context context, boolean large) {
super(context);
this.large = large;
}
@Override
protected void renderSafe(SimpleKineticBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer,
int light, int overlay) {
super.renderSafe(be, partialTicks, ms, buffer, light, overlay);
if (Backend.canUseInstancing(be.getLevel()))
return;
BlockState blockState = be.getBlockState();
Block block = blockState.getBlock();
if (!(block instanceof IRotate))
return;
IRotate def = (IRotate) block;
Direction.Axis axis = getRotationAxisOf(be);
BlockPos pos = be.getBlockPos();
float angle = large ? BracketedKineticBlockEntityRenderer.getAngleForLargeCogShaft(be, axis)
: getAngleForTe(be, pos, axis);
for (Direction d : Iterate.directionsInAxis(getRotationAxisOf(be))) {
if (!def.hasShaftTowards(be.getLevel(), be.getBlockPos(), blockState, d))
continue;
SuperByteBuffer shaft = CachedBufferer.partialFacing(AllPartialModels.SHAFT_HALF, be.getBlockState(), d);
kineticRotationTransform(shaft, be, axis, angle, light);
shaft.renderInto(ms, buffer.getBuffer(RenderType.cutoutMipped()));
}
}
@Override
protected SuperByteBuffer getRotatedModel(SimpleKineticBlockEntity be, BlockState state) {
return CachedBufferer.partialFacingVertical(
large ? TFMGPartialModels.LARGE_STEEL_COGHWEEL : TFMGPartialModels.STEEL_COGHWEEL, state,
Direction.fromAxisAndDirection(state.getValue(EncasedCogwheelBlock.AXIS), Direction.AxisDirection.POSITIVE));
}
}

View File

@@ -0,0 +1,208 @@
package com.drmangotea.tfmg.content.decoration.cogs;
import com.drmangotea.tfmg.registry.TFMGBlockEntities;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllShapes;
import com.simibubi.create.content.decoration.encasing.EncasableBlock;
import com.simibubi.create.content.kinetics.base.IRotate;
import com.simibubi.create.content.kinetics.base.KineticBlockEntity;
import com.simibubi.create.content.kinetics.simpleRelays.AbstractSimpleShaftBlock;
import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel;
import com.simibubi.create.content.kinetics.speedController.SpeedControllerBlock;
import com.simibubi.create.foundation.advancement.AllAdvancements;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
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 javax.annotation.ParametersAreNonnullByDefault;
import static net.minecraft.core.Direction.Axis;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public class TFMGCogWheelBlock extends AbstractSimpleShaftBlock implements ICogWheel, EncasableBlock {
boolean isLarge;
protected TFMGCogWheelBlock(boolean large, Properties properties) {
super(properties);
isLarge = large;
}
public static TFMGCogWheelBlock small(Properties properties) {
return new TFMGCogWheelBlock(false, properties);
}
public static TFMGCogWheelBlock large(Properties properties) {
return new TFMGCogWheelBlock(true, properties);
}
@Override
public boolean isLargeCog() {
return isLarge;
}
@Override
public boolean isSmallCog() {
return !isLarge;
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) {
return (isLarge ? AllShapes.LARGE_GEAR : AllShapes.SMALL_GEAR).get(state.getValue(AXIS));
}
@Override
public boolean canSurvive(BlockState state, LevelReader worldIn, BlockPos pos) {
return isValidCogwheelPosition(ICogWheel.isLargeCog(state), worldIn, pos, state.getValue(AXIS));
}
@Override
public void setPlacedBy(Level worldIn, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) {
super.setPlacedBy(worldIn, pos, state, placer, stack);
if (placer instanceof Player player)
triggerShiftingGearsAdvancement(worldIn, pos, state, player);
}
protected void triggerShiftingGearsAdvancement(Level world, BlockPos pos, BlockState state, Player player) {
if (world.isClientSide || player == null)
return;
Axis axis = state.getValue(TFMGCogWheelBlock.AXIS);
for (Axis perpendicular1 : Iterate.axes) {
if (perpendicular1 == axis)
continue;
Direction d1 = Direction.get(Direction.AxisDirection.POSITIVE, perpendicular1);
for (Axis perpendicular2 : Iterate.axes) {
if (perpendicular1 == perpendicular2)
continue;
if (axis == perpendicular2)
continue;
Direction d2 = Direction.get(Direction.AxisDirection.POSITIVE, perpendicular2);
for (int offset1 : Iterate.positiveAndNegative) {
for (int offset2 : Iterate.positiveAndNegative) {
BlockPos connectedPos = pos.relative(d1, offset1)
.relative(d2, offset2);
BlockState blockState = world.getBlockState(connectedPos);
if (!(blockState.getBlock() instanceof TFMGCogWheelBlock))
continue;
if (blockState.getValue(TFMGCogWheelBlock.AXIS) != axis)
continue;
if (ICogWheel.isLargeCog(blockState) == isLarge)
continue;
AllAdvancements.COGS.awardTo(player);
}
}
}
}
}
@Override
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand,
BlockHitResult ray) {
if (player.isShiftKeyDown() || !player.mayBuild())
return InteractionResult.PASS;
ItemStack heldItem = player.getItemInHand(hand);
InteractionResult result = tryEncase(state, world, pos, heldItem, player, hand, ray);
if (result.consumesAction())
return result;
return InteractionResult.PASS;
}
public static boolean isValidCogwheelPosition(boolean large, LevelReader worldIn, BlockPos pos, Axis cogAxis) {
for (Direction facing : Iterate.directions) {
if (facing.getAxis() == cogAxis)
continue;
BlockPos offsetPos = pos.relative(facing);
BlockState blockState = worldIn.getBlockState(offsetPos);
if (blockState.hasProperty(AXIS) && facing.getAxis() == blockState.getValue(AXIS))
continue;
if (ICogWheel.isLargeCog(blockState) || large && ICogWheel.isSmallCog(blockState))
return false;
}
return true;
}
protected Axis getAxisForPlacement(BlockPlaceContext context) {
if (context.getPlayer() != null && context.getPlayer()
.isShiftKeyDown())
return context.getClickedFace()
.getAxis();
Level world = context.getLevel();
BlockState stateBelow = world.getBlockState(context.getClickedPos()
.below());
if (AllBlocks.ROTATION_SPEED_CONTROLLER.has(stateBelow) && isLargeCog())
return stateBelow.getValue(SpeedControllerBlock.HORIZONTAL_AXIS) == Axis.X ? Axis.Z : Axis.X;
BlockPos placedOnPos = context.getClickedPos()
.relative(context.getClickedFace()
.getOpposite());
BlockState placedAgainst = world.getBlockState(placedOnPos);
Block block = placedAgainst.getBlock();
if (ICogWheel.isSmallCog(placedAgainst))
return ((IRotate) block).getRotationAxis(placedAgainst);
Axis preferredAxis = getPreferredAxis(context);
return preferredAxis != null ? preferredAxis
: context.getClickedFace()
.getAxis();
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
boolean shouldWaterlog = context.getLevel()
.getFluidState(context.getClickedPos())
.getType() == Fluids.WATER;
return this.defaultBlockState()
.setValue(AXIS, getAxisForPlacement(context))
.setValue(BlockStateProperties.WATERLOGGED, shouldWaterlog);
}
@Override
public float getParticleTargetRadius() {
return isLargeCog() ? 1.125f : .65f;
}
@Override
public float getParticleInitialRadius() {
return isLargeCog() ? 1f : .75f;
}
@Override
public boolean isDedicatedCogWheel() {
return true;
}
@Override
public BlockEntityType<? extends KineticBlockEntity> getBlockEntityType() {
return TFMGBlockEntities.TFMG_COGWHEEL.get();
}
}

View File

@@ -0,0 +1,305 @@
package com.drmangotea.tfmg.content.decoration.cogs;
import com.simibubi.create.AllShapes;
import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock;
import com.simibubi.create.content.kinetics.base.HorizontalKineticBlock;
import com.simibubi.create.content.kinetics.base.IRotate;
import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock;
import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel;
import com.simibubi.create.foundation.placement.IPlacementHelper;
import com.simibubi.create.foundation.placement.PlacementHelpers;
import com.simibubi.create.foundation.placement.PlacementOffset;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import java.util.List;
import java.util.function.Predicate;
import static com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock.AXIS;
public class TFMGCogwheelBlockItem extends BlockItem {
boolean large;
private final int placementHelperId;
private final int integratedCogHelperId;
public TFMGCogwheelBlockItem(TFMGCogWheelBlock block, Properties builder) {
super(block, builder);
large = block.isLarge;
placementHelperId = PlacementHelpers.register(large ? new LargeCogHelper() : new SmallCogHelper());
integratedCogHelperId =
PlacementHelpers.register(large ? new IntegratedLargeCogHelper() : new IntegratedSmallCogHelper());
}
@Override
public InteractionResult onItemUseFirst(ItemStack stack, UseOnContext context) {
Level world = context.getLevel();
BlockPos pos = context.getClickedPos();
BlockState state = world.getBlockState(pos);
IPlacementHelper helper = PlacementHelpers.get(placementHelperId);
Player player = context.getPlayer();
BlockHitResult ray = new BlockHitResult(context.getClickLocation(), context.getClickedFace(), pos, true);
if (helper.matchesState(state) && player != null && !player.isShiftKeyDown()) {
return helper.getOffset(player, world, state, pos, ray)
.placeInWorld(world, this, player, context.getHand(), ray);
}
if (integratedCogHelperId != -1) {
helper = PlacementHelpers.get(integratedCogHelperId);
if (helper.matchesState(state) && player != null && !player.isShiftKeyDown()) {
return helper.getOffset(player, world, state, pos, ray)
.placeInWorld(world, this, player, context.getHand(), ray);
}
}
return super.onItemUseFirst(stack, context);
}
@MethodsReturnNonnullByDefault
private static class SmallCogHelper extends DiagonalCogHelper {
@Override
public Predicate<ItemStack> getItemPredicate() {
return ((Predicate<ItemStack>) ICogWheel::isSmallCogItem).and(ICogWheel::isDedicatedCogItem);
}
@Override
public PlacementOffset getOffset(Player player, Level world, BlockState state, BlockPos pos,
BlockHitResult ray) {
if (hitOnShaft(state, ray))
return PlacementOffset.fail();
if (!ICogWheel.isLargeCog(state)) {
Axis axis = ((IRotate) state.getBlock()).getRotationAxis(state);
List<Direction> directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getLocation(), axis);
for (Direction dir : directions) {
BlockPos newPos = pos.relative(dir);
if (!TFMGCogWheelBlock.isValidCogwheelPosition(false, world, newPos, axis))
continue;
if (!world.getBlockState(newPos)
.canBeReplaced())
continue;
return PlacementOffset.success(newPos, s -> s.setValue(AXIS, axis));
}
return PlacementOffset.fail();
}
return super.getOffset(player, world, state, pos, ray);
}
}
@MethodsReturnNonnullByDefault
private static class LargeCogHelper extends DiagonalCogHelper {
@Override
public Predicate<ItemStack> getItemPredicate() {
return ((Predicate<ItemStack>) ICogWheel::isLargeCogItem).and(ICogWheel::isDedicatedCogItem);
}
@Override
public PlacementOffset getOffset(Player player, Level world, BlockState state, BlockPos pos,
BlockHitResult ray) {
if (hitOnShaft(state, ray))
return PlacementOffset.fail();
if (ICogWheel.isLargeCog(state)) {
Axis axis = ((IRotate) state.getBlock()).getRotationAxis(state);
Direction side = IPlacementHelper.orderedByDistanceOnlyAxis(pos, ray.getLocation(), axis)
.get(0);
List<Direction> directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getLocation(), axis);
for (Direction dir : directions) {
BlockPos newPos = pos.relative(dir)
.relative(side);
if (!TFMGCogWheelBlock.isValidCogwheelPosition(true, world, newPos, dir.getAxis()))
continue;
if (!world.getBlockState(newPos)
.canBeReplaced())
continue;
return PlacementOffset.success(newPos, s -> s.setValue(AXIS, dir.getAxis()));
}
return PlacementOffset.fail();
}
return super.getOffset(player, world, state, pos, ray);
}
}
@MethodsReturnNonnullByDefault
public abstract static class DiagonalCogHelper implements IPlacementHelper {
@Override
public Predicate<BlockState> getStatePredicate() {
return s -> ICogWheel.isSmallCog(s) || ICogWheel.isLargeCog(s);
}
@Override
public PlacementOffset getOffset(Player player, Level world, BlockState state, BlockPos pos,
BlockHitResult ray) {
// diagonal gears of different size
Axis axis = ((IRotate) state.getBlock()).getRotationAxis(state);
Direction closest = IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getLocation(), axis)
.get(0);
List<Direction> directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getLocation(), axis,
d -> d.getAxis() != closest.getAxis());
for (Direction dir : directions) {
BlockPos newPos = pos.relative(dir)
.relative(closest);
if (!world.getBlockState(newPos)
.canBeReplaced())
continue;
if (!TFMGCogWheelBlock.isValidCogwheelPosition(ICogWheel.isLargeCog(state), world, newPos, axis))
continue;
return PlacementOffset.success(newPos, s -> s.setValue(AXIS, axis));
}
return PlacementOffset.fail();
}
protected boolean hitOnShaft(BlockState state, BlockHitResult ray) {
return AllShapes.SIX_VOXEL_POLE.get(((IRotate) state.getBlock()).getRotationAxis(state))
.bounds()
.inflate(0.001)
.contains(ray.getLocation()
.subtract(ray.getLocation()
.align(Iterate.axisSet)));
}
}
@MethodsReturnNonnullByDefault
public static class IntegratedLargeCogHelper implements IPlacementHelper {
@Override
public Predicate<ItemStack> getItemPredicate() {
return ((Predicate<ItemStack>) ICogWheel::isLargeCogItem).and(ICogWheel::isDedicatedCogItem);
}
@Override
public Predicate<BlockState> getStatePredicate() {
return s -> !ICogWheel.isDedicatedCogWheel(s.getBlock()) && ICogWheel.isSmallCog(s);
}
@Override
public PlacementOffset getOffset(Player player, Level world, BlockState state, BlockPos pos,
BlockHitResult ray) {
Direction face = ray.getDirection();
Axis newAxis;
if (state.hasProperty(HorizontalKineticBlock.HORIZONTAL_FACING))
newAxis = state.getValue(HorizontalKineticBlock.HORIZONTAL_FACING)
.getAxis();
else if (state.hasProperty(DirectionalKineticBlock.FACING))
newAxis = state.getValue(DirectionalKineticBlock.FACING)
.getAxis();
else if (state.hasProperty(RotatedPillarKineticBlock.AXIS))
newAxis = state.getValue(RotatedPillarKineticBlock.AXIS);
else
newAxis = Axis.Y;
if (face.getAxis() == newAxis)
return PlacementOffset.fail();
List<Direction> directions =
IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getLocation(), face.getAxis(), newAxis);
for (Direction d : directions) {
BlockPos newPos = pos.relative(face)
.relative(d);
if (!world.getBlockState(newPos)
.canBeReplaced())
continue;
if (!TFMGCogWheelBlock.isValidCogwheelPosition(false, world, newPos, newAxis))
return PlacementOffset.fail();
return PlacementOffset.success(newPos, s -> s.setValue(TFMGCogWheelBlock.AXIS, newAxis));
}
return PlacementOffset.fail();
}
}
@MethodsReturnNonnullByDefault
public static class IntegratedSmallCogHelper implements IPlacementHelper {
@Override
public Predicate<ItemStack> getItemPredicate() {
return ((Predicate<ItemStack>) ICogWheel::isSmallCogItem).and(ICogWheel::isDedicatedCogItem);
}
@Override
public Predicate<BlockState> getStatePredicate() {
return s -> !ICogWheel.isDedicatedCogWheel(s.getBlock()) && ICogWheel.isSmallCog(s);
}
@Override
public PlacementOffset getOffset(Player player, Level world, BlockState state, BlockPos pos,
BlockHitResult ray) {
Direction face = ray.getDirection();
Axis newAxis;
if (state.hasProperty(HorizontalKineticBlock.HORIZONTAL_FACING))
newAxis = state.getValue(HorizontalKineticBlock.HORIZONTAL_FACING)
.getAxis();
else if (state.hasProperty(DirectionalKineticBlock.FACING))
newAxis = state.getValue(DirectionalKineticBlock.FACING)
.getAxis();
else if (state.hasProperty(RotatedPillarKineticBlock.AXIS))
newAxis = state.getValue(RotatedPillarKineticBlock.AXIS);
else
newAxis = Axis.Y;
if (face.getAxis() == newAxis)
return PlacementOffset.fail();
List<Direction> directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getLocation(), newAxis);
for (Direction d : directions) {
BlockPos newPos = pos.relative(d);
if (!world.getBlockState(newPos)
.canBeReplaced())
continue;
if (!TFMGCogWheelBlock.isValidCogwheelPosition(false, world, newPos, newAxis))
return PlacementOffset.fail();
return PlacementOffset.success()
.at(newPos)
.withTransform(s -> s.setValue(TFMGCogWheelBlock.AXIS, newAxis));
}
return PlacementOffset.fail();
}
}
}

View File

@@ -0,0 +1,109 @@
package com.drmangotea.tfmg.content.decoration.cogs;
import com.drmangotea.tfmg.registry.TFMGBlocks;
import com.drmangotea.tfmg.registry.TFMGPartialModels;
import com.jozufozu.flywheel.api.Instancer;
import com.jozufozu.flywheel.api.Material;
import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.core.PartialModel;
import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer;
import com.simibubi.create.content.kinetics.base.SingleRotatingInstance;
import com.simibubi.create.content.kinetics.base.flwdata.RotatingData;
import com.simibubi.create.content.kinetics.simpleRelays.BracketedKineticBlockEntityRenderer;
import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel;
import com.simibubi.create.content.kinetics.simpleRelays.SimpleKineticBlockEntity;
import com.simibubi.create.foundation.render.AllMaterialSpecs;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.core.Direction.AxisDirection;
public class TFMGCogwheelInstance extends SingleRotatingInstance<SimpleKineticBlockEntity> {
protected RotatingData additionalShaft;
public TFMGCogwheelInstance(MaterialManager materialManager, SimpleKineticBlockEntity blockEntity) {
super(materialManager, blockEntity);
}
@Override
public void init() {
super.init();
if (!ICogWheel.isLargeCog(blockEntity.getBlockState()))
return;
// Large cogs sometimes have to offset their teeth by 11.25 degrees in order to
// mesh properly
float speed = blockEntity.getSpeed();
Axis axis = KineticBlockEntityRenderer.getRotationAxisOf(blockEntity);
BlockPos pos = blockEntity.getBlockPos();
float offset = BracketedKineticBlockEntityRenderer.getShaftAngleOffset(axis, pos);
Direction facing = Direction.fromAxisAndDirection(axis, AxisDirection.POSITIVE);
Instancer<RotatingData> half = getRotatingMaterial().getModel(AllPartialModels.COGWHEEL_SHAFT, blockState,
facing, () -> this.rotateToAxis(axis));
additionalShaft = setup(half.createInstance(), speed);
additionalShaft.setRotationOffset(offset);
}
@Override
protected Instancer<RotatingData> getModel() {
Axis axis = KineticBlockEntityRenderer.getRotationAxisOf(blockEntity);
Direction facing = Direction.fromAxisAndDirection(axis, AxisDirection.POSITIVE);
if (!ICogWheel.isLargeCog(blockEntity.getBlockState()))
return getCutoutRotatingMaterial().getModel(blockState);
//return super.getModel();
PartialModel model = blockEntity.getBlockState().is(TFMGBlocks.LARGE_ALUMINUM_COGWHEEL.get()) ? TFMGPartialModels.LARGE_ALUMINUM_COGHWEEL : TFMGPartialModels.LARGE_STEEL_COGHWEEL;
return getCutoutRotatingMaterial().getModel(model, blockState, facing,
() -> this.rotateToAxis(axis));
}
protected Material<RotatingData> getCutoutRotatingMaterial() {
return materialManager.defaultCutout()
.material(AllMaterialSpecs.ROTATING);
}
private PoseStack rotateToAxis(Axis axis) {
Direction facing = Direction.fromAxisAndDirection(axis, AxisDirection.POSITIVE);
PoseStack poseStack = new PoseStack();
TransformStack.cast(poseStack)
.centre()
.rotateToFace(facing)
.multiply(com.mojang.math.Axis.XN.rotationDegrees(-90))
.unCentre();
return poseStack;
}
@Override
public void update() {
super.update();
if (additionalShaft != null) {
updateRotation(additionalShaft);
additionalShaft.setRotationOffset(TFMGCogwheelRenderer.getShaftAngleOffset(axis, pos));
}
}
@Override
public void updateLight() {
super.updateLight();
if (additionalShaft != null)
relight(pos, additionalShaft);
}
@Override
public void remove() {
super.remove();
if (additionalShaft != null)
additionalShaft.delete();
}
}

View File

@@ -0,0 +1,73 @@
package com.drmangotea.tfmg.content.decoration.cogs;
import com.drmangotea.tfmg.registry.TFMGBlocks;
import com.drmangotea.tfmg.registry.TFMGPartialModels;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.core.PartialModel;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer;
import com.simibubi.create.content.kinetics.simpleRelays.SimpleKineticBlockEntity;
import com.simibubi.create.foundation.render.CachedBufferer;
import com.simibubi.create.foundation.render.SuperByteBuffer;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider.Context;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.core.Direction.AxisDirection;
public class TFMGCogwheelRenderer extends KineticBlockEntityRenderer<SimpleKineticBlockEntity> {
public TFMGCogwheelRenderer(Context context) {
super(context);
}
@Override
protected void renderSafe(SimpleKineticBlockEntity be, float partialTicks, PoseStack ms,
MultiBufferSource buffer, int light, int overlay) {
if (Backend.canUseInstancing(be.getLevel()))
return;
if (!AllBlocks.LARGE_COGWHEEL.has(be.getBlockState())) {
super.renderSafe(be, partialTicks, ms, buffer, light, overlay);
return;
}
Axis axis = getRotationAxisOf(be);
Direction facing = Direction.fromAxisAndDirection(axis, AxisDirection.POSITIVE);
PartialModel model = be.getBlockState().is(TFMGBlocks.LARGE_ALUMINUM_COGWHEEL.get()) ? TFMGPartialModels.LARGE_ALUMINUM_COGHWEEL : TFMGPartialModels.LARGE_STEEL_COGHWEEL;
renderRotatingBuffer(be,
CachedBufferer.partialFacingVertical(model, be.getBlockState(), facing),
ms, buffer.getBuffer(RenderType.cutoutMipped()), light);
float angle = getAngleForLargeCogShaft(be, axis);
SuperByteBuffer shaft =
CachedBufferer.partialFacingVertical(AllPartialModels.COGWHEEL_SHAFT, be.getBlockState(), facing);
kineticRotationTransform(shaft, be, axis, angle, light);
shaft.renderInto(ms, buffer.getBuffer(RenderType.solid()));
}
public static float getAngleForLargeCogShaft(SimpleKineticBlockEntity be, Axis axis) {
BlockPos pos = be.getBlockPos();
float offset = getShaftAngleOffset(axis, pos);
float time = AnimationTickHolder.getRenderTime(be.getLevel());
float angle = ((time * be.getSpeed() * 3f / 10 + offset) % 360) / 180 * (float) Math.PI;
return angle;
}
public static float getShaftAngleOffset(Axis axis, BlockPos pos) {
float offset = 0;
double d = (((axis == Axis.X) ? 0 : pos.getX()) + ((axis == Axis.Y) ? 0 : pos.getY())
+ ((axis == Axis.Z) ? 0 : pos.getZ())) % 2;
if (d == 0)
offset = 22.5f;
return offset;
}
}

View File

@@ -0,0 +1,85 @@
package com.drmangotea.tfmg.content.decoration.concrete;
import com.drmangotea.tfmg.registry.TFMGBlocks;
import com.drmangotea.tfmg.registry.TFMGFluids;
import com.simibubi.create.foundation.data.SharedProperties;
import net.minecraft.core.BlockPos;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.SimpleWaterloggedBlock;
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.material.FluidState;
import net.minecraft.world.level.material.Fluids;
public interface ConcreteloggedBlock {
BooleanProperty CONCRETELOGGED = BooleanProperty.create("concretelogged");
default FluidState fluidState(BlockState state) {
return state.getValue(CONCRETELOGGED) ? TFMGFluids.LIQUID_CONCRETE.getSource().getSource(false) : Fluids.EMPTY.defaultFluidState();
}
default void updateConcrete(LevelAccessor level, BlockState state, BlockPos pos) {
if (state.getValue(CONCRETELOGGED))
level.scheduleTick(pos, TFMGFluids.LIQUID_CONCRETE.getSource(), TFMGFluids.LIQUID_CONCRETE.getSource().getTickDelay(level));
}
default InteractionResult onClicked(Level level, BlockPos pos, BlockState state, Player player, InteractionHand hand){
ItemStack stack = player.getItemInHand(hand);
if(state.getValue(CONCRETELOGGED)){
if(stack.is(Items.BUCKET)){
level.setBlock(pos, state.setValue(CONCRETELOGGED, false),3);
if(!player.isCreative())
player.setItemInHand(hand, TFMGFluids.LIQUID_CONCRETE.getBucket().get().getDefaultInstance());
player.playSound(SoundEvents.BUCKET_FILL, 1F, 1.0F + player.getRandom().nextFloat() * 0.4F);
return InteractionResult.SUCCESS;
}
}else {
if(stack.is(TFMGFluids.LIQUID_CONCRETE.getBucket().get())){
level.setBlock(pos, state.setValue(CONCRETELOGGED, true),3);
if(!player.isCreative())
player.setItemInHand(hand, Items.BUCKET.getDefaultInstance());
player.playSound(SoundEvents.BUCKET_EMPTY, 1F, 1.0F + player.getRandom().nextFloat() * 0.4F);
return InteractionResult.SUCCESS;
}
}
return InteractionResult.PASS;
}
default void tickDrying(Level level,BlockState state,BlockState newStack, BlockPos pos, RandomSource random){
if(!state.getValue(CONCRETELOGGED))
return;
int randomInt = random.nextInt(7) ;
if(randomInt==2) {
level.setBlock(pos, newStack, 3);
}
}
default BlockState withConcrete(BlockState placementState, BlockPlaceContext ctx) {
return withConcrete(ctx.getLevel(), placementState, ctx.getClickedPos());
}
static BlockState withConcrete(LevelAccessor level, BlockState placementState, BlockPos pos) {
if (placementState == null)
return null;
FluidState ifluidstate = level.getFluidState(pos);
if (placementState.isAir())
return ifluidstate.getType() == TFMGFluids.LIQUID_CONCRETE.getSource() ? ifluidstate.createLegacyBlock() : placementState;
return placementState.setValue(CONCRETELOGGED, ifluidstate.getType() == TFMGFluids.LIQUID_CONCRETE.getSource());
}
}

View File

@@ -0,0 +1,72 @@
package com.drmangotea.tfmg.content.decoration.concrete;
import com.drmangotea.tfmg.registry.TFMGBlocks;
import com.drmangotea.tfmg.registry.TFMGFluids;
import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.SimpleWaterloggedBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.phys.BlockHitResult;
public class RebarBlock extends Block implements ConcreteloggedBlock {
public RebarBlock(Properties p_49795_) {
super(p_49795_);
registerDefaultState(this.getStateDefinition().any().setValue(CONCRETELOGGED, false));
}
@Override
public FluidState getFluidState(BlockState state) {
return fluidState(state);
}
@Override
public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState,
LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) {
updateConcrete(pLevel, pState, pCurrentPos);
return pState;
}
@Override
public InteractionResult use(BlockState blockState, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult blockHitResult) {
return onClicked(level, pos, blockState, player, hand);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext pContext) {
return withConcrete(super.getStateForPlacement(pContext), pContext);
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource randomSource) {
tickDrying(level,state,TFMGBlocks.REBAR_CONCRETE.block.getDefaultState(),pos, randomSource);
}
@Override
public boolean isRandomlyTicking(BlockState p_49921_) {
return true;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(CONCRETELOGGED);
}
}

View File

@@ -0,0 +1,19 @@
package com.drmangotea.tfmg.content.decoration.concrete;
import com.drmangotea.tfmg.base.TFMGShapes;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class RebarFloorBlock extends RebarBlock{
public RebarFloorBlock(Properties p_49795_) {
super(p_49795_);
}
@Override
public VoxelShape getShape(BlockState p_60555_, BlockGetter p_60556_, BlockPos p_60557_, CollisionContext p_60558_) {
return TFMGShapes.REBAR_FLOOR;
}
}

View File

@@ -0,0 +1,80 @@
package com.drmangotea.tfmg.content.decoration.concrete;
import com.drmangotea.tfmg.TFMG;
import com.drmangotea.tfmg.base.TFMGDirectionalBlock;
import com.drmangotea.tfmg.base.TFMGShapes;
import com.drmangotea.tfmg.registry.TFMGBlocks;
import com.google.common.collect.ImmutableMap;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import java.util.function.Function;
public class RebarPillarBlock extends TFMGDirectionalBlock implements ConcreteloggedBlock {
public RebarPillarBlock(Properties p_49795_) {
super(p_49795_);
registerDefaultState(this.getStateDefinition().any().setValue(CONCRETELOGGED, false));
}
@Override
public FluidState getFluidState(BlockState state) {
return fluidState(state);
}
@Override
public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState,
LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) {
updateConcrete(pLevel, pState, pCurrentPos);
return pState;
}
@Override
public VoxelShape getShape(BlockState p_60555_, BlockGetter p_60556_, BlockPos p_60557_, CollisionContext p_60558_) {
return TFMGShapes.REBAR_PILLAR.get(p_60555_.getValue(FACING));
}
@Override
public InteractionResult use(BlockState blockState, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult blockHitResult) {
return onClicked(level, pos, blockState, player, hand);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext pContext) {
return withConcrete(super.getStateForPlacement(pContext), pContext);
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource randomSource) {
tickDrying(level,state,TFMGBlocks.REBAR_CONCRETE.block.getDefaultState(),pos, randomSource);
}
@Override
public boolean isRandomlyTicking(BlockState p_49921_) {
return true;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(CONCRETELOGGED);
}
}

View File

@@ -0,0 +1,66 @@
package com.drmangotea.tfmg.content.decoration.concrete;
import com.drmangotea.tfmg.registry.TFMGBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.StairBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.BlockHitResult;
public class RebarStairsBlock extends StairBlock implements ConcreteloggedBlock{
public RebarStairsBlock(BlockState state,Properties p_56863_) {
super(state, p_56863_);
}
@Override
public FluidState getFluidState(BlockState state) {
return fluidState(state);
}
@Override
public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState,
LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) {
updateConcrete(pLevel, pState, pCurrentPos);
return pState;
}
@Override
public InteractionResult use(BlockState blockState, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult blockHitResult) {
return onClicked(level, pos, blockState, player, hand);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext pContext) {
return withConcrete(super.getStateForPlacement(pContext), pContext);
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource randomSource) {
tickDrying(level,state,TFMGBlocks.REBAR_CONCRETE.stairs.getDefaultState().setValue(FACING, state.getValue(FACING)).setValue(HALF, state.getValue(HALF)),pos, randomSource);
}
@Override
public boolean isRandomlyTicking(BlockState p_49921_) {
return true;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(CONCRETELOGGED);
}
}

View File

@@ -0,0 +1,44 @@
package com.drmangotea.tfmg.content.decoration.concrete;
import com.drmangotea.tfmg.base.WallMountBlock;
import com.drmangotea.tfmg.content.decoration.LithiumTorchBlock;
import com.simibubi.create.foundation.data.SpecialBlockStateGen;
import com.tterrag.registrate.providers.DataGenContext;
import com.tterrag.registrate.providers.RegistrateBlockstateProvider;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.StairBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.Half;
import net.minecraftforge.client.model.generators.ModelFile;
import static com.simibubi.create.foundation.data.AssetLookup.partialBaseModel;
public class RebarStairsGenerator extends SpecialBlockStateGen {
@Override
protected int getXRotation(BlockState state) {
return 0;
}
@Override
protected int getYRotation(BlockState state) {
return switch (state.getValue(StairBlock.FACING)) {
case NORTH -> 270;
case SOUTH -> 90;
case WEST -> 180;
case EAST -> 0;
case DOWN -> 0;
case UP -> 0;
};
}
@Override
public <T extends Block> ModelFile getModel(DataGenContext<Block, T> ctx, RegistrateBlockstateProvider prov,
BlockState state) {
return state.getValue(StairBlock.HALF)== Half.TOP ? partialBaseModel(ctx, prov, "upside_down")
: partialBaseModel(ctx, prov);
}
}

View File

@@ -0,0 +1,27 @@
package com.drmangotea.tfmg.content.decoration.concrete;
import com.drmangotea.tfmg.base.TFMGShapes;
import com.drmangotea.tfmg.registry.TFMGBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class RebarWallBlock extends RebarBlock{
public RebarWallBlock(Properties p_49795_) {
super(p_49795_);
}
@Override
public VoxelShape getShape(BlockState p_60555_, BlockGetter p_60556_, BlockPos p_60557_, CollisionContext p_60558_) {
return TFMGShapes.CABLE_TUBE.get(Direction.UP);
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource randomSource) {
tickDrying(level,state,TFMGBlocks.REBAR_CONCRETE.wall.getDefaultState(),pos, randomSource);
}
}

View File

@@ -0,0 +1,253 @@
package com.drmangotea.tfmg.content.decoration.doors;
import com.drmangotea.tfmg.registry.TFMGBlockEntities;
import com.simibubi.create.content.contraptions.ContraptionWorld;
import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorShapes;
import com.simibubi.create.content.equipment.wrench.IWrenchable;
import com.simibubi.create.foundation.block.IBE;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.DoorBlock;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition.Builder;
import net.minecraft.world.level.block.state.properties.BlockSetType;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.DoorHingeSide;
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import javax.annotation.Nullable;
import static com.simibubi.create.content.decoration.slidingDoor.SlidingDoorBlock.TRAIN_SET_TYPE;
public class TFMGSlidingDoorBlock extends DoorBlock implements IWrenchable, IBE<TFMGSlidingDoorBlockEntity> {
public static final BooleanProperty VISIBLE = BooleanProperty.create("visible");
private boolean folds;
public static TFMGSlidingDoorBlock metal(Properties p_52737_, boolean folds) {
return new TFMGSlidingDoorBlock(p_52737_, TRAIN_SET_TYPE.get(), folds);
}
public TFMGSlidingDoorBlock(Properties p_52737_, BlockSetType type, boolean folds) {
super(p_52737_, type);
this.folds = folds;
}
public boolean isFoldingDoor() {
return folds;
}
@Override
protected void createBlockStateDefinition(Builder<Block, BlockState> pBuilder) {
super.createBlockStateDefinition(pBuilder.add(VISIBLE));
}
@Override
public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) {
if (!pState.getValue(OPEN) && (pState.getValue(VISIBLE) || pLevel instanceof ContraptionWorld))
return super.getShape(pState, pLevel, pPos, pContext);
Direction direction = pState.getValue(FACING);
boolean hinge = pState.getValue(HINGE) == DoorHingeSide.RIGHT;
return SlidingDoorShapes.get(direction, hinge, isFoldingDoor());
}
@Override
public boolean canSurvive(BlockState pState, LevelReader pLevel, BlockPos pPos) {
return pState.getValue(HALF) == DoubleBlockHalf.LOWER || pLevel.getBlockState(pPos.below())
.is(this);
}
@Override
public VoxelShape getInteractionShape(BlockState pState, BlockGetter pLevel, BlockPos pPos) {
return getShape(pState, pLevel, pPos, CollisionContext.empty());
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext pContext) {
BlockState stateForPlacement = super.getStateForPlacement(pContext);
if (stateForPlacement != null && stateForPlacement.getValue(OPEN))
return stateForPlacement.setValue(OPEN, false)
.setValue(POWERED, false);
return stateForPlacement;
}
@Override
public void onPlace(BlockState pState, Level pLevel, BlockPos pPos, BlockState pOldState, boolean pIsMoving) {
if (!pOldState.is(this))
deferUpdate(pLevel, pPos);
}
@Override
public BlockState updateShape(BlockState pState, Direction pFacing, BlockState pFacingState, LevelAccessor pLevel,
BlockPos pCurrentPos, BlockPos pFacingPos) {
BlockState blockState = super.updateShape(pState, pFacing, pFacingState, pLevel, pCurrentPos, pFacingPos);
if (blockState.isAir())
return blockState;
DoubleBlockHalf doubleblockhalf = blockState.getValue(HALF);
if (pFacing.getAxis() == Direction.Axis.Y
&& doubleblockhalf == DoubleBlockHalf.LOWER == (pFacing == Direction.UP)) {
return pFacingState.is(this) && pFacingState.getValue(HALF) != doubleblockhalf
? blockState.setValue(VISIBLE, pFacingState.getValue(VISIBLE))
: Blocks.AIR.defaultBlockState();
}
return blockState;
}
@Override
public void setOpen(@Nullable Entity entity, Level level, BlockState state, BlockPos pos, boolean open) {
if (!state.is(this))
return;
if (state.getValue(OPEN) == open)
return;
BlockState changedState = state.setValue(OPEN, open);
if (open)
changedState = changedState.setValue(VISIBLE, false);
level.setBlock(pos, changedState, 10);
DoorHingeSide hinge = changedState.getValue(HINGE);
Direction facing = changedState.getValue(FACING);
BlockPos otherPos =
pos.relative(hinge == DoorHingeSide.LEFT ? facing.getClockWise() : facing.getCounterClockWise());
BlockState otherDoor = level.getBlockState(otherPos);
if (isDoubleDoor(changedState, hinge, facing, otherDoor))
setOpen(entity, level, otherDoor, otherPos, open);
this.playSound(level, pos, open);
level.gameEvent(entity, open ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, pos);
}
@Override
public void neighborChanged(BlockState pState, Level pLevel, BlockPos pPos, Block pBlock, BlockPos pFromPos,
boolean pIsMoving) {
boolean lower = pState.getValue(HALF) == DoubleBlockHalf.LOWER;
boolean isPowered = isDoorPowered(pLevel, pPos, pState);
if (defaultBlockState().is(pBlock))
return;
if (isPowered == pState.getValue(POWERED))
return;
TFMGSlidingDoorBlockEntity be = getBlockEntity(pLevel, lower ? pPos : pPos.below());
if (be != null && be.deferUpdate)
return;
BlockState changedState = pState.setValue(POWERED, Boolean.valueOf(isPowered))
.setValue(OPEN, Boolean.valueOf(isPowered));
if (isPowered)
changedState = changedState.setValue(VISIBLE, false);
if (isPowered != pState.getValue(OPEN)) {
this.playSound(pLevel, pPos, isPowered);
pLevel.gameEvent(null, isPowered ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, pPos);
DoorHingeSide hinge = changedState.getValue(HINGE);
Direction facing = changedState.getValue(FACING);
BlockPos otherPos =
pPos.relative(hinge == DoorHingeSide.LEFT ? facing.getClockWise() : facing.getCounterClockWise());
BlockState otherDoor = pLevel.getBlockState(otherPos);
if (isDoubleDoor(changedState, hinge, facing, otherDoor)) {
otherDoor = otherDoor.setValue(POWERED, Boolean.valueOf(isPowered))
.setValue(OPEN, Boolean.valueOf(isPowered));
if (isPowered)
otherDoor = otherDoor.setValue(VISIBLE, false);
pLevel.setBlock(otherPos, otherDoor, 2);
}
}
pLevel.setBlock(pPos, changedState, 2);
}
public static boolean isDoorPowered(Level pLevel, BlockPos pPos, BlockState state) {
boolean lower = state.getValue(HALF) == DoubleBlockHalf.LOWER;
DoorHingeSide hinge = state.getValue(HINGE);
Direction facing = state.getValue(FACING);
BlockPos otherPos =
pPos.relative(hinge == DoorHingeSide.LEFT ? facing.getClockWise() : facing.getCounterClockWise());
BlockState otherDoor = pLevel.getBlockState(otherPos);
if (isDoubleDoor(state.cycle(OPEN), hinge, facing, otherDoor) && (pLevel.hasNeighborSignal(otherPos)
|| pLevel.hasNeighborSignal(otherPos.relative(lower ? Direction.UP : Direction.DOWN))))
return true;
return pLevel.hasNeighborSignal(pPos)
|| pLevel.hasNeighborSignal(pPos.relative(lower ? Direction.UP : Direction.DOWN));
}
@Override
public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand,
BlockHitResult pHit) {
pState = pState.cycle(OPEN);
if (pState.getValue(OPEN))
pState = pState.setValue(VISIBLE, false);
pLevel.setBlock(pPos, pState, 10);
pLevel.gameEvent(pPlayer, isOpen(pState) ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, pPos);
DoorHingeSide hinge = pState.getValue(HINGE);
Direction facing = pState.getValue(FACING);
BlockPos otherPos =
pPos.relative(hinge == DoorHingeSide.LEFT ? facing.getClockWise() : facing.getCounterClockWise());
BlockState otherDoor = pLevel.getBlockState(otherPos);
if (isDoubleDoor(pState, hinge, facing, otherDoor))
use(otherDoor, pLevel, otherPos, pPlayer, pHand, pHit);
else if (pState.getValue(OPEN))
pLevel.levelEvent(pPlayer, getOpenSound(), pPos, 0);
return InteractionResult.sidedSuccess(pLevel.isClientSide);
}
public void deferUpdate(LevelAccessor level, BlockPos pos) {
withBlockEntityDo(level, pos, sdte -> sdte.deferUpdate = true);
}
public static boolean isDoubleDoor(BlockState pState, DoorHingeSide hinge, Direction facing, BlockState otherDoor) {
return otherDoor.getBlock() == pState.getBlock() && otherDoor.getValue(HINGE) != hinge
&& otherDoor.getValue(FACING) == facing && otherDoor.getValue(OPEN) != pState.getValue(OPEN)
&& otherDoor.getValue(HALF) == pState.getValue(HALF);
}
@Override
public RenderShape getRenderShape(BlockState pState) {
return pState.getValue(VISIBLE) ? RenderShape.MODEL : RenderShape.ENTITYBLOCK_ANIMATED;
}
private void playSound(Level pLevel, BlockPos pPos, boolean pIsOpening) {
if (pIsOpening)
pLevel.levelEvent((Player) null, this.getOpenSound(), pPos, 0);
}
private int getOpenSound() {
return 1005;
}
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
if (state.getValue(HALF) == DoubleBlockHalf.UPPER)
return null;
return IBE.super.newBlockEntity(pos, state);
}
@Override
public Class<TFMGSlidingDoorBlockEntity> getBlockEntityClass() {
return TFMGSlidingDoorBlockEntity.class;
}
@Override
public BlockEntityType<? extends TFMGSlidingDoorBlockEntity> getBlockEntityType() {
return TFMGBlockEntities.TFMG_SLIDING_DOOR.get();
}
}

View File

@@ -0,0 +1,81 @@
package com.drmangotea.tfmg.content.decoration.doors;
import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser;
import net.minecraft.core.BlockPos;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.DoorBlock;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import java.util.List;
public class TFMGSlidingDoorBlockEntity extends SlidingDoorBlockEntity {
LerpedFloat animation;
int bridgeTicks;
boolean deferUpdate;
public TFMGSlidingDoorBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
animation = LerpedFloat.linear()
.startWithValue(isOpen(state) ? 1 : 0);
}
@Override
public void tick() {
if (deferUpdate && !level.isClientSide()) {
deferUpdate = false;
BlockState blockState = getBlockState();
blockState.neighborChanged(level, worldPosition, Blocks.AIR, worldPosition, false);
}
super.tick();
boolean open = isOpen(getBlockState());
boolean wasSettled = animation.settled();
animation.chase(open ? 1 : 0, .15f, Chaser.LINEAR);
animation.tickChaser();
if (level.isClientSide()) {
if (bridgeTicks < 2 && open)
bridgeTicks++;
else if (bridgeTicks > 0 && !open && isVisible(getBlockState()))
bridgeTicks--;
return;
}
if (!open && !wasSettled && animation.settled() && !isVisible(getBlockState()))
showBlockModel();
}
@Override
protected AABB createRenderBoundingBox() {
return super.createRenderBoundingBox().inflate(1);
}
protected boolean isVisible(BlockState state) {
return state.getOptionalValue(TFMGSlidingDoorBlock.VISIBLE)
.orElse(true);
}
protected boolean shouldRenderSpecial(BlockState state) {
return !isVisible(state) || bridgeTicks != 0;
}
protected void showBlockModel() {
level.setBlock(worldPosition, getBlockState().setValue(TFMGSlidingDoorBlock.VISIBLE, true), 3);
level.playSound(null, worldPosition, SoundEvents.IRON_DOOR_CLOSE, SoundSource.BLOCKS, .5f, 1);
}
@Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {}
public static boolean isOpen(BlockState state) {
return state.getOptionalValue(DoorBlock.OPEN)
.orElse(false);
}
}

View File

@@ -0,0 +1,90 @@
package com.drmangotea.tfmg.content.decoration.doors;
import com.drmangotea.tfmg.registry.TFMGPartialModels;
import com.jozufozu.flywheel.core.PartialModel;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer;
import com.simibubi.create.foundation.render.CachedBufferer;
import com.simibubi.create.foundation.render.SuperByteBuffer;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider.Context;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
import net.minecraft.world.level.block.DoorBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.DoorHingeSide;
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.registries.ForgeRegistries;
public class TFMGSlidingDoorRenderer extends SafeBlockEntityRenderer<TFMGSlidingDoorBlockEntity> {
public TFMGSlidingDoorRenderer(Context context) {}
@Override
protected void renderSafe(TFMGSlidingDoorBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer,
int light, int overlay) {
BlockState blockState = be.getBlockState();
if (!be.shouldRenderSpecial(blockState))
return;
Direction facing = blockState.getValue(DoorBlock.FACING);
Direction movementDirection = facing.getClockWise();
if (blockState.getValue(DoorBlock.HINGE) == DoorHingeSide.LEFT)
movementDirection = movementDirection.getOpposite();
float value = be.animation.getValue(partialTicks);
float value2 = Mth.clamp(value * 10, 0, 1);
VertexConsumer vb = buffer.getBuffer(RenderType.cutoutMipped());
Vec3 offset = Vec3.atLowerCornerOf(movementDirection.getNormal())
.scale(value * value * 13 / 16f)
.add(Vec3.atLowerCornerOf(facing.getNormal())
.scale(value2 * 1 / 32f));
if (((TFMGSlidingDoorBlock) blockState.getBlock()).isFoldingDoor()) {
Couple<PartialModel> partials =
TFMGPartialModels.FOLDING_DOORS.get(ForgeRegistries.BLOCKS.getKey(blockState.getBlock()));
if(partials==null)
return;
boolean flip = blockState.getValue(DoorBlock.HINGE) == DoorHingeSide.RIGHT;
for (boolean left : Iterate.trueAndFalse) {
SuperByteBuffer partial = CachedBufferer.partial(partials.get(left ^ flip), blockState);
float f = flip ? -1 : 1;
partial.translate(0, -1 / 512f, 0)
.translate(Vec3.atLowerCornerOf(facing.getNormal())
.scale(value2 * 1 / 32f));
partial.rotateCentered(Direction.UP,
Mth.DEG_TO_RAD * AngleHelper.horizontalAngle(facing.getClockWise()));
if (flip)
partial.translate(0, 0, 1);
partial.rotateY(91 * f * value * value);
if (!left)
partial.translate(0, 0, f / 2f)
.rotateY(-181 * f * value * value);
if (flip)
partial.translate(0, 0, -1 / 2f);
partial.light(light)
.renderInto(ms, vb);
}
return;
}
for (DoubleBlockHalf half : DoubleBlockHalf.values()) {
CachedBufferer.block(blockState.setValue(DoorBlock.OPEN, false)
.setValue(DoorBlock.HALF, half))
.translate(0, half == DoubleBlockHalf.UPPER ? 1 - 1 / 512f : 0, 0)
.translate(offset)
.light(light)
.renderInto(ms, vb);
}
}
}

View File

@@ -0,0 +1,305 @@
package com.drmangotea.tfmg.content.decoration.encased;
import com.drmangotea.tfmg.registry.TFMGBlockEntities;
import com.drmangotea.tfmg.registry.TFMGBlocks;
import com.simibubi.create.content.contraptions.ITransformableBlock;
import com.simibubi.create.content.contraptions.StructureTransform;
import com.simibubi.create.content.decoration.encasing.EncasedBlock;
import com.simibubi.create.content.kinetics.base.IRotate;
import com.simibubi.create.content.kinetics.base.KineticBlockEntity;
import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock;
import com.simibubi.create.content.kinetics.simpleRelays.CogWheelBlock;
import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel;
import com.simibubi.create.content.kinetics.simpleRelays.SimpleKineticBlockEntity;
import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement;
import com.simibubi.create.content.schematics.requirement.ItemRequirement;
import com.simibubi.create.foundation.block.IBE;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.VoxelShaper;
import com.tterrag.registrate.util.entry.BlockEntityEntry;
import com.tterrag.registrate.util.entry.BlockEntry;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import java.util.function.Supplier;
public class TFMGEncasedCogwheelBlock extends RotatedPillarKineticBlock
implements ICogWheel, IBE<SimpleKineticBlockEntity>, ISpecialBlockItemRequirement, ITransformableBlock, EncasedBlock {
public static final BooleanProperty TOP_SHAFT = BooleanProperty.create("top_shaft");
public static final BooleanProperty BOTTOM_SHAFT = BooleanProperty.create("bottom_shaft");
protected final boolean isLarge;
private final Supplier<Block> casing;
private final BlockEntry<?> blockSmall;
private final BlockEntry<?> blockLarge;
private final BlockEntityEntry<SimpleKineticBlockEntity> beSmall;
private final BlockEntityEntry<SimpleKineticBlockEntity> beLarge;
public static TFMGEncasedCogwheelBlock steel(Properties properties, boolean large, Supplier<Block> casing) {
return new TFMGEncasedCogwheelBlock(properties, large, casing, TFMGBlocks.STEEL_COGWHEEL, TFMGBlocks.LARGE_STEEL_COGWHEEL, TFMGBlockEntities.ENCASED_STEEL_COGWHEEL, TFMGBlockEntities.ENCASED_LARGE_STEEL_COGWHEEL);
}
public static TFMGEncasedCogwheelBlock aluminum(Properties properties, boolean large, Supplier<Block> casing) {
return new TFMGEncasedCogwheelBlock(properties, large, casing, TFMGBlocks.ALUMINUM_COGWHEEL, TFMGBlocks.LARGE_ALUMINUM_COGWHEEL, TFMGBlockEntities.ENCASED_ALUMINUM_COGWHEEL, TFMGBlockEntities.ENCASED_LARGE_ALUMINUM_COGWHEEL);
}
public TFMGEncasedCogwheelBlock(Properties properties, boolean large, Supplier<Block> casing, BlockEntry<?> blockSmall, BlockEntry<?> blockLarge, BlockEntityEntry<SimpleKineticBlockEntity> beSmall, BlockEntityEntry<SimpleKineticBlockEntity> beLarge) {
super(properties);
this.beSmall = beSmall;
this.beLarge = beLarge;
this.blockSmall = blockSmall;
this.blockLarge = blockLarge;
isLarge = large;
this.casing = casing;
registerDefaultState(defaultBlockState().setValue(TOP_SHAFT, false)
.setValue(BOTTOM_SHAFT, false));
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder.add(TOP_SHAFT, BOTTOM_SHAFT));
}
@Override
public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter world, BlockPos pos, Player player) {
if (target instanceof BlockHitResult)
return ((BlockHitResult) target).getDirection()
.getAxis() != getRotationAxis(state)
? isLarge ? blockLarge.asStack() : blockSmall.asStack()
: getCasing().asItem().getDefaultInstance();
return super.getCloneItemStack(state, target, world, pos, player);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockState placedOn = context.getLevel()
.getBlockState(context.getClickedPos()
.relative(context.getClickedFace()
.getOpposite()));
BlockState stateForPlacement = super.getStateForPlacement(context);
if (ICogWheel.isSmallCog(placedOn))
stateForPlacement =
stateForPlacement.setValue(AXIS, ((IRotate) placedOn.getBlock()).getRotationAxis(placedOn));
return stateForPlacement;
}
@Override
public boolean skipRendering(BlockState pState, BlockState pAdjacentBlockState, Direction pDirection) {
return pState.getBlock() == pAdjacentBlockState.getBlock()
&& pState.getValue(AXIS) == pAdjacentBlockState.getValue(AXIS);
}
@Override
public InteractionResult onWrenched(BlockState state, UseOnContext context) {
if (context.getClickedFace()
.getAxis() != state.getValue(AXIS))
return super.onWrenched(state, context);
Level level = context.getLevel();
if (level.isClientSide)
return InteractionResult.SUCCESS;
BlockPos pos = context.getClickedPos();
KineticBlockEntity.switchToBlockState(level, pos, state.cycle(context.getClickedFace()
.getAxisDirection() == Direction.AxisDirection.POSITIVE ? TOP_SHAFT : BOTTOM_SHAFT));
playRotateSound(level, pos);
return InteractionResult.SUCCESS;
}
@Override
public BlockState getRotatedBlockState(BlockState originalState, Direction targetedFace) {
originalState = swapShaftsForRotation(originalState, Rotation.CLOCKWISE_90, targetedFace.getAxis());
return originalState.setValue(RotatedPillarKineticBlock.AXIS,
VoxelShaper
.axisAsFace(originalState.getValue(RotatedPillarKineticBlock.AXIS))
.getClockWise(targetedFace.getAxis())
.getAxis());
}
@Override
public InteractionResult onSneakWrenched(BlockState state, UseOnContext context) {
if (context.getLevel().isClientSide)
return InteractionResult.SUCCESS;
context.getLevel()
.levelEvent(2001, context.getClickedPos(), Block.getId(state));
KineticBlockEntity.switchToBlockState(context.getLevel(), context.getClickedPos(),
(isLarge ? blockLarge : blockSmall).getDefaultState()
.setValue(AXIS, state.getValue(AXIS)));
return InteractionResult.SUCCESS;
}
@Override
public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) {
return face.getAxis() == state.getValue(AXIS)
&& state.getValue(face.getAxisDirection() == Direction.AxisDirection.POSITIVE ? TOP_SHAFT : BOTTOM_SHAFT);
}
@Override
protected boolean areStatesKineticallyEquivalent(BlockState oldState, BlockState newState) {
if (newState.getBlock() instanceof TFMGEncasedCogwheelBlock
&& oldState.getBlock() instanceof TFMGEncasedCogwheelBlock) {
if (newState.getValue(TOP_SHAFT) != oldState.getValue(TOP_SHAFT))
return false;
if (newState.getValue(BOTTOM_SHAFT) != oldState.getValue(BOTTOM_SHAFT))
return false;
}
return super.areStatesKineticallyEquivalent(oldState, newState);
}
@Override
public boolean isSmallCog() {
return !isLarge;
}
@Override
public boolean isLargeCog() {
return isLarge;
}
@Override
public boolean canSurvive(BlockState state, LevelReader worldIn, BlockPos pos) {
return CogWheelBlock.isValidCogwheelPosition(ICogWheel.isLargeCog(state), worldIn, pos, state.getValue(AXIS));
}
@Override
public Direction.Axis getRotationAxis(BlockState state) {
return state.getValue(AXIS);
}
public BlockState swapShafts(BlockState state) {
boolean bottom = state.getValue(BOTTOM_SHAFT);
boolean top = state.getValue(TOP_SHAFT);
state = state.setValue(BOTTOM_SHAFT, top);
state = state.setValue(TOP_SHAFT, bottom);
return state;
}
public BlockState swapShaftsForRotation(BlockState state, Rotation rotation, Direction.Axis rotationAxis) {
if (rotation == Rotation.NONE) {
return state;
}
Direction.Axis axis = state.getValue(AXIS);
if (axis == rotationAxis) {
return state;
}
if (rotation == Rotation.CLOCKWISE_180) {
return swapShafts(state);
}
boolean clockwise = rotation == Rotation.CLOCKWISE_90;
if (rotationAxis == Direction.Axis.X) {
if (axis == Direction.Axis.Z && !clockwise
|| axis == Direction.Axis.Y && clockwise) {
return swapShafts(state);
}
} else if (rotationAxis == Direction.Axis.Y) {
if (axis == Direction.Axis.X && !clockwise
|| axis == Direction.Axis.Z && clockwise) {
return swapShafts(state);
}
} else if (rotationAxis == Direction.Axis.Z) {
if (axis == Direction.Axis.Y && !clockwise
|| axis == Direction.Axis.X && clockwise) {
return swapShafts(state);
}
}
return state;
}
@Override
public BlockState mirror(BlockState state, Mirror mirror) {
Direction.Axis axis = state.getValue(AXIS);
if (axis == Direction.Axis.X && mirror == Mirror.FRONT_BACK
|| axis == Direction.Axis.Z && mirror == Mirror.LEFT_RIGHT) {
return swapShafts(state);
}
return state;
}
@Override
public BlockState rotate(BlockState state, Rotation rotation) {
state = swapShaftsForRotation(state, rotation, Direction.Axis.Y);
return super.rotate(state, rotation);
}
@Override
public BlockState transform(BlockState state, StructureTransform transform) {
if (transform.mirror != null) {
state = mirror(state, transform.mirror);
}
if (transform.rotationAxis == Direction.Axis.Y) {
return rotate(state, transform.rotation);
}
state = swapShaftsForRotation(state, transform.rotation, transform.rotationAxis);
state = state.setValue(AXIS, transform.rotateAxis(state.getValue(AXIS)));
return state;
}
@Override
public ItemRequirement getRequiredItems(BlockState state, BlockEntity be) {
return ItemRequirement
.of(isLarge ? blockLarge.getDefaultState() : blockSmall.getDefaultState(), be);
}
@Override
public Class<SimpleKineticBlockEntity> getBlockEntityClass() {
return SimpleKineticBlockEntity.class;
}
@Override
public BlockEntityType<? extends SimpleKineticBlockEntity> getBlockEntityType() {
return isLarge ? beLarge.get() : beSmall.get();
}
@Override
public Block getCasing() {
return casing.get();
}
@Override
public void handleEncasing(BlockState state, Level level, BlockPos pos, ItemStack heldItem, Player player, InteractionHand hand,
BlockHitResult ray) {
BlockState encasedState = defaultBlockState()
.setValue(AXIS, state.getValue(AXIS));
for (Direction d : Iterate.directionsInAxis(state.getValue(AXIS))) {
BlockState adjacentState = level.getBlockState(pos.relative(d));
if (!(adjacentState.getBlock() instanceof IRotate))
continue;
IRotate def = (IRotate) adjacentState.getBlock();
if (!def.hasShaftTowards(level, pos.relative(d), adjacentState, d.getOpposite()))
continue;
encasedState =
encasedState.cycle(d.getAxisDirection() == Direction.AxisDirection.POSITIVE ? TFMGEncasedCogwheelBlock.TOP_SHAFT
: TFMGEncasedCogwheelBlock.BOTTOM_SHAFT);
}
KineticBlockEntity.switchToBlockState(level, pos, encasedState);
}
}

View File

@@ -0,0 +1,86 @@
package com.drmangotea.tfmg.content.decoration.encased;
import com.drmangotea.tfmg.registry.TFMGBlockEntities;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.decoration.encasing.EncasedBlock;
import com.simibubi.create.content.kinetics.base.AbstractEncasedShaftBlock;
import com.simibubi.create.content.kinetics.base.KineticBlockEntity;
import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock;
import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement;
import com.simibubi.create.content.schematics.requirement.ItemRequirement;
import com.simibubi.create.foundation.block.IBE;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import java.util.function.Supplier;
public class TFMGEncasedShaftBlock extends AbstractEncasedShaftBlock
implements IBE<KineticBlockEntity>, ISpecialBlockItemRequirement, EncasedBlock {
private final Supplier<Block> casing;
public TFMGEncasedShaftBlock(Properties properties, Supplier<Block> casing) {
super(properties);
this.casing = casing;
}
@Override
public InteractionResult onSneakWrenched(BlockState state, UseOnContext context) {
if (context.getLevel().isClientSide)
return InteractionResult.SUCCESS;
context.getLevel()
.levelEvent(2001, context.getClickedPos(), Block.getId(state));
KineticBlockEntity.switchToBlockState(context.getLevel(), context.getClickedPos(),
AllBlocks.SHAFT.getDefaultState()
.setValue(AXIS, state.getValue(AXIS)));
return InteractionResult.SUCCESS;
}
@Override
public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter world, BlockPos pos, Player player) {
if (target instanceof BlockHitResult)
return ((BlockHitResult) target).getDirection()
.getAxis() == getRotationAxis(state) ? AllBlocks.SHAFT.asStack() : getCasing().asItem().getDefaultInstance();
return super.getCloneItemStack(state, target, world, pos, player);
}
@Override
public ItemRequirement getRequiredItems(BlockState state, BlockEntity be) {
return ItemRequirement.of(AllBlocks.SHAFT.getDefaultState(), be);
}
@Override
public Class<KineticBlockEntity> getBlockEntityClass() {
return KineticBlockEntity.class;
}
@Override
public BlockEntityType<? extends KineticBlockEntity> getBlockEntityType() {
return TFMGBlockEntities.TFMG_ENCASED_SHAFT.get();
}
@Override
public Block getCasing() {
return casing.get();
}
@Override
public void handleEncasing(BlockState state, Level level, BlockPos pos, ItemStack heldItem, Player player, InteractionHand hand,
BlockHitResult ray) {
KineticBlockEntity.switchToBlockState(level, pos, defaultBlockState()
.setValue(RotatedPillarKineticBlock.AXIS, state.getValue(RotatedPillarKineticBlock.AXIS)));
}
}

View File

@@ -0,0 +1,65 @@
package com.drmangotea.tfmg.content.decoration.flywheels;
import com.drmangotea.tfmg.registry.TFMGBlockEntities;
import com.simibubi.create.AllShapes;
import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock;
import com.simibubi.create.foundation.block.IBE;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class TFMGFlywheelBlock extends RotatedPillarKineticBlock implements IBE<TFMGFlywheelBlockEntity> {
public TFMGFlywheelBlock(Properties properties) {
super(properties);
}
@Override
public Class<TFMGFlywheelBlockEntity> getBlockEntityClass() {
return TFMGFlywheelBlockEntity.class;
}
@Override
public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) {
return AllShapes.LARGE_GEAR.get(pState.getValue(AXIS));
}
@Override
public RenderShape getRenderShape(BlockState pState) {
return RenderShape.ENTITYBLOCK_ANIMATED;
}
@Override
public BlockEntityType<? extends TFMGFlywheelBlockEntity> getBlockEntityType() {
return TFMGBlockEntities.TFMG_FLYWHEEL.get();
}
@Override
public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) {
return face.getAxis() == getRotationAxis(state);
}
@Override
public Axis getRotationAxis(BlockState state) {
return state.getValue(AXIS);
}
@Override
public float getParticleTargetRadius() {
return 2f;
}
@Override
public float getParticleInitialRadius() {
return 1.75f;
}
}

View File

@@ -0,0 +1,53 @@
package com.drmangotea.tfmg.content.decoration.flywheels;
import com.simibubi.create.content.kinetics.base.KineticBlockEntity;
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
public class TFMGFlywheelBlockEntity extends KineticBlockEntity {
LerpedFloat visualSpeed = LerpedFloat.linear();
float angle;
public TFMGFlywheelBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
}
@Override
protected AABB createRenderBoundingBox() {
return super.createRenderBoundingBox().inflate(2);
}
@Override
public void write(CompoundTag compound, boolean clientPacket) {
super.write(compound, clientPacket);
}
@Override
protected void read(CompoundTag compound, boolean clientPacket) {
super.read(compound, clientPacket);
if (clientPacket)
visualSpeed.chase(getGeneratedSpeed(), 1 / 64f, Chaser.EXP);
}
@Override
public void tick() {
super.tick();
if (!level.isClientSide)
return;
float targetSpeed = getSpeed();
visualSpeed.updateChaseTarget(targetSpeed);
visualSpeed.tickChaser();
angle += visualSpeed.getValue() * 3 / 10f;
angle %= 360;
}
}

View File

@@ -0,0 +1,75 @@
package com.drmangotea.tfmg.content.decoration.flywheels;
import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.core.materials.model.ModelData;
import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.content.kinetics.base.KineticBlockEntityInstance;
import com.simibubi.create.content.kinetics.base.flwdata.RotatingData;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import net.minecraft.core.Direction;
public class TFMGFlywheelInstance extends KineticBlockEntityInstance<TFMGFlywheelBlockEntity> implements DynamicInstance {
protected final RotatingData shaft;
protected final ModelData wheel;
protected float lastAngle = Float.NaN;
public TFMGFlywheelInstance(MaterialManager materialManager, TFMGFlywheelBlockEntity blockEntity) {
super(materialManager, blockEntity);
shaft = setup(getRotatingMaterial().getModel(shaft())
.createInstance());
wheel = getTransformMaterial().getModel(blockState)
.createInstance();
animate(blockEntity.angle);
}
@Override
public void beginFrame() {
float partialTicks = AnimationTickHolder.getPartialTicks();
float speed = blockEntity.visualSpeed.getValue(partialTicks) * 3 / 10f;
float angle = blockEntity.angle + speed * partialTicks;
if (Math.abs(angle - lastAngle) < 0.001)
return;
animate(angle);
lastAngle = angle;
}
private void animate(float angle) {
PoseStack ms = new PoseStack();
TransformStack msr = TransformStack.cast(ms);
msr.translate(getInstancePosition());
msr.centre()
.rotate(Direction.get(Direction.AxisDirection.POSITIVE, axis), AngleHelper.rad(angle))
.unCentre();
wheel.setTransform(ms);
}
@Override
public void update() {
updateRotation(shaft);
}
@Override
public void updateLight() {
relight(pos, shaft, wheel);
}
@Override
public void remove() {
shaft.delete();
wheel.delete();
}
}

View File

@@ -0,0 +1,50 @@
package com.drmangotea.tfmg.content.decoration.flywheels;
import com.jozufozu.flywheel.backend.Backend;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer;
import com.simibubi.create.foundation.render.CachedBufferer;
import com.simibubi.create.foundation.render.SuperByteBuffer;
import com.simibubi.create.foundation.utility.AngleHelper;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.world.level.block.state.BlockState;
public class TFMGFlywheelRenderer extends KineticBlockEntityRenderer<TFMGFlywheelBlockEntity> {
public TFMGFlywheelRenderer(BlockEntityRendererProvider.Context context) {
super(context);
}
@Override
protected void renderSafe(TFMGFlywheelBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer,
int light, int overlay) {
super.renderSafe(be, partialTicks, ms, buffer, light, overlay);
if (Backend.canUseInstancing(be.getLevel()))
return;
BlockState blockState = be.getBlockState();
float speed = be.visualSpeed.getValue(partialTicks) * 3 / 10f;
float angle = be.angle + speed * partialTicks;
VertexConsumer vb = buffer.getBuffer(RenderType.solid());
renderFlywheel(be, ms, light, blockState, angle, vb);
}
private void renderFlywheel(TFMGFlywheelBlockEntity be, PoseStack ms, int light, BlockState blockState, float angle,
VertexConsumer vb) {
SuperByteBuffer wheel = CachedBufferer.block(blockState);
kineticRotationTransform(wheel, be, getRotationAxisOf(be), AngleHelper.rad(angle), light);
wheel.renderInto(ms, vb);
}
@Override
protected BlockState getRenderedBlockState(TFMGFlywheelBlockEntity be) {
return shaft(getRotationAxisOf(be));
}
}

View File

@@ -0,0 +1,66 @@
package com.drmangotea.tfmg.content.decoration.gearbox;
import com.drmangotea.tfmg.registry.TFMGBlockEntities;
import com.drmangotea.tfmg.registry.TFMGItems;
import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock;
import com.simibubi.create.content.kinetics.gearbox.GearboxBlockEntity;
import com.simibubi.create.foundation.block.IBE;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.PushReaction;
import net.minecraft.world.phys.HitResult;
public class SteelGearboxBlock extends RotatedPillarKineticBlock implements IBE<GearboxBlockEntity> {
public SteelGearboxBlock(Properties properties) {
super(properties);
}
@Override
public PushReaction getPistonPushReaction(BlockState state) {
return PushReaction.PUSH_ONLY;
}
@Override
public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter world, BlockPos pos,
Player player) {
if (state.getValue(AXIS).isVertical())
return super.getCloneItemStack(state, target, world, pos, player);
return new ItemStack(TFMGItems.STEEL_VERTICAL_GEARBOX.get());
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return defaultBlockState().setValue(AXIS, Axis.Y);
}
// IRotate:
@Override
public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) {
return face.getAxis() != state.getValue(AXIS);
}
@Override
public Axis getRotationAxis(BlockState state) {
return state.getValue(AXIS);
}
@Override
public Class<GearboxBlockEntity> getBlockEntityClass() {
return GearboxBlockEntity.class;
}
@Override
public BlockEntityType<? extends GearboxBlockEntity> getBlockEntityType() {
return TFMGBlockEntities.STEEL_GEARBOX.get();
}
}

View File

@@ -0,0 +1,59 @@
package com.drmangotea.tfmg.content.decoration.gearbox;
import com.drmangotea.tfmg.registry.TFMGBlocks;
import com.simibubi.create.content.kinetics.base.IRotate;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import java.util.Map;
public class SteelVerticalGearboxItem extends BlockItem {
public SteelVerticalGearboxItem(Properties builder) {
super(TFMGBlocks.STEEL_GEARBOX.get(), builder);
}
@Override
public String getDescriptionId() {
return "item.tfmg.steel_vertical_gearbox";
}
@Override
public void registerBlocks(Map<Block, Item> p_195946_1_, Item p_195946_2_) {
}
@Override
protected boolean updateCustomBlockEntityTag(BlockPos pos, Level world, Player player, ItemStack stack, BlockState state) {
Axis prefferedAxis = null;
for (Direction side : Iterate.horizontalDirections) {
BlockState blockState = world.getBlockState(pos.relative(side));
if (blockState.getBlock() instanceof IRotate) {
if (((IRotate) blockState.getBlock()).hasShaftTowards(world, pos.relative(side), blockState,
side.getOpposite()))
if (prefferedAxis != null && prefferedAxis != side.getAxis()) {
prefferedAxis = null;
break;
} else {
prefferedAxis = side.getAxis();
}
}
}
Axis axis = prefferedAxis == null ? player.getDirection()
.getClockWise()
.getAxis() : prefferedAxis == Axis.X ? Axis.Z : Axis.X;
world.setBlockAndUpdate(pos, state.setValue(BlockStateProperties.AXIS, axis));
return super.updateCustomBlockEntityTag(pos, world, player, stack, state);
}
}

View File

@@ -0,0 +1,67 @@
package com.drmangotea.tfmg.content.decoration.pipes;
import com.drmangotea.tfmg.registry.TFMGBlockEntities;
import com.simibubi.create.content.fluids.FluidTransportBehaviour;
import com.simibubi.create.content.fluids.pipes.EncasedPipeBlock;
import com.simibubi.create.content.fluids.pipes.FluidPipeBlockEntity;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.HitResult;
import java.util.function.Supplier;
public class TFMGEncasedPipeBlock extends EncasedPipeBlock {
public final TFMGPipes.PipeMaterial material;
public TFMGEncasedPipeBlock(Properties p_i48339_1_, Supplier<Block> casing, TFMGPipes.PipeMaterial material) {
super(p_i48339_1_, casing);
this.material = material;
}
@Override
public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter world, BlockPos pos, Player player) {
return TFMGPipes.TFMG_PIPES.get(material).get(0).asStack();
}
@Override
public InteractionResult onWrenched(BlockState state, UseOnContext context) {
Level world = context.getLevel();
BlockPos pos = context.getClickedPos();
if (world.isClientSide)
return InteractionResult.SUCCESS;
context.getLevel()
.levelEvent(2001, context.getClickedPos(), Block.getId(state));
BlockState equivalentPipe = transferSixWayProperties(state, TFMGPipes.TFMG_PIPES.get(material).get(0).getDefaultState());
Direction firstFound = Direction.UP;
for (Direction d : Iterate.directions)
if (state.getValue(FACING_TO_PROPERTY_MAP.get(d))) {
firstFound = d;
break;
}
FluidTransportBehaviour.cacheFlows(world, pos);
world.setBlockAndUpdate(pos, ((TFMGPipeBlock)TFMGPipes.TFMG_PIPES.get(material).get(0).get())
.updateBlockState(equivalentPipe, firstFound, null, world, pos));
FluidTransportBehaviour.loadFlows(world, pos);
return InteractionResult.SUCCESS;
}
@Override
public Class<FluidPipeBlockEntity> getBlockEntityClass() {
return FluidPipeBlockEntity.class;
}
@Override
public BlockEntityType<? extends FluidPipeBlockEntity> getBlockEntityType() {
return TFMGBlockEntities.ENCASED_TFMG_PIPE.get();
}
}

View File

@@ -0,0 +1,33 @@
package com.drmangotea.tfmg.content.decoration.pipes;
import com.drmangotea.tfmg.registry.TFMGBlockEntities;
import com.simibubi.create.content.fluids.pipes.IAxisPipe;
import com.simibubi.create.content.fluids.pipes.valve.FluidValveBlock;
import com.simibubi.create.content.fluids.pipes.valve.FluidValveBlockEntity;
import com.simibubi.create.foundation.block.IBE;
import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
public class TFMGFluidValveBlock extends FluidValveBlock
implements IAxisPipe, IBE<FluidValveBlockEntity>, ProperWaterloggedBlock {
public static final BooleanProperty ENABLED = BooleanProperty.create("enabled");
public TFMGFluidValveBlock(Properties properties) {
super(properties);
registerDefaultState(defaultBlockState().setValue(ENABLED, false)
.setValue(WATERLOGGED, false));
}
@Override
public Class<FluidValveBlockEntity> getBlockEntityClass() {
return FluidValveBlockEntity.class;
}
@Override
public BlockEntityType<? extends FluidValveBlockEntity> getBlockEntityType() {
return TFMGBlockEntities.TFMG_FLUID_VALVE.get();
}
}

View File

@@ -0,0 +1,86 @@
package com.drmangotea.tfmg.content.decoration.pipes;
import com.drmangotea.tfmg.registry.TFMGBlockEntities;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.fluids.FluidTransportBehaviour;
import com.simibubi.create.content.fluids.pipes.EncasedPipeBlock;
import com.simibubi.create.content.fluids.pipes.FluidPipeBlock;
import com.simibubi.create.content.fluids.pipes.GlassFluidPipeBlock;
import com.simibubi.create.content.fluids.pipes.StraightPipeBlockEntity;
import com.simibubi.create.content.schematics.requirement.ItemRequirement;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import java.util.Map;
public class TFMGGlassPipeBlock extends GlassFluidPipeBlock {
public final TFMGPipes.PipeMaterial material;
public TFMGGlassPipeBlock(Properties p_i48339_1_, TFMGPipes.PipeMaterial material) {
super(p_i48339_1_);
this.material = material;
}
@Override
public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) {
return ItemRequirement.of(TFMGPipes.TFMG_PIPES.get(material).get(0).getDefaultState(), te);
}
@Override
public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter world, BlockPos pos,
Player player) {
return TFMGPipes.TFMG_PIPES.get(material).get(0).asStack();
}
@Override
public BlockState toRegularPipe(LevelAccessor world, BlockPos pos, BlockState state) {
Direction side = Direction.get(Direction.AxisDirection.POSITIVE, state.getValue(AXIS));
Map<Direction, BooleanProperty> facingToPropertyMap = FluidPipeBlock.PROPERTY_BY_DIRECTION;
return ((TFMGPipeBlock) TFMGPipes.TFMG_PIPES.get(material).get(0).get())
.updateBlockState(TFMGPipes.TFMG_PIPES.get(material).get(0).getDefaultState()
.setValue(facingToPropertyMap.get(side), true)
.setValue(facingToPropertyMap.get(side.getOpposite()), true), side, null, world, pos);
}
@Override
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand,
BlockHitResult hit) {
if (!AllBlocks.COPPER_CASING.isIn(player.getItemInHand(hand)))
return InteractionResult.PASS;
if (world.isClientSide)
return InteractionResult.SUCCESS;
BlockState newState = TFMGPipes.TFMG_PIPES.get(material).get(1).getDefaultState();
for (Direction d : Iterate.directionsInAxis(getAxis(state)))
newState = newState.setValue(EncasedPipeBlock.FACING_TO_PROPERTY_MAP.get(d), true);
FluidTransportBehaviour.cacheFlows(world, pos);
world.setBlockAndUpdate(pos, newState);
FluidTransportBehaviour.loadFlows(world, pos);
return InteractionResult.SUCCESS;
}
@Override
public Class<StraightPipeBlockEntity> getBlockEntityClass() {
return StraightPipeBlockEntity.class;
}
@Override
public BlockEntityType<? extends StraightPipeBlockEntity> getBlockEntityType() {
return TFMGBlockEntities.GLASS_TFMG_PIPE.get();
}
}

View File

@@ -0,0 +1,148 @@
package com.drmangotea.tfmg.content.decoration.pipes;
import com.drmangotea.tfmg.registry.TFMGPartialModels;
import com.simibubi.create.content.decoration.bracket.BracketedBlockEntityBehaviour;
import com.simibubi.create.content.fluids.FluidTransportBehaviour;
import com.simibubi.create.content.fluids.pipes.FluidPipeBlock;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
import com.simibubi.create.foundation.model.BakedModelWrapperWithData;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ItemBlockRenderTypes;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.ChunkRenderTypeSet;
import net.minecraftforge.client.model.data.ModelData;
import net.minecraftforge.client.model.data.ModelProperty;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static net.minecraft.world.level.block.PipeBlock.PROPERTY_BY_DIRECTION;
public class TFMGPipeAttachmentModel extends BakedModelWrapperWithData {
public final TFMGPipes.PipeMaterial material;
private static final ModelProperty<PipeModelData> PIPE_PROPERTY = new ModelProperty<>();
public TFMGPipeAttachmentModel(BakedModel template, TFMGPipes.PipeMaterial material) {
super(template);
this.material = material;
}
@Override
protected ModelData.Builder gatherModelData(ModelData.Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state,
ModelData blockEntityData) {
PipeModelData data = new PipeModelData();
FluidTransportBehaviour transport = BlockEntityBehaviour.get(world, pos, FluidTransportBehaviour.TYPE);
BracketedBlockEntityBehaviour bracket = BlockEntityBehaviour.get(world, pos, BracketedBlockEntityBehaviour.TYPE);
if (transport != null)
for (Direction d : Iterate.directions) {
boolean shouldConnect = true;
if (world.getBlockState(pos.relative(d)).getBlock() instanceof FluidPipeBlock) {
if (d.getAxis().isHorizontal())
shouldConnect = world.getBlockState(pos.relative(d)).getValue(PROPERTY_BY_DIRECTION.get(d.getOpposite()));
}
data.putAttachment(d, transport.getRenderedRimAttachment(world, pos, state, d));
if (!shouldConnect)
if (state.getBlock() instanceof FluidPipeBlock)
if (state.getValue(PROPERTY_BY_DIRECTION.get(d)))
data.putAttachment(d, FluidTransportBehaviour.AttachmentTypes.RIM);
}
if (bracket != null)
data.putBracket(bracket.getBracket());
data.setEncased(FluidPipeBlock.shouldDrawCasing(world, pos, state));
return builder.with(PIPE_PROPERTY, data);
}
@SuppressWarnings("removal")
@Override
public ChunkRenderTypeSet getRenderTypes(@NotNull BlockState state, @NotNull RandomSource rand, @NotNull ModelData data) {
ChunkRenderTypeSet set = super.getRenderTypes(state, rand, data);
if (set.isEmpty()) {
return ItemBlockRenderTypes.getRenderLayers(state);
}
return set;
}
@Override
public List<BakedQuad> getQuads(BlockState state, Direction side, RandomSource rand, ModelData data, RenderType renderType) {
List<BakedQuad> quads = super.getQuads(state, side, rand, data, renderType);
if (data.has(PIPE_PROPERTY)) {
PipeModelData pipeData = data.get(PIPE_PROPERTY);
quads = new ArrayList<>(quads);
addQuads(quads, state, side, rand, data, pipeData, renderType);
}
return quads;
}
private void addQuads(List<BakedQuad> quads, BlockState state, Direction side, RandomSource rand, ModelData data,
PipeModelData pipeData, RenderType renderType) {
BakedModel bracket = pipeData.getBracket();
if (bracket != null)
quads.addAll(bracket.getQuads(state, side, rand, data, renderType));
for (Direction d : Iterate.directions) {
FluidTransportBehaviour.AttachmentTypes type = pipeData.getAttachment(d);
for (FluidTransportBehaviour.AttachmentTypes.ComponentPartials partial : type.partials) {
quads.addAll(TFMGPartialModels.PIPE_ATTACHMENTS.get(material).get(partial)
.get(d)
.get()
.getQuads(state, side, rand, data, renderType));
}
}
if (pipeData.isEncased())
quads.addAll(TFMGPartialModels.PIPE_CASINGS.get(material).get()
.getQuads(state, side, rand, data, renderType));
}
private static class PipeModelData {
private FluidTransportBehaviour.AttachmentTypes[] attachments;
private boolean encased;
private BakedModel bracket;
public PipeModelData() {
attachments = new FluidTransportBehaviour.AttachmentTypes[6];
Arrays.fill(attachments, FluidTransportBehaviour.AttachmentTypes.NONE);
}
public void putBracket(BlockState state) {
if (state != null) {
this.bracket = Minecraft.getInstance()
.getBlockRenderer()
.getBlockModel(state);
}
}
public BakedModel getBracket() {
return bracket;
}
public void putAttachment(Direction face, FluidTransportBehaviour.AttachmentTypes rim) {
attachments[face.get3DDataValue()] = rim;
}
public FluidTransportBehaviour.AttachmentTypes getAttachment(Direction face) {
return attachments[face.get3DDataValue()];
}
public void setEncased(boolean encased) {
this.encased = encased;
}
public boolean isEncased() {
return encased;
}
}
}

View File

@@ -0,0 +1,192 @@
package com.drmangotea.tfmg.content.decoration.pipes;
import com.drmangotea.tfmg.registry.TFMGBlockEntities;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.decoration.bracket.BracketedBlockEntityBehaviour;
import com.simibubi.create.content.fluids.FluidPropagator;
import com.simibubi.create.content.fluids.FluidTransportBehaviour;
import com.simibubi.create.content.fluids.pipes.EncasedPipeBlock;
import com.simibubi.create.content.fluids.pipes.FluidPipeBlock;
import com.simibubi.create.content.fluids.pipes.FluidPipeBlockEntity;
import com.simibubi.create.content.fluids.pipes.GlassFluidPipeBlock;
import com.simibubi.create.foundation.advancement.AllAdvancements;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import javax.annotation.Nullable;
import java.util.Arrays;
public class TFMGPipeBlock extends FluidPipeBlock {
public final TFMGPipes.PipeMaterial material;
public TFMGPipeBlock(BlockBehaviour.Properties properties, TFMGPipes.PipeMaterial material) {
super(properties);
this.material = material;
}
public BlockState updateBlockState(BlockState state, Direction preferredDirection, @Nullable Direction ignore,
BlockAndTintGetter world, BlockPos pos) {
if (world.getBlockEntity(pos) instanceof TFMGPipeBlockEntity)
if (((TFMGPipeBlockEntity) world.getBlockEntity(pos)).locked) {
return state;
}
BracketedBlockEntityBehaviour bracket = BlockEntityBehaviour.get(world, pos, BracketedBlockEntityBehaviour.TYPE);
if (bracket != null && bracket.isBracketPresent())
return state;
BlockState prevState = state;
int prevStateSides = (int) Arrays.stream(Iterate.directions)
.map(PROPERTY_BY_DIRECTION::get)
.filter(prevState::getValue)
.count();
// Update sides that are not ignored
for (Direction d : Iterate.directions)
if (d != ignore) {
boolean shouldConnect = canConnectTo(world, pos.relative(d), world.getBlockState(pos.relative(d)), d);
if (world.getBlockEntity(pos.relative(d)) instanceof TFMGPipeBlockEntity) {
if (((TFMGPipeBlockEntity) world.getBlockEntity(pos.relative(d))).locked) {
shouldConnect = false;
if (world.getBlockState(pos.relative(d)).getValue(PROPERTY_BY_DIRECTION.get(d.getOpposite()))) {
shouldConnect = true;
}
}
}
state = state.setValue(PROPERTY_BY_DIRECTION.get(d), shouldConnect);
}
// See if it has enough connections
Direction connectedDirection = null;
for (Direction d : Iterate.directions) {
if (isOpenAt(state, d)) {
if (connectedDirection != null)
return state;
connectedDirection = d;
}
}
// Add opposite end if only one connection
if (connectedDirection != null)
return state.setValue(PROPERTY_BY_DIRECTION.get(connectedDirection.getOpposite()), true);
// If we can't connect to anything and weren't connected before, do nothing
if (prevStateSides == 2)
return prevState;
// Use preferred
return state.setValue(PROPERTY_BY_DIRECTION.get(preferredDirection), true)
.setValue(PROPERTY_BY_DIRECTION.get(preferredDirection.getOpposite()), true);
}
@Override
public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource r) {
super.tick(state, world, pos, r);
}
@Override
public InteractionResult onWrenched(BlockState state, UseOnContext context) {
if (tryRemoveBracket(context))
return InteractionResult.SUCCESS;
Level world = context.getLevel();
BlockPos pos = context.getClickedPos();
Direction clickedFace = context.getClickedFace();
Direction.Axis axis = getAxis(world, pos, state);
if (axis == null) {
Vec3 clickLocation = context.getClickLocation()
.subtract(pos.getX(), pos.getY(), pos.getZ());
double closest = Float.MAX_VALUE;
Direction argClosest = Direction.UP;
for (Direction direction : Iterate.directions) {
if (clickedFace.getAxis() == direction.getAxis())
continue;
Vec3 centerOf = Vec3.atCenterOf(direction.getNormal());
double distance = centerOf.distanceToSqr(clickLocation);
if (distance < closest) {
closest = distance;
argClosest = direction;
}
}
axis = argClosest.getAxis();
}
if (clickedFace.getAxis() == axis)
return InteractionResult.PASS;
if (!world.isClientSide) {
withBlockEntityDo(world, pos, fpte -> fpte.getBehaviour(FluidTransportBehaviour.TYPE).interfaces.values()
.stream()
.filter(pc -> pc != null && pc.hasFlow())
.findAny()
.ifPresent($ -> AllAdvancements.GLASS_PIPE.awardTo(context.getPlayer())));
FluidTransportBehaviour.cacheFlows(world, pos);
world.setBlockAndUpdate(pos, TFMGPipes.TFMG_PIPES.get(material).get(2).getDefaultState()
.setValue(GlassFluidPipeBlock.AXIS, axis)
.setValue(BlockStateProperties.WATERLOGGED, state.getValue(BlockStateProperties.WATERLOGGED)));
FluidTransportBehaviour.loadFlows(world, pos);
}
return InteractionResult.SUCCESS;
}
@Nullable
private Direction.Axis getAxis(BlockGetter world, BlockPos pos, BlockState state) {
return FluidPropagator.getStraightPipeAxis(state);
}
@Override
public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter world, BlockPos pos,
Player player) {
return TFMGPipes.TFMG_PIPES.get(material).get(0).asStack();
}
@Override
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand,
BlockHitResult hit) {
if (!AllBlocks.COPPER_CASING.isIn(player.getItemInHand(hand)))
return InteractionResult.PASS;
if (world.isClientSide)
return InteractionResult.SUCCESS;
FluidTransportBehaviour.cacheFlows(world, pos);
world.setBlockAndUpdate(pos,
EncasedPipeBlock.transferSixWayProperties(state, TFMGPipes.TFMG_PIPES.get(material).get(1).getDefaultState()));
FluidTransportBehaviour.loadFlows(world, pos);
return InteractionResult.SUCCESS;
}
@Override
public Class<FluidPipeBlockEntity> getBlockEntityClass() {
return FluidPipeBlockEntity.class;
}
@Override
public BlockEntityType<? extends FluidPipeBlockEntity> getBlockEntityType() {
return TFMGBlockEntities.TFMG_PIPE.get();
}
}

View File

@@ -0,0 +1,66 @@
package com.drmangotea.tfmg.content.decoration.pipes;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.fluids.FluidTransportBehaviour;
import com.simibubi.create.content.fluids.pipes.FluidPipeBlock;
import com.simibubi.create.content.fluids.pipes.FluidPipeBlockEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.entity.BlockEntityType;
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 java.util.Map;
public class TFMGPipeBlockEntity extends FluidPipeBlockEntity {
public boolean locked = false;
public TFMGPipeBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
}
public void toggleLock(Player player) {
level.playSound(player, getBlockPos(), SoundEvents.ITEM_PICKUP, SoundSource.BLOCKS, 0.4f, 0.5f);
locked = !locked;
if (locked)
return;
BlockState newState;
Level world = level;
BlockPos pos = getBlockPos();
FluidTransportBehaviour.cacheFlows(world, pos);
newState = updatePipe(world, pos, getBlockState()).setValue(BlockStateProperties.WATERLOGGED, getBlockState().getValue(BlockStateProperties.WATERLOGGED));
world.setBlock(pos, newState, 3);
FluidTransportBehaviour.loadFlows(world, pos);
}
public BlockState updatePipe(LevelAccessor world, BlockPos pos, BlockState state) {
Direction side = Direction.UP;
Map<Direction, BooleanProperty> facingToPropertyMap = FluidPipeBlock.PROPERTY_BY_DIRECTION;
return AllBlocks.FLUID_PIPE.get()
.updateBlockState(state.getBlock().defaultBlockState()
.setValue(facingToPropertyMap.get(side), true)
.setValue(facingToPropertyMap.get(side.getOpposite()), true), side, null, world, pos);
}
@Override
public void write(CompoundTag compound, boolean clientPacket) {
compound.putBoolean("Locked", locked);
super.write(compound, clientPacket);
}
@Override
protected void read(CompoundTag compound, boolean clientPacket) {
super.read(compound, clientPacket);
locked = compound.getBoolean("Locked");
}
}

View File

@@ -0,0 +1,49 @@
package com.drmangotea.tfmg.content.decoration.pipes;
import com.simibubi.create.content.fluids.FluidTransportBehaviour;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.state.BlockState;
import java.util.Arrays;
public class TFMGPipeModelData {
private FluidTransportBehaviour.AttachmentTypes[] attachments;
private boolean encased;
private BakedModel bracket;
public TFMGPipeModelData() {
attachments = new FluidTransportBehaviour.AttachmentTypes[6];
Arrays.fill(attachments, FluidTransportBehaviour.AttachmentTypes.NONE);
}
public void putBracket(BlockState state) {
if (state != null) {
this.bracket = Minecraft.getInstance()
.getBlockRenderer()
.getBlockModel(state);
}
}
public BakedModel getBracket() {
return bracket;
}
public void putAttachment(Direction face, FluidTransportBehaviour.AttachmentTypes rim) {
attachments[face.get3DDataValue()] = rim;
}
public FluidTransportBehaviour.AttachmentTypes getAttachment(Direction face) {
return attachments[face.get3DDataValue()];
}
public void setEncased(boolean encased) {
this.encased = encased;
}
public boolean isEncased() {
return encased;
}
}

View File

@@ -0,0 +1,157 @@
package com.drmangotea.tfmg.content.decoration.pipes;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllSpriteShifts;
import com.simibubi.create.content.decoration.encasing.EncasedCTBehaviour;
import com.simibubi.create.content.decoration.encasing.EncasingRegistry;
import com.simibubi.create.content.fluids.PipeAttachmentModel;
import com.simibubi.create.content.fluids.pipes.SmartFluidPipeGenerator;
import com.simibubi.create.content.fluids.pipes.valve.FluidValveBlock;
import com.simibubi.create.content.kinetics.BlockStressDefaults;
import com.simibubi.create.foundation.data.AssetLookup;
import com.simibubi.create.foundation.data.BlockStateGen;
import com.simibubi.create.foundation.data.CreateRegistrate;
import com.simibubi.create.foundation.data.SharedProperties;
import com.tterrag.registrate.util.entry.BlockEntry;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.material.MapColor;
import net.minecraftforge.client.model.generators.ConfiguredModel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.drmangotea.tfmg.TFMG.REGISTRATE;
import static com.simibubi.create.foundation.data.ModelGen.customItemModel;
import static com.simibubi.create.foundation.data.TagGen.axeOrPickaxe;
import static com.simibubi.create.foundation.data.TagGen.pickaxeOnly;
@SuppressWarnings("removal")
public class TFMGPipes {
public static final Map<PipeMaterial, List<BlockEntry<? extends Block>>> TFMG_PIPES = new HashMap<>();
static {
for (PipeMaterial pipeType : PipeMaterial.values()) {
List<BlockEntry<? extends Block>> pipes = new ArrayList<>();
BlockEntry<TFMGPipeBlock> pipe =
REGISTRATE.block(pipeType.name + "_pipe", p -> new TFMGPipeBlock(p, pipeType))
.initialProperties(SharedProperties::copperMetal)
.transform(pickaxeOnly())
.blockstate(BlockStateGen.pipe())
.onRegister(CreateRegistrate.blockModel(() -> t -> new TFMGPipeAttachmentModel(t, pipeType)))
.item()
.transform(customItemModel())
.register();
pipes.add(pipe);
BlockEntry<TFMGEncasedPipeBlock> copper_encased_pipe =
REGISTRATE.block("copper_encased_" + pipeType.name + "_pipe", p -> new TFMGEncasedPipeBlock(p, AllBlocks.COPPER_CASING::get, pipeType))
.initialProperties(SharedProperties::copperMetal)
.properties(p -> p.noOcclusion().mapColor(MapColor.TERRACOTTA_LIGHT_GRAY))
.transform(axeOrPickaxe())
.blockstate(BlockStateGen.encasedPipe())
.onRegister(CreateRegistrate.connectedTextures(() -> new EncasedCTBehaviour(AllSpriteShifts.COPPER_CASING)))
.onRegister(CreateRegistrate.casingConnectivity((block, cc) -> cc.make(block, AllSpriteShifts.COPPER_CASING,
(s, f) -> !s.getValue(TFMGEncasedPipeBlock.FACING_TO_PROPERTY_MAP.get(f)))))
.onRegister(CreateRegistrate.blockModel(() -> PipeAttachmentModel::new))
.loot((p, b) -> p.dropOther(b, pipe.get()))
.transform(EncasingRegistry.addVariantTo(AllBlocks.FLUID_PIPE))
.register();
pipes.add(copper_encased_pipe);
BlockEntry<TFMGGlassPipeBlock> glass_pipe =
REGISTRATE.block("glass_" + pipeType.name + "_pipe", p -> new TFMGGlassPipeBlock(p, pipeType))
.initialProperties(SharedProperties::copperMetal)
.addLayer(() -> RenderType::cutoutMipped)
.transform(pickaxeOnly())
.blockstate((c, p) -> {
p.getVariantBuilder(c.getEntry())
.forAllStatesExcept(state -> {
Direction.Axis axis = state.getValue(BlockStateProperties.AXIS);
return ConfiguredModel.builder()
.modelFile(p.models()
.getExistingFile(p.modLoc("block/" + pipeType.name + "_pipe/window")))
.uvLock(false)
.rotationX(axis == Direction.Axis.Y ? 0 : 90)
.rotationY(axis == Direction.Axis.X ? 90 : 0)
.build();
}, BlockStateProperties.WATERLOGGED);
})
.onRegister(CreateRegistrate.blockModel(() -> t -> new TFMGPipeAttachmentModel(t, pipeType)))
.loot((p, b) -> p.dropOther(b, pipe.get()))
.register();
pipes.add(glass_pipe);
BlockEntry<TFMGPumpBlock> fluid_pump =
REGISTRATE.block(pipeType.name + "_mechanical_pump", TFMGPumpBlock::new)
.initialProperties(SharedProperties::copperMetal)
.transform(pickaxeOnly())
.blockstate(BlockStateGen.directionalBlockProviderIgnoresWaterlogged(true))
.onRegister(CreateRegistrate.blockModel(() -> t -> new TFMGPipeAttachmentModel(t, pipeType)))
.transform(BlockStressDefaults.setImpact(4.0))
.item()
.transform(customItemModel())
.register();
pipes.add(fluid_pump);
BlockEntry<TFMGSmartFluidPipeBlock> smart_pipe =
REGISTRATE.block(pipeType.name + "_smart_fluid_pipe", TFMGSmartFluidPipeBlock::new)
.initialProperties(SharedProperties::copperMetal)
.transform(pickaxeOnly())
.blockstate(new SmartFluidPipeGenerator()::generate)
.onRegister(CreateRegistrate.blockModel(() -> t -> new TFMGPipeAttachmentModel(t, pipeType)))
.item()
.transform(customItemModel())
.register();
pipes.add(smart_pipe);
BlockEntry<TFMGFluidValveBlock> fluid_valve =
REGISTRATE.block(pipeType.name + "_fluid_valve", TFMGFluidValveBlock::new)
.initialProperties(SharedProperties::copperMetal)
.transform(pickaxeOnly())
.blockstate((c, p) -> BlockStateGen.directionalAxisBlock(c, p,
(state, vertical) -> AssetLookup.partialBaseModel(c, p, vertical ? "vertical" : "horizontal",
state.getValue(FluidValveBlock.ENABLED) ? "open" : "closed")))
.onRegister(CreateRegistrate.blockModel(() -> t -> new TFMGPipeAttachmentModel(t, pipeType)))
.item()
.transform(customItemModel())
.register();
pipes.add(fluid_valve);
TFMG_PIPES.put(pipeType, pipes);
}
}
public static void init() {}
public enum PipeMaterial {
BRASS("brass"),
STEEL("steel"),
ALUMINUM("aluminum"),
CAST_IRON("cast_iron"),
PLASTIC("plastic");
public final String name;
PipeMaterial(String name) {
this.name = name;
}
}
}

View File

@@ -0,0 +1,34 @@
package com.drmangotea.tfmg.content.decoration.pipes;
import com.drmangotea.tfmg.registry.TFMGBlockEntities;
import com.simibubi.create.content.fluids.pump.PumpBlock;
import com.simibubi.create.content.fluids.pump.PumpBlockEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
public class TFMGPumpBlock extends PumpBlock {
public TFMGPumpBlock(Properties p_i48415_1_) {
super(p_i48415_1_);
}
@Override
public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource r) {
super.tick(state, world, pos, r);
this.getBlockEntity(world, pos).updatePressureChange();
}
@Override
public Class<PumpBlockEntity> getBlockEntityClass() {
return PumpBlockEntity.class;
}
@Override
public BlockEntityType<? extends PumpBlockEntity> getBlockEntityType() {
return TFMGBlockEntities.TFMG_MECHANICAL_PUMP.get();
}
}

View File

@@ -0,0 +1,29 @@
package com.drmangotea.tfmg.content.decoration.pipes;
import com.drmangotea.tfmg.registry.TFMGBlockEntities;
import com.simibubi.create.content.equipment.wrench.IWrenchable;
import com.simibubi.create.content.fluids.pipes.IAxisPipe;
import com.simibubi.create.content.fluids.pipes.SmartFluidPipeBlock;
import com.simibubi.create.content.fluids.pipes.SmartFluidPipeBlockEntity;
import com.simibubi.create.foundation.block.IBE;
import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
import net.minecraft.world.level.block.entity.BlockEntityType;
public class TFMGSmartFluidPipeBlock extends SmartFluidPipeBlock
implements IBE<SmartFluidPipeBlockEntity>, IAxisPipe, IWrenchable, ProperWaterloggedBlock {
public TFMGSmartFluidPipeBlock(Properties p_i48339_1_) {
super(p_i48339_1_);
}
@Override
public Class<SmartFluidPipeBlockEntity> getBlockEntityClass() {
return SmartFluidPipeBlockEntity.class;
}
@Override
public BlockEntityType<? extends SmartFluidPipeBlockEntity> getBlockEntityType() {
return TFMGBlockEntities.TFMG_SMART_FLUID_PIPE.get();
}
}

View File

@@ -0,0 +1,114 @@
package com.drmangotea.tfmg.content.decoration.tank;
import com.drmangotea.tfmg.registry.TFMGPartialModels;
import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer;
import com.simibubi.create.foundation.fluid.FluidRenderer;
import com.simibubi.create.foundation.render.CachedBufferer;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.templates.FluidTank;
public class SteelFluidTankRenderer extends SafeBlockEntityRenderer<SteelTankBlockEntity> {
public SteelFluidTankRenderer(BlockEntityRendererProvider.Context context) {}
@Override
protected void renderSafe(SteelTankBlockEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer,
int light, int overlay) {
if (!te.isController())
return;
if (!te.window) {
if (te.isDistillationTower)
renderAsDistillationTower(te, partialTicks, ms, buffer, light, overlay);
return;
}
LerpedFloat fluidLevel = te.getFluidLevel();
if (fluidLevel == null)
return;
float capHeight = 1 / 4f;
float tankHullWidth = 1 / 16f + 1 / 128f;
float minPuddleHeight = 1 / 16f;
float totalHeight = te.height - 2 * capHeight - minPuddleHeight;
float level = fluidLevel.getValue(partialTicks);
if (level < 1 / (512f * totalHeight))
return;
float clampedLevel = Mth.clamp(level * totalHeight, 0, totalHeight);
FluidTank tank = te.tankInventory;
FluidStack fluidStack = tank.getFluid();
if (fluidStack.isEmpty())
return;
boolean top = fluidStack.getFluid()
.getFluidType()
.isLighterThanAir();
float xMin = tankHullWidth;
float xMax = xMin + te.width - 2 * tankHullWidth;
float yMin = totalHeight + capHeight + minPuddleHeight - clampedLevel;
float yMax = yMin + clampedLevel;
if (top) {
yMin += totalHeight - clampedLevel;
yMax += totalHeight - clampedLevel;
}
float zMin = tankHullWidth;
float zMax = zMin + te.width - 2 * tankHullWidth;
ms.pushPose();
ms.translate(0, clampedLevel - totalHeight, 0);
FluidRenderer.renderFluidBox(fluidStack, xMin, yMin, zMin, xMax, yMax, zMax, buffer, ms, light, false);
ms.popPose();
}
protected void renderAsDistillationTower(SteelTankBlockEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer,
int light, int overlay) {
BlockState blockState = te.getBlockState();
VertexConsumer vb = buffer.getBuffer(RenderType.solid());
ms.pushPose();
TransformStack msr = TransformStack.cast(ms);
msr.translate(te.width / 2f, 0.5, te.width / 2f);
float dialPivot = 5.75f / 16;
for (Direction d : Iterate.horizontalDirections) {
ms.pushPose();
CachedBufferer.partial(TFMGPartialModels.TOWER_GAUGE, blockState)
.rotateY(d.toYRot())
.unCentre()
.translate(te.width / 2f - 6 / 16f, 0, 0)
.light(light)
.renderInto(ms, vb);
CachedBufferer.partial(AllPartialModels.BOILER_GAUGE_DIAL, blockState)
.rotateY(d.toYRot())
.unCentre()
.translate(te.width / 2f - 6 / 16f, 0, 0)
.translate(0, dialPivot, dialPivot)
.rotateX(-te.visualGaugeRotation.getValue(partialTicks))
.translate(0, -dialPivot, -dialPivot)
.light(light)
.renderInto(ms, vb);
ms.popPose();
}
ms.popPose();
}
@Override
public boolean shouldRenderOffScreen(SteelTankBlockEntity te) {
return te.isController();
}
}

View File

@@ -0,0 +1,355 @@
package com.drmangotea.tfmg.content.decoration.tank;
import com.drmangotea.tfmg.registry.TFMGBlockEntities;
import com.simibubi.create.api.connectivity.ConnectivityHandler;
import com.simibubi.create.content.equipment.wrench.IWrenchable;
import com.simibubi.create.content.fluids.transfer.GenericItemEmptying;
import com.simibubi.create.content.fluids.transfer.GenericItemFilling;
import com.simibubi.create.foundation.block.IBE;
import com.simibubi.create.foundation.blockEntity.ComparatorUtil;
import com.simibubi.create.foundation.fluid.FluidHelper;
import com.simibubi.create.foundation.fluid.FluidHelper.FluidExchange;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.BlockParticleOption;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition.Builder;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.ForgeSoundType;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
public class SteelTankBlock extends Block implements IWrenchable, IBE<SteelTankBlockEntity> {
public static final BooleanProperty TOP = BooleanProperty.create("top");
public static final BooleanProperty BOTTOM = BooleanProperty.create("bottom");
public static final EnumProperty<Shape> SHAPE = EnumProperty.create("shape", Shape.class);
private boolean creative;
public static SteelTankBlock regular(Properties p_i48440_1_) {
return new SteelTankBlock(p_i48440_1_, false);
}
public static SteelTankBlock creative(Properties p_i48440_1_) {
return new SteelTankBlock(p_i48440_1_, true);
}
protected SteelTankBlock(Properties p_i48440_1_, boolean creative) {
super(p_i48440_1_);
this.creative = creative;
registerDefaultState(defaultBlockState().setValue(TOP, true)
.setValue(BOTTOM, true)
.setValue(SHAPE, Shape.WINDOW));
}
public static boolean isTank(BlockState state) {
return state.getBlock() instanceof SteelTankBlock;
}
@Override
public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean moved) {
if (oldState.getBlock() == state.getBlock())
return;
if (moved)
return;
withBlockEntityDo(world, pos, SteelTankBlockEntity::updateConnectivity);
}
@Override
protected void createBlockStateDefinition(Builder<Block, BlockState> p_206840_1_) {
p_206840_1_.add(TOP, BOTTOM, SHAPE);
}
@Override
public int getLightEmission(BlockState state, BlockGetter world, BlockPos pos) {
SteelTankBlockEntity tankAt = ConnectivityHandler.partAt(getBlockEntityType(), world, pos);
if (tankAt == null)
return 0;
SteelTankBlockEntity controllerTE = (SteelTankBlockEntity) tankAt.getControllerBE();
if (controllerTE == null || !controllerTE.window)
return 0;
return tankAt.luminosity;
}
@Override
public InteractionResult onWrenched(BlockState state, UseOnContext context) {
withBlockEntityDo(context.getLevel(), context.getClickedPos(), SteelTankBlockEntity::toggleWindows);
return InteractionResult.SUCCESS;
}
static final VoxelShape CAMPFIRE_SMOKE_CLIP = Block.box(0, 4, 0, 16, 16, 16);
@Override
public VoxelShape getCollisionShape(BlockState pState, BlockGetter pLevel, BlockPos pPos,
CollisionContext pContext) {
if (pContext == CollisionContext.empty())
return CAMPFIRE_SMOKE_CLIP;
return pState.getShape(pLevel, pPos);
}
@Override
public VoxelShape getBlockSupportShape(BlockState pState, BlockGetter pReader, BlockPos pPos) {
return Shapes.block();
}
@Override
public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState,
LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) {
if (pDirection == Direction.DOWN && pNeighborState.getBlock() != this)
withBlockEntityDo(pLevel, pCurrentPos, SteelTankBlockEntity::updateBoilerTemperature);
return pState;
}
@Override
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand,
BlockHitResult ray) {
ItemStack heldItem = player.getItemInHand(hand);
boolean onClient = world.isClientSide;
if (heldItem.isEmpty())
return InteractionResult.PASS;
if (!player.isCreative() && !creative)
return InteractionResult.PASS;
FluidExchange exchange = null;
SteelTankBlockEntity te = ConnectivityHandler.partAt(getBlockEntityType(), world, pos);
if (te == null)
return InteractionResult.FAIL;
LazyOptional<IFluidHandler> tankCapability = te.getCapability(ForgeCapabilities.FLUID_HANDLER);
if (!tankCapability.isPresent())
return InteractionResult.PASS;
IFluidHandler fluidTank = tankCapability.orElse(null);
FluidStack prevFluidInTank = fluidTank.getFluidInTank(0)
.copy();
if (FluidHelper.tryEmptyItemIntoBE(world, player, hand, heldItem, te))
exchange = FluidExchange.ITEM_TO_TANK;
else if (FluidHelper.tryFillItemFromBE(world, player, hand, heldItem, te))
exchange = FluidExchange.TANK_TO_ITEM;
if (exchange == null) {
if (GenericItemEmptying.canItemBeEmptied(world, heldItem)
|| GenericItemFilling.canItemBeFilled(world, heldItem))
return InteractionResult.SUCCESS;
return InteractionResult.PASS;
}
SoundEvent soundevent = null;
BlockState fluidState = null;
FluidStack fluidInTank = tankCapability.map(fh -> fh.getFluidInTank(0))
.orElse(FluidStack.EMPTY);
if (exchange == FluidExchange.ITEM_TO_TANK) {
Fluid fluid = fluidInTank.getFluid();
fluidState = fluid.defaultFluidState()
.createLegacyBlock();
soundevent = FluidHelper.getEmptySound(fluidInTank);
}
if (exchange == FluidExchange.TANK_TO_ITEM) {
Fluid fluid = prevFluidInTank.getFluid();
fluidState = fluid.defaultFluidState()
.createLegacyBlock();
soundevent = FluidHelper.getFillSound(prevFluidInTank);
}
if (soundevent != null && !onClient) {
float pitch = Mth
.clamp(1 - (1f * fluidInTank.getAmount() / (SteelTankBlockEntity.getCapacityMultiplier() * 16)), 0, 1);
pitch /= 1.5f;
pitch += .5f;
pitch += (world.random.nextFloat() - .5f) / 4f;
world.playSound(null, pos, soundevent, SoundSource.BLOCKS, .5f, pitch);
}
if (!fluidInTank.isFluidStackIdentical(prevFluidInTank)) {
if (te instanceof SteelTankBlockEntity) {
SteelTankBlockEntity controllerTE = (SteelTankBlockEntity) ((SteelTankBlockEntity) te).getControllerBE();
if (controllerTE != null) {
if (fluidState != null && onClient) {
BlockParticleOption blockParticleData =
new BlockParticleOption(ParticleTypes.BLOCK, fluidState);
float level = (float) fluidInTank.getAmount() / fluidTank.getTankCapacity(0);
boolean reversed = fluidInTank.getFluid()
.getFluidType()
.isLighterThanAir();
if (reversed)
level = 1 - level;
Vec3 vec = ray.getLocation();
vec = new Vec3(vec.x, controllerTE.getBlockPos()
.getY() + level * (controllerTE.height - .5f) + .25f, vec.z);
Vec3 motion = player.position()
.subtract(vec)
.scale(1 / 20f);
vec = vec.add(motion);
world.addParticle(blockParticleData, vec.x, vec.y, vec.z, motion.x, motion.y, motion.z);
return InteractionResult.SUCCESS;
}
controllerTE.sendDataImmediately();
controllerTE.setChanged();
}
}
}
return InteractionResult.SUCCESS;
}
@Override
public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) {
if (state.hasBlockEntity() && (state.getBlock() != newState.getBlock() || !newState.hasBlockEntity())) {
BlockEntity te = world.getBlockEntity(pos);
if (!(te instanceof SteelTankBlockEntity))
return;
SteelTankBlockEntity tankTE = (SteelTankBlockEntity) te;
world.removeBlockEntity(pos);
ConnectivityHandler.splitMulti(tankTE);
}
}
@Override
public Class<SteelTankBlockEntity> getBlockEntityClass() {
return SteelTankBlockEntity.class;
}
@Override
public BlockEntityType<? extends SteelTankBlockEntity> getBlockEntityType() {
return creative ? TFMGBlockEntities.STEEL_FLUID_TANK.get() : TFMGBlockEntities.STEEL_FLUID_TANK.get();
}
@Override
public BlockState mirror(BlockState state, Mirror mirror) {
if (mirror == Mirror.NONE)
return state;
boolean x = mirror == Mirror.FRONT_BACK;
switch (state.getValue(SHAPE)) {
case WINDOW_NE:
return state.setValue(SHAPE, x ? Shape.WINDOW_NW : Shape.WINDOW_SE);
case WINDOW_NW:
return state.setValue(SHAPE, x ? Shape.WINDOW_NE : Shape.WINDOW_SW);
case WINDOW_SE:
return state.setValue(SHAPE, x ? Shape.WINDOW_SW : Shape.WINDOW_NE);
case WINDOW_SW:
return state.setValue(SHAPE, x ? Shape.WINDOW_SE : Shape.WINDOW_NW);
default:
return state;
}
}
@Override
public BlockState rotate(BlockState state, Rotation rotation) {
for (int i = 0; i < rotation.ordinal(); i++)
state = rotateOnce(state);
return state;
}
private BlockState rotateOnce(BlockState state) {
switch (state.getValue(SHAPE)) {
case WINDOW_NE:
return state.setValue(SHAPE, Shape.WINDOW_SE);
case WINDOW_NW:
return state.setValue(SHAPE, Shape.WINDOW_NE);
case WINDOW_SE:
return state.setValue(SHAPE, Shape.WINDOW_SW);
case WINDOW_SW:
return state.setValue(SHAPE, Shape.WINDOW_NW);
default:
return state;
}
}
public enum Shape implements StringRepresentable {
PLAIN, WINDOW, WINDOW_NW, WINDOW_SW, WINDOW_NE, WINDOW_SE;
@Override
public String getSerializedName() {
return Lang.asId(name());
}
}
// Tanks are less noisy when placed in batch
public static final SoundType SILENCED_METAL =
new ForgeSoundType(0.1F, 1.5F, () -> SoundEvents.METAL_BREAK, () -> SoundEvents.METAL_STEP,
() -> SoundEvents.METAL_PLACE, () -> SoundEvents.METAL_HIT, () -> SoundEvents.METAL_FALL);
@Override
public SoundType getSoundType(BlockState state, LevelReader world, BlockPos pos, Entity entity) {
SoundType soundType = super.getSoundType(state, world, pos, entity);
if (entity != null && entity.getPersistentData()
.contains("SilenceTankSound"))
return SILENCED_METAL;
return soundType;
}
@Override
public boolean hasAnalogOutputSignal(BlockState state) {
return true;
}
@Override
public int getAnalogOutputSignal(BlockState blockState, Level worldIn, BlockPos pos) {
return getBlockEntityOptional(worldIn, pos).map(SteelTankBlockEntity::getControllerBE)
.map(te -> ComparatorUtil.fractionToRedstoneLevel(te.getFillState()))
.orElse(0);
}
public static boolean updateTowerState(Level pLevel, BlockPos tankPos, boolean assemble, boolean simulate) {
BlockState tankState = pLevel.getBlockState(tankPos);
if (!(tankState.getBlock() instanceof SteelTankBlock tank))
return false;
SteelTankBlockEntity tankBE = tank.getBlockEntity(pLevel, tankPos);
if (tankBE == null)
return false;
if (assemble && tankBE.getControllerBE().isDistillationTower)
return false;
if (!simulate) {
tankBE.getControllerBE().updateBoilerState();
tankBE.getControllerBE().isDistillationTower = assemble;
tankBE.getControllerBE().refreshCapability();
tankBE.updateBoilerState();
tankBE.isDistillationTower = assemble;
tankBE.refreshCapability();
}
return true;
}
}

View File

@@ -0,0 +1,650 @@
package com.drmangotea.tfmg.content.decoration.tank;
import com.drmangotea.tfmg.registry.TFMGBlocks;
import com.simibubi.create.api.connectivity.ConnectivityHandler;
import com.simibubi.create.content.equipment.goggles.IHaveGoggleInformation;
import com.simibubi.create.content.fluids.tank.BoilerHeaters;
import com.simibubi.create.content.fluids.tank.FluidTankBlockEntity;
import com.simibubi.create.foundation.blockEntity.IMultiBlockEntityContainer;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
import com.simibubi.create.foundation.fluid.SmartFluidTank;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser;
import com.simibubi.create.infrastructure.config.AllConfigs;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidType;
import net.minecraftforge.fluids.IFluidTank;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
import net.minecraftforge.fluids.capability.templates.FluidTank;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import static java.lang.Math.abs;
public class SteelTankBlockEntity extends FluidTankBlockEntity implements IHaveGoggleInformation, IMultiBlockEntityContainer.Fluid {
private static final int MAX_SIZE = 3;
protected LazyOptional<IFluidHandler> fluidCapability;
protected boolean forceFluidLevelUpdate;
public FluidTank tankInventory;
protected BlockPos controller;
protected BlockPos lastKnownPos;
protected boolean updateConnectivity;
public boolean window;
public int luminosity;
public int width;
public int height;
public int gaugeRotation = 0;
public int activeHeat;
public boolean isDistillationTower = false;
private static final int SYNC_RATE = 8;
protected int syncCooldown;
protected boolean queuedSync;
// For rendering purposes only
private LerpedFloat fluidLevel;
public LerpedFloat visualGaugeRotation = LerpedFloat.angular();
public SteelTankBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
setLazyTickRate(10);
tankInventory = createInventory();
fluidCapability = LazyOptional.of(() -> tankInventory);
forceFluidLevelUpdate = true;
updateConnectivity = false;
window = true;
height = 1;
width = 1;
refreshCapability();
}
protected SmartFluidTank createInventory() {
return new SmartFluidTank(getCapacityMultiplier(), this::onFluidStackChanged);
}
public void updateConnectivity() {
updateConnectivity = false;
if (level.isClientSide)
return;
if (!isController())
return;
refreshCapability();
ConnectivityHandler.formMulti(this);
}
@Override
public void tick() {
super.tick();
getGaugeRotation();
visualGaugeRotation.chase(gaugeRotation, 0.2f, Chaser.EXP);
visualGaugeRotation.tickChaser();
if (syncCooldown > 0) {
syncCooldown--;
if (syncCooldown == 0 && queuedSync)
sendData();
}
if (lastKnownPos == null)
lastKnownPos = getBlockPos();
else if (!lastKnownPos.equals(worldPosition) && worldPosition != null) {
onPositionChanged();
return;
}
if (updateConnectivity)
updateConnectivity();
if (fluidLevel != null)
fluidLevel.tickChaser();
}
@Override
public BlockPos getLastKnownPos() {
return lastKnownPos;
}
@Override
public boolean isController() {
return controller == null || worldPosition.getX() == controller.getX()
&& worldPosition.getY() == controller.getY() && worldPosition.getZ() == controller.getZ();
}
@Override
public void initialize() {
super.initialize();
sendData();
if (level.isClientSide)
invalidateRenderBoundingBox();
}
private void onPositionChanged() {
removeController(true);
lastKnownPos = worldPosition;
}
protected void onFluidStackChanged(FluidStack newFluidStack) {
if (!hasLevel())
return;
FluidType attributes = newFluidStack.getFluid()
.getFluidType();
int luminosity = (int) (attributes.getLightLevel(newFluidStack) / 1.2f);
boolean reversed = attributes.isLighterThanAir();
int maxY = (int) ((getFillState() * height) + 1);
for (int yOffset = 0; yOffset < height; yOffset++) {
boolean isBright = reversed ? (height - yOffset <= maxY) : (yOffset < maxY);
int actualLuminosity = isBright ? luminosity : luminosity > 0 ? 1 : 0;
for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos pos = this.worldPosition.offset(xOffset, yOffset, zOffset);
SteelTankBlockEntity tankAt = ConnectivityHandler.partAt(getType(), level, pos);
if (tankAt == null)
continue;
level.updateNeighbourForOutputSignal(pos, tankAt.getBlockState()
.getBlock());
if (tankAt.luminosity == actualLuminosity)
continue;
tankAt.setLuminosity(actualLuminosity);
}
}
}
if (!level.isClientSide) {
setChanged();
sendData();
}
if (isVirtual()) {
if (fluidLevel == null)
fluidLevel = LerpedFloat.linear()
.startWithValue(getFillState());
fluidLevel.chase(getFillState(), .5f, Chaser.EXP);
}
}
protected void setLuminosity(int luminosity) {
if (level.isClientSide)
return;
if (this.luminosity == luminosity)
return;
this.luminosity = luminosity;
sendData();
}
@SuppressWarnings("unchecked")
@Override
public SteelTankBlockEntity getControllerBE() {
if (isController())
return this;
BlockEntity tileEntity = level.getBlockEntity(controller);
if (tileEntity instanceof SteelTankBlockEntity)
return (SteelTankBlockEntity) tileEntity;
return null;
}
public void applyFluidTankSize(int blocks) {
tankInventory.setCapacity(blocks * getCapacityMultiplier());
int overflow = tankInventory.getFluidAmount() - tankInventory.getCapacity();
if (overflow > 0)
tankInventory.drain(overflow, FluidAction.EXECUTE);
forceFluidLevelUpdate = true;
}
public void removeController(boolean keepFluids) {
if (level.isClientSide)
return;
updateConnectivity = true;
if (!keepFluids)
applyFluidTankSize(1);
controller = null;
width = 1;
height = 1;
onFluidStackChanged(tankInventory.getFluid());
BlockState state = getBlockState();
if (SteelTankBlock.isTank(state)) {
state = state.setValue(SteelTankBlock.BOTTOM, true);
state = state.setValue(SteelTankBlock.TOP, true);
state = state.setValue(SteelTankBlock.SHAPE, window ? SteelTankBlock.Shape.WINDOW : SteelTankBlock.Shape.PLAIN);
getLevel().setBlock(worldPosition, state, 22);
}
refreshCapability();
setChanged();
sendData();
}
public void toggleWindows() {
SteelTankBlockEntity te = getControllerBE();
if (te == null)
return;
if (isDistillationTower)
return;
te.setWindows(!te.window);
}
public void sendDataImmediately() {
syncCooldown = 0;
queuedSync = false;
sendData();
}
@Override
public void sendData() {
if (syncCooldown > 0) {
queuedSync = true;
return;
}
super.sendData();
queuedSync = false;
syncCooldown = SYNC_RATE;
}
public void setWindows(boolean window) {
this.window = window;
for (int yOffset = 0; yOffset < height; yOffset++) {
for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos pos = this.worldPosition.offset(xOffset, yOffset, zOffset);
BlockState blockState = level.getBlockState(pos);
if (!SteelTankBlock.isTank(blockState))
continue;
SteelTankBlock.Shape shape = SteelTankBlock.Shape.PLAIN;
if (window) {
// SIZE 1: Every tank has a window
if (width == 1)
shape = SteelTankBlock.Shape.WINDOW;
// SIZE 2: Every tank has a corner window
if (width == 2)
shape = xOffset == 0 ? zOffset == 0 ? SteelTankBlock.Shape.WINDOW_NW : SteelTankBlock.Shape.WINDOW_SW
: zOffset == 0 ? SteelTankBlock.Shape.WINDOW_NE : SteelTankBlock.Shape.WINDOW_SE;
// SIZE 3: Tanks in the center have a window
if (width == 3 && abs(abs(xOffset) - abs(zOffset)) == 1)
shape = SteelTankBlock.Shape.WINDOW;
}
level.setBlock(pos, blockState.setValue(SteelTankBlock.SHAPE, shape), 22);
level.getChunkSource()
.getLightEngine()
.checkBlock(pos);
}
}
}
}
public void updateBoilerState() {
if (!isController())
return;
boolean wasTower = isDistillationTower;
boolean changed = evaluate();
if (wasTower != isDistillationTower) {
if (isDistillationTower)
setWindows(false);
for (int yOffset = 0; yOffset < height; yOffset++)
for (int xOffset = 0; xOffset < width; xOffset++)
for (int zOffset = 0; zOffset < width; zOffset++)
if (level.getBlockEntity(
worldPosition.offset(xOffset, yOffset, zOffset)) instanceof SteelTankBlockEntity fte)
fte.refreshCapability();
}
if (changed) {
notifyUpdate();
refreshCapability();
}
}
public boolean evaluate() {
boolean hadController = isDistillationTower;
boolean foundController = false;
BlockPos pos1 = controller == null ? getBlockPos() : controller;
for (int yOffset = 0; yOffset < getControllerBE().height; yOffset++) {
for (int xOffset = 0; xOffset < getControllerBE().width; xOffset++) {
for (int zOffset = 0; zOffset < getControllerBE().width; zOffset++) {
BlockPos pos = pos1.offset(xOffset, yOffset, zOffset);
BlockState blockState = level.getBlockState(pos);
if (!SteelTankBlock.isTank(blockState))
continue;
for (Direction d : Iterate.directions) {
BlockPos attachedPos = pos.relative(d);
BlockState attachedState = level.getBlockState(attachedPos);
if (attachedState.is(TFMGBlocks.STEEL_DISTILLATION_CONTROLLER.get())) {
if (!foundController) {
foundController = true;
} else
level.destroyBlock(attachedPos, true);
}
}
}
}
}
isDistillationTower = foundController;
return hadController != foundController;
}
@Override
public void lazyTick() {
super.lazyTick();
if (isDistillationTower)
updateTemperature();
}
public void updateTemperature() {
int prevHeat = activeHeat;
activeHeat = 0;
BlockPos pos1 = controller == null ? getBlockPos() : controller;
SteelTankBlockEntity be = getControllerBE() == null ? this : getControllerBE();
for (int xOffset = 0; xOffset < be.width; xOffset++) {
for (int zOffset = 0; zOffset < be.width; zOffset++) {
BlockPos pos = pos1.offset(xOffset, -1, zOffset);
BlockState blockState = level.getBlockState(pos);
float heat = BoilerHeaters.getActiveHeat(level, pos, blockState);
if (heat > 0) {
activeHeat += heat;
}
}
}
if (activeHeat != prevHeat)
notifyUpdate();
}
@Override
public void setController(BlockPos controller) {
if (level.isClientSide && !isVirtual())
return;
if (controller.equals(this.controller))
return;
this.controller = controller;
refreshCapability();
setChanged();
sendData();
}
public void refreshCapability() {
LazyOptional<IFluidHandler> oldCap = fluidCapability;
fluidCapability = LazyOptional.of(() -> handlerForCapability());
oldCap.invalidate();
}
private IFluidHandler handlerForCapability() {
return isController() ?
tankInventory
: getControllerBE() != null ? getControllerBE().handlerForCapability() : tankInventory;
}
@Override
public BlockPos getController() {
return isController() ? worldPosition : controller;
}
@Override
protected AABB createRenderBoundingBox() {
if (isController())
return super.createRenderBoundingBox().expandTowards(width - 1, height - 1, width - 1);
else
return super.createRenderBoundingBox();
}
@Nullable
public SteelTankBlockEntity getOtherFluidTankTileEntity(Direction direction) {
BlockEntity otherTE = level.getBlockEntity(worldPosition.relative(direction));
if (otherTE instanceof SteelTankBlockEntity)
return (SteelTankBlockEntity) otherTE;
return null;
}
@Override
public boolean addToGoggleTooltip(List<Component> tooltip, boolean isPlayerSneaking) {
SteelTankBlockEntity controllerTE = getControllerBE();
if (isDistillationTower)
return false;
if (getControllerBE() != null)
if (getControllerBE().isDistillationTower)
return false;
return containedFluidTooltip(tooltip, isPlayerSneaking,
controllerTE.getCapability(ForgeCapabilities.FLUID_HANDLER));
}
@Override
protected void read(CompoundTag compound, boolean clientPacket) {
super.read(compound, clientPacket);
BlockPos controllerBefore = controller;
int prevSize = width;
int prevHeight = height;
int prevLum = luminosity;
updateConnectivity = compound.contains("Uninitialized");
luminosity = compound.getInt("Luminosity");
controller = null;
lastKnownPos = null;
isDistillationTower = compound.getBoolean("isDistillationTower");
if (compound.contains("LastKnownPos"))
lastKnownPos = NbtUtils.readBlockPos(compound.getCompound("LastKnownPos"));
if (compound.contains("Controller"))
controller = NbtUtils.readBlockPos(compound.getCompound("Controller"));
if (isController()) {
window = compound.getBoolean("Window");
width = compound.getInt("Size");
height = compound.getInt("Height");
tankInventory.setCapacity(getTotalTankSize() * getCapacityMultiplier());
tankInventory.readFromNBT(compound.getCompound("TankContent"));
if (tankInventory.getSpace() < 0)
tankInventory.drain(-tankInventory.getSpace(), FluidAction.EXECUTE);
}
if (compound.contains("ForceFluidLevel") || fluidLevel == null)
fluidLevel = LerpedFloat.linear()
.startWithValue(getFillState());
if (!clientPacket)
return;
boolean changeOfController =
controllerBefore == null ? controller != null : !controllerBefore.equals(controller);
if (changeOfController || prevSize != width || prevHeight != height) {
if (hasLevel())
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 16);
if (isController())
tankInventory.setCapacity(getCapacityMultiplier() * getTotalTankSize());
invalidateRenderBoundingBox();
}
if (isController()) {
float fillState = getFillState();
if (compound.contains("ForceFluidLevel") || fluidLevel == null)
fluidLevel = LerpedFloat.linear()
.startWithValue(fillState);
fluidLevel.chase(fillState, 0.5f, Chaser.EXP);
}
if (luminosity != prevLum && hasLevel())
level.getChunkSource()
.getLightEngine()
.checkBlock(worldPosition);
if (compound.contains("LazySync"))
fluidLevel.chase(fluidLevel.getChaseTarget(), 0.125f, Chaser.EXP);
}
public void getGaugeRotation() {
gaugeRotation = Math.min(90, activeHeat * 15);
}
public float getFillState() {
return (float) tankInventory.getFluidAmount() / tankInventory.getCapacity();
}
@Override
public void write(CompoundTag compound, boolean clientPacket) {
if (updateConnectivity)
compound.putBoolean("Uninitialized", true);
compound.putBoolean("isDistillationTower", isDistillationTower);
if (lastKnownPos != null)
compound.put("LastKnownPos", NbtUtils.writeBlockPos(lastKnownPos));
if (!isController())
compound.put("Controller", NbtUtils.writeBlockPos(controller));
if (isController()) {
compound.putBoolean("Window", window);
compound.put("TankContent", tankInventory.writeToNBT(new CompoundTag()));
compound.putInt("Size", width);
compound.putInt("Height", height);
}
compound.putInt("Luminosity", luminosity);
forEachBehaviour(tb -> tb.write(compound, clientPacket));
if (!clientPacket)
return;
if (forceFluidLevelUpdate)
compound.putBoolean("ForceFluidLevel", true);
if (queuedSync)
compound.putBoolean("LazySync", true);
forceFluidLevelUpdate = false;
}
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
if (!fluidCapability.isPresent())
refreshCapability();
if (cap == ForgeCapabilities.FLUID_HANDLER)
return fluidCapability.cast();
return super.getCapability(cap, side);
}
@Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
//registerAwardables(behaviours, AllAdvancements.STEAM_ENGINE_MAXED, AllAdvancements.PIPE_ORGAN);
}
public IFluidTank getTankInventory() {
return tankInventory;
}
public int getTotalTankSize() {
return width * width * height;
}
public static int getMaxSize() {
return MAX_SIZE;
}
public static int getCapacityMultiplier() {
return AllConfigs.server().fluids.fluidTankCapacity.get() * 1000;
}
public static int getMaxHeight() {
return AllConfigs.server().fluids.fluidTankMaxHeight.get();
}
public LerpedFloat getFluidLevel() {
return fluidLevel;
}
public void setFluidLevel(LerpedFloat fluidLevel) {
this.fluidLevel = fluidLevel;
}
@Override
public void preventConnectivityUpdate() {
updateConnectivity = false;
}
@Override
public void notifyMultiUpdated() {
BlockState state = this.getBlockState();
if (SteelTankBlock.isTank(state)) { // safety
state = state.setValue(SteelTankBlock.BOTTOM, getController().getY() == getBlockPos().getY());
state = state.setValue(SteelTankBlock.TOP, getController().getY() + height - 1 == getBlockPos().getY());
level.setBlock(getBlockPos(), state, 6);
}
if (isController())
setWindows(window);
onFluidStackChanged(tankInventory.getFluid());
updateBoilerState();
setChanged();
}
@Override
public void setExtraData(@Nullable Object data) {
if (data instanceof Boolean)
window = (boolean) data;
}
@Override
@Nullable
public Object getExtraData() {
return window;
}
@Override
public Object modifyExtraData(Object data) {
if (data instanceof Boolean windows) {
windows |= window;
return windows;
}
return data;
}
@Override
public Direction.Axis getMainConnectionAxis() {
return Direction.Axis.Y;
}
@Override
public int getMaxLength(Direction.Axis longAxis, int width) {
if (longAxis == Direction.Axis.Y)
return getMaxHeight();
return getMaxWidth();
}
@Override
public int getMaxWidth() {
return MAX_SIZE;
}
@Override
public int getHeight() {
return height;
}
@Override
public void setHeight(int height) {
this.height = height;
}
@Override
public int getWidth() {
return width;
}
@Override
public void setWidth(int width) {
this.width = width;
}
@Override
public boolean hasTank() {
return true;
}
@Override
public int getTankSize(int tank) {
return getCapacityMultiplier();
}
@Override
public void setTankSize(int tank, int blocks) {
applyFluidTankSize(blocks);
}
@Override
public IFluidTank getTank(int tank) {
return tankInventory;
}
@Override
public FluidStack getFluid(int tank) {
return tankInventory.getFluid()
.copy();
}
}

View File

@@ -0,0 +1,63 @@
package com.drmangotea.tfmg.content.decoration.tank;
import com.simibubi.create.foundation.data.AssetLookup;
import com.simibubi.create.foundation.data.SpecialBlockStateGen;
import com.tterrag.registrate.providers.DataGenContext;
import com.tterrag.registrate.providers.RegistrateBlockstateProvider;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.generators.ModelFile;
public class SteelTankGenerator extends SpecialBlockStateGen {
private String prefix;
public SteelTankGenerator() {
this("");
}
public SteelTankGenerator(String prefix) {
this.prefix = prefix;
}
@Override
protected int getXRotation(BlockState state) {
return 0;
}
@Override
protected int getYRotation(BlockState state) {
return 0;
}
@Override
public <T extends Block> ModelFile getModel(DataGenContext<Block, T> ctx, RegistrateBlockstateProvider prov,
BlockState state) {
Boolean top = state.getValue(SteelTankBlock.TOP);
Boolean bottom = state.getValue(SteelTankBlock.BOTTOM);
SteelTankBlock.Shape shape = state.getValue(SteelTankBlock.SHAPE);
String shapeName = "middle";
if (top && bottom)
shapeName = "single";
else if (top)
shapeName = "top";
else if (bottom)
shapeName = "bottom";
String modelName = shapeName + (shape == SteelTankBlock.Shape.PLAIN ? "" : "_" + shape.getSerializedName());
if (!prefix.isEmpty())
return prov.models()
.withExistingParent(prefix + modelName, prov.modLoc("block/fluid_tank/block_" + modelName))
.texture("0", prov.modLoc("block/" + prefix + "casing"))
.texture("1", prov.modLoc("block/" + prefix + "fluid_tank"))
.texture("3", prov.modLoc("block/" + prefix + "fluid_tank_window"))
.texture("4", prov.modLoc("block/" + prefix + "casing"))
.texture("5", prov.modLoc("block/" + prefix + "fluid_tank_window_single"))
.texture("particle", prov.modLoc("block/" + prefix + "steel_fluid_tank"));
return AssetLookup.partialBaseModel(ctx, prov, modelName);
}
}

View File

@@ -0,0 +1,132 @@
package com.drmangotea.tfmg.content.decoration.tank;
import com.drmangotea.tfmg.registry.TFMGBlockEntities;
import com.simibubi.create.api.connectivity.ConnectivityHandler;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.fluids.FluidStack;
public class SteelTankItem extends BlockItem {
public SteelTankItem(Block p_i48527_1_, Properties p_i48527_2_) {
super(p_i48527_1_, p_i48527_2_);
}
@Override
public InteractionResult place(BlockPlaceContext ctx) {
InteractionResult initialResult = super.place(ctx);
if (!initialResult.consumesAction())
return initialResult;
tryMultiPlace(ctx);
return initialResult;
}
@Override
protected boolean updateCustomBlockEntityTag(BlockPos p_195943_1_, Level p_195943_2_, Player p_195943_3_,
ItemStack p_195943_4_, BlockState p_195943_5_) {
MinecraftServer minecraftserver = p_195943_2_.getServer();
if (minecraftserver == null)
return false;
CompoundTag nbt = p_195943_4_.getTagElement("BlockEntityTag");
if (nbt != null) {
nbt.remove("Luminosity");
nbt.remove("Size");
nbt.remove("Height");
nbt.remove("Controller");
nbt.remove("LastKnownPos");
if (nbt.contains("TankContent")) {
FluidStack fluid = FluidStack.loadFluidStackFromNBT(nbt.getCompound("TankContent"));
if (!fluid.isEmpty()) {
fluid.setAmount(Math.min(SteelTankBlockEntity.getCapacityMultiplier(), fluid.getAmount()));
nbt.put("TankContent", fluid.writeToNBT(new CompoundTag()));
}
}
}
return super.updateCustomBlockEntityTag(p_195943_1_, p_195943_2_, p_195943_3_, p_195943_4_, p_195943_5_);
}
private void tryMultiPlace(BlockPlaceContext ctx) {
Player player = ctx.getPlayer();
if (player == null)
return;
if (player.isShiftKeyDown())
return;
Direction face = ctx.getClickedFace();
if (!face.getAxis()
.isVertical())
return;
ItemStack stack = ctx.getItemInHand();
Level world = ctx.getLevel();
BlockPos pos = ctx.getClickedPos();
BlockPos placedOnPos = pos.relative(face.getOpposite());
BlockState placedOnState = world.getBlockState(placedOnPos);
if (!SteelTankBlock.isTank(placedOnState))
return;
SteelTankBlockEntity tankAt = ConnectivityHandler.partAt(
TFMGBlockEntities.STEEL_FLUID_TANK.get(), world, placedOnPos
);
if (tankAt == null)
return;
SteelTankBlockEntity controllerTE = (SteelTankBlockEntity) tankAt.getControllerBE();
if (controllerTE == null)
return;
int width = controllerTE.width;
if (width == 1)
return;
int tanksToPlace = 0;
BlockPos startPos = face == Direction.DOWN ? controllerTE.getBlockPos()
.below()
: controllerTE.getBlockPos()
.above(controllerTE.height);
if (startPos.getY() != pos.getY())
return;
for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos offsetPos = startPos.offset(xOffset, 0, zOffset);
BlockState blockState = world.getBlockState(offsetPos);
if (SteelTankBlock.isTank(blockState))
continue;
if (!blockState.canBeReplaced())
return;
tanksToPlace++;
}
}
if (!player.isCreative() && stack.getCount() < tanksToPlace)
return;
for (int xOffset = 0; xOffset < width; xOffset++) {
for (int zOffset = 0; zOffset < width; zOffset++) {
BlockPos offsetPos = startPos.offset(xOffset, 0, zOffset);
BlockState blockState = world.getBlockState(offsetPos);
if (SteelTankBlock.isTank(blockState))
continue;
BlockPlaceContext context = BlockPlaceContext.at(ctx, offsetPos, face);
player.getPersistentData()
.putBoolean("SilenceTankSound", true);
super.place(context);
player.getPersistentData()
.remove("SilenceTankSound");
}
}
}
}

View File

@@ -0,0 +1,89 @@
package com.drmangotea.tfmg.content.decoration.tank;
import com.drmangotea.tfmg.base.TFMGSpriteShifts;
import com.simibubi.create.api.connectivity.ConnectivityHandler;
import com.simibubi.create.content.fluids.tank.FluidTankCTBehaviour;
import com.simibubi.create.foundation.block.connected.CTModel;
import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.data.ModelData;
import net.minecraftforge.client.model.data.ModelProperty;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class TFMGFluidTankModel extends CTModel {
protected static final ModelProperty<CullData> CULL_PROPERTY = new ModelProperty<>();
public static TFMGFluidTankModel standard(BakedModel originalModel) {
return new TFMGFluidTankModel(originalModel, TFMGSpriteShifts.STEEL_FLUID_TANK, TFMGSpriteShifts.STEEL_FLUID_TANK_TOP,
TFMGSpriteShifts.STEEL_FLUID_TANK_INNER);
}
private TFMGFluidTankModel(BakedModel originalModel, CTSpriteShiftEntry side, CTSpriteShiftEntry top,
CTSpriteShiftEntry inner) {
super(originalModel, new FluidTankCTBehaviour(side, top, inner));
}
@Override
protected ModelData.Builder gatherModelData(ModelData.Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state,
ModelData blockEntityData) {
super.gatherModelData(builder, world, pos, state, blockEntityData);
CullData cullData = new CullData();
for (Direction d : Iterate.horizontalDirections)
cullData.setCulled(d, ConnectivityHandler.isConnected(world, pos, pos.relative(d)));
return builder.with(CULL_PROPERTY, cullData);
}
@Override
public List<BakedQuad> getQuads(BlockState state, Direction side, RandomSource rand, ModelData extraData, RenderType renderType) {
if (side != null)
return Collections.emptyList();
List<BakedQuad> quads = new ArrayList<>();
for (Direction d : Iterate.directions) {
if (extraData.has(CULL_PROPERTY) && extraData.get(CULL_PROPERTY)
.isCulled(d))
continue;
quads.addAll(super.getQuads(state, d, rand, extraData, renderType));
}
quads.addAll(super.getQuads(state, null, rand, extraData, renderType));
return quads;
}
private class CullData {
boolean[] culledFaces;
public CullData() {
culledFaces = new boolean[4];
Arrays.fill(culledFaces, false);
}
void setCulled(Direction face, boolean cull) {
if (face.getAxis()
.isVertical())
return;
culledFaces[face.get2DDataValue()] = cull;
}
boolean isCulled(Direction face) {
if (face.getAxis()
.isVertical())
return false;
return culledFaces[face.get2DDataValue()];
}
}
}

View File

@@ -0,0 +1,41 @@
package com.drmangotea.tfmg.content.electricity.base;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.networking.BlockEntityDataPacket;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
public class ConnectNeightborsPacket extends BlockEntityDataPacket<SmartBlockEntity> {
public ConnectNeightborsPacket(BlockPos pos) {
super(pos);
}
public ConnectNeightborsPacket(FriendlyByteBuf buffer) {
super(buffer);
}
@Override
protected void writeData(FriendlyByteBuf buffer) {}
@Override
protected void handlePacket(SmartBlockEntity blockEntity) {
if(blockEntity instanceof IElectric be) {
be.onPlaced();
}
}
}

View File

@@ -0,0 +1,40 @@
package com.drmangotea.tfmg.content.electricity.base;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.networking.BlockEntityDataPacket;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
public class ConnectionPacket extends BlockEntityDataPacket<SmartBlockEntity> {
public ConnectionPacket(BlockPos pos) {
super(pos);
}
public ConnectionPacket(FriendlyByteBuf buffer) {
super(buffer);
}
@Override
protected void writeData(FriendlyByteBuf buffer) {}
@Override
protected void handlePacket(SmartBlockEntity blockEntity) {
if(blockEntity instanceof IElectric be) {
be.onConnected();
}
}
}

View File

@@ -0,0 +1,245 @@
package com.drmangotea.tfmg.content.electricity.base;
import com.drmangotea.tfmg.TFMG;
import com.drmangotea.tfmg.registry.TFMGPackets;
import com.simibubi.create.content.equipment.goggles.IHaveHoveringInformation;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.network.PacketDistributor;
import java.util.List;
public class ElectricBlockEntity extends SmartBlockEntity implements IElectric, IHaveHoveringInformation {
public ElectricBlockValues data = new ElectricBlockValues(getPos());
int powerPercentage = 100;
public ElectricBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
data.connectNextTick = true;
}
@Override
public boolean addToTooltip(List<Component> tooltip, boolean isPlayerSneaking) {
return makeElectricityTooltip(tooltip, isPlayerSneaking);
}
@Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {}
@Override
public LevelAccessor getLevelAccessor(){
return level;
}
@Override
public boolean destroyed() {
return data.destroyed;
}
@Override
public ElectricalNetwork getOrCreateElectricNetwork() {
if(level.getBlockEntity(BlockPos.of(data.electricalNetworkId)) instanceof IElectric) {
return TFMG.NETWORK_MANAGER.getOrCreateNetworkFor((IElectric) level.getBlockEntity(BlockPos.of(data.electricalNetworkId)));
} else {
ElectricNetworkManager.networks.get(getLevel())
.remove(data.electricalNetworkId);
return TFMG.NETWORK_MANAGER.getOrCreateNetworkFor(this);
}
}
@Override
public ElectricBlockValues getData() {
return data;
}
@Override
public int getPowerPercentage() {
return powerPercentage;
}
@Override
public float resistance() {
return 0;
}
@Override
public int voltageGeneration() {
int voltageGeneration = 0;
for(Direction direction : Direction.values()){
if(hasElectricitySlot(direction)){
if(level.getBlockEntity(getBlockPos().relative(direction)) instanceof VoltageAlteringBlockEntity be)
if(be.getData().getId() !=getData().getId())
if(be.getData().getVoltage()!=0)
if(be.hasElectricitySlot(direction)){
voltageGeneration = Math.max(voltageGeneration,be.getOutputVoltage());
data.getsOutsidePower = true;
}
}
}
if(voltageGeneration == 0)
data.getsOutsidePower = false;
return voltageGeneration;
}
@Override
public int powerGeneration() {
int powerGeneration = 0;
for(Direction direction : Direction.values()){
if(hasElectricitySlot(direction)){
if(level.getBlockEntity(getBlockPos().relative(direction)) instanceof VoltageAlteringBlockEntity be)
if(be.getData().getId() !=getData().getId())
if(be.getData().getVoltage()!=0)
if(be.hasElectricitySlot(direction)){
powerGeneration = Math.max(powerGeneration,be.getOutputPower());
}
}
}
return powerGeneration;
}
@Override
public int frequencyGeneration() {
return 0;
}
@Override
public void updateNextTick() {
data.updateNextTick = true;
}
@Override
public void updateNetwork() {
getOrCreateElectricNetwork().updateNetwork();
if(!level.isClientSide)
TFMGPackets.getChannel().send(PacketDistributor.ALL.noArg(), new NetworkUpdatePacket(BlockPos.of(getPos())));
sendData();
}
@Override
public void sendStuff() {
sendData();
}
@Override
public void setVoltage(int newVoltage) {
if(canBeInGroups()){
data.voltage = (int) (((float)resistance()/data.group.resistance)*(float)data.voltageSupply);
return;
}
data.voltage = newVoltage;
}
@Override
public void setFrequency(int newFrequency) {
data.frequency = newFrequency;
}
@Override
public void setNetworkResistance(int newUsage) {
data.networkResistance = newUsage;
}
@Override
public int getNetworkResistance() {
return data.networkResistance;
}
@Override
public void setWattage(int newWattage) {
}
@Override
public void setPowerPercentage(int percentage) {
powerPercentage = percentage;
}
@Override
public void setNetwork(long network) {
this.data.electricalNetworkId = network;
if(network!=getPos())
ElectricNetworkManager.networks.get(getLevel())
.remove(getPos());
}
public boolean networkUndersupplied(){
return getNetworkPowerUsage()>data.networkPowerGeneration;
}
@Override
public long getPos() {
return getBlockPos().asLong();
}
@Override
public void remove() {
super.remove();
this.data.destroyed = true;
for(Direction d : Direction.values()) {
if(hasElectricitySlot(d))
if(getLevelAccessor().getBlockEntity(BlockPos.of(getPos()).relative(d)) instanceof IElectric be&&be.hasElectricitySlot(d.getOpposite())) {
ElectricNetworkManager.networks.get(getLevel())
.remove(be.getPos());
be.setNetwork(be.getPos());
be.onPlaced();
be.updateNextTick();
}
}
if(data.electricalNetworkId != getPos())
getOrCreateElectricNetwork().getMembers().remove(this);
if(data.electricalNetworkId == getPos())
ElectricNetworkManager.networks.get(getLevel())
.remove(getData().getId());
}
@Override
public void tick() {
super.tick();
if(data.connectNextTick) {
onPlaced();
data.connectNextTick = false;
}
if(data.updateNextTick) {
updateNetwork();
data.updateNextTick = false;
}
}
@Override
protected void write(CompoundTag tag, boolean clientPacket) {
super.write(tag, clientPacket);
}
@Override
protected void read(CompoundTag tag, boolean clientPacket) {
super.read(tag, clientPacket);
if(!clientPacket)
data.connectNextTick = true;
}
}

View File

@@ -0,0 +1,34 @@
package com.drmangotea.tfmg.content.electricity.base;
public class ElectricBlockValues {
public long electricalNetworkId;
public boolean destroyed = false;
public boolean connectNextTick = false;
public boolean updateNextTick = false;
public boolean getsOutsidePower = false;
public int networkResistance = 0;
public int voltage = 0;
public int frequency = 0;
public int voltageSupply = 0;
public int networkPowerGeneration =0;
public ElectricalGroup group = new ElectricalGroup(0);
public ElectricBlockValues(long pos){
this.electricalNetworkId = pos;
}
public long getId(){
return electricalNetworkId;
}
public boolean destroyed(){
return destroyed;
}
public int getVoltage(){
return voltage;
}
}

View File

@@ -0,0 +1,38 @@
package com.drmangotea.tfmg.content.electricity.base;
import net.minecraft.world.level.LevelAccessor;
import java.util.HashMap;
import java.util.Map;
public class ElectricNetworkManager {
public static Map<LevelAccessor, Map<Long, ElectricalNetwork>> networks = new HashMap<>();
public void onLoadWorld(LevelAccessor world) {
networks.put(world, new HashMap<>());
}
public void onUnloadWorld(LevelAccessor world) {
networks.remove(world);
}
public ElectricalNetwork getOrCreateNetworkFor(IElectric be) {
Long id = be.getData().getId();
ElectricalNetwork network;
Map<Long, ElectricalNetwork> map = networks.computeIfAbsent(be.getLevelAccessor(), $ -> new HashMap<>());
if (!map.containsKey(id)) {
network = new ElectricalNetwork(id);
if(be instanceof IElectric) {
network.add((IElectric) be);
be.setNetwork(be.getData().getId());
}
map.put(id, network);
}
network = map.get(id);
return network;
}
}

View File

@@ -0,0 +1,16 @@
package com.drmangotea.tfmg.content.electricity.base;
import java.util.List;
public class ElectricalGroup {
public int id;
public float resistance=0;
public ElectricalGroup(int id){
this.id = id;
}
}

View File

@@ -0,0 +1,83 @@
package com.drmangotea.tfmg.content.electricity.base;
import com.drmangotea.tfmg.TFMG;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ElectricalNetwork {
public ElectricalNetwork(long id) {
this.id = id;
}
public List<IElectric> members = new ArrayList<>();
public long id;
public long getId() {
return id;
}
public void add(IElectric be) {
List<Long> posList = new ArrayList<>();
members.forEach(member -> posList.add(member.getData().getId()));
if (posList.contains(be.getData().getId()))
return;
members.add(be);
}
public void updateNetwork() {
int maxVoltage = 0;
int power = 0;
int frequency = 0;
int resistance = 0;
int powerGeneration = 0;
Map<Integer, Float> groups = new HashMap<>();
for (IElectric member : members) {
int groupId = member.getData().group.id;
maxVoltage = Math.max(member.voltageGeneration(), maxVoltage);
power += member.powerGeneration();
frequency = frequency == 0 ? member.frequencyGeneration() : (frequency + member.frequencyGeneration()) / 2;
resistance += (int) member.resistance();
powerGeneration += member.powerGeneration();
if(member.canBeInGroups())
groups.put(groupId, (groups.containsKey(groupId) ? groups.get(groupId) + member.resistance() : member.resistance()));
}
int powerPercentage = resistance > 0 ? (int) (Math.min(((float) power / (float) resistance * 100f), 100)) : 100;
for (IElectric member : members) {
int oldVoltage = member.getData().getVoltage();
int oldPower = member.getPowerUsage();
member.setVoltage(maxVoltage);
member.getData().voltageSupply = maxVoltage;
member.getData().networkPowerGeneration = powerGeneration;
member.setWattage(power);
member.setFrequency(frequency);
member.setNetworkResistance(resistance);
member.onNetworkChanged(oldVoltage, oldPower);
member.setPowerPercentage(powerPercentage);
member.updateNearbyNetworks(member);
if(groups.containsKey(member.getData().group.id))
member.getData().group.resistance = groups.get(member.getData().group.id);
}
}
public List<IElectric> getMembers() {
return members;
}
}

View File

@@ -0,0 +1,172 @@
package com.drmangotea.tfmg.content.electricity.base;
import com.drmangotea.tfmg.TFMG;
import com.drmangotea.tfmg.base.TFMGUtils;
import com.drmangotea.tfmg.registry.TFMGPackets;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.LevelAccessor;
import net.minecraftforge.network.PacketDistributor;
import java.util.List;
public interface IElectric {
long getPos();
LevelAccessor getLevelAccessor();
boolean destroyed();
ElectricalNetwork getOrCreateElectricNetwork();
default boolean hasElectricitySlot(Direction direction){
return true;
}
default void onPlaced(){
if(!getLevelAccessor().isClientSide())
TFMGPackets.getChannel().send(PacketDistributor.ALL.noArg(), new ConnectNeightborsPacket(BlockPos.of(getPos())));
TFMG.NETWORK_MANAGER.getOrCreateNetworkFor(this);
setNetwork(getPos());
updateNetwork();
onConnected();
sendStuff();
updateNextTick();
}
default void onConnected(){
BlockPos pos = BlockPos.of(getPos());
for(Direction d : Direction.values()){
if(hasElectricitySlot(d))
if(getLevelAccessor().getBlockEntity(pos.relative(d)) instanceof IElectric be){
if(be.hasElectricitySlot(d.getOpposite())) {
if (!be.destroyed()) {
getOrCreateElectricNetwork().add(be);
if (be.getData().getId() != getData().getId()) {
be.setNetwork(getData().getId());
be.onConnected();
if (!getLevelAccessor().isClientSide())
sendStuff();
}
}
} else if(be.getData().getId()!=getData().getId()){
be.updateNextTick();
}
}
}
sendStuff();
}
default boolean makeElectricityTooltip(List<Component> tooltip, boolean isPlayerSneaking){
Lang.translate("multimeter.header")
.style(ChatFormatting.WHITE)
.forGoggles(tooltip, 1);
Lang.text(" R = "+TFMGUtils.formatUnits(voltageGeneration()>0 ? getGeneratorResistance() : resistance(), "Ω"))
.style(ChatFormatting.GOLD)
.forGoggles(tooltip, 1);
Lang.text(" P = "+TFMGUtils.formatUnits(getPowerUsage(), "W"))
.style(ChatFormatting.GOLD)
.forGoggles(tooltip, 1);
Lang.text(" U = "+TFMGUtils.formatUnits(getData().getVoltage(), "V"))
.style(ChatFormatting.AQUA)
.forGoggles(tooltip, 1);
Lang.text(" I = "+TFMGUtils.formatUnits(getCurrent(), "A"))
.style(ChatFormatting.GREEN)
.forGoggles(tooltip, 1);
////////
Lang.text(" Network Resistance: "+TFMGUtils.formatUnits(getNetworkResistance(), "Ω"))
.style(ChatFormatting.YELLOW)
.forGoggles(tooltip, 1);
Lang.text(" Network Power Usage: "+TFMGUtils.formatUnits(getNetworkPowerUsage(), "W"))
.style(ChatFormatting.YELLOW)
.forGoggles(tooltip, 1);
Lang.text(" Group: "+getData().group.id)
.style(ChatFormatting.DARK_PURPLE)
.forGoggles(tooltip, 1);
Lang.text(" Group Resistance: "+getData().group.resistance)
.style(ChatFormatting.DARK_PURPLE)
.forGoggles(tooltip, 1);
Lang.text(" Voltage Supply: "+getData().voltageSupply)
.style(ChatFormatting.DARK_PURPLE)
.forGoggles(tooltip, 1);
if(voltageGeneration() > 0) {
Lang.translate("multimeter.power_generated")
.add(Component.literal(TFMGUtils.formatUnits(powerGeneration(), "W")))
.style(ChatFormatting.BLUE)
.forGoggles(tooltip, 1);
Lang.translate("multimeter.voltage_generated")
.add(Component.literal(TFMGUtils.formatUnits(voltageGeneration(), "V")))
.style(ChatFormatting.BLUE)
.forGoggles(tooltip, 1);
}
return true;
}
default void updateNearbyNetworks(IElectric member){
if(member.getData().getsOutsidePower)
for(Direction direction : Direction.values()){
if(member.getLevelAccessor().getBlockEntity(BlockPos.of(member.getPos()).relative(direction)) instanceof IElectric be&&be.getData().getId()!=be.getData().getId()){
be.updateNextTick();
}
}
}
ElectricBlockValues getData();
default int getPowerUsage(){
return (int) (getData().getVoltage()*getCurrent());
}
default int getNetworkPowerUsage(){
int power=0;
for(IElectric member : getOrCreateElectricNetwork().members)
power+=member.getPowerUsage();
return power;
}
default void onNetworkChanged(int oldVoltage, int oldPower){}
default float getGeneratorResistance(){
if(getData().voltageSupply == 0)
return 0;
return (float) powerGeneration() / (float)getData().networkPowerGeneration *(float)getNetworkResistance();
}
default float getGeneratorLoad(){
if(getNetworkPowerUsage() == 0)
return 0;
return (float) powerGeneration() / (float)getData().networkPowerGeneration *getNetworkPowerUsage();
}
int getPowerPercentage();
float resistance();
int voltageGeneration();
int powerGeneration();
int frequencyGeneration();
int getNetworkResistance();
default int getMaxAmps(){
return (int) getCurrent();
}
default float getCurrent(){
return getData().getVoltage()==0||resistance() == 0 ? 0 : ((float) getData().getVoltage() / (float) resistance());
}
void updateNextTick();
void updateNetwork();
void sendStuff();
void setVoltage(int newVoltage);
void setFrequency(int newFrequency);
void setNetworkResistance(int newUsage);
void setWattage(int newWattage);
void setPowerPercentage(int percentage);
void setNetwork(long network);
default boolean canBeInGroups(){
return false;
}
}

View File

@@ -0,0 +1,4 @@
package com.drmangotea.tfmg.content.electricity.base;
public interface IVoltageChanger {
}

View File

@@ -0,0 +1,266 @@
package com.drmangotea.tfmg.content.electricity.base;
import com.drmangotea.tfmg.TFMG;
import com.drmangotea.tfmg.registry.TFMGPackets;
import com.simibubi.create.content.equipment.goggles.IHaveGoggleInformation;
import com.simibubi.create.content.equipment.goggles.IHaveHoveringInformation;
import com.simibubi.create.content.kinetics.base.GeneratingKineticBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.network.PacketDistributor;
import java.util.List;
public class KineticElectricBlockEntity extends GeneratingKineticBlockEntity implements IElectric, IHaveGoggleInformation, IHaveHoveringInformation {
public ElectricBlockValues data = new ElectricBlockValues(getPos());
int powerPercentage = 100;
int timer = 0;
public KineticElectricBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
data.connectNextTick = true;
}
@Override
public boolean addToTooltip(List<Component> tooltip, boolean isPlayerSneaking) {
return makeElectricityTooltip(tooltip, isPlayerSneaking);
}
@Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {}
@Override
public LevelAccessor getLevelAccessor(){
return level;
}
@Override
public boolean destroyed() {
return data.destroyed;
}
@Override
public ElectricalNetwork getOrCreateElectricNetwork() {
if(level.getBlockEntity(BlockPos.of(data.electricalNetworkId)) instanceof IElectric) {
return TFMG.NETWORK_MANAGER.getOrCreateNetworkFor((IElectric) level.getBlockEntity(BlockPos.of(data.electricalNetworkId)));
} else {
ElectricNetworkManager.networks.get(getLevel())
.remove(data.electricalNetworkId);
return TFMG.NETWORK_MANAGER.getOrCreateNetworkFor(this);
}
}
@Override
public ElectricBlockValues getData() {
return data;
}
@Override
public int getPowerPercentage() {
return powerPercentage;
}
@Override
public float resistance() {
return 0;
}
@Override
public int voltageGeneration() {
int voltageGeneration = 0;
for(Direction direction : Direction.values()){
if(hasElectricitySlot(direction)){
if(level.getBlockEntity(getBlockPos().relative(direction)) instanceof VoltageAlteringBlockEntity be)
if(be.getData().getId() !=getData().getId())
if(be.getData().getVoltage()!=0)
if(be.hasElectricitySlot(direction)){
voltageGeneration = Math.max(voltageGeneration,be.getOutputVoltage());
data.getsOutsidePower = true;
}
}
}
if(voltageGeneration == 0)
data.getsOutsidePower = false;
return voltageGeneration;
}
@Override
public int powerGeneration() {
int powerGeneration = 0;
for(Direction direction : Direction.values()){
if(hasElectricitySlot(direction)){
if(level.getBlockEntity(getBlockPos().relative(direction)) instanceof VoltageAlteringBlockEntity be)
if(be.getData().getId() !=getData().getId())
if(be.getData().getVoltage()!=0)
if(be.hasElectricitySlot(direction)){
powerGeneration = Math.max(powerGeneration,be.getOutputPower());
}
}
}
return powerGeneration;
}
@Override
public int frequencyGeneration() {
return 0;
}
@Override
public void updateNextTick() {
data.updateNextTick = true;
}
@Override
public void updateNetwork() {
getOrCreateElectricNetwork().updateNetwork();
if(!level.isClientSide)
TFMGPackets.getChannel().send(PacketDistributor.ALL.noArg(), new NetworkUpdatePacket(BlockPos.of(getPos())));
sendData();
}
@Override
public void sendStuff() {
sendData();
}
@Override
public void setVoltage(int newVoltage) {
if(canBeInGroups()){
data.voltage = (int) (((float)resistance()/data.group.resistance)*(float)data.voltageSupply);
return;
}
data.voltage = newVoltage;
}
@Override
public void setFrequency(int newFrequency) {
data.frequency = newFrequency;
}
@Override
public void setNetworkResistance(int newUsage) {
data.networkResistance = newUsage;
}
@Override
public int getNetworkResistance() {
return data.networkResistance;
}
@Override
public void setWattage(int newWattage) {
}
@Override
public void setPowerPercentage(int percentage) {
powerPercentage = percentage;
}
@Override
public void setNetwork(long network) {
this.data.electricalNetworkId = network;
if(network!=getPos())
ElectricNetworkManager.networks.get(getLevel())
.remove(getPos());
}
public boolean networkUndersupplied(){
return getNetworkPowerUsage()>data.networkPowerGeneration;
}
@Override
public long getPos() {
return getBlockPos().asLong();
}
@Override
public void remove() {
super.remove();
this.data.destroyed = true;
for(Direction d : Direction.values()) {
if(hasElectricitySlot(d))
if(getLevelAccessor().getBlockEntity(BlockPos.of(getPos()).relative(d)) instanceof IElectric be&&be.hasElectricitySlot(d.getOpposite())) {
ElectricNetworkManager.networks.get(getLevel())
.remove(be.getPos());
be.setNetwork(be.getPos());
be.onPlaced();
be.updateNextTick();
}
}
if(data.electricalNetworkId != getPos())
getOrCreateElectricNetwork().getMembers().remove(this);
if(data.electricalNetworkId == getPos())
ElectricNetworkManager.networks.get(getLevel())
.remove(getData().getId());
}
@Override
public void tick() {
super.tick();
if(timer == 2){
updateNextTick();
}
if(timer<=2){
timer++;
}
if(data.connectNextTick) {
onPlaced();
data.connectNextTick = false;
}
if(data.updateNextTick) {
updateNetwork();
data.updateNextTick = false;
}
}
@Override
protected void write(CompoundTag tag, boolean clientPacket) {
super.write(tag, clientPacket);
}
@Override
protected void read(CompoundTag tag, boolean clientPacket) {
super.read(tag, clientPacket);
if(!clientPacket)
data.connectNextTick = true;
}
@Override
public void onSpeedChanged(float previousSpeed) {
super.onSpeedChanged(previousSpeed);
updateNextTick();
timer = 0;
}
}

View File

@@ -0,0 +1,42 @@
package com.drmangotea.tfmg.content.electricity.base;
import com.drmangotea.tfmg.content.electricity.utilities.diode.ElectricDiodeBlockEntity;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.networking.BlockEntityDataPacket;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
public class NetworkUpdatePacket extends BlockEntityDataPacket<SmartBlockEntity> {
public NetworkUpdatePacket(BlockPos pos) {
super(pos);
}
public NetworkUpdatePacket(FriendlyByteBuf buffer) {
super(buffer);
}
@Override
protected void writeData(FriendlyByteBuf buffer) {}
@Override
protected void handlePacket(SmartBlockEntity blockEntity) {
if(blockEntity instanceof IElectric be) {
be.updateNetwork();
}
}
}

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