list = new ArrayList<>();
+
+ ItemStack copperSpool = TFMGItems.COPPER_SPOOL.asStack();
+ copperSpool.set(TFMGDataComponents.SPOOL_AMOUNT,1000);
+ list.add(copperSpool);
+
+ ItemStack aluminumSpool = TFMGItems.ALUMINUM_SPOOL.asStack();
+ aluminumSpool.set(TFMGDataComponents.SPOOL_AMOUNT,1000);
+ list.add(aluminumSpool);
+
+ ItemStack constantanSpool = TFMGItems.CONSTANTAN_SPOOL.asStack();
+ constantanSpool.set(TFMGDataComponents.SPOOL_AMOUNT,1000);
+ list.add(constantanSpool);
+
+ CompoundTag gasolineTag = new CompoundTag();
+ gasolineTag.putString("gasoline", "c:gasoline");
+ gasolineTag.putString("kerosene", "c:kerosene");
+ gasolineTag.putString("naphtha", "c:naphtha");
+ CompoundTag gasolineTagName = new CompoundTag();
+ gasolineTagName.putString("gasoline", "fluid.tfmg.gasoline");
+ gasolineTagName.putString("kerosene", "fluid.tfmg.kerosene");
+ gasolineTagName.putString("naphtha", "fluid.tfmg.naphtha");
+ //
+ CompoundTag creosoteTag = new CompoundTag();
+ creosoteTag.putString("creosote", "c:creosote");
+ creosoteTag.putString("furnace_gas", "c:furnace_gas");
+ CompoundTag creosoteTagName = new CompoundTag();
+ creosoteTagName.putString("creosote", "fluid.tfmg.creosote");
+ creosoteTagName.putString("furnace_gas", "fluid.tfmg.furnace_gas");
+ //
+ CompoundTag dieselTag = new CompoundTag();
+ dieselTag.putString("diesel", "c:diesel");
+ CompoundTag dieselTagName = new CompoundTag();
+ dieselTagName.putString("diesel", "fluid.tfmg.diesel");
+ //
+ CompoundTag lpgTag = new CompoundTag();
+ lpgTag.putString("lpg", "c:lpg");
+ CompoundTag lpgTagName = new CompoundTag();
+ lpgTagName.putString("lpg", "fluid.tfmg.lpg");
+ //
+ CompoundTag keroseneTag = new CompoundTag();
+ keroseneTag.putString("kerosene", "c:kerosene");
+ CompoundTag keroseneTagName = new CompoundTag();
+ keroseneTagName.putString("kerosene", "fluid.tfmg.kerosene");
+ //
+
+
+ ItemStack gasoline = TFMGItems.ENGINE_CYLINDER.asStack();
+ gasoline.set(TFMGDataComponents.FUELS, gasolineTagName);
+ gasoline.set(TFMGDataComponents.FUEL_TAGS, gasolineTag);
+ list.add(gasoline);
+ ItemStack diesel = TFMGItems.DIESEL_ENGINE_CYLINDER.asStack();
+ diesel.set(TFMGDataComponents.FUELS, dieselTagName);
+ diesel.set(TFMGDataComponents.FUEL_TAGS, dieselTag);
+ list.add(diesel);
+ ItemStack lpg = TFMGItems.ENGINE_CYLINDER.asStack();
+ lpg.set(TFMGDataComponents.FUELS, lpgTagName);
+ lpg.set(TFMGDataComponents.FUEL_TAGS, lpgTag);
+ list.add(lpg);
+ ItemStack creosote = TFMGItems.SIMPLE_ENGINE_CYLINDER.asStack();
+ creosote.set(TFMGDataComponents.FUELS, creosoteTagName);
+ creosote.set(TFMGDataComponents.FUEL_TAGS, creosoteTag);
+ list.add(creosote);
+
+
+ ItemStack kerosene = TFMGItems.TURBINE_BLADE.asStack();
+ kerosene.set(TFMGDataComponents.FUELS, keroseneTagName);
+ kerosene.set(TFMGDataComponents.FUEL_TAGS, keroseneTag);
+ list.add(kerosene);
+
+ return list;
+ }
+
+ @ApiStatus.Internal
+ public static void register(IEventBus modEventBus) {
+ REGISTER.register(modEventBus);
+ }
+
+
+}
+
+
diff --git a/src/main/java/com/drmangotea/tfmg/base/TFMGIcons.java b/src/main/java/com/drmangotea/tfmg/base/TFMGIcons.java
new file mode 100644
index 00000000..29b44e04
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/TFMGIcons.java
@@ -0,0 +1,98 @@
+package com.drmangotea.tfmg.base;
+
+import com.drmangotea.tfmg.TFMG;
+import com.mojang.blaze3d.systems.RenderSystem;
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.blaze3d.vertex.VertexConsumer;
+import com.simibubi.create.foundation.gui.AllIcons;
+import net.createmod.catnip.gui.element.DelegatedStencilElement;
+import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.renderer.LightTexture;
+import net.minecraft.client.renderer.MultiBufferSource;
+import net.minecraft.client.renderer.RenderType;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.phys.Vec3;
+
+
+import net.neoforged.api.distmarker.Dist;
+import net.neoforged.api.distmarker.OnlyIn;
+import org.joml.Matrix4f;
+
+import java.awt.*;
+
+public class TFMGIcons extends AllIcons {
+
+
+ public static final ResourceLocation ICON_ATLAS = TFMG.asResource("textures/gui/icons.png");
+ public static final int ICON_ATLAS_SIZE = 256;
+
+ private static int x = 0, y = -1;
+ private int iconX;
+ private int iconY;
+
+
+ public static final TFMGIcons
+ DISTILLATION_OUTPUT_ICON_DO_NOT_VOID = newRow(),
+ DISTILLATION_OUTPUT_ICON_VOID = next();
+
+ public TFMGIcons(int x, int y) {
+ super(x, y);
+ iconX = x * 16;
+ iconY = y * 16;
+ }
+
+ private static TFMGIcons next() {
+ return new TFMGIcons(++x, y);
+ }
+
+ private static TFMGIcons newRow() {
+ return new TFMGIcons(x = 0, ++y);
+ }
+
+ @OnlyIn(Dist.CLIENT)
+ public void bind() {
+ RenderSystem.setShaderTexture(0, ICON_ATLAS);
+ }
+
+ @OnlyIn(Dist.CLIENT)
+ @Override
+ public void render(GuiGraphics graphics, int x, int y) {
+ graphics.blit(ICON_ATLAS, x, y, 0, iconX, iconY, 16, 16, 256, 256);
+ }
+
+ @OnlyIn(Dist.CLIENT)
+ public void render(PoseStack ms, MultiBufferSource buffer, int color) {
+ VertexConsumer builder = buffer.getBuffer(RenderType.text(ICON_ATLAS));
+ Matrix4f matrix = ms.last().pose();
+ Color rgb = new Color(color);
+ int light = LightTexture.FULL_BRIGHT;
+
+ Vec3 vec1 = new Vec3(0, 0, 0);
+ Vec3 vec2 = new Vec3(0, 1, 0);
+ Vec3 vec3 = new Vec3(1, 1, 0);
+ Vec3 vec4 = new Vec3(1, 0, 0);
+
+ float u1 = iconX * 1f / ICON_ATLAS_SIZE;
+ float u2 = (iconX + 16) * 1f / ICON_ATLAS_SIZE;
+ float v1 = iconY * 1f / ICON_ATLAS_SIZE;
+ float v2 = (iconY + 16) * 1f / ICON_ATLAS_SIZE;
+
+ vertex(builder, matrix, vec1, rgb, u1, v1, light);
+ vertex(builder, matrix, vec2, rgb, u1, v2, light);
+ vertex(builder, matrix, vec3, rgb, u2, v2, light);
+ vertex(builder, matrix, vec4, rgb, u2, v1, light);
+ }
+
+ @OnlyIn(Dist.CLIENT)
+ private void vertex(VertexConsumer builder, Matrix4f matrix, Vec3 vec, Color rgb, float u, float v, int light) {
+ builder.addVertex(matrix, (float) vec.x, (float) vec.y, (float) vec.z)
+ .setColor(rgb.getRed(), rgb.getGreen(), rgb.getBlue(), 255)
+ .setUv(u, v)
+ .setLight(light);
+ }
+
+ @OnlyIn(Dist.CLIENT)
+ public DelegatedStencilElement asStencil() {
+ return new DelegatedStencilElement().withStencilRenderer((ms, w, h, alpha) -> this.render(ms, 0, 0)).withBounds(16, 16);
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/TFMGMetalBarsGen.java b/src/main/java/com/drmangotea/tfmg/base/TFMGMetalBarsGen.java
new file mode 100644
index 00000000..204dda68
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/TFMGMetalBarsGen.java
@@ -0,0 +1,144 @@
+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.neoforged.neoforge.client.model.generators.ModelFile;
+
+
+import java.util.function.Supplier;
+
+import static net.minecraft.world.level.block.state.properties.BlockStateProperties.*;
+
+public class TFMGMetalBarsGen {
+
+ public static NonNullBiConsumer, 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 createBars(String name, boolean specialEdge,
+ Supplier 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();
+ }
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/TFMGRegistrate.java b/src/main/java/com/drmangotea/tfmg/base/TFMGRegistrate.java
new file mode 100644
index 00000000..7b078792
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/TFMGRegistrate.java
@@ -0,0 +1,72 @@
+package com.drmangotea.tfmg.base;
+
+import com.drmangotea.tfmg.TFMG;
+import com.drmangotea.tfmg.base.fluid.GasFluidType;
+import com.simibubi.create.content.fluids.VirtualFluid;
+import com.simibubi.create.foundation.data.CreateRegistrate;
+import com.simibubi.create.foundation.data.VirtualFluidBuilder;
+import com.simibubi.create.foundation.item.TooltipModifier;
+import com.tterrag.registrate.Registrate;
+import com.tterrag.registrate.builders.FluidBuilder;
+import net.minecraft.core.registries.BuiltInRegistries;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.item.CreativeModeTab;
+import net.minecraft.world.item.Item;
+import net.minecraft.world.level.block.*;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.function.Function;
+
+import static com.drmangotea.tfmg.registry.TFMGFluids.getGasTexture;
+import static com.simibubi.create.foundation.data.ModelGen.customItemModel;
+
+public class TFMGRegistrate extends CreateRegistrate {
+ protected TFMGRegistrate(String modid) {
+ super(modid);
+ }
+
+ public TFMGRegistrate setTooltipModifierFactory(@Nullable Function- factory) {
+ currentTooltipModifierFactory = factory;
+ return this;
+ }
+
+
+ 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();
+ }
+
+ public FluidBuilder gasFluid(String name, int color) {
+ return entry(name, c -> new VirtualFluidBuilder<>(self(),self(), name, c, getGasTexture(), getGasTexture(),
+ GasFluidType.create(color),VirtualFluid::createSource,VirtualFluid::createFlowing));
+ }
+
+
+
+ public static TFMGRegistrate create(String id) {
+ return new TFMGRegistrate(id);
+ }
+
+ //public static Block getBlock(String name) {
+ // return TFMG.REGISTRATE.get(name, Registrate.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", Registries.ITEM).get();
+ }
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/TFMGRegistrateTags.java b/src/main/java/com/drmangotea/tfmg/base/TFMGRegistrateTags.java
new file mode 100644
index 00000000..640a4979
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/TFMGRegistrateTags.java
@@ -0,0 +1,53 @@
+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 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
- provIn) {
+ TagGen.CreateTagsProvider
- 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 provIn) {
+ TagGen.CreateTagsProvider 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);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/TFMGShapes.java b/src/main/java/com/drmangotea/tfmg/base/TFMGShapes.java
new file mode 100644
index 00000000..c6e956bc
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/TFMGShapes.java
@@ -0,0 +1,216 @@
+package com.drmangotea.tfmg.base;
+
+
+import net.createmod.catnip.math.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 = shape(0, 0, 0, 16, 7, 16).add(3, 7, 0, 13, 12, 16)
+ .forDirectional(SOUTH),
+ ENGINE_GEARBOX = shape(0, 0, -1, 3, 5, 15)
+ .add(13, 0, -1, 16, 5, 15)
+ .add(3, 0, -1, 13, 12, 11)
+ .add(3, 0, 11, 13, 11, 15)
+ .add(13, 5, 3, 16, 13, 13)
+ .add(0, 5, 3, 3, 13, 13)
+ .add(13, 5, -1, 16, 7, 1)
+ .add(0, 5, -1, 3, 7, 1)
+ .add(15, 5, 9, 15, 11, 9)
+ .forDirectional(NORTH),
+ TURBINE_ENGINE_FRONT = shape(2, 2, 0, 14, 14, 16)
+ .add(3, 0, 8, 13, 2, 16)
+ .forHorizontal(SOUTH),
+ TURBINE_ENGINE_MIDDLE = shape(11, 0, 2, 16, 5, 14)
+ .add(1, 1, 0, 15, 15, 16)
+ .add(0, 0, 2, 5, 5, 14)
+ .forHorizontal(SOUTH),
+ TURBINE_ENGINE_BACK = shape(5.3, 0, 5, 11.3, 3, 14)
+ .add(3, 3, 2, 13, 13, 16)
+ .forHorizontal(SOUTH),
+ ENGINE_CONTROLLER = shape(0, 0, 0, 4, 5, 16)
+ .add(2, 5, 5, 14, 12, 14)
+ .add(4, 0, 5, 15, 5, 16)
+ .forHorizontal(SOUTH),
+ ENGINE_FRONT = shape(0, 0, 1, 16, 7, 16).add(3, 7, 1, 13, 12, 16)
+ .forDirectional(SOUTH),
+ PUMPJACK_HAMMER_PART = shape(0, 2, 0, 16, 14, 16)
+ .forDirectional(),
+ RADIAL_ENGINE_SINGLE = shape(1, 4, 1, 15, 12, 15)
+ .forDirectional(),
+ RADIAL_ENGINE_SIDE = shape(1, 4, 1, 15, 16, 15)
+ .forDirectional(),
+ RADIAL_ENGINE_MIDDLE = shape(1, 0, 1, 15, 16, 15)
+ .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(),
+ RESISTOR = shape(6, 0, 3, 10, 4, 13)
+ .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(),
+ POTENTIOMETER = shape(3, 0, 3, 13, 16, 13).add(1, 1, 13, 15, 15, 16)
+ .forDirectional(),
+ WINDING_MACHINE = shape(0, 0, 0, 16, 8, 16).add(0, 8, 4, 10, 12, 12)
+ .forHorizontal(NORTH),
+ RESISTOR_VERTICAL = shape(3, 0, 3, 13, 16, 13)
+ .forDirectional(),
+ BLAST_FURNACE_REINFORCEMENT_WALL = shape(0, 0, 0, 16, 6, 16)
+ .forDirectional(),
+
+ ROTOR = shape(4, 5, 4, 12, 11, 12).add(5, 0, 5, 11, 16, 11)
+ .forDirectional(),
+ STATOR = shape(5, 1, 0, 16, 15.2, 5).add(5, 1, 5, 10, 15.2, 10).add(0, 1, 0, 5, 15.2, 16)
+ .forDirectional(),
+ STATOR_ROTATED = shape(5, 1, 11, 16, 15, 16).add(5, 1, 6, 10, 15, 11).add(0, 1, 0, 5, 15, 16)
+ .forDirectional(),
+ STATOR_VERTICAL = shape(5, 0, 1, 16, 5, 15).add(5, 5, 1, 10, 10, 15).add(0, 0, 1, 5, 16, 15)
+ .forDirectional(),
+ VOLTMETER = shape(0, 0, 2, 16, 3, 14)
+ .forDirectional(),
+ ELECTRIC_PUMP = shape(2, 6, 2, 14, 10, 14)
+ .add(4, 3, 4, 12, 11, 12)
+ .add(3, 11, 3, 13, 16, 13)
+ .add(3, 0, 3, 13, 5, 13)
+ .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(),
+ CASTING_BASIN = shape(0, 0, 0, 16, 8, 16)
+ .add(4, 8, 14, 12, 13, 16)
+ .forHorizontal(NORTH),
+ TRANSFORMER = shape(0, 0, 0, 16, 6, 16)
+ .add(1, 6, 5, 15, 15, 11)
+ .forHorizontal(NORTH),
+ 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(),
+ 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 factory, Direction direction) {
+ return factory.apply(shape, direction);
+ }
+
+ public VoxelShaper build(BiFunction 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);
+ }
+
+ }
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/TFMGSharedProperties.java b/src/main/java/com/drmangotea/tfmg/base/TFMGSharedProperties.java
new file mode 100644
index 00000000..1f454301
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/TFMGSharedProperties.java
@@ -0,0 +1,5 @@
+package com.drmangotea.tfmg.base;
+
+
+
+public class TFMGSharedProperties {}
diff --git a/src/main/java/com/drmangotea/tfmg/base/TFMGSpriteShifts.java b/src/main/java/com/drmangotea/tfmg/base/TFMGSpriteShifts.java
new file mode 100644
index 00000000..833f5f11
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/TFMGSpriteShifts.java
@@ -0,0 +1,72 @@
+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 net.createmod.catnip.render.SpriteShiftEntry;
+import net.createmod.catnip.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 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 FIREBOX_TOP = getCT(AllCTTypes.RECTANGLE, "firebox_top");
+
+ 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 ALUMINUM_FLUID_TANK = getCT(AllCTTypes.RECTANGLE, "aluminum_fluid_tank"), ALUMINUM_FLUID_TANK_TOP = getCT(AllCTTypes.RECTANGLE, "aluminum_fluid_tank_top"), ALUMINUM_FLUID_TANK_INNER = getCT(AllCTTypes.RECTANGLE, "aluminum_fluid_tank_inner");
+ public static final CTSpriteShiftEntry CAST_IRON_FLUID_TANK = getCT(AllCTTypes.RECTANGLE, "cast_iron_fluid_tank"), CAST_IRON_FLUID_TANK_TOP = getCT(AllCTTypes.RECTANGLE, "cast_iron_fluid_tank_top"), CAST_IRON_FLUID_TANK_INNER = getCT(AllCTTypes.RECTANGLE, "cast_iron_fluid_tank_inner");
+
+ public static final CTSpriteShiftEntry STEEL_VAT = getCT(AllCTTypes.RECTANGLE, "steel_vat"), STEEL_VAT_TOP = getCT(AllCTTypes.RECTANGLE, "steel_vat_top"), STEEL_VAT_INNER = getCT(AllCTTypes.RECTANGLE, "steel_vat_inner");
+ public static final CTSpriteShiftEntry CAST_IRON_VAT = getCT(AllCTTypes.RECTANGLE, "cast_iron_vat"), CAST_IRON_VAT_TOP = getCT(AllCTTypes.RECTANGLE, "cast_iron_vat_top"), CAST_IRON_VAT_INNER = getCT(AllCTTypes.RECTANGLE, "cast_iron_vat_inner");
+ public static final CTSpriteShiftEntry FIREPROOF_VAT = getCT(AllCTTypes.RECTANGLE, "firebrick_vat");
+
+ 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));
+ }
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/TFMGTiers.java b/src/main/java/com/drmangotea/tfmg/base/TFMGTiers.java
new file mode 100644
index 00000000..228d4c8e
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/TFMGTiers.java
@@ -0,0 +1,88 @@
+package com.drmangotea.tfmg.base;
+
+import com.drmangotea.tfmg.TFMG;
+import com.drmangotea.tfmg.registry.TFMGItems;
+import com.simibubi.create.AllSoundEvents;
+import com.simibubi.create.AllTags;
+import com.simibubi.create.Create;
+import net.minecraft.core.Holder;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.sounds.SoundEvent;
+import net.minecraft.tags.BlockTags;
+import net.minecraft.tags.TagKey;
+import net.minecraft.util.LazyLoadedValue;
+import net.minecraft.world.item.ArmorItem;
+import net.minecraft.world.item.ArmorMaterial;
+import net.minecraft.world.item.Tier;
+import net.minecraft.world.item.crafting.Ingredient;
+import net.minecraft.world.level.block.Block;
+import net.neoforged.bus.api.IEventBus;
+import net.neoforged.neoforge.common.SimpleTier;
+import net.neoforged.neoforge.common.Tags;
+import net.neoforged.neoforge.registries.DeferredRegister;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.EnumMap;
+import java.util.List;
+import java.util.function.Supplier;
+
+public enum TFMGTiers implements Tier {
+
+
+
+
+
+ STEEL(TFMG.asResource("steel").toString(),1000, 7.5f, 3f, 12,()-> Ingredient.of(AllTags.commonItemTag("ingots/steel"))),
+ ALUMINUM(TFMG.asResource("aluminum").toString(),220, 6, 2f, 22,()-> Ingredient.of(AllTags.commonItemTag("ingots/aluminum"))),
+ LEAD(TFMG.asResource("lead").toString(),32, 2, 0.5f, 5,()-> Ingredient.of(AllTags.commonItemTag("ingots/lead")));
+
+
+ public final String name;
+
+ private final int uses;
+ private final float speed;
+ private final float damageBonus;
+ private final int enchantValue;
+ private final Supplier repairMaterial;
+
+ private TFMGTiers(String name, int uses, float speed, float damageBonus, int enchantValue,
+ Supplier repairMaterial) {
+ this.name = name;
+ this.uses = uses;
+ this.speed = speed;
+ this.damageBonus = damageBonus;
+ this.enchantValue = enchantValue;
+ this.repairMaterial = repairMaterial;
+ }
+
+ @Override
+ public int getUses() {
+ return uses;
+ }
+
+ @Override
+ public float getSpeed() {
+ return speed;
+ }
+
+ @Override
+ public float getAttackDamageBonus() {
+ return damageBonus;
+ }
+
+ @Override
+ public @NotNull TagKey getIncorrectBlocksForDrops() {
+ return BlockTags.INCORRECT_FOR_WOODEN_TOOL;
+ }
+
+ @Override
+ public int getEnchantmentValue() {
+ return enchantValue;
+ }
+
+ @Override
+ public @NotNull Ingredient getRepairIngredient() {
+ return repairMaterial.get();
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/TFMGUtils.java b/src/main/java/com/drmangotea/tfmg/base/TFMGUtils.java
new file mode 100644
index 00000000..355a95b2
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/TFMGUtils.java
@@ -0,0 +1,386 @@
+package com.drmangotea.tfmg.base;
+
+
+import com.drmangotea.tfmg.TFMG;
+import com.drmangotea.tfmg.base.spark.ElectricSparkParticle;
+import com.drmangotea.tfmg.base.spark.Spark;
+import com.drmangotea.tfmg.content.electricity.connection.cables.CablePos;
+import com.drmangotea.tfmg.registry.TFMGEntityTypes;
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.blaze3d.vertex.VertexConsumer;
+import com.simibubi.create.AllSoundEvents;
+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.CreateLang;
+import net.createmod.catnip.lang.LangBuilder;
+import net.minecraft.ChatFormatting;
+import net.minecraft.client.renderer.LevelRenderer;
+import net.minecraft.client.renderer.LightTexture;
+import net.minecraft.client.renderer.MultiBufferSource;
+import net.minecraft.client.renderer.RenderType;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.network.chat.Component;
+import net.minecraft.sounds.SoundEvent;
+import net.minecraft.sounds.SoundSource;
+import net.minecraft.util.Mth;
+import net.minecraft.util.RandomSource;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.level.BlockAndTintGetter;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.LightLayer;
+import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.material.Fluid;
+import net.minecraft.world.phys.AABB;
+import net.minecraft.world.phys.Vec3;
+import net.neoforged.neoforge.capabilities.Capabilities;
+import net.neoforged.neoforge.fluids.FluidStack;
+import net.neoforged.neoforge.fluids.capability.IFluidHandler;
+import net.neoforged.neoforge.items.IItemHandler;
+import net.neoforged.neoforge.items.IItemHandlerModifiable;
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
+import org.joml.Matrix4f;
+
+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 float toYRot(Direction facing) {
+ return switch (facing){
+ case DOWN -> 0.0F;
+ case UP -> 0.0F;
+ case NORTH -> 0.0F;
+ case SOUTH -> 180F;
+ case WEST -> 90;
+ case EAST -> 270F;
+ };
+ }
+ 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 playSound(Level level, BlockPos pos, SoundEvent sound, SoundSource source){
+ playSound(level,pos,sound,source,1,1,null);
+ }
+ public static void playSound(Level level, BlockPos pos, SoundEvent sound, SoundSource source, Player player){
+ playSound(level,pos,sound,source,1,1,player);
+ }
+ public static void playSound(Level level, BlockPos pos, SoundEvent sound, SoundSource source, float volume, float pitch){
+ playSound(level,pos,sound,source,volume,pitch,null);
+ }
+ public static void playSound(Level level, BlockPos pos, SoundEvent sound, SoundSource source, float volume, float pitch, Player player){
+ level.playSound(player,pos,sound,source,volume,pitch);
+ }
+
+ 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 tooltip) {
+ createFluidTooltip(be, tooltip);
+ createItemTooltip(be, tooltip);
+ }
+
+ public static boolean createFluidTooltip(BlockEntity be, List tooltip) {
+ LangBuilder mb = CreateLang.translate("generic.unit.millibuckets");
+
+ /////////
+ IFluidHandler handler = Capabilities.FluidHandler.BLOCK.getCapability(be.getLevel(),be.getBlockPos(),be.getBlockState(),be,null);
+ //Optional resolve = handler.resolve();
+ //if (!resolve.isPresent()) return false;
+
+ if(handler == null)
+ return true;
+
+ IFluidHandler tank = handler;
+ if (tank.getTanks() == 0) return false;
+
+ CreateLang.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;
+ CreateLang.fluidName(fluidStack).style(ChatFormatting.GRAY).forGoggles(tooltip, 1);
+ CreateLang.builder().add(CreateLang.number(fluidStack.getAmount()).add(mb).style(ChatFormatting.DARK_GREEN)).text(ChatFormatting.GRAY, " / ").add(CreateLang.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;
+
+ CreateLang.translate("gui.goggles.fluid_container.capacity").add(CreateLang.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 tooltip) {
+
+ IItemHandlerModifiable handler = (IItemHandlerModifiable) Capabilities.ItemHandler.BLOCK.getCapability(be.getLevel(),be.getBlockPos(),be.getBlockState(),be,null);
+
+ IItemHandlerModifiable inventory = handler;
+ if (inventory.getSlots() == 0) return false;
+ CreateLang.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;
+ CreateLang.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;
+
+ CreateLang.translate("item_attributes.shulker_level.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().getFluidHolder(), 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 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 updateCallback) {
+ return createTank(capacity, extractionAllowed, true, updateCallback, null);
+ }
+
+ public static SmartFluidTank createTank(int capacity, boolean extractionAllowed, boolean insertionAllowed, Consumer updateCallback) {
+ return createTank(capacity, extractionAllowed, insertionAllowed, updateCallback, null);
+ }
+
+ public static SmartFluidTank createTank(int capacity, boolean extractionAllowed, boolean insertionAllowed, Consumer 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);
+ }
+
+ public FluidStack forceDrain(FluidStack resource, FluidAction action){
+ 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);
+ }
+ };
+ }
+
+ /// //////////////////////
+ public static void renderWire(Level level, PoseStack pMatrixStack, MultiBufferSource pBuffer, CablePos pos1, CablePos pos2,
+ float curve, float r, float g, float b) {
+ renderWire(level, pMatrixStack, pBuffer, pos1, pos2, curve, r, g, b, false);
+ }
+
+ public static void renderWire(Level level, PoseStack pMatrixStack, MultiBufferSource pBuffer, CablePos pos1, CablePos pos2,
+ float curve, float r, float g, float b, boolean flippedLighting) {
+ pMatrixStack.pushPose();
+ Vec3 vec3 = new Vec3(0, 0, 0);
+ CablePos pos2Local = pos1.subtract(pos2);
+ pMatrixStack.translate(0.5, 0.5, 0.5);
+ vec3 = vec3.add(pos2Local.x() + 0.01, pos2Local.y(), pos2Local.z() + 0.01);
+ float f = (float) (vec3.x);
+ float f1 = (float) (vec3.y);
+ float f2 = (float) (vec3.z);
+ VertexConsumer vertexconsumer = pBuffer.getBuffer(RenderType.leash());
+ Matrix4f matrix4f = pMatrixStack.last().pose();
+ float f4 = (float) (Mth.fastInvSqrt(f * f + f2 * f2) * 0.025F / 2.0F);
+ float f5 = f2 * f4;
+ float f6 = f * f4;
+ //int i =15;
+ //int j = 15;
+
+ BlockPos blockpos2;
+ BlockPos blockpos1;
+ if (flippedLighting) {
+ blockpos1 = new BlockPos((int) pos1.x(), (int) pos1.y(), (int) pos1.z());
+ blockpos2 = new BlockPos((int) pos2.x(), (int) pos2.y(), (int) pos2.z());
+ } else {
+ blockpos2 = new BlockPos((int) pos1.x(), (int) pos1.y(), (int) pos1.z());
+ blockpos1 = new BlockPos((int) pos2.x(), (int) pos2.y(), (int) pos2.z());
+ }
+ int i = level.getBrightness(LightLayer.SKY, blockpos1);
+ int j = level.getBrightness(LightLayer.SKY, blockpos2);
+ int k = level.getBrightness(LightLayer.SKY, blockpos1);
+ int l = level.getBrightness(LightLayer.SKY, blockpos2);
+
+
+ //int k = 15;
+ //int l = 15;
+ for (int i1 = 0; i1 <= 24; ++i1) {
+ addVertexPair(vertexconsumer, matrix4f, f, f1, f2, i, j, k, l, 0.030F, 0.030F, f5, f6, i1, false, curve, r, g, b);
+ }
+
+ for (int j1 = 24; j1 >= 0; --j1) {
+ addVertexPair(vertexconsumer, matrix4f, f, f1, f2, i, j, k, l, 0.030F, 0.00F, f5, f6, j1, true, curve, r, g, b);
+ }
+ pMatrixStack.popPose();
+ }
+
+
+
+ private static void addVertexPair(VertexConsumer vertexConsumer, Matrix4f matrix4f, float p_174310_, float p_174311_, float p_174312_, int light_1, int light_2, int p_174315_, int p_174316_, float thickness, float p_174318_, float p_174319_, float p_174320_, int value, boolean p_174322_, float curve, float r, float g, float b) {
+ float f = (float) (value / 24.0F);
+ int i = (int) Mth.lerp(f, (float) light_1, (float) light_2);
+ int j = (int) Mth.lerp(f, (float) p_174315_, (float) p_174316_);
+ int k = LightTexture.pack(i, j);
+ float f1 = value % 2 == (p_174322_ ? 1 : 0) ? 0.7F : 1.0F;
+ float red = r / 255 * f1;
+ float green = g / 255 * f1;
+ float blue = b / 255 * f1;
+ float x = p_174310_ * f;
+
+ float pain;
+ pain = ((value * curve * 24) - (value * value * curve)) * -1f;
+
+ float y = p_174311_ > 0.0F ? p_174311_ * f * f : p_174311_ - p_174311_ * (1.0F - f) * (1.0F - f);
+ float z = p_174312_ * f;
+ vertexConsumer.addVertex(matrix4f, x - p_174319_, y + p_174318_ + pain, z + p_174320_).setColor(red, green, blue, 1.0F).setLight(k);
+ vertexConsumer.addVertex(matrix4f, x + p_174319_, y + thickness - p_174318_ + pain, z - p_174320_).setColor(red, green, blue, 1.0F).setLight(k);
+ }
+
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/blocks/TFMGDirectionalBlock.java b/src/main/java/com/drmangotea/tfmg/base/blocks/TFMGDirectionalBlock.java
new file mode 100644
index 00000000..43269781
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/blocks/TFMGDirectionalBlock.java
@@ -0,0 +1,32 @@
+package com.drmangotea.tfmg.base.blocks;
+
+import com.drmangotea.tfmg.content.electricity.generators.large_generator.StatorBlock;
+import com.mojang.serialization.MapCodec;
+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.state.BlockState;
+import net.minecraft.world.level.block.state.StateDefinition;
+import org.checkerframework.checker.units.qual.C;
+
+public class TFMGDirectionalBlock extends DirectionalBlock {
+
+ public TFMGDirectionalBlock(Properties p_54120_) {
+ super(p_54120_);
+ }
+ public static final MapCodec CODEC = simpleCodec(TFMGDirectionalBlock::new);
+ @Override
+ protected MapCodec extends DirectionalBlock> codec() {
+ return CODEC;
+ }
+
+ @Override
+ protected void createBlockStateDefinition(StateDefinition.Builder builder) {
+ builder.add(FACING);
+ super.createBlockStateDefinition(builder);
+ }
+ public BlockState getStateForPlacement(BlockPlaceContext pContext) {
+ return this.defaultBlockState().setValue(FACING, pContext.getNearestLookingDirection().getOpposite());
+ }
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/blocks/TFMGHorizontalDirectionalBlock.java b/src/main/java/com/drmangotea/tfmg/base/blocks/TFMGHorizontalDirectionalBlock.java
new file mode 100644
index 00000000..a1db6132
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/blocks/TFMGHorizontalDirectionalBlock.java
@@ -0,0 +1,29 @@
+package com.drmangotea.tfmg.base.blocks;
+
+import com.mojang.serialization.MapCodec;
+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 static final MapCodec CODEC = simpleCodec(TFMGHorizontalDirectionalBlock::new);
+ public TFMGHorizontalDirectionalBlock(Properties p_54120_) {
+ super(p_54120_);
+ }
+
+ @Override
+ protected MapCodec extends HorizontalDirectionalBlock> codec() {
+ return CODEC;
+ }
+
+ @Override
+ protected void createBlockStateDefinition(StateDefinition.Builder builder) {
+ builder.add(FACING);
+ super.createBlockStateDefinition(builder);
+ }
+ public BlockState getStateForPlacement(BlockPlaceContext pContext) {
+ return this.defaultBlockState().setValue(FACING, pContext.getHorizontalDirection().getOpposite());
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/blocks/TFMGVanillaBlockStates.java b/src/main/java/com/drmangotea/tfmg/base/blocks/TFMGVanillaBlockStates.java
new file mode 100644
index 00000000..2790e922
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/blocks/TFMGVanillaBlockStates.java
@@ -0,0 +1,64 @@
+package com.drmangotea.tfmg.base.blocks;
+
+import com.drmangotea.tfmg.TFMG;
+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.neoforged.neoforge.client.model.generators.ModelFile;
+
+public class TFMGVanillaBlockStates {
+
+
+ //WALL
+ public static void generateWallBlockState(DataGenContext ctx, RegistrateBlockstateProvider prov,
+ String name) {
+ prov.wallBlock(ctx.get(), name, TFMG.asResource("block/" + name));
+ }
+
+ public static ItemBuilder> transformWallItem(
+ ItemBuilder> builder, String name) {
+ builder.model((c, p) -> p.wallInventory(c.getName(), TFMG.asResource("block/" + name)));
+ return builder;
+ }
+
+ //STAIR
+ public static void generateStairBlockState(DataGenContext ctx, RegistrateBlockstateProvider prov,
+ String name) {
+ prov.stairsBlock(ctx.get(), name, TFMG.asResource("block/" + name));
+ }
+
+ public static ItemBuilder> transformStairItem(
+ ItemBuilder> builder, String variantName) {
+ return builder;
+ }
+
+ //SLAB
+
+ public static void generateSlabBlockState(DataGenContext 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> transformSlabItem(
+ ItemBuilder> builder, String variantName) {
+ return builder;
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/blocks/WallMountBlock.java b/src/main/java/com/drmangotea/tfmg/base/blocks/WallMountBlock.java
new file mode 100644
index 00000000..506efd1d
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/blocks/WallMountBlock.java
@@ -0,0 +1,43 @@
+package com.drmangotea.tfmg.base.blocks;
+
+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 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;
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/events/TFMGClientEvents.java b/src/main/java/com/drmangotea/tfmg/base/events/TFMGClientEvents.java
new file mode 100644
index 00000000..c6302565
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/events/TFMGClientEvents.java
@@ -0,0 +1,58 @@
+package com.drmangotea.tfmg.base.events;
+
+import com.drmangotea.tfmg.TFMG;
+import com.drmangotea.tfmg.content.electricity.measurement.MultimeterOverlayRenderer;
+import com.drmangotea.tfmg.content.engines.engine_controller.EngineControllerClientHandler;
+import net.minecraft.client.Minecraft;
+import net.minecraft.world.entity.player.Player;
+import net.neoforged.api.distmarker.Dist;
+import net.neoforged.bus.api.SubscribeEvent;
+import net.neoforged.fml.common.EventBusSubscriber;
+import net.neoforged.neoforge.client.event.ClientTickEvent;
+import net.neoforged.neoforge.client.event.RegisterGuiLayersEvent;
+import net.neoforged.neoforge.client.gui.VanillaGuiLayers;
+import net.neoforged.neoforge.event.entity.player.PlayerEvent;
+
+
+@EventBusSubscriber(Dist.CLIENT)
+public class TFMGClientEvents {
+
+
+ @SubscribeEvent
+ public static void onTickPre(ClientTickEvent.Pre event) {
+ onTick( true);
+ }
+
+ @SubscribeEvent
+ public static void onTickPost(ClientTickEvent.Post event) {
+ onTick(false);
+ }
+
+
+ public static void onTick(boolean isPreEvent) {
+ if (!isGameActive())
+ return;
+
+
+ if (isPreEvent) {
+ EngineControllerClientHandler.tick();
+
+ }
+ }
+ @SubscribeEvent
+ public static void PlayerLoggedOut(PlayerEvent.PlayerLoggedOutEvent event) {
+ Player player = event.getEntity();
+
+ if (player != null)
+ player.getPersistentData().remove("IsUsingEngineController");
+ }
+
+ //@SubscribeEvent
+ public static void registerGuiOverlays(RegisterGuiLayersEvent event) {
+ event.registerAbove(VanillaGuiLayers.HOTBAR, TFMG.asResource("multimeter_info"), MultimeterOverlayRenderer.OVERLAY);
+
+ }
+ protected static boolean isGameActive() {
+ return !(Minecraft.getInstance().level == null || Minecraft.getInstance().player == null);
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/events/TFMGCommonEvents.java b/src/main/java/com/drmangotea/tfmg/base/events/TFMGCommonEvents.java
new file mode 100644
index 00000000..020dd2ea
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/events/TFMGCommonEvents.java
@@ -0,0 +1,110 @@
+package com.drmangotea.tfmg.base.events;
+
+
+import com.drmangotea.tfmg.TFMG;
+import com.drmangotea.tfmg.content.decoration.tanks.TFMGFluidTankBlockEntity;
+import com.drmangotea.tfmg.content.decoration.tanks.steel.SteelTankBlockEntity;
+import com.drmangotea.tfmg.content.electricity.base.IElectric;
+import com.drmangotea.tfmg.content.electricity.storage.AccumulatorBlockEntity;
+import com.drmangotea.tfmg.content.electricity.utilities.converter.ConverterBlockEntity;
+import com.drmangotea.tfmg.content.electricity.utilities.polarizer.PolarizerBlockEntity;
+import com.drmangotea.tfmg.content.engines.base.AbstractEngineBlockEntity;
+import com.drmangotea.tfmg.content.engines.fuels.EngineFuelTypeManager;
+import com.drmangotea.tfmg.content.engines.types.large_engine.LargeEngineBlockEntity;
+import com.drmangotea.tfmg.content.machinery.metallurgy.blast_furnace.BlastFurnaceHatchBlockEntity;
+import com.drmangotea.tfmg.content.machinery.metallurgy.blast_furnace.BlastFurnaceOutputBlockEntity;
+import com.drmangotea.tfmg.content.machinery.metallurgy.blast_stove.BlastStoveBlockEntity;
+import com.drmangotea.tfmg.content.machinery.metallurgy.casting_basin.CastingBasinBlockEntity;
+import com.drmangotea.tfmg.content.machinery.metallurgy.coke_oven.CokeOvenBlockEntity;
+import com.drmangotea.tfmg.content.machinery.misc.air_intake.AirIntakeBlockEntity;
+import com.drmangotea.tfmg.content.machinery.misc.concrete_hose.ConcreteHoseBlockEntity;
+import com.drmangotea.tfmg.content.machinery.misc.exhaust.ExhaustBlockEntity;
+import com.drmangotea.tfmg.content.machinery.misc.firebox.FireboxBlockEntity;
+import com.drmangotea.tfmg.content.machinery.misc.flarestack.FlarestackBlockEntity;
+import com.drmangotea.tfmg.content.machinery.misc.smokestack.SmokestackBlockEntity;
+import com.drmangotea.tfmg.content.machinery.oil_processing.distillation_tower.controller.DistillationControllerBlockEntity;
+import com.drmangotea.tfmg.content.machinery.oil_processing.distillation_tower.output.DistillationOutputBlockEntity;
+import com.drmangotea.tfmg.content.machinery.oil_processing.pumpjack.pumpjack.base.PumpjackBaseBlockEntity;
+import com.drmangotea.tfmg.content.machinery.vat.base.VatBlockEntity;
+import com.drmangotea.tfmg.registry.TFMGDataComponents;
+import com.drmangotea.tfmg.registry.TFMGItems;
+import net.minecraft.world.InteractionHand;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.level.LevelAccessor;
+import net.neoforged.bus.api.SubscribeEvent;
+import net.neoforged.fml.common.EventBusSubscriber;
+import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent;
+import net.neoforged.neoforge.event.AddReloadListenerEvent;
+import net.neoforged.neoforge.event.level.BlockEvent;
+import net.neoforged.neoforge.event.level.LevelEvent;
+
+
+@EventBusSubscriber
+public class TFMGCommonEvents {
+
+
+
+ @SubscribeEvent
+ public static void onUnloadWorld(LevelEvent.Unload event) {
+ LevelAccessor world = event.getLevel();
+ TFMG.NETWORK_MANAGER.onUnloadWorld(world);
+
+
+ }
+
+ @SubscribeEvent
+ public static void onLoadWorld(LevelEvent.Load event) {
+ LevelAccessor world = event.getLevel();
+ TFMG.NETWORK_MANAGER.onLoadWorld(world);
+ TFMG.DEPOSITS.levelLoaded(world);
+ }
+
+ @SubscribeEvent
+ public static void onBlockPlaced(BlockEvent.EntityPlaceEvent event) {
+
+ if (event.getEntity() instanceof Player player) {
+ if (player.getItemInHand(InteractionHand.OFF_HAND).is(TFMGItems.CONFIGURATION_WRENCH.get()) && event.getLevel().getBlockEntity(event.getPos()) instanceof IElectric be && be.canBeInGroups()) {
+
+ be.getData().group.id = player.getItemInHand(InteractionHand.OFF_HAND).get(TFMGDataComponents.CONFIGURATION_WRENCH_NUMBER);
+ be.updateNextTick();
+ be.sendStuff();
+
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public static void addReloadListeners(AddReloadListenerEvent event) {
+ event.addListener(EngineFuelTypeManager.ReloadListener.INSTANCE);
+ }
+ @EventBusSubscriber(bus = EventBusSubscriber.Bus.MOD)
+ public static class ModBusEvents {
+ @net.neoforged.bus.api.SubscribeEvent
+ public static void registerCapabilities(RegisterCapabilitiesEvent event) {
+
+ AbstractEngineBlockEntity.registerCapabilities(event);
+ DistillationOutputBlockEntity.registerCapabilities(event);
+ ConcreteHoseBlockEntity.registerCapabilities(event);
+ PumpjackBaseBlockEntity.registerCapabilities(event);
+ PolarizerBlockEntity.registerCapabilities(event);
+ LargeEngineBlockEntity.registerCapabilities(event);
+ ConverterBlockEntity.registerCapabilities(event);
+ CastingBasinBlockEntity.registerCapabilities(event);
+ FireboxBlockEntity.registerCapabilities(event);
+ DistillationControllerBlockEntity.registerCapabilities(event);
+ AccumulatorBlockEntity.registerCapabilities(event);
+ SteelTankBlockEntity.registerCapabilities(event);
+ TFMGFluidTankBlockEntity.registerCapabilities(event);
+ VatBlockEntity.registerCapabilities(event);
+ BlastStoveBlockEntity.registerCapabilities(event);
+ SmokestackBlockEntity.registerCapabilities(event);
+ ExhaustBlockEntity.registerCapabilities(event);
+ BlastFurnaceHatchBlockEntity.registerCapabilities(event);
+ FlarestackBlockEntity.registerCapabilities(event);
+ BlastFurnaceOutputBlockEntity.registerCapabilities(event);
+ CokeOvenBlockEntity.registerCapabilities(event);
+ AirIntakeBlockEntity.registerCapabilities(event);
+ }
+ }
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/fluid/AcidFluidType.java b/src/main/java/com/drmangotea/tfmg/base/fluid/AcidFluidType.java
new file mode 100644
index 00000000..7cd4ada4
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/fluid/AcidFluidType.java
@@ -0,0 +1,73 @@
+package com.drmangotea.tfmg.base.fluid;
+
+
+import com.drmangotea.tfmg.datagen.TFMGDamageSources;
+import com.drmangotea.tfmg.datagen.TFMGDamageTypes;
+import com.simibubi.create.AllFluids;
+import com.simibubi.create.Create;
+import com.tterrag.registrate.builders.FluidBuilder;
+import net.createmod.catnip.theme.Color;
+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.neoforged.neoforge.fluids.FluidStack;
+import org.joml.Vector3f;
+
+import java.awt.*;
+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 fogDistance;
+
+ public static FluidBuilder.FluidTypeFactory create(int fogColor, Supplier 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(TFMGDamageSources.acid(entity.level()),2);
+
+ return false;
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/drmangotea/tfmg/base/fluid/AsphaltFluid.java b/src/main/java/com/drmangotea/tfmg/base/fluid/AsphaltFluid.java
new file mode 100644
index 00000000..3af3fc27
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/fluid/AsphaltFluid.java
@@ -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.neoforged.neoforge.fluids.BaseFlowingFluid;
+
+public class AsphaltFluid extends BaseFlowingFluid {
+
+
+ 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 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;
+ }
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/fluid/ConcreteFluid.java b/src/main/java/com/drmangotea/tfmg/base/fluid/ConcreteFluid.java
new file mode 100644
index 00000000..60a322ce
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/fluid/ConcreteFluid.java
@@ -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.neoforged.neoforge.fluids.BaseFlowingFluid;
+
+import static com.drmangotea.tfmg.content.decoration.concrete.ConcreteloggedBlock.CONCRETELOGGED;
+
+public class ConcreteFluid extends BaseFlowingFluid {
+ 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 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;
+ }
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/fluid/GasFluidType.java b/src/main/java/com/drmangotea/tfmg/base/fluid/GasFluidType.java
new file mode 100644
index 00000000..a7cefefb
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/fluid/GasFluidType.java
@@ -0,0 +1,94 @@
+package com.drmangotea.tfmg.base.fluid;
+
+
+import com.drmangotea.tfmg.registry.TFMGFluids;
+import com.mojang.blaze3d.shaders.FogShape;
+import com.mojang.blaze3d.systems.RenderSystem;
+import com.simibubi.create.AllFluids;
+import com.tterrag.registrate.builders.FluidBuilder;
+import net.minecraft.client.Camera;
+import net.minecraft.client.multiplayer.ClientLevel;
+import net.minecraft.client.renderer.FogRenderer;
+import net.minecraft.core.BlockPos;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.level.BlockAndTintGetter;
+import net.minecraft.world.level.material.FluidState;
+import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions;
+import net.neoforged.neoforge.fluids.FluidStack;
+import org.jetbrains.annotations.NotNull;
+import org.joml.Vector3f;
+
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+import static com.drmangotea.tfmg.registry.TFMGFluids.getGasTexture;
+
+public class GasFluidType extends TFMGFluids.SolidRenderedPlaceableFluidType {
+
+ final int color;
+
+
+
+ public GasFluidType(Properties properties, ResourceLocation stillTexture, ResourceLocation flowingTexture, int color) {
+ super(properties, stillTexture, flowingTexture);
+ this.color = color;
+ }
+
+ public static FluidBuilder.FluidTypeFactory create(int color) {
+ return (p, s, f) -> {
+ GasFluidType fluidType = new GasFluidType(p,s,f,color);
+ return fluidType;
+ };
+ }
+ @Override
+ public void initializeClient(Consumer consumer) {
+ consumer.accept(new IClientFluidTypeExtensions() {
+
+ @Override
+ public ResourceLocation getStillTexture() {
+ return getGasTexture();
+ }
+
+ @Override
+ public ResourceLocation getFlowingTexture() {
+ return getGasTexture();
+ }
+
+ @Override
+ public int getTintColor(FluidStack stack) {
+ return color;
+ }
+
+ @Override
+ public int getTintColor(FluidState state, BlockAndTintGetter getter, BlockPos pos) {
+ return 0xff99f22f;
+ }
+
+ @Override
+ public @NotNull Vector3f modifyFogColor(Camera camera, float partialTick, ClientLevel level,
+ int renderDistance, float darkenWorldAmount, Vector3f fluidFogColor) {
+ Vector3f customFogColor = GasFluidType.this.getCustomFogColor();
+ return customFogColor == null ? fluidFogColor : customFogColor;
+ }
+
+ @Override
+ public void modifyFogRender(Camera camera, FogRenderer.FogMode mode, float renderDistance, float partialTick,
+ float nearDistance, float farDistance, FogShape shape) {
+ float modifier = GasFluidType.this.getFogDistanceModifier();
+ float baseWaterFog = 96.0f;
+ if (modifier != 1f) {
+ RenderSystem.setShaderFogShape(FogShape.CYLINDER);
+ RenderSystem.setShaderFogStart(-8);
+ RenderSystem.setShaderFogEnd(baseWaterFog * modifier);
+ }
+ }
+
+ });
+ }
+
+
+ @Override
+ public int getDensity() {
+ return -1;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/drmangotea/tfmg/base/fluid/HotFluidType.java b/src/main/java/com/drmangotea/tfmg/base/fluid/HotFluidType.java
new file mode 100644
index 00000000..e6bdf6d9
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/fluid/HotFluidType.java
@@ -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.tterrag.registrate.builders.FluidBuilder;
+import net.createmod.catnip.theme.Color;
+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.neoforged.neoforge.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 fogDistance;
+
+ public static FluidBuilder.FluidTypeFactory create(int fogColor, Supplier 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.setRemainingFireTicks(10);
+
+ if(Create.RANDOM.nextInt(30)==27)
+ entity.lavaHurt();
+
+ return false;
+ }
+
+ public boolean canExtinguish(Entity entity)
+ {
+ return false;
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/fluid/TFMGFluidInteractions.java b/src/main/java/com/drmangotea/tfmg/base/fluid/TFMGFluidInteractions.java
new file mode 100644
index 00000000..a1f038ee
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/fluid/TFMGFluidInteractions.java
@@ -0,0 +1,97 @@
+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.neoforged.neoforge.fluids.FluidInteractionRegistry;
+
+
+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();
+ // }
+ // }
+ // ));
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/palettes/TFMGPaletteBlockPartial.java b/src/main/java/com/drmangotea/tfmg/base/palettes/TFMGPaletteBlockPartial.java
new file mode 100644
index 00000000..bd610c7e
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/palettes/TFMGPaletteBlockPartial.java
@@ -0,0 +1,265 @@
+package com.drmangotea.tfmg.base.palettes;
+
+
+import com.drmangotea.tfmg.TFMG;
+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.CreateLang;
+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.neoforged.neoforge.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 {
+
+ public static final TFMGPaletteBlockPartial STAIR = new Stairs();
+ public static final TFMGPaletteBlockPartial SLAB = new Slab(false);
+ public static final TFMGPaletteBlockPartial UNIQUE_SLAB = new Slab(true);
+ public static final TFMGPaletteBlockPartial 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 create(String variantName, TFMGPaletteBlockPattern pattern,
+ BlockEntry extends Block> block, TFMGPaletteStoneTypes variant) {
+ String patternName = CreateLang.nonPluralId(pattern.createName(variantName));
+ String blockName = patternName + "_" + this.name;
+
+ BlockBuilder 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> 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 transformBlock(BlockBuilder builder,
+ String variantName, TFMGPaletteBlockPattern pattern) {
+ getBlockTags().forEach(builder::tag);
+ return builder.transform(pickaxeOnly());
+ }
+ protected ItemBuilder> transformItem(
+ ItemBuilder> builder, String variantName,
+ TFMGPaletteBlockPattern pattern) {
+ getItemTags().forEach(builder::tag);
+ return builder;
+ }
+ protected boolean canRecycle() {
+ return true;
+ }
+ protected abstract Iterable> getBlockTags();
+ protected abstract Iterable> getItemTags();
+ protected abstract B createBlock(Supplier extends Block> block);
+ protected abstract void createRecipes(TFMGPaletteStoneTypes type, BlockEntry extends Block> patternBlock,
+ DataGenContext c, RegistrateRecipeProvider p);
+ protected abstract void generateBlockState(DataGenContext ctx, RegistrateBlockstateProvider prov, String variantName, TFMGPaletteBlockPattern pattern, Supplier extends Block> block);
+ private static class Stairs extends TFMGPaletteBlockPartial {
+ public Stairs() {
+ super("stairs");
+ }
+
+ @Override
+ protected StairBlock createBlock(Supplier extends Block> block) {
+ return new StairBlock(block.get()
+ .defaultBlockState(), Properties.ofFullCopy(block.get()));
+ }
+
+ @Override
+ protected void generateBlockState(DataGenContext ctx, RegistrateBlockstateProvider prov,
+ String variantName, TFMGPaletteBlockPattern pattern, Supplier extends Block> block) {
+ prov.stairsBlock(ctx.get(), getTexture(variantName, pattern, 0));
+ }
+ @Override
+ protected Iterable> getBlockTags() {
+ return Arrays.asList(BlockTags.STAIRS);
+ }
+
+ @Override
+ protected Iterable> getItemTags() {
+ return Arrays.asList(ItemTags.STAIRS);
+ }
+
+ @Override
+ protected void createRecipes(TFMGPaletteStoneTypes type, BlockEntry extends Block> patternBlock,
+ DataGenContext 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 {
+
+ private boolean customSide;
+
+ public Slab(boolean customSide) {
+ super("slab");
+ this.customSide = customSide;
+ }
+
+ @Override
+ protected SlabBlock createBlock(Supplier extends Block> block) {
+ return new SlabBlock(Properties.ofFullCopy(block.get()));
+ }
+
+ @Override
+ protected boolean canRecycle() {
+ return false;
+ }
+
+ @Override
+ protected void generateBlockState(DataGenContext 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> getBlockTags() {
+ return Arrays.asList(BlockTags.SLABS);
+ }
+
+ @Override
+ protected Iterable> getItemTags() {
+ return Arrays.asList(ItemTags.SLABS);
+ }
+
+ @Override
+ protected void createRecipes(TFMGPaletteStoneTypes type, BlockEntry extends Block> patternBlock,
+ DataGenContext 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.toVanilla())
+ .requires(ingredient.toVanilla())
+ .unlockedBy("has_" + c.getName(), ingredient.getCriterion(p))
+ .save(p, TFMG.MOD_ID + ":" + c.getName() + "_recycling");
+ }
+
+ @Override
+ protected BlockBuilder transformBlock(
+ BlockBuilder 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 {
+
+ public Wall() {
+ super("wall");
+ }
+
+ @Override
+ protected WallBlock createBlock(Supplier extends Block> block) {
+ return new WallBlock(Properties.ofFullCopy(block.get()));
+ }
+
+ @Override
+ protected ItemBuilder> transformItem(
+ ItemBuilder> 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 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> getBlockTags() {
+ return Arrays.asList(BlockTags.WALLS);
+ }
+
+ @Override
+ protected Iterable> getItemTags() {
+ return Arrays.asList(ItemTags.WALLS);
+ }
+
+ @Override
+ protected void createRecipes(TFMGPaletteStoneTypes type, BlockEntry extends Block> patternBlock,
+ DataGenContext 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.toVanilla())
+ .unlockedBy("has_" + p.safeName(ingredient), ingredient.getCriterion(p))
+ .save(p, p.safeId(c.get()));
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/drmangotea/tfmg/base/palettes/TFMGPaletteBlockPattern.java b/src/main/java/com/drmangotea/tfmg/base/palettes/TFMGPaletteBlockPattern.java
new file mode 100644
index 00000000..0614522c
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/palettes/TFMGPaletteBlockPattern.java
@@ -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.neoforged.api.distmarker.Dist;
+import net.neoforged.api.distmarker.OnlyIn;
+import net.neoforged.neoforge.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[] blockTags;
+ private TagKey
- [] itemTags;
+ private Optional> ctFactory;
+ private IPatternBlockStateGenerator blockStateGenerator;
+ private NonNullFunction blockFactory;
+ private NonNullFunction, NonNullBiConsumer, 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[] getBlockTags() {
+ return blockTags;
+ }
+
+ public TagKey
- [] getItemTags() {
+ return itemTags;
+ }
+
+ public NonNullFunction getBlockFactory() {
+ return blockFactory;
+ }
+
+ public TFMGPaletteBlockPartial extends Block>[] getPartials() {
+ return partials;
+ }
+
+ public String getTexture(int index) {
+ return textures[index];
+ }
+
+ public void addRecipes(NonNullSupplier baseBlock, DataGenContext c,
+ RegistrateRecipeProvider p) {
+ additionalRecipes.apply(baseBlock)
+ .accept(c, p);
+ }
+
+ public Optional> 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 blockFactory) {
+ this.blockFactory = blockFactory;
+ return this;
+ }
+
+ private TFMGPaletteBlockPattern connectedTextures(Function 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,
+ ResourceLocation.fromNamespaceAndPath(resLocTarget.getNamespace(), resLocTarget.getPath() + "_connected"));
+ }
+
+ @FunctionalInterface
+ static interface IPatternBlockStateGenerator
+ extends Function> {
+ }
+
+ @FunctionalInterface
+ static interface IBlockStateProvider
+ extends NonNullBiConsumer, 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 srcFactory;
+ private Function targetFactory;
+
+ private CTs(CTType type, Function factory) {
+ this(type, factory, factory);
+ }
+
+ private CTs(CTType type, Function srcFactory,
+ Function targetFactory) {
+ this.type = type;
+ this.srcFactory = srcFactory;
+ this.targetFactory = targetFactory;
+ }
+
+ }
+
+}
+
diff --git a/src/main/java/com/drmangotea/tfmg/base/palettes/TFMGPalettesVariantEntry.java b/src/main/java/com/drmangotea/tfmg/base/palettes/TFMGPalettesVariantEntry.java
new file mode 100644
index 00000000..9dfd481b
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/palettes/TFMGPalettesVariantEntry.java
@@ -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>>)'")
+public class TFMGPalettesVariantEntry {
+
+ public final ImmutableList> registeredBlocks;
+ public final ImmutableList> 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>>)'")
+ public TFMGPalettesVariantEntry(String name, TFMGPaletteStoneTypes paletteStoneVariants) {
+ ImmutableList.Builder> registeredBlocks = ImmutableList.builder();
+ ImmutableList.Builder> registeredPartials = ImmutableList.builder();
+ NonNullSupplier 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> itemBuilder =
+ builder.item();
+
+ TagKey[] blockTags = pattern.getBlockTags();
+ if (blockTags != null)
+ builder.tag(blockTags);
+ TagKey
- [] 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();
+ }
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/spark/BlueSpark.java b/src/main/java/com/drmangotea/tfmg/base/spark/BlueSpark.java
new file mode 100644
index 00000000..679309b8
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/spark/BlueSpark.java
@@ -0,0 +1,120 @@
+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.network.syncher.SynchedEntityData;
+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 double getDefaultGravity() {
+ return 0.02f;
+ }
+
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+
+ }
+
+ 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)) {
+ 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.setRemainingFireTicks(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 entityBuilder = (EntityType.Builder) builder;
+ return entityBuilder.sized(.25f, .25f);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/drmangotea/tfmg/base/spark/BlueSparkRenderer.java b/src/main/java/com/drmangotea/tfmg/base/spark/BlueSparkRenderer.java
new file mode 100644
index 00000000..21e1921a
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/spark/BlueSparkRenderer.java
@@ -0,0 +1,58 @@
+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.neoforged.api.distmarker.Dist;
+import net.neoforged.api.distmarker.OnlyIn;
+import org.joml.Matrix3f;
+import org.joml.Matrix4f;
+
+@OnlyIn(Dist.CLIENT)
+public class BlueSparkRenderer extends EntityRenderer {
+ 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_.addVertex(p_114091_, p_114094_ - 0.5F, (float)p_114095_ - 0.25F, 0.0F).setColor(255, 255, 255, 255).setUv((float)p_114096_, (float)p_114097_).setOverlay(OverlayTexture.NO_OVERLAY).setUv2(p_114093_,p_114093_).setNormal( 0.0F, 1.0F, 0.0F);
+ }
+
+ public ResourceLocation getTextureLocation(BlueSpark p_114078_) {
+ return TEXTURE_LOCATION;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/drmangotea/tfmg/base/spark/ElectricSparkParticle.java b/src/main/java/com/drmangotea/tfmg/base/spark/ElectricSparkParticle.java
new file mode 100644
index 00000000..c79db1d4
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/spark/ElectricSparkParticle.java
@@ -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 {
+ @Override
+ public IBasicParticleFactory 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();
+ }
+ }
+
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/base/spark/GreenSpark.java b/src/main/java/com/drmangotea/tfmg/base/spark/GreenSpark.java
new file mode 100644
index 00000000..a6e795e6
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/spark/GreenSpark.java
@@ -0,0 +1,108 @@
+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.network.syncher.SynchedEntityData;
+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 double getDefaultGravity() {
+ return 0.02f;
+ }
+
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+
+ }
+
+ 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)) {
+ 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.setRemainingFireTicks(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 entityBuilder = (EntityType.Builder) builder;
+ return entityBuilder.sized(.25f, .25f);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/drmangotea/tfmg/base/spark/GreenSparkRenderer.java b/src/main/java/com/drmangotea/tfmg/base/spark/GreenSparkRenderer.java
new file mode 100644
index 00000000..4e375855
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/spark/GreenSparkRenderer.java
@@ -0,0 +1,58 @@
+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.neoforged.api.distmarker.Dist;
+import net.neoforged.api.distmarker.OnlyIn;
+import org.joml.Matrix3f;
+import org.joml.Matrix4f;
+
+@OnlyIn(Dist.CLIENT)
+public class GreenSparkRenderer extends EntityRenderer {
+ 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_.addVertex(p_114091_, p_114094_ - 0.5F, (float)p_114095_ - 0.25F, 0.0F).setColor(255, 255, 255, 255).setUv((float)p_114096_, (float)p_114097_).setOverlay(OverlayTexture.NO_OVERLAY).setUv2(p_114093_,p_114093_).setNormal( 0.0F, 1.0F, 0.0F);
+ }
+
+ public ResourceLocation getTextureLocation(GreenSpark p_114078_) {
+ return TEXTURE_LOCATION;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/drmangotea/tfmg/base/spark/Spark.java b/src/main/java/com/drmangotea/tfmg/base/spark/Spark.java
new file mode 100644
index 00000000..01f36ea5
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/spark/Spark.java
@@ -0,0 +1,105 @@
+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.network.syncher.SynchedEntityData;
+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 double getDefaultGravity() {
+ return 0.02f;
+ }
+
+ @Override
+ protected void defineSynchedData(SynchedEntityData.Builder builder) {
+
+ }
+
+ 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) ) {
+ 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.setRemainingFireTicks(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 entityBuilder = (EntityType.Builder) builder;
+ return entityBuilder.sized(.25f, .25f);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/drmangotea/tfmg/base/spark/SparkRenderer.java b/src/main/java/com/drmangotea/tfmg/base/spark/SparkRenderer.java
new file mode 100644
index 00000000..48c46ffa
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/base/spark/SparkRenderer.java
@@ -0,0 +1,54 @@
+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.neoforged.api.distmarker.Dist;
+import net.neoforged.api.distmarker.OnlyIn;
+import org.joml.Matrix3f;
+import org.joml.Matrix4f;
+
+@OnlyIn(Dist.CLIENT)
+public class SparkRenderer extends EntityRenderer {
+ private static final ResourceLocation TEXTURE_LOCATION = ResourceLocation.withDefaultNamespace("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_.addVertex(p_114091_, p_114094_ - 0.5F, (float)p_114095_ - 0.25F, 0.0F).setColor(255, 255, 255, 255).setUv((float)p_114096_, (float)p_114097_).setOverlay(OverlayTexture.NO_OVERLAY).setUv2(p_114093_,p_114093_).setNormal( 0.0F, 1.0F, 0.0F);
+ }
+ public ResourceLocation getTextureLocation(Spark p_114078_) {
+ return TEXTURE_LOCATION;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/drmangotea/tfmg/config/DepositConfig.java b/src/main/java/com/drmangotea/tfmg/config/DepositConfig.java
new file mode 100644
index 00000000..cb1020ad
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/config/DepositConfig.java
@@ -0,0 +1,19 @@
+package com.drmangotea.tfmg.config;
+
+
+import net.createmod.catnip.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.";
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/config/MachineConfig.java b/src/main/java/com/drmangotea/tfmg/config/MachineConfig.java
new file mode 100644
index 00000000..914a49ea
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/config/MachineConfig.java
@@ -0,0 +1,80 @@
+package com.drmangotea.tfmg.config;
+
+
+import net.createmod.catnip.config.ConfigBase;
+
+public class MachineConfig extends ConfigBase {
+
+
+ public final ConfigInt electricMotorMinimumPower = i(250, 1, "electricMotorMinimumPower", Comments.electricMotorMinimumPower);
+ public final ConfigInt electricMotorMinimumVoltage = i(150, 1, "electricMotorMinimumVoltage", Comments.electricMotorMinimumVoltage);
+ public final ConfigFloat electricMotorInternalResistance = f(100, 0, "electricMotorInternalResistance", Comments.electricMotorInternalResistance);
+ public final ConfigInt cokeOvenMaxSize = i(5, 1, "cokeOvenMaxSize", Comments.cokeOvenMaxSize);
+ public final ConfigFloat FEtoWattTickConversionRate = f(1, 0, "FEtoWattTickConversionRate", Comments.FEtoWattTickConversionRate);
+
+ 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);
+
+
+ public final ConfigGroup accumulator = group(1, "accumulator", "Accumulator");
+ 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 ConfigGroup firebox = group(1, "firebox", "Firebox");
+ public final ConfigBool fireboxExhaustRequirement = b(true, "fireboxExhaustRequirement", Comments.fireboxExhaustRequirement);
+ public final ConfigInt fireboxFuelConsumption = i(100, 1, "fireboxFuelConsumption", Comments.fireboxFuelConsumption);
+
+ public final ConfigGroup engines = group(1, "engines", "Engines");
+ public final ConfigFloat engineLoudness = f(1,0, "engineLoudness", Comments.engineLoudness);
+
+
+ public final ConfigGroup generators = group(1, "generators", "Generators");
+ public final ConfigFloat largeGeneratorModifier = f(4, 0, "largeGeneratorModifier", Comments.largeGenerator);
+ public final ConfigFloat largeGeneratorMinSpeed = f(70, 0, "largeGeneratorMinSpeed", Comments.largeGeneratorMinSpeed);
+ //
+ public final ConfigFloat generatorModifier = f(1.4f, 0, "GeneratorModifier", Comments.generator);
+ public final ConfigFloat generatorMinSpeed = f(40, 0, "generatorMinSpeed", Comments.generatorMinSpeed);
+
+ public final ConfigGroup blast_furnace = group(1, "blast_furnace", "Blast Furnace");
+ 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);
+
+ @Override
+ public String getName() {
+ return "machines";
+ }
+
+
+ private static class Comments {
+ static String largeGenerator = "Determines how powerful the large generator is.";
+ static String generator = "Determines how powerful the generator is.";
+ static String largeGeneratorMinSpeed = "Changes the lowest speed the large generator can work on.";
+ static String generatorMinSpeed = "Changes the lowest speed the generator can work on.";
+ 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 electricMotorInternalResistance = "Sets the internal resistance of the electric motor.";
+ 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.";
+ static String engineLoudness = "Changes the volume of engines.";
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/config/TFMGCommonConfig.java b/src/main/java/com/drmangotea/tfmg/config/TFMGCommonConfig.java
new file mode 100644
index 00000000..456e5742
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/config/TFMGCommonConfig.java
@@ -0,0 +1,16 @@
+package com.drmangotea.tfmg.config;
+
+
+
+public class TFMGCommonConfig extends net.createmod.catnip.config.ConfigBase {
+
+ public final MachineConfig machines = nested(0, MachineConfig::new, "Config options for TFMG's machinery");
+ public final DepositConfig worldgen = nested(1, DepositConfig::new, "Worldgen Settings");
+
+ @Override
+ public String getName() {
+ return "common";
+ }
+
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/config/TFMGConfigs.java b/src/main/java/com/drmangotea/tfmg/config/TFMGConfigs.java
new file mode 100644
index 00000000..747977f3
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/config/TFMGConfigs.java
@@ -0,0 +1,81 @@
+package com.drmangotea.tfmg.config;
+
+import com.simibubi.create.api.stress.BlockStressValues;
+import com.simibubi.create.infrastructure.config.CCommon;
+
+import net.createmod.catnip.config.ConfigBase;
+import net.neoforged.bus.api.SubscribeEvent;
+import net.neoforged.fml.ModContainer;
+import net.neoforged.fml.ModLoadingContext;
+import net.neoforged.fml.common.EventBusSubscriber;
+import net.neoforged.fml.config.ModConfig;
+import net.neoforged.fml.event.config.ModConfigEvent;
+import net.neoforged.neoforge.common.ModConfigSpec;
+import org.apache.commons.lang3.tuple.Pair;
+
+import java.util.EnumMap;
+import java.util.Map;
+import java.util.function.Supplier;
+
+@EventBusSubscriber(bus = EventBusSubscriber.Bus.MOD)
+public class TFMGConfigs {
+
+ private static final Map 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 register(Supplier factory, ModConfig.Type side) {
+ Pair specPair = new ModConfigSpec.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, ModContainer container) {
+ server = register(TFMGServerConfig::new, ModConfig.Type.SERVER);
+ common = register(TFMGCommonConfig::new, ModConfig.Type.COMMON);
+ for (Map.Entry pair : CONFIGS.entrySet())
+ container.registerConfig(pair.getKey(), pair.getValue().specification);
+ TFMGStress stress = TFMGConfigs.server().stressValues;
+ BlockStressValues.IMPACTS.registerProvider(stress::getImpact);
+ BlockStressValues.CAPACITIES.registerProvider(stress::getCapacity);
+ }
+
+ @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();
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/drmangotea/tfmg/config/TFMGServerConfig.java b/src/main/java/com/drmangotea/tfmg/config/TFMGServerConfig.java
new file mode 100644
index 00000000..99a3ee77
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/config/TFMGServerConfig.java
@@ -0,0 +1,16 @@
+package com.drmangotea.tfmg.config;
+
+
+import net.createmod.catnip.config.ConfigBase;
+
+public class TFMGServerConfig extends ConfigBase {
+
+
+
+ public final TFMGStress stressValues = nested(0, TFMGStress::new, "Fine tune the kinetic stats of individual components");
+
+ @Override
+ public String getName() {
+ return "server";
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/config/TFMGStress.java b/src/main/java/com/drmangotea/tfmg/config/TFMGStress.java
new file mode 100644
index 00000000..af887321
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/config/TFMGStress.java
@@ -0,0 +1,101 @@
+package com.drmangotea.tfmg.config;
+
+
+import com.drmangotea.tfmg.TFMG;
+import com.tterrag.registrate.builders.BlockBuilder;
+import com.tterrag.registrate.util.nullness.NonNullUnaryOperator;
+import it.unimi.dsi.fastutil.objects.Object2DoubleMap;
+import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap;
+import net.createmod.catnip.config.ConfigBase;
+import net.createmod.catnip.platform.CatnipServices;
+import net.createmod.catnip.registry.RegisteredObjectsHelper;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.level.block.Block;
+
+import net.neoforged.neoforge.common.ModConfigSpec;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.DoubleSupplier;
+
+public class TFMGStress extends ConfigBase {
+ // bump this version to reset configured values.
+ private static final int VERSION = 2;
+
+ // IDs need to be used since configs load before registration
+
+ private static final Object2DoubleMap DEFAULT_IMPACTS = new Object2DoubleOpenHashMap<>();
+ private static final Object2DoubleMap DEFAULT_CAPACITIES = new Object2DoubleOpenHashMap<>();
+
+ protected final Map> capacities = new HashMap<>();
+ protected final Map> impacts = new HashMap<>();
+
+ @Override
+ public void registerAll(ModConfigSpec.Builder builder) {
+ builder.comment(".", Comments.su, Comments.impact)
+ .push("impact");
+ DEFAULT_IMPACTS.forEach((id, value) -> this.impacts.put(id, builder.define(id.getPath(), value)));
+ builder.pop();
+
+ builder.comment(".", Comments.su, Comments.capacity)
+ .push("capacity");
+ DEFAULT_CAPACITIES.forEach((id, value) -> this.capacities.put(id, builder.define(id.getPath(), value)));
+ builder.pop();
+ }
+
+ @Override
+ public String getName() {
+ return "stressValues.v" + VERSION;
+ }
+
+ @Nullable
+ public DoubleSupplier getImpact(Block block) {
+ ResourceLocation id = RegisteredObjectsHelper.getKeyOrThrow(block);
+ ModConfigSpec.ConfigValue value = this.impacts.get(id);
+ return value == null ? null : value::get;
+ }
+
+ @Nullable
+ public DoubleSupplier getCapacity(Block block) {
+ ResourceLocation id = RegisteredObjectsHelper.getKeyOrThrow(block);
+ ModConfigSpec.ConfigValue value = this.capacities.get(id);
+ return value == null ? null : value::get;
+ }
+
+ public static NonNullUnaryOperator> setNoImpact() {
+ return setImpact(0);
+ }
+
+ public static NonNullUnaryOperator> setImpact(double value) {
+ return builder -> {
+ assertFromCreate(builder);
+ ResourceLocation id = TFMG.asResource(builder.getName());
+ DEFAULT_IMPACTS.put(id, value);
+ return builder;
+ };
+ }
+
+ public static NonNullUnaryOperator> setCapacity(double value) {
+ return builder -> {
+ assertFromCreate(builder);
+ ResourceLocation id = TFMG.asResource(builder.getName());
+ DEFAULT_CAPACITIES.put(id, value);
+ return builder;
+ };
+ }
+
+ private static void assertFromCreate(BlockBuilder, ?> builder) {
+ if (!builder.getOwner().getModid().equals(TFMG.MOD_ID)) {
+ throw new IllegalStateException("Skibidi Sigma Error");
+ }
+ }
+
+ 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.";
+ }
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/FrameBlock.java b/src/main/java/com/drmangotea/tfmg/content/decoration/FrameBlock.java
new file mode 100644
index 00000000..8bdbc54e
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/FrameBlock.java
@@ -0,0 +1,47 @@
+package com.drmangotea.tfmg.content.decoration;
+
+import com.simibubi.create.content.equipment.wrench.IWrenchable;
+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, IWrenchable {
+
+
+
+ public FrameBlock(Properties p_55926_) {
+ super(p_55926_);
+ this.registerDefaultState(this.defaultBlockState().setValue(WATERLOGGED, false));
+ }
+
+
+ protected void createBlockStateDefinition(StateDefinition.Builder 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);
+ }
+}
+
+
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/LithiumBlock.java b/src/main/java/com/drmangotea/tfmg/content/decoration/LithiumBlock.java
new file mode 100644
index 00000000..0c11e0f2
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/LithiumBlock.java
@@ -0,0 +1,55 @@
+package com.drmangotea.tfmg.content.decoration;
+
+import com.drmangotea.tfmg.content.items.weapons.lithium_blade.LithiumSpark;
+import com.drmangotea.tfmg.registry.TFMGEntityTypes;
+import com.simibubi.create.Create;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.util.Mth;
+import net.minecraft.util.RandomSource;
+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.material.Fluids;
+
+public class LithiumBlock extends Block {
+ public LithiumBlock(Properties p_49795_) {
+ super(p_49795_);
+ }
+
+ @Override
+ public boolean isRandomlyTicking(BlockState p_49921_) {
+ return true;
+ }
+
+ @Override
+ public void randomTick(BlockState blockState, ServerLevel level, BlockPos pos, RandomSource randomSource) {
+ super.randomTick(blockState, level, pos, randomSource);
+
+ for(Direction direction : Direction.values()){
+ if(level.getFluidState(pos.relative(direction)).is(Fluids.WATER)){
+ for (int i = 0; i < 12; i++) {
+ float x = Create.RANDOM.nextFloat(360);
+ float y = Create.RANDOM.nextFloat(360);
+ float z = Create.RANDOM.nextFloat(360);
+ LithiumSpark spark = TFMGEntityTypes.LITHIUM_SPARK.create(level);
+ spark.moveTo(pos.getX(), pos.getY() + 0.5, 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(), 1, Level.ExplosionInteraction.NONE);
+
+ level.destroyBlock(pos,false);
+ break;
+ }
+
+ }
+
+
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/LithiumTorchBlock.java b/src/main/java/com/drmangotea/tfmg/content/decoration/LithiumTorchBlock.java
new file mode 100644
index 00000000..07338134
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/LithiumTorchBlock.java
@@ -0,0 +1,100 @@
+package com.drmangotea.tfmg.content.decoration;
+
+import com.drmangotea.tfmg.base.blocks.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;
+
+public class LithiumTorchBlock extends WallMountBlock implements SimpleWaterloggedBlock {
+
+ public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
+
+ private static final Map 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 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);
+ }
+
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/LithiumTorchGenerator.java b/src/main/java/com/drmangotea/tfmg/content/decoration/LithiumTorchGenerator.java
new file mode 100644
index 00000000..06fea97a
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/LithiumTorchGenerator.java
@@ -0,0 +1,43 @@
+package com.drmangotea.tfmg.content.decoration;
+
+import com.drmangotea.tfmg.base.blocks.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.neoforged.neoforge.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 ModelFile getModel(DataGenContext ctx, RegistrateBlockstateProvider prov,
+ BlockState state) {
+
+
+ return state.getValue(WallMountBlock.FACING).getAxis().isHorizontal() ? partialBaseModel(ctx, prov, "wall")
+ : partialBaseModel(ctx, prov);
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/TrussBlock.java b/src/main/java/com/drmangotea/tfmg/content/decoration/TrussBlock.java
new file mode 100644
index 00000000..e0793b9f
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/TrussBlock.java
@@ -0,0 +1,54 @@
+package com.drmangotea.tfmg.content.decoration;
+
+import com.simibubi.create.content.equipment.wrench.IWrenchable;
+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, IWrenchable {
+
+
+
+ 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 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);
+ }
+}
+
+
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/cogs/TFMGCogWheelBlock.java b/src/main/java/com/drmangotea/tfmg/content/decoration/cogs/TFMGCogWheelBlock.java
new file mode 100644
index 00000000..fe0aea84
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/cogs/TFMGCogWheelBlock.java
@@ -0,0 +1,207 @@
+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 net.createmod.catnip.data.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.ItemInteractionResult;
+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
+ protected ItemInteractionResult useItemOn(ItemStack stack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult) {
+ if (player.isShiftKeyDown() || !player.mayBuild())
+ return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
+
+ ItemInteractionResult result = tryEncase(state, level, pos, stack, player, hand, hitResult);
+ if (result.consumesAction())
+ return result;
+
+ return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
+ }
+
+ 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();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/cogs/TFMGCogwheelBlockItem.java b/src/main/java/com/drmangotea/tfmg/content/decoration/cogs/TFMGCogwheelBlockItem.java
new file mode 100644
index 00000000..af81ad2d
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/cogs/TFMGCogwheelBlockItem.java
@@ -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 net.createmod.catnip.data.Iterate;
+import net.createmod.catnip.placement.IPlacementHelper;
+import net.createmod.catnip.placement.PlacementHelpers;
+import net.createmod.catnip.placement.PlacementOffset;
+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).result();
+ }
+
+ 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).result();
+ }
+ }
+
+ return super.onItemUseFirst(stack, context);
+ }
+
+ @MethodsReturnNonnullByDefault
+ private static class SmallCogHelper extends DiagonalCogHelper {
+
+ @Override
+ public Predicate getItemPredicate() {
+ return ((Predicate) 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 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 getItemPredicate() {
+ return ((Predicate) 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 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 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 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 getItemPredicate() {
+ return ((Predicate) ICogWheel::isLargeCogItem).and(ICogWheel::isDedicatedCogItem);
+ }
+
+ @Override
+ public Predicate 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 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 getItemPredicate() {
+ return ((Predicate) ICogWheel::isSmallCogItem).and(ICogWheel::isDedicatedCogItem);
+ }
+
+ @Override
+ public Predicate 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 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();
+ }
+
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/cogs/TFMGCogwheelRenderer.java b/src/main/java/com/drmangotea/tfmg/content/decoration/cogs/TFMGCogwheelRenderer.java
new file mode 100644
index 00000000..0362b0e4
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/cogs/TFMGCogwheelRenderer.java
@@ -0,0 +1,71 @@
+package com.drmangotea.tfmg.content.decoration.cogs;
+
+import com.drmangotea.tfmg.registry.TFMGBlocks;
+import com.drmangotea.tfmg.registry.TFMGPartialModels;
+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 dev.engine_room.flywheel.api.visualization.VisualizationManager;
+import dev.engine_room.flywheel.lib.model.baked.PartialModel;
+import net.createmod.catnip.animation.AnimationTickHolder;
+import net.createmod.catnip.render.CachedBuffers;
+import net.createmod.catnip.render.SuperByteBuffer;
+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 {
+
+ public TFMGCogwheelRenderer(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void renderSafe(SimpleKineticBlockEntity be, float partialTicks, PoseStack ms,
+ MultiBufferSource buffer, int light, int overlay) {
+
+ if (VisualizationManager.supportsVisualization(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,
+ CachedBuffers.partialFacingVertical(model, be.getBlockState(), facing),
+ ms, buffer.getBuffer(RenderType.cutoutMipped()), light);
+
+ float angle = getAngleForLargeCogShaft(be, axis);
+ SuperByteBuffer shaft =
+ CachedBuffers.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;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/cogs/TFMGCogwheelVisual.java b/src/main/java/com/drmangotea/tfmg/content/decoration/cogs/TFMGCogwheelVisual.java
new file mode 100644
index 00000000..80787751
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/cogs/TFMGCogwheelVisual.java
@@ -0,0 +1,106 @@
+package com.drmangotea.tfmg.content.decoration.cogs;
+
+import com.drmangotea.tfmg.registry.TFMGBlocks;
+import com.drmangotea.tfmg.registry.TFMGPartialModels;
+import com.simibubi.create.AllBlocks;
+import com.simibubi.create.AllPartialModels;
+import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer;
+import com.simibubi.create.content.kinetics.base.RotatingInstance;
+import com.simibubi.create.content.kinetics.base.SingleAxisRotatingVisual;
+import com.simibubi.create.content.kinetics.simpleRelays.BracketedKineticBlockEntity;
+import com.simibubi.create.content.kinetics.simpleRelays.BracketedKineticBlockEntityRenderer;
+import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel;
+import com.simibubi.create.foundation.render.AllInstanceTypes;
+import dev.engine_room.flywheel.api.instance.Instance;
+import dev.engine_room.flywheel.api.material.Material;
+import dev.engine_room.flywheel.api.model.Model;
+import dev.engine_room.flywheel.api.visual.BlockEntityVisual;
+import dev.engine_room.flywheel.api.visualization.VisualizationContext;
+import dev.engine_room.flywheel.lib.material.Materials;
+import dev.engine_room.flywheel.lib.model.Models;
+
+import net.minecraft.core.Direction;
+
+import java.util.function.Consumer;
+
+public class TFMGCogwheelVisual {
+
+ public static BlockEntityVisual create(VisualizationContext context, BracketedKineticBlockEntity blockEntity, float partialTick) {
+ if (ICogWheel.isLargeCog(blockEntity.getBlockState())) {
+ return new LargeCogVisual(context, blockEntity, partialTick);
+ } else {
+
+ Model model;
+
+
+ if (TFMGBlocks.STEEL_COGWHEEL.is(blockEntity.getBlockState().getBlock())) {
+ model = Models.partial(TFMGPartialModels.STEEL_COGHWEEL);
+ } else {
+ model = Models.partial(TFMGPartialModels.ALUMINUM_COGHWEEL);
+ }
+ return new SingleAxisRotatingVisual<>(context, blockEntity, partialTick, model);
+ }
+ }
+
+ // Large cogs sometimes have to offset their teeth by 11.25 degrees in order to
+ // mesh properly
+ public static class LargeCogVisual extends SingleAxisRotatingVisual {
+
+ protected final RotatingInstance additionalShaft;
+
+ private LargeCogVisual(VisualizationContext context, BracketedKineticBlockEntity blockEntity, float partialTick) {
+ super(context, blockEntity, partialTick, getLargeModel(blockEntity));
+
+ Direction.Axis axis = KineticBlockEntityRenderer.getRotationAxisOf(blockEntity);
+
+ additionalShaft = instancerProvider().instancer(AllInstanceTypes.ROTATING, Models.partial(AllPartialModels.COGWHEEL_SHAFT))
+ .createInstance();
+
+
+ additionalShaft.rotateToFace(axis)
+ .setup(blockEntity)
+ .setRotationOffset(BracketedKineticBlockEntityRenderer.getShaftAngleOffset(axis, pos))
+ .setPosition(getVisualPosition())
+ .setChanged();
+ }
+
+
+
+ public static Model getLargeModel(BracketedKineticBlockEntity blockEntity){
+
+ if (TFMGBlocks.LARGE_STEEL_COGWHEEL.is(blockEntity.getBlockState().getBlock())) {
+ return Models.partial(TFMGPartialModels.LARGE_STEEL_COGHWEEL);
+ } else {
+ return Models.partial(TFMGPartialModels.LARGE_ALUMINUM_COGHWEEL);
+ }
+ }
+
+
+
+ @Override
+ public void update(float pt) {
+ super.update(pt);
+ additionalShaft.setup(blockEntity)
+ .setRotationOffset(BracketedKineticBlockEntityRenderer.getShaftAngleOffset(rotationAxis(), pos))
+ .setChanged();
+ }
+
+ @Override
+ public void updateLight(float partialTick) {
+ super.updateLight(partialTick);
+ relight(additionalShaft);
+ }
+
+ @Override
+ protected void _delete() {
+ super._delete();
+ additionalShaft.delete();
+ }
+
+ @Override
+ public void collectCrumblingInstances(Consumer consumer) {
+ super.collectCrumblingInstances(consumer);
+ consumer.accept(additionalShaft);
+ }
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/cogs/TFMGEncasedCogRenderer.java b/src/main/java/com/drmangotea/tfmg/content/decoration/cogs/TFMGEncasedCogRenderer.java
new file mode 100644
index 00000000..f166ecd2
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/cogs/TFMGEncasedCogRenderer.java
@@ -0,0 +1,85 @@
+package com.drmangotea.tfmg.content.decoration.cogs;
+
+import com.drmangotea.tfmg.registry.TFMGPartialModels;
+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 dev.engine_room.flywheel.api.visualization.VisualizationManager;
+import dev.engine_room.flywheel.lib.model.baked.PartialModel;
+import net.createmod.catnip.data.Iterate;
+import net.createmod.catnip.render.CachedBuffers;
+import net.createmod.catnip.render.SuperByteBuffer;
+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 TFMGEncasedCogRenderer extends KineticBlockEntityRenderer {
+
+ private boolean large;
+ private boolean steel;
+
+ public static TFMGEncasedCogRenderer steelSmall(BlockEntityRendererProvider.Context context) {
+ return new TFMGEncasedCogRenderer(context, false,true);
+ }
+
+ public static TFMGEncasedCogRenderer steellarge(BlockEntityRendererProvider.Context context) {
+ return new TFMGEncasedCogRenderer(context, true,true);
+ }
+ public static TFMGEncasedCogRenderer aluminumSmall(BlockEntityRendererProvider.Context context) {
+ return new TFMGEncasedCogRenderer(context, false,false);
+ }
+
+ public static TFMGEncasedCogRenderer aluminumlarge(BlockEntityRendererProvider.Context context) {
+ return new TFMGEncasedCogRenderer(context, true,false);
+ }
+
+ public TFMGEncasedCogRenderer(BlockEntityRendererProvider.Context context, boolean large, boolean steel) {
+ super(context);
+ this.large = large;
+ this.steel = steel;
+ }
+
+ @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 (VisualizationManager.supportsVisualization(be.getLevel()))
+ return;
+
+ BlockState blockState = be.getBlockState();
+ Block block = blockState.getBlock();
+ if (!(block instanceof IRotate def))
+ return;
+
+ Direction.Axis axis = getRotationAxisOf(be);
+ BlockPos pos = be.getBlockPos();
+ float angle = large ? BracketedKineticBlockEntityRenderer.getAngleForLargeCogShaft(be, axis)
+ : getAngleForBe(be, pos, axis);
+
+ for (Direction d : Iterate.directionsInAxis(getRotationAxisOf(be))) {
+ if (!def.hasShaftTowards(be.getLevel(), be.getBlockPos(), blockState, d))
+ continue;
+ SuperByteBuffer shaft = CachedBuffers.partialFacing(AllPartialModels.SHAFT_HALF, be.getBlockState(), d);
+ kineticRotationTransform(shaft, be, axis, angle, light);
+ shaft.renderInto(ms, buffer.getBuffer(RenderType.solid()));
+ }
+ }
+
+ @Override
+ protected SuperByteBuffer getRotatedModel(SimpleKineticBlockEntity be, BlockState state) {
+ return CachedBuffers.partialFacingVertical(
+ large ? steel? TFMGPartialModels.SHAFTLESS_LARGE_STEEL_COGHWEEL :TFMGPartialModels.SHAFTLESS_LARGE_ALUMINUM_COGHWEEL : steel ? TFMGPartialModels.SHAFTLESS_STEEL_COGHWEEL : TFMGPartialModels.SHAFTLESS_ALUMINUM_COGHWEEL, state,
+ Direction.fromAxisAndDirection(state.getValue(EncasedCogwheelBlock.AXIS), Direction.AxisDirection.POSITIVE));
+ }
+
+
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/cogs/TFMGEncasedCogVisual.java b/src/main/java/com/drmangotea/tfmg/content/decoration/cogs/TFMGEncasedCogVisual.java
new file mode 100644
index 00000000..9680841e
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/cogs/TFMGEncasedCogVisual.java
@@ -0,0 +1,120 @@
+package com.drmangotea.tfmg.content.decoration.cogs;
+
+import com.drmangotea.tfmg.registry.TFMGPartialModels;
+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.KineticBlockEntityVisual;
+import com.simibubi.create.content.kinetics.base.RotatingInstance;
+import com.simibubi.create.content.kinetics.simpleRelays.BracketedKineticBlockEntityRenderer;
+import com.simibubi.create.foundation.render.AllInstanceTypes;
+import dev.engine_room.flywheel.api.instance.Instance;
+import dev.engine_room.flywheel.api.model.Model;
+import dev.engine_room.flywheel.api.visualization.VisualizationContext;
+import dev.engine_room.flywheel.lib.model.Models;
+import net.createmod.catnip.data.Iterate;
+import net.minecraft.core.Direction;
+import net.minecraft.world.level.block.Block;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.function.Consumer;
+
+public class TFMGEncasedCogVisual extends KineticBlockEntityVisual {
+
+
+ protected final RotatingInstance rotatingModel;
+ @Nullable
+ protected final RotatingInstance rotatingTopShaft;
+ @Nullable
+ protected final RotatingInstance rotatingBottomShaft;
+
+ public static TFMGEncasedCogVisual steelSmall(VisualizationContext modelManager, KineticBlockEntity blockEntity, float partialTick) {
+ return new TFMGEncasedCogVisual(modelManager, blockEntity, false, partialTick, Models.partial(TFMGPartialModels.SHAFTLESS_STEEL_COGHWEEL));
+ }
+
+ public static TFMGEncasedCogVisual steelLarge(VisualizationContext modelManager, KineticBlockEntity blockEntity, float partialTick) {
+ return new TFMGEncasedCogVisual(modelManager, blockEntity, true, partialTick, Models.partial(TFMGPartialModels.SHAFTLESS_LARGE_STEEL_COGHWEEL));
+ }
+
+ public static TFMGEncasedCogVisual aluminumSmall(VisualizationContext modelManager, KineticBlockEntity blockEntity, float partialTick) {
+ return new TFMGEncasedCogVisual(modelManager, blockEntity, false, partialTick, Models.partial(TFMGPartialModels.SHAFTLESS_ALUMINUM_COGHWEEL));
+ }
+
+ public static TFMGEncasedCogVisual aluminumLarge(VisualizationContext modelManager, KineticBlockEntity blockEntity, float partialTick) {
+ return new TFMGEncasedCogVisual(modelManager, blockEntity, true, partialTick, Models.partial(TFMGPartialModels.SHAFTLESS_LARGE_ALUMINUM_COGHWEEL));
+ }
+
+ public TFMGEncasedCogVisual(VisualizationContext modelManager, KineticBlockEntity blockEntity, boolean large, float partialTick, Model model) {
+ super(modelManager, blockEntity, partialTick);
+
+ rotatingModel = instancerProvider().instancer(AllInstanceTypes.ROTATING, model)
+ .createInstance();
+
+ rotatingModel.setup(blockEntity)
+ .setPosition(getVisualPosition())
+ .rotateToFace(rotationAxis())
+ .setChanged();
+
+ RotatingInstance rotatingTopShaft = null;
+ RotatingInstance rotatingBottomShaft = null;
+
+ Block block = blockState.getBlock();
+ if (block instanceof IRotate def) {
+ for (Direction d : Iterate.directionsInAxis(rotationAxis())) {
+ if (!def.hasShaftTowards(blockEntity.getLevel(), blockEntity.getBlockPos(), blockState, d))
+ continue;
+ RotatingInstance instance = instancerProvider().instancer(AllInstanceTypes.ROTATING, Models.partial(AllPartialModels.SHAFT_HALF))
+ .createInstance();
+ instance.setup(blockEntity)
+ .setPosition(getVisualPosition())
+ .rotateToFace(Direction.SOUTH, d)
+ .setChanged();
+
+ if (large) {
+ instance.setRotationOffset(BracketedKineticBlockEntityRenderer.getShaftAngleOffset(rotationAxis(), pos));
+ }
+
+ if (d.getAxisDirection() == Direction.AxisDirection.POSITIVE) {
+ rotatingTopShaft = instance;
+ } else {
+ rotatingBottomShaft = instance;
+ }
+ }
+ }
+
+ this.rotatingTopShaft = rotatingTopShaft;
+ this.rotatingBottomShaft = rotatingBottomShaft;
+ }
+
+ @Override
+ public void update(float pt) {
+ rotatingModel.setup(blockEntity)
+ .setChanged();
+ if (rotatingTopShaft != null) rotatingTopShaft.setup(blockEntity)
+ .setChanged();
+ if (rotatingBottomShaft != null) rotatingBottomShaft.setup(blockEntity)
+ .setChanged();
+ }
+
+ @Override
+ public void updateLight(float partialTick) {
+ relight(rotatingModel);
+
+ if (rotatingTopShaft != null) relight(rotatingTopShaft);
+ if (rotatingBottomShaft != null) relight(rotatingBottomShaft);
+ }
+
+ @Override
+ protected void _delete() {
+ rotatingModel.delete();
+ if (rotatingTopShaft != null) rotatingTopShaft.delete();
+ if (rotatingBottomShaft != null) rotatingBottomShaft.delete();
+ }
+
+ @Override
+ public void collectCrumblingInstances(Consumer<@Nullable Instance> consumer) {
+ consumer.accept(rotatingModel);
+ consumer.accept(rotatingTopShaft);
+ consumer.accept(rotatingBottomShaft);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/ConcreteloggedBlock.java b/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/ConcreteloggedBlock.java
new file mode 100644
index 00000000..b0bd9fe4
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/ConcreteloggedBlock.java
@@ -0,0 +1,88 @@
+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.ItemInteractionResult;
+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();
+ return state.getValue(CONCRETELOGGED) ? TFMGFluids.LIQUID_CONCRETE.get().getSource(false) : Fluids.EMPTY.defaultFluidState();
+ }
+
+ default void updateConcrete(LevelAccessor level, BlockState state, BlockPos pos) {
+ if (state.getValue(CONCRETELOGGED))
+ //level.scheduleTick(pos, TFMGFluids.LIQUID_CONCRETE.get(), TFMGFluids.LIQUID_CONCRETE.get().getTickDelay(level));
+ level.scheduleTick(pos, TFMGFluids.LIQUID_CONCRETE.get(), TFMGFluids.LIQUID_CONCRETE.get().getTickDelay(level));
+ }
+ default ItemInteractionResult 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 ItemInteractionResult.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 ItemInteractionResult.SUCCESS;
+ }
+ }
+ return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
+ }
+
+ 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());
+ }
+
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/RebarFloorBlock.java b/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/RebarFloorBlock.java
new file mode 100644
index 00000000..1022ee2d
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/RebarFloorBlock.java
@@ -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 SimpleConcreteloggedBlock {
+ 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;
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/RebarPillarBlock.java b/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/RebarPillarBlock.java
new file mode 100644
index 00000000..66ce4e2a
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/RebarPillarBlock.java
@@ -0,0 +1,78 @@
+package com.drmangotea.tfmg.content.decoration.concrete;
+
+import com.drmangotea.tfmg.base.blocks.TFMGDirectionalBlock;
+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.InteractionHand;
+import net.minecraft.world.InteractionResult;
+import net.minecraft.world.ItemInteractionResult;
+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.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;
+
+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
+ protected ItemInteractionResult useItemOn(ItemStack stack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult) {
+ return onClicked(level, pos, state, 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 builder) {
+ super.createBlockStateDefinition(builder);
+ builder.add(CONCRETELOGGED);
+ }
+
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/RebarStairsBlock.java b/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/RebarStairsBlock.java
new file mode 100644
index 00000000..696d895d
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/RebarStairsBlock.java
@@ -0,0 +1,71 @@
+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.ItemInteractionResult;
+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.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
+ protected ItemInteractionResult useItemOn(ItemStack stack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult) {
+ return onClicked(level, pos, state, 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 builder) {
+ super.createBlockStateDefinition(builder);
+ builder.add(CONCRETELOGGED);
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/RebarStairsGenerator.java b/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/RebarStairsGenerator.java
new file mode 100644
index 00000000..30b45b0a
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/RebarStairsGenerator.java
@@ -0,0 +1,42 @@
+package com.drmangotea.tfmg.content.decoration.concrete;
+
+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.StairBlock;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.block.state.properties.Half;
+import net.neoforged.neoforge.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 ModelFile getModel(DataGenContext ctx, RegistrateBlockstateProvider prov,
+ BlockState state) {
+ return state.getValue(StairBlock.HALF)== Half.TOP ? partialBaseModel(ctx, prov, "upside_down")
+ : partialBaseModel(ctx, prov);
+ }
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/RebarWallBlock.java b/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/RebarWallBlock.java
new file mode 100644
index 00000000..b830df9c
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/RebarWallBlock.java
@@ -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 SimpleConcreteloggedBlock {
+ 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);
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/SimpleConcreteloggedBlock.java b/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/SimpleConcreteloggedBlock.java
new file mode 100644
index 00000000..a67eec83
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/concrete/SimpleConcreteloggedBlock.java
@@ -0,0 +1,70 @@
+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.ItemInteractionResult;
+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.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;
+
+public class SimpleConcreteloggedBlock extends Block implements ConcreteloggedBlock {
+
+
+ public SimpleConcreteloggedBlock(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
+ protected ItemInteractionResult useItemOn(ItemStack stack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult) {
+ return onClicked(level, pos, state, 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 builder) {
+ super.createBlockStateDefinition(builder);
+ builder.add(CONCRETELOGGED);
+ }
+
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/doors/TFMGSlidingDoorBlock.java b/src/main/java/com/drmangotea/tfmg/content/decoration/doors/TFMGSlidingDoorBlock.java
new file mode 100644
index 00000000..ba358f66
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/doors/TFMGSlidingDoorBlock.java
@@ -0,0 +1,259 @@
+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.ItemInteractionResult;
+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.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 {
+
+ 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(type,p_52737_ );
+ this.folds = folds;
+ }
+
+ public boolean isFoldingDoor() {
+ return folds;
+ }
+
+ @Override
+ protected void createBlockStateDefinition(Builder 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
+protected InteractionResult useWithoutItem(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, 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))
+ useWithoutItem(otherDoor, pLevel, otherPos, pPlayer, 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 getBlockEntityClass() {
+ return TFMGSlidingDoorBlockEntity.class;
+ }
+
+ @Override
+ public BlockEntityType extends TFMGSlidingDoorBlockEntity> getBlockEntityType() {
+ return TFMGBlockEntities.TFMG_SLIDING_DOOR.get();
+ }
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/doors/TFMGSlidingDoorBlockEntity.java b/src/main/java/com/drmangotea/tfmg/content/decoration/doors/TFMGSlidingDoorBlockEntity.java
new file mode 100644
index 00000000..00bf18bb
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/doors/TFMGSlidingDoorBlockEntity.java
@@ -0,0 +1,80 @@
+package com.drmangotea.tfmg.content.decoration.doors;
+
+import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorBlockEntity;
+import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
+import net.createmod.catnip.animation.LerpedFloat;
+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.handleNeighborChanged(level, worldPosition, Blocks.AIR, worldPosition, false);
+ }
+
+ super.tick();
+ boolean open = isOpen(getBlockState());
+ boolean wasSettled = animation.settled();
+ animation.chase(open ? 1 : 0, .15f, LerpedFloat.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 behaviours) {}
+
+ public static boolean isOpen(BlockState state) {
+ return state.getOptionalValue(DoorBlock.OPEN)
+ .orElse(false);
+ }
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/doors/TFMGSlidingDoorRenderer.java b/src/main/java/com/drmangotea/tfmg/content/decoration/doors/TFMGSlidingDoorRenderer.java
new file mode 100644
index 00000000..a0dc0e63
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/doors/TFMGSlidingDoorRenderer.java
@@ -0,0 +1,103 @@
+package com.drmangotea.tfmg.content.decoration.doors;
+
+
+
+import com.drmangotea.tfmg.registry.TFMGPartialModels;
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.blaze3d.vertex.VertexConsumer;
+import com.simibubi.create.AllPartialModels;
+import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorBlock;
+import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorBlockEntity;
+import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer;
+
+import dev.engine_room.flywheel.lib.model.baked.PartialModel;
+import net.createmod.catnip.data.Couple;
+import net.createmod.catnip.data.Iterate;
+import net.createmod.catnip.math.AngleHelper;
+import net.createmod.catnip.render.CachedBuffers;
+import net.createmod.catnip.render.SuperByteBuffer;
+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.core.registries.BuiltInRegistries;
+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;
+
+
+
+public class TFMGSlidingDoorRenderer extends SafeBlockEntityRenderer {
+
+ 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 partials =
+ TFMGPartialModels.FOLDING_DOORS.get(BuiltInRegistries.BLOCK.getKey(blockState.getBlock()));
+
+ boolean flip = blockState.getValue(DoorBlock.HINGE) == DoorHingeSide.RIGHT;
+ for (boolean left : Iterate.trueAndFalse) {
+ SuperByteBuffer partial = CachedBuffers.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(
+ Mth.DEG_TO_RAD * AngleHelper.horizontalAngle(facing.getClockWise()), Direction.UP);
+
+ if (flip)
+ partial.translate(0, 0, 1);
+ partial.rotateYDegrees(91 * f * value * value);
+
+ if (!left)
+ partial.translate(0, 0, f / 2f)
+ .rotateYDegrees(-181 * f * value * value);
+
+ if (flip)
+ partial.translate(0, 0, -1 / 2f);
+
+ partial.light(light)
+ .renderInto(ms, vb);
+ }
+
+ return;
+ }
+
+ for (DoubleBlockHalf half : DoubleBlockHalf.values()) {
+ CachedBuffers.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);
+ }
+
+ }
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/encased/TFMGEncasedCogwheelBlock.java b/src/main/java/com/drmangotea/tfmg/content/decoration/encased/TFMGEncasedCogwheelBlock.java
new file mode 100644
index 00000000..2286e76b
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/encased/TFMGEncasedCogwheelBlock.java
@@ -0,0 +1,299 @@
+package com.drmangotea.tfmg.content.decoration.encased;
+
+
+import com.drmangotea.tfmg.registry.TFMGBlockEntities;
+import com.drmangotea.tfmg.registry.TFMGBlocks;
+import com.simibubi.create.api.contraption.transformable.TransformableBlock;
+import com.simibubi.create.api.schematic.requirement.SpecialBlockItemRequirement;
+import com.simibubi.create.content.contraptions.StructureTransform;
+import com.simibubi.create.content.decoration.encasing.EncasedBlock;
+import com.simibubi.create.content.equipment.wrench.IWrenchable;
+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.kinetics.simpleRelays.encased.EncasedCogwheelBlock;
+import com.simibubi.create.content.schematics.requirement.ItemRequirement;
+import com.simibubi.create.foundation.block.IBE;
+import com.tterrag.registrate.util.entry.BlockEntityEntry;
+import com.tterrag.registrate.util.entry.BlockEntry;
+import net.createmod.catnip.data.Iterate;
+import net.createmod.catnip.math.VoxelShaper;
+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, SpecialBlockItemRequirement, TransformableBlock, EncasedBlock {
+ public static final BooleanProperty TOP_SHAFT = EncasedCogwheelBlock.TOP_SHAFT;
+ public static final BooleanProperty BOTTOM_SHAFT = EncasedCogwheelBlock.BOTTOM_SHAFT;
+ protected final boolean isLarge;
+ private final Supplier casing;
+ private final BlockEntry> blockSmall;
+ private final BlockEntry> blockLarge;
+ private final BlockEntityEntry beSmall;
+ private final BlockEntityEntry beLarge;
+
+ public static TFMGEncasedCogwheelBlock steel(Properties properties, boolean large, Supplier 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 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 casing, BlockEntry> blockSmall, BlockEntry> blockLarge, BlockEntityEntry beSmall, BlockEntityEntry 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 builder) {
+ super.createBlockStateDefinition(builder.add(TOP_SHAFT, BOTTOM_SHAFT));
+ }
+
+
+ @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));
+ IWrenchable.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 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);
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/encased/TFMGEncasedShaftBlock.java b/src/main/java/com/drmangotea/tfmg/content/decoration/encased/TFMGEncasedShaftBlock.java
new file mode 100644
index 00000000..38e61ed8
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/encased/TFMGEncasedShaftBlock.java
@@ -0,0 +1,80 @@
+package com.drmangotea.tfmg.content.decoration.encased;
+
+
+import com.drmangotea.tfmg.registry.TFMGBlockEntities;
+import com.simibubi.create.AllBlocks;
+import com.simibubi.create.api.schematic.requirement.SpecialBlockItemRequirement;
+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.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, SpecialBlockItemRequirement, EncasedBlock {
+
+ private final Supplier casing;
+
+ public TFMGEncasedShaftBlock(Properties properties, Supplier 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 ItemRequirement getRequiredItems(BlockState state, BlockEntity be) {
+ return ItemRequirement.of(AllBlocks.SHAFT.getDefaultState(), be);
+ }
+
+ @Override
+ public Class 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)));
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/flywheels/TFMGFlywheelBlock.java b/src/main/java/com/drmangotea/tfmg/content/decoration/flywheels/TFMGFlywheelBlock.java
new file mode 100644
index 00000000..e48745e9
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/flywheels/TFMGFlywheelBlock.java
@@ -0,0 +1,88 @@
+package com.drmangotea.tfmg.content.decoration.flywheels;
+
+
+import com.drmangotea.tfmg.registry.TFMGBlockEntities;
+import com.drmangotea.tfmg.registry.TFMGPartialModels;
+import com.simibubi.create.AllShapes;
+import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock;
+import com.simibubi.create.foundation.block.IBE;
+import dev.engine_room.flywheel.lib.model.baked.PartialModel;
+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 {
+
+
+ public final PartialModel model;
+
+ public static TFMGFlywheelBlock steel(Properties properties){
+ return new TFMGFlywheelBlock(properties, TFMGPartialModels.STEEL_FLYWHEEL);
+ }
+ public static TFMGFlywheelBlock aluminum(Properties properties){
+ return new TFMGFlywheelBlock(properties, TFMGPartialModels.ALUMINUM_FLYWHEEL);
+ }
+ public static TFMGFlywheelBlock cast_iron(Properties properties){
+ return new TFMGFlywheelBlock(properties, TFMGPartialModels.CAST_IRON_FLYWHEEL);
+ }
+ public static TFMGFlywheelBlock lead(Properties properties){
+ return new TFMGFlywheelBlock(properties, TFMGPartialModels.LEAD_FLYWHEEL);
+ }
+ public static TFMGFlywheelBlock nickel(Properties properties){
+ return new TFMGFlywheelBlock(properties, TFMGPartialModels.NICKEL_FLYWHEEL);
+ }
+
+
+ public TFMGFlywheelBlock(Properties properties,PartialModel model) {
+ super(properties);
+ this.model = model;
+ }
+
+ @Override
+ public Class 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;
+ }
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/flywheels/TFMGFlywheelBlockEntity.java b/src/main/java/com/drmangotea/tfmg/content/decoration/flywheels/TFMGFlywheelBlockEntity.java
new file mode 100644
index 00000000..acd40318
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/flywheels/TFMGFlywheelBlockEntity.java
@@ -0,0 +1,56 @@
+package com.drmangotea.tfmg.content.decoration.flywheels;
+
+import com.simibubi.create.content.kinetics.base.KineticBlockEntity;
+import dev.engine_room.flywheel.lib.model.baked.PartialModel;
+import net.createmod.catnip.animation.LerpedFloat;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.HolderLookup;
+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, HolderLookup.Provider registries, boolean clientPacket) {
+ super.write(compound,registries , clientPacket);
+ }
+
+ @Override
+ protected void read(CompoundTag compound, HolderLookup.Provider registries, boolean clientPacket) {
+ super.read(compound,registries , clientPacket);
+ if (clientPacket)
+ visualSpeed.chase(getGeneratedSpeed(), 1 / 64f, LerpedFloat.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;
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/flywheels/TFMGFlywheelRenderer.java b/src/main/java/com/drmangotea/tfmg/content/decoration/flywheels/TFMGFlywheelRenderer.java
new file mode 100644
index 00000000..9a1ca08e
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/flywheels/TFMGFlywheelRenderer.java
@@ -0,0 +1,50 @@
+package com.drmangotea.tfmg.content.decoration.flywheels;
+
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.blaze3d.vertex.VertexConsumer;
+import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer;
+import dev.engine_room.flywheel.api.visualization.VisualizationManager;
+import net.createmod.catnip.math.AngleHelper;
+import net.createmod.catnip.render.CachedBuffers;
+import net.createmod.catnip.render.SuperByteBuffer;
+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 {
+
+ 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 (VisualizationManager.supportsVisualization(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 = CachedBuffers.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));
+ }
+
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/flywheels/TFMGFlywheelVisual.java b/src/main/java/com/drmangotea/tfmg/content/decoration/flywheels/TFMGFlywheelVisual.java
new file mode 100644
index 00000000..dc38e01c
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/flywheels/TFMGFlywheelVisual.java
@@ -0,0 +1,107 @@
+package com.drmangotea.tfmg.content.decoration.flywheels;
+
+import com.drmangotea.tfmg.registry.TFMGPartialModels;
+import com.simibubi.create.AllPartialModels;
+import com.simibubi.create.content.kinetics.base.KineticBlockEntityVisual;
+import com.simibubi.create.content.kinetics.base.RotatingInstance;
+import com.simibubi.create.content.kinetics.flywheel.FlywheelBlockEntity;
+import com.simibubi.create.foundation.render.AllInstanceTypes;
+import dev.engine_room.flywheel.api.instance.Instance;
+import dev.engine_room.flywheel.api.visualization.VisualizationContext;
+import dev.engine_room.flywheel.lib.instance.InstanceTypes;
+import dev.engine_room.flywheel.lib.instance.TransformedInstance;
+import dev.engine_room.flywheel.lib.model.Models;
+import dev.engine_room.flywheel.lib.model.baked.PartialModel;
+import dev.engine_room.flywheel.lib.visual.SimpleDynamicVisual;
+import net.createmod.catnip.math.AngleHelper;
+import net.minecraft.core.Direction;
+import org.joml.Matrix4f;
+import org.joml.Quaternionf;
+
+import java.util.function.Consumer;
+
+public class TFMGFlywheelVisual extends KineticBlockEntityVisual implements SimpleDynamicVisual {
+
+ protected final RotatingInstance shaft;
+ protected final TransformedInstance wheel;
+ protected float lastAngle = Float.NaN;
+
+ protected final Matrix4f baseTransform = new Matrix4f();
+
+
+
+
+
+ public TFMGFlywheelVisual(VisualizationContext context, TFMGFlywheelBlockEntity blockEntity, float partialTick) {
+ super(context, blockEntity, partialTick);
+
+ var axis = rotationAxis();
+ shaft = instancerProvider().instancer(AllInstanceTypes.ROTATING, Models.partial(AllPartialModels.SHAFT))
+ .createInstance();
+
+ shaft.setup(TFMGFlywheelVisual.this.blockEntity)
+ .setPosition(getVisualPosition())
+ .rotateToFace(axis)
+ .setChanged();
+
+ wheel = instancerProvider().instancer(InstanceTypes.TRANSFORMED, Models.partial(((TFMGFlywheelBlock)blockEntity.getBlockState().getBlock()).model))
+ .createInstance();
+
+
+ Direction align = Direction.fromAxisAndDirection(axis, Direction.AxisDirection.POSITIVE);
+
+ wheel.translate(getVisualPosition())
+ .center()
+ .rotate(new Quaternionf().rotateTo(0, 1, 0, align.getStepX(), align.getStepY(), align.getStepZ()));
+
+ baseTransform.set(wheel.pose);
+
+ animate(blockEntity.angle);
+ }
+
+ @Override
+ public void beginFrame(Context ctx) {
+
+ float partialTicks = ctx.partialTick();
+
+ 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) {
+ wheel.setTransform(baseTransform)
+ .rotateY(AngleHelper.rad(angle))
+ .uncenter()
+ .setChanged();
+ }
+
+ @Override
+ public void update(float pt) {
+ shaft.setup(blockEntity)
+ .setChanged();
+ }
+
+ @Override
+ public void updateLight(float partialTick) {
+ relight(shaft, wheel);
+ }
+
+ @Override
+ protected void _delete() {
+ shaft.delete();
+ wheel.delete();
+ }
+
+ @Override
+ public void collectCrumblingInstances(Consumer consumer) {
+ consumer.accept(shaft);
+ consumer.accept(wheel);
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/gearbox/SteelGearboxBlock.java b/src/main/java/com/drmangotea/tfmg/content/decoration/gearbox/SteelGearboxBlock.java
new file mode 100644
index 00000000..fd4fbc1b
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/gearbox/SteelGearboxBlock.java
@@ -0,0 +1,67 @@
+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 {
+
+ 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 getBlockEntityClass() {
+ return GearboxBlockEntity.class;
+ }
+
+ @Override
+ public BlockEntityType extends GearboxBlockEntity> getBlockEntityType() {
+ return TFMGBlockEntities.STEEL_GEARBOX.get();
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/gearbox/SteelVerticalGearboxItem.java b/src/main/java/com/drmangotea/tfmg/content/decoration/gearbox/SteelVerticalGearboxItem.java
new file mode 100644
index 00000000..4528238b
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/gearbox/SteelVerticalGearboxItem.java
@@ -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 net.createmod.catnip.data.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 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);
+ }
+}
diff --git a/src/main/java/com/drmangotea/tfmg/content/decoration/pipes/TFMGEncasedPipeBlock.java b/src/main/java/com/drmangotea/tfmg/content/decoration/pipes/TFMGEncasedPipeBlock.java
new file mode 100644
index 00000000..d8819c22
--- /dev/null
+++ b/src/main/java/com/drmangotea/tfmg/content/decoration/pipes/TFMGEncasedPipeBlock.java
@@ -0,0 +1,68 @@
+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 net.createmod.catnip.data.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