From de23da4bfe73d56d53f851edebc0d1dd33525251 Mon Sep 17 00:00:00 2001 From: Albazavr Date: Wed, 24 Jun 2026 15:50:53 +0300 Subject: [PATCH 01/18] Models port --- .../client/model/armor/TFArmorModel.java | 56 +++--- .../model/armor/TravellersWingsModel.java | 17 +- .../model/block/ReactorDebrisModel.java | 39 ---- .../aurorablock/NoiseVaryingModelBuilder.java | 10 +- .../model/block/carpet/RoyalRagsBuilder.java | 17 -- .../model/block/carpet/RoyalRagsModel.java | 184 ----------------- .../block/carpet/RoyalRagsModelLoader.java | 14 +- .../block/carpet/UnbakedRoyalRagsModel.java | 183 +++++++++++------ .../connected/ConnectedTextureBuilder.java | 6 +- .../connected/ConnectedTextureModel.java | 131 +++---------- .../ConnectedTextureModelLoader.java | 11 +- .../block/connected/ConnectionLogic.java | 11 +- .../UnbakedConnectedTextureModel.java | 185 +++++++++++------- .../block/forcefield/ForceFieldModel.java | 176 ++++++++--------- .../forcefield/ForceFieldModelBuilder.java | 99 ++++------ .../forcefield/ForceFieldModelLoader.java | 12 +- .../forcefield/UnbakedForceFieldModel.java | 26 +-- .../block/giantblock/GiantBlockBuilder.java | 15 ++ .../block/giantblock/GiantBlockModel.java | 1 - .../model/block/patch/PatchBuilder.java | 2 - .../client/model/block/patch/PatchModel.java | 135 ++++++------- .../model/block/patch/PatchModelLoader.java | 5 +- .../model/block/patch/UnbakedPatchModel.java | 11 +- .../client/model/entity/HostileWolfModel.java | 6 +- .../client/model/entity/LichMinionModel.java | 32 --- .../model/entity/LowerGoblinKnightModel.java | 3 +- .../client/model/entity/LoyalZombieModel.java | 31 +-- .../model/entity/UpperGoblinKnightModel.java | 8 +- .../client/model/item/TrollsteinnModel.java | 50 ----- 29 files changed, 590 insertions(+), 886 deletions(-) delete mode 100644 src/main/java/twilightforest/client/model/block/ReactorDebrisModel.java delete mode 100644 src/main/java/twilightforest/client/model/block/carpet/RoyalRagsBuilder.java delete mode 100644 src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModel.java delete mode 100644 src/main/java/twilightforest/client/model/entity/LichMinionModel.java delete mode 100644 src/main/java/twilightforest/client/model/item/TrollsteinnModel.java diff --git a/src/main/java/twilightforest/client/model/armor/TFArmorModel.java b/src/main/java/twilightforest/client/model/armor/TFArmorModel.java index eaaa75ff28..be667d4e92 100644 --- a/src/main/java/twilightforest/client/model/armor/TFArmorModel.java +++ b/src/main/java/twilightforest/client/model/armor/TFArmorModel.java @@ -1,43 +1,47 @@ package twilightforest.client.model.armor; +import net.minecraft.client.Minecraft; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.renderer.entity.state.HumanoidRenderState; import net.minecraft.util.Mth; -import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.decoration.ArmorStand; +import org.jetbrains.annotations.NotNull; -public class TFArmorModel extends HumanoidModel { - +public class TFArmorModel extends HumanoidModel<@NotNull HumanoidRenderState> { public TFArmorModel(ModelPart root) { super(root); } @Override - public void setupAnim(LivingEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) { + public void setupAnim(HumanoidRenderState state) { // [VanillaCopy] ArmorStandArmorModel // this prevents helmets from always facing south, and the armor "breathing" on the stand - if (entity instanceof ArmorStand stand) { - this.head.xRot = Mth.DEG_TO_RAD * stand.getHeadPose().getX(); - this.head.yRot = Mth.DEG_TO_RAD * stand.getHeadPose().getY(); - this.head.zRot = Mth.DEG_TO_RAD * stand.getHeadPose().getZ(); - this.body.xRot = Mth.DEG_TO_RAD * stand.getBodyPose().getX(); - this.body.yRot = Mth.DEG_TO_RAD * stand.getBodyPose().getY(); - this.body.zRot = Mth.DEG_TO_RAD * stand.getBodyPose().getZ(); - this.leftArm.xRot = Mth.DEG_TO_RAD * stand.getLeftArmPose().getX(); - this.leftArm.yRot = Mth.DEG_TO_RAD * stand.getLeftArmPose().getY(); - this.leftArm.zRot = Mth.DEG_TO_RAD * stand.getLeftArmPose().getZ(); - this.rightArm.xRot = Mth.DEG_TO_RAD * stand.getRightArmPose().getX(); - this.rightArm.yRot = Mth.DEG_TO_RAD * stand.getRightArmPose().getY(); - this.rightArm.zRot = Mth.DEG_TO_RAD * stand.getRightArmPose().getZ(); - this.leftLeg.xRot = Mth.DEG_TO_RAD * stand.getLeftLegPose().getX(); - this.leftLeg.yRot = Mth.DEG_TO_RAD * stand.getLeftLegPose().getY(); - this.leftLeg.zRot = Mth.DEG_TO_RAD * stand.getLeftLegPose().getZ(); - this.rightLeg.xRot = Mth.DEG_TO_RAD * stand.getRightLegPose().getX(); - this.rightLeg.yRot = Mth.DEG_TO_RAD * stand.getRightLegPose().getY(); - this.rightLeg.zRot = Mth.DEG_TO_RAD * stand.getRightLegPose().getZ(); - this.hat.copyFrom(this.head); + if (state.entityType == EntityType.ARMOR_STAND) { + ArmorStand stand = (ArmorStand) state.entityType.create(Minecraft.getInstance().level, EntitySpawnReason.NATURAL); + this.head.xRot = Mth.DEG_TO_RAD * stand.getHeadPose().x(); + this.head.yRot = Mth.DEG_TO_RAD * stand.getHeadPose().y(); + this.head.zRot = Mth.DEG_TO_RAD * stand.getHeadPose().z(); + this.body.xRot = Mth.DEG_TO_RAD * stand.getBodyPose().x(); + this.body.yRot = Mth.DEG_TO_RAD * stand.getBodyPose().y(); + this.body.zRot = Mth.DEG_TO_RAD * stand.getBodyPose().z(); + this.leftArm.xRot = Mth.DEG_TO_RAD * stand.getLeftArmPose().x(); + this.leftArm.yRot = Mth.DEG_TO_RAD * stand.getLeftArmPose().y(); + this.leftArm.zRot = Mth.DEG_TO_RAD * stand.getLeftArmPose().z(); + this.rightArm.xRot = Mth.DEG_TO_RAD * stand.getRightArmPose().x(); + this.rightArm.yRot = Mth.DEG_TO_RAD * stand.getRightArmPose().y(); + this.rightArm.zRot = Mth.DEG_TO_RAD * stand.getRightArmPose().z(); + this.leftLeg.xRot = Mth.DEG_TO_RAD * stand.getLeftLegPose().x(); + this.leftLeg.yRot = Mth.DEG_TO_RAD * stand.getLeftLegPose().y(); + this.leftLeg.zRot = Mth.DEG_TO_RAD * stand.getLeftLegPose().z(); + this.rightLeg.xRot = Mth.DEG_TO_RAD * stand.getRightLegPose().x(); + this.rightLeg.yRot = Mth.DEG_TO_RAD * stand.getRightLegPose().y(); + this.rightLeg.zRot = Mth.DEG_TO_RAD * stand.getRightLegPose().z(); + this.hat.loadPose(this.head.getInitialPose()); } else { - super.setupAnim(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch); - } // TF - Defer to super otherwise + super.setupAnim(state); + } } } diff --git a/src/main/java/twilightforest/client/model/armor/TravellersWingsModel.java b/src/main/java/twilightforest/client/model/armor/TravellersWingsModel.java index 935db1e795..3152e9db63 100644 --- a/src/main/java/twilightforest/client/model/armor/TravellersWingsModel.java +++ b/src/main/java/twilightforest/client/model/armor/TravellersWingsModel.java @@ -7,18 +7,19 @@ import net.minecraft.client.model.geom.ModelPart; import net.minecraft.client.model.geom.PartPose; import net.minecraft.client.model.geom.builders.*; +import net.minecraft.client.renderer.entity.state.HumanoidRenderState; import net.minecraft.util.Mth; import net.minecraft.world.entity.LivingEntity; +import org.jetbrains.annotations.NotNull; import org.joml.Vector3f; import twilightforest.components.entity.TravellersWingsAnimAttachment; import twilightforest.components.entity.TravellersWingsAttachment; import twilightforest.init.TFDataAttachments; import twilightforest.util.TFMathUtil; -import java.util.Collections; import java.util.List; -public class TravellersWingsModel extends HumanoidModel { +public class TravellersWingsModel extends HumanoidModel<@NotNull HumanoidRenderState> { private static final double TAU = 4; // Time (in ticks) in which distance reduces in e times private static final float ANGLE_10_DEG = Mth.PI / 18; private static final Vector3f SMALL_SWING = new Vector3f(8.0F, 8.0F, 8.0F); @@ -167,9 +168,9 @@ protected static void createBelt(PartDefinition root, float deformation) { ); } - public void setupModelAnimations(LivingEntity entity, float f, float f1, double ageInTicks, float netHeadYaw, float headPitch) { + public void setupModelAnimations(LivingEntity entity, double ageInTicks) { this.bodyParts().forEach(modelPart -> modelPart.getAllParts().forEach(ModelPart::resetPose)); - super.setupAnim(entity, f, f1, (float) ageInTicks, netHeadYaw, headPitch); + super.setupAnim(new HumanoidRenderState()); TravellersWingsAnimAttachment animAttachment = entity.getData(TFDataAttachments.TRAVELLERS_WINGS_ANIM); TravellersWingsAttachment attachment = entity.getData(TFDataAttachments.TRAVELLERS_WINGS); @@ -220,7 +221,7 @@ public void setupModelAnimations(LivingEntity entity, float f, float f1, double animAttachment.zRotOld = this.wingBaseRight.zRot; // If the wing model keeps a non-changing offset then looking at it with a spyglass even 4 chunks away will reveal Z-fighting. - float distance = (float) (Math.sqrt(entity.distanceToSqr(this.mainCamera.getPosition())) * PART_OFFSET); + float distance = (float) (Math.sqrt(entity.distanceToSqr(this.mainCamera.position())) * PART_OFFSET); // The below solution is to animate its offset based off of camera distance. The animation is not time-based. int partCount = Math.min(this.wingPartsLeft.size(), this.wingPartsRight.size()); for (int partIndex = 0; partIndex < partCount; partIndex++) { @@ -240,12 +241,6 @@ private Vector3f calculateRotations(TravellersWingsAnimAttachment attachment, do ); } - @Override - protected Iterable headParts() { - return Collections.emptyList(); - } - - @Override protected Iterable bodyParts() { return ImmutableList.of(body, leftLeg, rightLeg); } diff --git a/src/main/java/twilightforest/client/model/block/ReactorDebrisModel.java b/src/main/java/twilightforest/client/model/block/ReactorDebrisModel.java deleted file mode 100644 index 25d2195401..0000000000 --- a/src/main/java/twilightforest/client/model/block/ReactorDebrisModel.java +++ /dev/null @@ -1,39 +0,0 @@ -package twilightforest.client.model.block; - -import com.google.common.base.MoreObjects; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.DelegateBakedModel; -import net.minecraft.core.BlockPos; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; -import net.neoforged.neoforge.client.model.data.ModelData; -import net.neoforged.neoforge.client.model.data.ModelProperty; -import org.jetbrains.annotations.NotNull; -import twilightforest.block.entity.ReactorDebrisBlockEntity; -import twilightforest.client.renderer.block.ReactorDebrisRenderer; - - -public class ReactorDebrisModel extends DelegateBakedModel { - public static final ModelProperty TEXTURE_FOR_PARTICLE = new ModelProperty<>(); - public ReactorDebrisModel(BakedModel defaultModel) { - super(defaultModel); - } - - @Override - public @NotNull ModelData getModelData(BlockAndTintGetter level, BlockPos pos, BlockState state, ModelData modelData) { - if (!(level.getBlockEntity(pos) instanceof ReactorDebrisBlockEntity reactorDebrisBlockEntity) - || !(level instanceof ClientLevel clientLevel)) - return modelData.derive().with(TEXTURE_FOR_PARTICLE, ReactorDebrisBlockEntity.DEFAULT_TEXTURE).build(); - final ResourceLocation textureForParticle = reactorDebrisBlockEntity.textures[clientLevel.random.nextInt(reactorDebrisBlockEntity.textures.length)]; - return modelData.derive().with(TEXTURE_FOR_PARTICLE, textureForParticle).build(); - } - - @Override - public @NotNull TextureAtlasSprite getParticleIcon(ModelData data) { - ResourceLocation texturePath = MoreObjects.firstNonNull(data.get(TEXTURE_FOR_PARTICLE), ReactorDebrisBlockEntity.DEFAULT_TEXTURE); - return ReactorDebrisRenderer.getSprite(texturePath); - } -} diff --git a/src/main/java/twilightforest/client/model/block/aurorablock/NoiseVaryingModelBuilder.java b/src/main/java/twilightforest/client/model/block/aurorablock/NoiseVaryingModelBuilder.java index 74776241bd..235cd28a28 100644 --- a/src/main/java/twilightforest/client/model/block/aurorablock/NoiseVaryingModelBuilder.java +++ b/src/main/java/twilightforest/client/model/block/aurorablock/NoiseVaryingModelBuilder.java @@ -38,11 +38,19 @@ protected NoiseVaryingModelBuilder copyInternal() { @Override public JsonObject toJson(JsonObject json) { JsonObject mainJson = super.toJson(json); - JsonArray variants = new JsonArray(); + this.variants.forEach(Identifier -> variants.add(Identifier.toString())); mainJson.add("variants", variants); + if (mainJson.has("loader")) { + mainJson.remove("loader"); + } + if (mainJson.has("type")) { + mainJson.remove("type"); + } + return mainJson; } + } diff --git a/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsBuilder.java b/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsBuilder.java deleted file mode 100644 index b6548da59f..0000000000 --- a/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsBuilder.java +++ /dev/null @@ -1,17 +0,0 @@ -package twilightforest.client.model.block.carpet; - -import net.neoforged.neoforge.client.model.generators.CustomLoaderBuilder; -import net.neoforged.neoforge.client.model.generators.ModelBuilder; -import net.neoforged.neoforge.common.data.ExistingFileHelper; -import twilightforest.TwilightForestMod; - -public class RoyalRagsBuilder> extends CustomLoaderBuilder { - - protected RoyalRagsBuilder(T parent, ExistingFileHelper existingFileHelper) { - super(TwilightForestMod.prefix("royal_rags"), parent, existingFileHelper, false); - } - - public static > RoyalRagsBuilder begin(T parent, ExistingFileHelper helper) { - return new RoyalRagsBuilder<>(parent, helper); - } -} \ No newline at end of file diff --git a/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModel.java b/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModel.java deleted file mode 100644 index e80e8fce5b..0000000000 --- a/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModel.java +++ /dev/null @@ -1,184 +0,0 @@ -package twilightforest.client.model.block.carpet; - -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.block.model.ItemOverrides; -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.util.RandomSource; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.neoforged.neoforge.client.ChunkRenderTypeSet; -import net.neoforged.neoforge.client.RenderTypeGroup; -import net.neoforged.neoforge.client.model.IDynamicBakedModel; -import net.neoforged.neoforge.client.model.data.ModelData; -import net.neoforged.neoforge.client.model.data.ModelProperty; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import twilightforest.client.model.block.connected.ConnectionLogic; -import twilightforest.init.TFBlocks; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -@SuppressWarnings("deprecation") -public class RoyalRagsModel implements IDynamicBakedModel { - @Nullable - private final List[] baseQuads; - private final BakedQuad[][][] quads; - private final TextureAtlasSprite particle; - private final ItemOverrides overrides; - private final ItemTransforms transforms; - private final ChunkRenderTypeSet blockRenderTypes; - private final List itemRenderTypes; - private final List fabulousItemRenderTypes; - // FIXME Generalize - private final Block[] validConnectors = {TFBlocks.CORONATION_CARPET.value()}; - private static final ModelProperty DATA = new ModelProperty<>(); - - public RoyalRagsModel(@Nullable List[] baseQuads, BakedQuad[][][] quads, TextureAtlasSprite particle, ItemOverrides overrides, ItemTransforms transforms, RenderTypeGroup group) { - this.baseQuads = baseQuads; - this.quads = quads; - this.particle = particle; - this.overrides = overrides; - this.transforms = transforms; - this.blockRenderTypes = !group.isEmpty() ? ChunkRenderTypeSet.of(group.block()) : null; - this.itemRenderTypes = !group.isEmpty() ? List.of(group.entity()) : null; - this.fabulousItemRenderTypes = !group.isEmpty() ? List.of(group.entityFabulous()) : null; - } - - @NotNull - @Override - public List getQuads(@Nullable BlockState state, @Nullable Direction side, @NotNull RandomSource random, @NotNull ModelData extraData, @Nullable RenderType type) { - if (side != null) { - ArrayList quads = new ArrayList<>(4 + (this.baseQuads != null ? 4 : 0)); - if (side.getAxis().isHorizontal()) { - if (this.baseQuads != null) { - quads.addAll(this.baseQuads[side.get2DDataValue()]); - } - } else { - int faceIndex = side.get3DDataValue(); - LoftyCarpetData data = extraData.get(DATA); - for (int quad = 0; quad < 4; ++quad) { - //if our model data is null (I really hope it isn't) we can skip connected textures since we dont have the info we need - //i'd rather do this than crash the game or skip rendering the block entirely - ConnectionLogic connectionType = data != null ? data.logic[faceIndex][quad] : ConnectionLogic.NONE; - quads.add(this.quads[faceIndex][quad][connectionType.ordinal()]); - } - } - - return quads; - } else { - return List.of(); - } - } - - @NotNull - @Override - public ModelData getModelData(@NotNull BlockAndTintGetter getter, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull ModelData modelData) { - LoftyCarpetData data = new LoftyCarpetData(); - - for (Direction face : Direction.values()) { - Direction[] directions = ConnectionLogic.AXIS_PLANE_DIRECTIONS[face.getAxis().ordinal()]; - boolean[] sideStates = new boolean[4]; - - int faceIndex; - for (faceIndex = 0; faceIndex < directions.length; faceIndex++) { - sideStates[faceIndex] = this.shouldConnectSide(getter, pos, face, directions[faceIndex]); - } - - faceIndex = face.get3DDataValue(); - - for (int dir = 0; dir < directions.length; dir++) { - int cornerOffset = (dir + 1) % directions.length; - boolean side1 = sideStates[dir]; - boolean side2 = sideStates[cornerOffset]; - boolean corner = side1 && side2 && this.isCornerBlockPresent(getter, pos, face, directions[dir], directions[cornerOffset]); - data.logic[faceIndex][dir] = dir % 2 == 0 ? ConnectionLogic.of(side1, side2, corner) : ConnectionLogic.of(side2, side1, corner); - } - } - - return modelData.derive().with(DATA, data).build(); - } - - private boolean shouldConnectSide(BlockAndTintGetter getter, BlockPos pos, Direction face, Direction side) { - BlockState neighborState = getter.getBlockState(pos.relative(side)); - return Arrays.stream(this.validConnectors).anyMatch(neighborState::is) && Block.shouldRenderFace(neighborState, getter, pos, face, pos.relative(face)); - } - - private boolean isCornerBlockPresent(BlockAndTintGetter getter, BlockPos pos, Direction face, Direction side1, Direction side2) { - BlockState neighborState = getter.getBlockState(pos.relative(side1).relative(side2)); - return Arrays.stream(this.validConnectors).anyMatch(neighborState::is) && Block.shouldRenderFace(neighborState, getter, pos, face, pos.relative(face)); - } - - @Override - public boolean useAmbientOcclusion() { - return true; - } - - @Override - public boolean isGui3d() { - return true; - } - - @Override - public boolean usesBlockLight() { - return true; - } - - @Override - public boolean isCustomRenderer() { - return false; - } - - @NotNull - @Override - public TextureAtlasSprite getParticleIcon() { - return this.particle; - } - - @NotNull - @Override - public ItemOverrides getOverrides() { - return this.overrides; - } - - @NotNull - @Override - public ItemTransforms getTransforms() { - return this.transforms; - } - - @NotNull - @Override - public ChunkRenderTypeSet getRenderTypes(@NotNull BlockState state, @NotNull RandomSource rand, @NotNull ModelData data) { - return this.blockRenderTypes != null ? this.blockRenderTypes : IDynamicBakedModel.super.getRenderTypes(state, rand, data); - } - - @NotNull - @Override - public List getRenderTypes(@NotNull ItemStack stack, boolean fabulous) { - if (!fabulous) { - if (this.itemRenderTypes != null) { - return this.itemRenderTypes; - } - } else if (this.fabulousItemRenderTypes != null) { - return this.fabulousItemRenderTypes; - } - - return IDynamicBakedModel.super.getRenderTypes(stack, fabulous); - } - - //we need a class to make model data. Fine, here you go - private static final class LoftyCarpetData { - private final ConnectionLogic[][] logic = new ConnectionLogic[6][4]; - - private LoftyCarpetData() { - } - } -} \ No newline at end of file diff --git a/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java b/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java index f73af20a25..3b556fc6ec 100644 --- a/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java +++ b/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java @@ -1,18 +1,12 @@ package twilightforest.client.model.block.carpet; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import net.neoforged.neoforge.client.model.geometry.IGeometryLoader; +import org.jetbrains.annotations.NotNull; +import twilightforest.block.GenericModelLoader; -public class RoyalRagsModelLoader implements IGeometryLoader { - @Deprecated // FIXME: Generalize alongside with CastleDoor models +public class RoyalRagsModelLoader extends GenericModelLoader<@NotNull UnbakedRoyalRagsModel> { public static final RoyalRagsModelLoader INSTANCE = new RoyalRagsModelLoader(); public RoyalRagsModelLoader() { - } - - public UnbakedRoyalRagsModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) throws JsonParseException { - return new UnbakedRoyalRagsModel(); + super(UnbakedRoyalRagsModel::new); } } diff --git a/src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java b/src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java index 9e3452b574..9ee617a39c 100644 --- a/src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java +++ b/src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java @@ -1,61 +1,67 @@ package twilightforest.client.model.block.carpet; -import com.mojang.math.Transformation; -import net.minecraft.client.renderer.block.model.*; +import com.mojang.blaze3d.platform.Transparency; +import net.minecraft.client.renderer.block.dispatch.ModelState; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.Material; import net.minecraft.client.resources.model.ModelBaker; -import net.minecraft.client.resources.model.ModelState; +import net.minecraft.client.resources.model.ModelDebugName; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.geometry.QuadCollection; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.resources.model.sprite.Material; +import net.minecraft.client.resources.model.sprite.TextureSlots; import net.minecraft.core.Direction; import net.minecraft.core.Vec3i; -import net.minecraft.resources.Identifier; -import net.neoforged.neoforge.client.RenderTypeGroup; -import net.neoforged.neoforge.client.model.SimpleModelState; -import net.neoforged.neoforge.client.model.geometry.IGeometryBakingContext; -import net.neoforged.neoforge.client.model.geometry.IUnbakedGeometry; -import net.neoforged.neoforge.client.model.geometry.UnbakedGeometryHelper; -import org.apache.commons.lang3.mutable.MutableObject; import org.joml.Vector3f; import twilightforest.client.model.block.connected.ConnectionLogic; -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.function.Function; +import java.awt.*; //for now, im keeping this hardcoded to a 2 layer block, with the overlay layer being fullbright and tinted. //It might be worth expanding this in the future to be more flexible for other kinds of blocks (1 layer blocks, determining emissivity and tinting per layer, maybe >2 layer blocks?) but for now, I see no point. //I only wanted this system for castle doors after all! -public class UnbakedRoyalRagsModel implements IUnbakedGeometry { - - private final BlockElement[][] baseElements; - private final BlockElement[][][] faceElements; +public class UnbakedRoyalRagsModel implements UnbakedGeometry, UnbakedModel { + private final Vector3f[][][] baseElements; // [horizontal_dir][quad][0 = from, 1 = to] + private final Vector3f[][][][] faceElements; // [up_down_dir][quad][connection_logic][0 = from, 1 = to] public UnbakedRoyalRagsModel() { - //base elements - the side faces without ctm. No Connected Textures on this bit. - //the array is made of horizontal directions (Direction.get2DDataValue) and quads - this.baseElements = new BlockElement[4][4]; - - //face elements - the connected bit of the model. - //the array is made of the directions, quads, and each logic value in the ConnectionLogic class - //Topmost array indexes to up/dpwn directions (Direction.get3DDataValue, down = 0, up = 1) then inside are quads - this.faceElements = new BlockElement[2][4][5]; + // Properly size the arrays to handle the extra [2] dimension at the end for from/to + this.baseElements = new Vector3f[4][4][2]; + this.faceElements = new Vector3f[2][4][5][2]; Vec3i center = new Vec3i(8, 8, 8); for (Direction face : Direction.values()) { Direction[] planeDirections = ConnectionLogic.AXIS_PLANE_DIRECTIONS[face.getAxis().ordinal()]; for (int quad = 0; quad < 4; quad++) { - Vec3i corner = face.getNormal().offset(planeDirections[quad].getNormal()).offset(planeDirections[(quad + 1) % 4].getNormal()).offset(1, 1, 1).multiply(8); - BlockElement element = new BlockElement(new Vector3f((float) Math.min(center.getX(), corner.getX()), (float) Math.min(center.getY(), corner.getY()) / 16f, (float) Math.min(center.getZ(), corner.getZ())), new Vector3f((float) Math.max(center.getX(), corner.getX()), (float) Math.max(center.getY(), corner.getY()) / 16f, (float) Math.max(center.getZ(), corner.getZ())), Map.of(), null, true); + Vec3i vFace = face.getUnitVec3i(); + Vec3i vP1 = planeDirections[quad].getUnitVec3i(); + Vec3i vP2 = planeDirections[(quad + 1) % 4].getUnitVec3i(); + + int cornerX = (vFace.getX() + vP1.getX() + vP2.getX() + 1) * 8; + int cornerY = (vFace.getY() + vP1.getY() + vP2.getY() + 1) * 8; + int cornerZ = (vFace.getZ() + vP1.getZ() + vP2.getZ() + 1) * 8; + + Vector3f from = new Vector3f( + (float) Math.min(center.getX(), cornerX), + (float) Math.min(center.getY(), cornerY) / 16f, + (float) Math.min(center.getZ(), cornerZ) + ); + + Vector3f to = new Vector3f( + (float) Math.max(center.getX(), cornerX), + (float) Math.max(center.getY(), cornerY) / 16f, + (float) Math.max(center.getZ(), cornerZ) + ); if (face.getAxis().isHorizontal()) { - this.baseElements[face.get2DDataValue()][quad] = new BlockElement(element.from, element.to, Map.of(face, new BlockElementFace(face, -1, "", new BlockFaceUV(ConnectionLogic.NONE.remapUVs(element.uvsByFace(face)), 0))), null, true); + this.baseElements[face.get2DDataValue()][quad][0] = from; + this.baseElements[face.get2DDataValue()][quad][1] = to; } else { for (ConnectionLogic connectionType : ConnectionLogic.values()) { - this.faceElements[face.get3DDataValue()][quad][connectionType.ordinal()] = new BlockElement(element.from, element.to, Map.of(face, new BlockElementFace(face, 0, "", new BlockFaceUV(connectionType.remapUVs(element.uvsByFace(face)), 0), null, new MutableObject<>())), null, true); + this.faceElements[face.get3DDataValue()][quad][connectionType.ordinal()][0] = from; + this.faceElements[face.get3DDataValue()][quad][connectionType.ordinal()][1] = to; } } } @@ -63,43 +69,104 @@ public UnbakedRoyalRagsModel() { } @Override - public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, Function spriteGetter, ModelState modelState, ItemOverrides overrides) { - Transformation transformation = context.getRootTransform(); - - if (!transformation.isIdentity()) { - modelState = new SimpleModelState(modelState.getRotation().compose(transformation), modelState.isUvLocked()); - } + public QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName modelDebugName) { + QuadCollection.Builder builder = new QuadCollection.Builder(); - //making an array list like this is cursed, would not recommend - @SuppressWarnings("unchecked") //this is fine, I hope - List[] baseQuads = (List[]) Array.newInstance(List.class, 4); - TextureAtlasSprite baseTexture = spriteGetter.apply(context.getMaterial("wool")); + TextureAtlasSprite baseTexture = modelBaker.materials().resolveSlot(textureSlots, "wool", modelDebugName).sprite(); + TextureAtlasSprite ctmTexture = modelBaker.materials().resolveSlot(textureSlots, "wool_ctm", modelDebugName).sprite(); + TextureAtlasSprite[] textures = new TextureAtlasSprite[]{baseTexture, ctmTexture}; for (Direction direction : Direction.Plane.HORIZONTAL) { - baseQuads[direction.get2DDataValue()] = new ArrayList<>(); + int horSideIndex = direction.get2DDataValue(); + + for (int quad = 0; quad < 4; quad++) { + Vector3f from = this.baseElements[horSideIndex][quad][0]; + Vector3f to = this.baseElements[horSideIndex][quad][1]; + + if (from == null || to == null) continue; - for (BlockElement element : this.baseElements[direction.get2DDataValue()]) { - baseQuads[direction.get2DDataValue()].add(UnbakedGeometryHelper.bakeElementFace(element, element.faces.values().iterator().next(), baseTexture, direction, modelState)); + Material.Baked material = modelBaker.materials().get(textureSlots.getMaterial("wool"), modelDebugName); + BakedQuad bakedQuad = createModernQuad(from, to, direction, material, baseTexture, -1, baseTexture.transparency()); + builder.addUnculledFace(bakedQuad); } } - //we'll use this to figure out which texture to use with the Connected Texture logic - //NONE uses the first one, everything else uses the 2nd one - TextureAtlasSprite[] sprites = new TextureAtlasSprite[]{spriteGetter.apply(context.getMaterial("wool")), spriteGetter.apply(context.getMaterial("wool_ctm"))}; + for (int direction = 0; direction < 2; direction++) { + Direction actualDirection = direction == 0 ? Direction.DOWN: Direction.UP; - BakedQuad[][][] quads = new BakedQuad[2][4][5]; - - for (int dir = 0; dir < 2; dir++) { for (int quad = 0; quad < 4; quad++) { - for (int type = 0; type < 5; type++) { - BlockElement element = this.faceElements[dir][quad][type]; - quads[dir][quad][type] = UnbakedGeometryHelper.bakeElementFace(element, element.faces.values().iterator().next(), ConnectionLogic.values()[type].chooseTexture(sprites), Direction.values()[dir], modelState); + for (int connectionState = 0; connectionState < 5; connectionState++) { + Vector3f from = this.faceElements[direction][quad][connectionState][0]; + Vector3f to = this.faceElements[direction][quad][connectionState][1]; + + if (from == null || to == null) continue; + + TextureAtlasSprite chosenTexture = ConnectionLogic.values()[connectionState].chooseTexture(textures); + + Material.Baked material = modelBaker.materials().get(textureSlots.getMaterial(chosenTexture == baseTexture ? "wool" : "wool_ctm"), modelDebugName); + BakedQuad bakedQuad = createModernQuad(from, to, actualDirection, material, chosenTexture, 0, baseTexture.transparency()); + builder.addCulledFace(actualDirection, bakedQuad); } } } - Identifier renderTypeHint = context.getRenderTypeHint(); - RenderTypeGroup renderTypes = renderTypeHint != null ? context.getRenderType(renderTypeHint) : RenderTypeGroup.EMPTY; - return new RoyalRagsModel(baseQuads, quads, spriteGetter.apply(context.getMaterial("wool")), overrides, context.getTransforms(), renderTypes); + return builder.build(); + } + + private BakedQuad createModernQuad( + Vector3f from, Vector3f to, + Direction direction, + Material.Baked material, + TextureAtlasSprite activeSprite, + int tintIndex, + Transparency transparency) { + + float x0 = from.x(), y0 = from.y(), z0 = from.z(); + float x1 = to.x(), y1 = to.y(), z1 = to.z(); + + Vector3f p0 = new Vector3f(); + Vector3f p1 = new Vector3f(); + Vector3f p2 = new Vector3f(); + Vector3f p3 = new Vector3f(); + + switch (direction) { + case DOWN -> { + p0.set(x0, y0, z0); p1.set(x1, y0, z0); p2.set(x1, y0, z1); p3.set(x0, y0, z1); + } + case UP -> { + p0.set(x0, y1, z1); p1.set(x1, y1, z1); p2.set(x1, y1, z0); p3.set(x0, y1, z0); + } + case NORTH -> { + p0.set(x1, y1, z0); p1.set(x1, y0, z0); p2.set(x0, y0, z0); p3.set(x0, y1, z0); + } + case SOUTH -> { + p0.set(x0, y1, z1); p1.set(x0, y0, z1); p2.set(x1, y0, z1); p3.set(x1, y1, z1); + } + case WEST -> { + p0.set(x0, y1, z0); p1.set(x0, y0, z0); p2.set(x0, y0, z1); p3.set(x0, y1, z1); + } + case EAST -> { + p0.set(x1, y1, z1); p1.set(x1, y0, z1); p2.set(x1, y0, z0); p3.set(x1, y1, z0); + } + } + + float u0 = activeSprite.getU0(), u1 = activeSprite.getU1(); + float v0 = activeSprite.getV0(), v1 = activeSprite.getV1(); + + long uv0 = ((long) Float.floatToRawIntBits(u0) << 32) | (Float.floatToRawIntBits(v0) & 0xFFFFFFFFL); + long uv1 = ((long) Float.floatToRawIntBits(u1) << 32) | (Float.floatToRawIntBits(v0) & 0xFFFFFFFFL); + long uv2 = ((long) Float.floatToRawIntBits(u1) << 32) | (Float.floatToRawIntBits(v1) & 0xFFFFFFFFL); + long uv3 = ((long) Float.floatToRawIntBits(u0) << 32) | (Float.floatToRawIntBits(v1) & 0xFFFFFFFFL); + + BakedQuad.MaterialInfo materialInfo = BakedQuad.MaterialInfo.of( + material, + transparency, + tintIndex, + true, + 0, + true + ); + + return new BakedQuad(p0, p1, p2, p3, uv0, uv1, uv2, uv3, direction, materialInfo); } } \ No newline at end of file diff --git a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureBuilder.java b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureBuilder.java index 5d2acdb209..8776f7e26e 100644 --- a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureBuilder.java +++ b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureBuilder.java @@ -8,6 +8,7 @@ import net.minecraft.tags.TagKey; import net.minecraft.world.level.block.Block; import net.neoforged.neoforge.client.model.generators.template.CustomLoaderBuilder; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; import twilightforest.TwilightForestMod; @@ -17,10 +18,9 @@ @SuppressWarnings("unused") public class ConnectedTextureBuilder extends CustomLoaderBuilder { - private List connectedFaces = new ArrayList<>(); private List connectableBlocks = new ArrayList<>(); - private List> connectableTags = new ArrayList<>(); + private List> connectableTags = new ArrayList<>(); @Nullable private Pair element; private boolean renderOverlayOnAllFaces = true; @@ -80,7 +80,7 @@ public final ConnectedTextureBuilder connectsTo(Block... blocks) { @SuppressWarnings("varargs") @SafeVarargs - public final ConnectedTextureBuilder connectsTo(TagKey... blocks) { + public final ConnectedTextureBuilder connectsTo(TagKey<@NotNull Block>... blocks) { this.connectableTags.addAll(List.of(blocks)); return this; } diff --git a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java index b853ee29c5..0c3de70e8f 100644 --- a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java +++ b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java @@ -1,65 +1,60 @@ package twilightforest.client.model.block.connected; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.dispatch.ModelState; +import net.minecraft.client.resources.model.ModelBaker; +import net.minecraft.client.resources.model.ModelDebugName; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.geometry.QuadCollection; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.resources.model.sprite.TextureSlots; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.util.RandomSource; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; -import net.neoforged.neoforge.client.ChunkRenderTypeSet; -import net.neoforged.neoforge.client.RenderTypeGroup; -import net.neoforged.neoforge.client.model.IDynamicBakedModel; -import net.neoforged.neoforge.client.model.data.ModelData; -import net.neoforged.neoforge.client.model.data.ModelProperty; -import org.jetbrains.annotations.Nullable; +import net.neoforged.neoforge.model.data.ModelData; +import net.neoforged.neoforge.model.data.ModelProperty; +import org.jetbrains.annotations.NotNull; import java.util.*; -public class ConnectedTextureModel implements IDynamicBakedModel { - +public class ConnectedTextureModel implements UnbakedGeometry { private final Set connectedFaces; private final Set unculledFaces; private final boolean renderOverlayOnAllFaces; private final Map baseQuads; private final Map connectedQuads; - private final TextureAtlasSprite particle; - private final boolean usesAO; - private final boolean usesBlockLight; - private final ItemTransforms transforms; - @Nullable - private final ChunkRenderTypeSet blockRenderTypes; - @Nullable - private final RenderType itemRenderType; private final List validConnectors; - private static final ModelProperty DATA = new ModelProperty<>(); + private static final ModelProperty<@NotNull ConnectedTextureData> DATA = new ModelProperty<>(); - public ConnectedTextureModel(Set connectedFaces, Set unculledFaces, boolean renderOverlayOnAllFaces, List connectableBlocks, Map baseQuads, Map connectedQuads, TextureAtlasSprite particle, boolean usesAO, boolean usesBlockLight, ItemTransforms transforms, RenderTypeGroup group) { + public ConnectedTextureModel(Set connectedFaces, Set unculledFaces, boolean renderOverlayOnAllFaces, List connectableBlocks, Map baseQuads, Map connectedQuads) { this.connectedFaces = connectedFaces; this.unculledFaces = unculledFaces; this.renderOverlayOnAllFaces = renderOverlayOnAllFaces; this.validConnectors = connectableBlocks; this.baseQuads = baseQuads; this.connectedQuads = connectedQuads; - this.particle = particle; - this.usesAO = usesAO; - this.usesBlockLight = usesBlockLight; - this.transforms = transforms; - this.blockRenderTypes = !group.isEmpty() ? ChunkRenderTypeSet.of(group.block()) : null; - this.itemRenderType = !group.isEmpty() ? group.entity() : null; } @Override - public List getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource random, ModelData extraData, @Nullable RenderType type) { - if (side == null) { - List quadList = new ArrayList<>(); - for (Direction direction : this.unculledFaces) quadList.addAll(this.getQuadsForFace(direction, extraData)); - return quadList; - } else return this.getQuadsForFace(side, extraData); + public QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName modelDebugName) { + QuadCollection.Builder builder = new QuadCollection.Builder(); + + for (Direction direction : this.unculledFaces) { + List unculledQuads = this.getQuadsForFace(direction, ModelData.EMPTY); + for (BakedQuad quad : unculledQuads) { + builder.addUnculledFace(quad); + } + } + + for (Direction direction : Direction.values()) { + List culledQuads = this.getQuadsForFace(direction, ModelData.EMPTY); + for (BakedQuad quad : culledQuads) { + builder.addCulledFace(direction, quad); + } + } + + return builder.build(); } public List getQuadsForFace(Direction side, ModelData extraData) { @@ -79,33 +74,6 @@ public List getQuadsForFace(Direction side, ModelData extraData) { return quads; } - @Override - public ModelData getModelData(BlockAndTintGetter getter, BlockPos pos, BlockState state, ModelData modelData) { - ConnectedTextureData data = new ConnectedTextureData(); - - for (Direction face : Direction.values()) { - Direction[] directions = ConnectionLogic.AXIS_PLANE_DIRECTIONS[face.getAxis().ordinal()]; - boolean[] sideStates = new boolean[4]; - - int faceIndex; - for (faceIndex = 0; faceIndex < directions.length; faceIndex++) { - sideStates[faceIndex] = this.shouldConnectSide(getter, pos, face, directions[faceIndex]); - } - - faceIndex = face.get3DDataValue(); - - for (int dir = 0; dir < directions.length; dir++) { - int cornerOffset = (dir + 1) % directions.length; - boolean side1 = sideStates[dir]; - boolean side2 = sideStates[cornerOffset]; - boolean corner = side1 && side2 && this.isCornerBlockPresent(getter, pos, face, directions[dir], directions[cornerOffset]); - data.logic[faceIndex][dir] = dir % 2 == 0 ? ConnectionLogic.of(side1, side2, corner) : ConnectionLogic.of(side2, side1, corner); - } - } - - return modelData.derive().with(DATA, data).build(); - } - private boolean shouldConnectSide(BlockAndTintGetter getter, BlockPos pos, Direction face, Direction side) { BlockState neighborState = getter.getBlockState(pos.relative(side)); if (this.unculledFaces.contains(face)) return this.validConnectors.stream().anyMatch(neighborState::is); @@ -118,41 +86,6 @@ private boolean isCornerBlockPresent(BlockAndTintGetter getter, BlockPos pos, Di return this.validConnectors.stream().anyMatch(neighborState::is) && Block.shouldRenderFace(getter, pos.relative(face), neighborState, getter.getBlockState(pos.relative(face)), face); } - @Override - public boolean useAmbientOcclusion() { - return this.usesAO; - } - - @Override - public boolean isGui3d() { - return true; - } - - @Override - public boolean usesBlockLight() { - return this.usesBlockLight; - } - - @Override - public TextureAtlasSprite getParticleIcon() { - return this.particle; - } - - @Override - public ItemTransforms getTransforms() { - return this.transforms; - } - - @Override - public ChunkRenderTypeSet getRenderTypes(BlockState state, RandomSource rand, ModelData data) { - return this.blockRenderTypes != null ? this.blockRenderTypes : IDynamicBakedModel.super.getRenderTypes(state, rand, data); - } - - @Override - public RenderType getRenderType(ItemStack stack) { - return this.itemRenderType != null ? this.itemRenderType : IDynamicBakedModel.super.getRenderType(stack); - } - private static final class ConnectedTextureData { private final ConnectionLogic[][] logic = new ConnectionLogic[6][4]; diff --git a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java index ed8e9188ea..a7a8cc13dd 100644 --- a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java +++ b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java @@ -5,20 +5,21 @@ import net.minecraft.core.Direction; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.tags.TagKey; import net.minecraft.util.GsonHelper; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.neoforged.neoforge.client.model.StandardModelParameters; import net.neoforged.neoforge.client.model.UnbakedModelLoader; +import org.jetbrains.annotations.NotNull; import org.joml.Vector3f; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; -public class ConnectedTextureModelLoader implements UnbakedModelLoader { +public class ConnectedTextureModelLoader implements UnbakedModelLoader<@NotNull UnbakedConnectedTextureModel> { public static final ConnectedTextureModelLoader INSTANCE = new ConnectedTextureModelLoader(); public ConnectedTextureModelLoader() { @@ -45,7 +46,7 @@ public UnbakedConnectedTextureModel read(JsonObject jsonObject, JsonDeserializat EnumSet faces = this.parseEnabledFaces(overlayInfo, "faces"); List connectables = this.parseConnnectableBlocks(jsonObject); - return new UnbakedConnectedTextureModel(element, faces, renderDisabled, connectables, baseTintIndex, baseEmissivity, tintIndex, emissivity, StandardModelParameters.parse(jsonObject, deserializationContext)); + return new UnbakedConnectedTextureModel(element, faces, renderDisabled, connectables, baseEmissivity, emissivity, StandardModelParameters.parse(jsonObject, deserializationContext)); } private EnumSet parseEnabledFaces(JsonObject object, String key) { @@ -75,14 +76,14 @@ private List parseConnnectableBlocks(JsonObject object) { for (JsonElement element : object.getAsJsonArray("connectable_blocks")) { if (element.getAsString().startsWith("#")) { - ResourceLocation tag = ResourceLocation.tryParse(element.getAsString().substring(1)); + Identifier tag = Identifier.tryParse(element.getAsString().substring(1)); if (tag != null) { BuiltInRegistries.BLOCK.getTagOrEmpty(TagKey.create(Registries.BLOCK, tag)).forEach(blockHolder -> blocks.add(blockHolder.value())); } else { throw new JsonParseException("Invalid block tag: " + element.getAsString()); } } else { - Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.tryParse(element.getAsString())); + Block block = BuiltInRegistries.BLOCK.getValue(Identifier.tryParse(element.getAsString())); if (block == Blocks.AIR) { throw new JsonParseException("Invalid block: " + element.getAsString()); } diff --git a/src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java b/src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java index 39b2cf1d6b..b023dcd4df 100644 --- a/src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java +++ b/src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java @@ -59,7 +59,16 @@ public TextureAtlasSprite chooseTexture(TextureAtlasSprite[] sprites) { } public float[] remapUVs(float[] uvs) { - return new float[]{this.getU(uvs[0]), this.getV(uvs[1]), this.getU(uvs[2]), this.getV(uvs[3])}; + if (uvs.length == 2) { + return new float[]{this.getU(uvs[0]), this.getV(uvs[1])}; + } + + if (uvs.length >= 4) { + // Fallback + return new float[]{this.getU(uvs[0]), this.getV(uvs[1]), this.getU(uvs[2]), this.getV(uvs[3])}; + } + + return uvs; } public float getU(float delta) { diff --git a/src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java b/src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java index 7eaf0d2497..748a5e34ca 100644 --- a/src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java +++ b/src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java @@ -1,47 +1,40 @@ package twilightforest.client.model.block.connected; import com.mojang.datafixers.util.Pair; -import com.mojang.math.Transformation; -import net.minecraft.client.renderer.block.model.*; +import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.ModelBaker; -import net.minecraft.client.resources.model.ModelState; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.resources.model.sprite.Material; import net.minecraft.core.Direction; -import net.minecraft.core.Vec3i; -import net.minecraft.util.context.ContextMap; +import net.minecraft.resources.Identifier; +import net.minecraft.util.Mth; import net.minecraft.world.level.block.Block; import net.neoforged.neoforge.client.model.AbstractUnbakedModel; -import net.neoforged.neoforge.client.model.NeoForgeModelProperties; import net.neoforged.neoforge.client.model.StandardModelParameters; -import net.neoforged.neoforge.client.model.UnbakedElementsHelper; +import net.neoforged.neoforge.client.model.quad.MutableQuad; import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; import java.util.*; public class UnbakedConnectedTextureModel extends AbstractUnbakedModel { - protected final boolean renderOverlayOnAllFaces; protected final Set connectedFaces; protected final List connectableBlocks; - protected BlockElement[][] baseElements; - protected BlockElement[][][] connectedElements; - public UnbakedConnectedTextureModel(Pair element, Set connectedFaces, boolean renderOnDisabledFaces, List connectableBlocks, int baseTintIndex, int baseEmissivity, int tintIndex, int emissivity, StandardModelParameters parameters) { + protected MutableQuad[][] baseElements; + protected MutableQuad[][][] connectedElements; + + + public UnbakedConnectedTextureModel(Pair element, Set connectedFaces, boolean renderOnDisabledFaces, List connectableBlocks, int baseEmissivity, int emissivity, StandardModelParameters parameters) { super(parameters); - //a list of block faces that should have connected textures. this.connectedFaces = connectedFaces; - //whether the overlay texture should render on all faces or not. Defaults to true this.renderOverlayOnAllFaces = renderOnDisabledFaces; - //a list of blocks this block can connect its texture to this.connectableBlocks = connectableBlocks; - //base elements - the base block. No Connected Textures on this bit. - //the array is made of the directions and "sections". Each section is a corner quadrant of the block - this.baseElements = new BlockElement[6][4]; - //face elements - the connected bit of the model. - //the array is made of the directions, "sections", and each logic value in the ConnectionLogic class - this.connectedElements = new BlockElement[6][4][5]; + + this.baseElements = new MutableQuad[6][4]; + this.connectedElements = new MutableQuad[6][4][5]; int center = 8; @@ -50,26 +43,65 @@ public UnbakedConnectedTextureModel(Pair element, Set baseQuads = new HashMap<>(); - Set unculledFaces = new HashSet<>(); + String modId = "twilightforest"; - if (textureSlots.getMaterial("base_texture") != null) { - TextureAtlasSprite baseTexture = baker.findSprite(textureSlots, "base_texture"); + Identifier idBase = Identifier.fromNamespaceAndPath(modId, "block/glass"); + Identifier idOverlay = Identifier.fromNamespaceAndPath(modId, "block/glass_overlay"); + Identifier idConnected = Identifier.fromNamespaceAndPath(modId, "block/glass_overlay_connected"); - for (Direction dir : Direction.values()) { - List quadList = new ArrayList<>(); + Material matBase = new Material(idBase); + Material matOverlay = new Material(idOverlay); + Material matConnected = new Material(idConnected); - for (BlockElement element : this.baseElements[dir.get3DDataValue()]) { - quadList.add(FaceBakery.bakeQuad(element.from, element.to, element.faces.get(dir), baseTexture, dir, state, element.rotation, element.shade, element.lightEmission)); - } - baseQuads.put(dir, quadList.toArray(new BakedQuad[0])); - } - } + matBase = matBase.withForceTranslucent(true); + matOverlay = matOverlay.withForceTranslucent(true); + matConnected = matConnected.withForceTranslucent(true); - //we'll use this to figure out which texture to use with the Connected Texture logic - //NONE uses the first one, everything else uses the 2nd one - TextureAtlasSprite[] sprites = new TextureAtlasSprite[]{baker.findSprite(textureSlots, "overlay_texture"), baker.findSprite(textureSlots, "overlay_connected"), baker.findSprite(textureSlots, "particle")}; - if (textureSlots.getMaterial("particle") == null) { - sprites[2] = sprites[0]; - } + TextureAtlasSprite baseTexture = atlas.getSprite(matBase.sprite()); + TextureAtlasSprite overlayTexture = atlas.getSprite(matOverlay.sprite()); + TextureAtlasSprite connectedTexture = atlas.getSprite(matConnected.sprite()); + TextureAtlasSprite particleTexture = overlayTexture; - Map connectedQuads = new HashMap<>(); + TextureAtlasSprite[] sprites = new TextureAtlasSprite[]{overlayTexture, connectedTexture, particleTexture}; + + Map finalBaseQuads = new HashMap<>(); + Map finalConnectedQuads = new HashMap<>(); + Set unculledFaces = new HashSet<>(); for (Direction dir : Direction.values()) { + int dirIdx = dir.get3DDataValue(); + + List baseQuadList = new ArrayList<>(); + for (int i = 0; i < 4; i++) { + MutableQuad quad = this.baseElements[dirIdx][i]; + for (int v = 0; v < 4; v++) { + quad.setUv(v, baseTexture.getU(quad.u(v) * 16f), baseTexture.getV(quad.v(v) * 16f)); + } + baseQuadList.add(quad.toBakedQuad()); + } + finalBaseQuads.put(dir, baseQuadList.toArray(new BakedQuad[0])); + BakedQuad[][] dirQuads = new BakedQuad[4][5]; - for (int quad = 0; quad < 4; quad++) { - for (int type = 0; type < 5; type++) { - BlockElement element = this.connectedElements[dir.get3DDataValue()][quad][type]; - BlockElementFace face = element.faces.get(dir); - if (face.cullForDirection() == null) unculledFaces.add(dir); - dirQuads[quad][type] = FaceBakery.bakeQuad(element.from, element.to, face, ConnectionLogic.values()[type].chooseTexture(sprites), dir, state, element.rotation, element.shade, element.lightEmission); + for (int quadIdx = 0; quadIdx < 4; quadIdx++) { + for (int typeIdx = 0; typeIdx < 5; typeIdx++) { + MutableQuad quad = this.connectedElements[dirIdx][quadIdx][typeIdx]; + + TextureAtlasSprite chosenSprite = ConnectionLogic.values()[typeIdx].chooseTexture(sprites); + + for (int v = 0; v < 4; v++) { + quad.setUv(v, chosenSprite.getU(quad.u(v) * 16f), chosenSprite.getV(quad.v(v) * 16f)); + } + dirQuads[quadIdx][typeIdx] = quad.toBakedQuad(); } } - connectedQuads.put(dir, dirQuads); + finalConnectedQuads.put(dir, dirQuads); } - return new ConnectedTextureModel(this.connectedFaces, unculledFaces, this.renderOverlayOnAllFaces, this.connectableBlocks, baseQuads, connectedQuads, sprites[2], useAmbientOcclusion, usesBlockLight, itemTransforms, this.parameters.renderTypeGroup()); + return new ConnectedTextureModel( + this.connectedFaces, + unculledFaces, + this.renderOverlayOnAllFaces, + this.connectableBlocks, + finalBaseQuads, + finalConnectedQuads + ); } } \ No newline at end of file diff --git a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java index e4a1968854..80e2e99e94 100644 --- a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java +++ b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java @@ -1,22 +1,26 @@ package twilightforest.client.model.block.forcefield; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.block.model.*; +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.dispatch.ModelState; +import net.minecraft.client.renderer.rendertype.RenderType; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.BlockModelRotation; +import net.minecraft.client.resources.model.ModelBaker; +import net.minecraft.client.resources.model.ModelDebugName; +import net.minecraft.client.resources.model.cuboid.ItemTransforms; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.geometry.QuadCollection; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.resources.model.sprite.Material; +import net.minecraft.client.resources.model.sprite.TextureSlots; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.util.RandomSource; +import net.minecraft.resources.Identifier; import net.minecraft.util.StringRepresentable; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.block.state.BlockState; -import net.neoforged.neoforge.client.ChunkRenderTypeSet; -import net.neoforged.neoforge.client.RenderTypeGroup; -import net.neoforged.neoforge.client.model.IDynamicBakedModel; -import net.neoforged.neoforge.client.model.data.ModelData; -import net.neoforged.neoforge.client.model.data.ModelProperty; +import net.neoforged.neoforge.client.model.quad.MutableQuad; +import net.neoforged.neoforge.model.data.ModelData; +import net.neoforged.neoforge.model.data.ModelProperty; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import twilightforest.block.ForceFieldBlock; @@ -24,65 +28,92 @@ import java.util.*; import java.util.function.Function; -public class ForceFieldModel implements IDynamicBakedModel { +public class ForceFieldModel implements UnbakedGeometry { private static final ModelProperty DATA = new ModelProperty<>(); - private final Map parts; - private final Function spriteFunction; - private final TextureAtlasSprite particle; + private final Map parts; + private final Function spriteFunction; private final boolean usesAO; private final boolean usesBlockLight; private final ItemTransforms transforms; @Nullable - private final ChunkRenderTypeSet blockRenderTypes; - @Nullable - private final RenderType itemRenderType; + private final Set renderTypes; - public ForceFieldModel(Map parts, Function spriteFunction, boolean useAmbientOcclusion, boolean usesBlockLight, ItemTransforms itemTransforms, RenderTypeGroup group) { + public ForceFieldModel(Map parts, Function spriteFunction, boolean useAmbientOcclusion, boolean usesBlockLight, ItemTransforms itemTransforms, @Nullable Set renderTypes) { this.parts = parts; this.spriteFunction = spriteFunction; - this.particle = spriteFunction.apply("particle"); this.usesAO = useAmbientOcclusion; this.usesBlockLight = usesBlockLight; this.transforms = itemTransforms; - this.blockRenderTypes = !group.isEmpty() ? ChunkRenderTypeSet.of(group.block()) : null; - this.itemRenderType = !group.isEmpty() ? group.entity() : null; + this.renderTypes = renderTypes; } @Override - public @NotNull List getQuads(@Nullable BlockState state, @Nullable Direction cullFace, @NotNull RandomSource rand, @NotNull ModelData extraData, @Nullable RenderType renderType) { - List quads = new ArrayList<>(); - ForceFieldData data = extraData.get(DATA); - - if (data != null) { - if (cullFace == null) { - for (Direction direction : Direction.values()) { - quads = this.getQuads(quads, direction, data, false); - } - } else return this.getQuads(quads, cullFace, data, true); + public QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName modelDebugName) { + QuadCollection.Builder builder = new QuadCollection.Builder(); + + ForceFieldData defaultData = new ForceFieldData(java.util.Collections.emptyMap()); + + List unculledQuads = new java.util.ArrayList<>(); + for (Direction direction : Direction.values()) { + unculledQuads = this.getQuads(unculledQuads, direction, defaultData); + } + for (BakedQuad quad : unculledQuads) { + builder.addUnculledFace(quad); } - return quads; + for (Direction direction : Direction.values()) { + List culledQuads = new java.util.ArrayList<>(); + culledQuads = this.getQuads(culledQuads, direction, defaultData); + for (BakedQuad quad : culledQuads) { + builder.addCulledFace(direction, quad); + } + } + + return builder.build(); } - public @NotNull List getQuads(List quads, Direction side, ForceFieldData data, boolean cull) { - for (Map.Entry entry : this.parts.entrySet()) { - BlockElementFace blockelementface = entry.getKey().faces.get(side); - if (blockelementface != null && blockelementface.cullForDirection() != null == cull) { - if (ForceFieldModel.skipRender(data.directions(), entry.getValue().direction(), entry.getValue().b(), entry.getValue().parents(), side)) continue; - - TextureAtlasSprite sprite = this.spriteFunction.apply(blockelementface.texture()); - quads.add(FaceBakery.bakeQuad( - entry.getKey().from, - entry.getKey().to, - blockelementface, - sprite, - side, - BlockModelRotation.X0_Y0, - entry.getKey().rotation, - entry.getKey().shade, - entry.getKey().lightEmission) - ); + public List getQuads(List quads, Direction side, ForceFieldData data) { + for (Map.Entry entry : this.parts.entrySet()) { + + if (ForceFieldModel.skipRender(data.directions(), entry.getValue().direction(), entry.getValue().b(), entry.getValue().parents(), side)) { + continue; + } + + String texturePath = this.spriteFunction.apply(entry.getKey() + "_" + side.getName()); + + if (texturePath != null) { + Identifier identifier = Identifier.parse(texturePath); + Material material = new Material(identifier); + + material = material.withForceTranslucent(true); + + TextureAtlasSprite sprite = net.minecraft.client.Minecraft.getInstance() + .getAtlasManager().getAtlasOrThrow(net.minecraft.client.renderer.texture.TextureAtlas.LOCATION_BLOCKS) + .getSprite(material.sprite()); + + MutableQuad mutableQuad = new MutableQuad(); + + for (int vertexIndex = 0; vertexIndex < 4; vertexIndex++) { + float x = (vertexIndex == 1 || vertexIndex == 2) ? 1.0f : 0.0f; + float y = (vertexIndex == 2 || vertexIndex == 3) ? 1.0f : 0.0f; + float z = 0.5f; + + mutableQuad.setPosition(vertexIndex, new org.joml.Vector3f(x, y, z)); + + float u = sprite.getU(x * 16.0f); + float v = sprite.getV(y * 16.0f); + mutableQuad.setUv(vertexIndex, u, v); + } + + mutableQuad.setDirection(side); + mutableQuad.setShade(this.usesAO); + + if (this.usesBlockLight) { + mutableQuad.setLightEmission(15); + } + + quads.add(mutableQuad.toBakedQuad()); } } return quads; @@ -97,7 +128,6 @@ protected static boolean skipRender(Map> directi return false; } - @Override public @NotNull ModelData getModelData(@NotNull BlockAndTintGetter level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull ModelData modelData) { if (modelData == ModelData.EMPTY) { Map> map = new HashMap<>(); @@ -160,43 +190,6 @@ public static List getExtraDirections(BlockState state, BlockGet return directions; } - @Override - public boolean useAmbientOcclusion() { - return this.usesAO; - } - - @Override - public boolean isGui3d() { - return false; - } - - @Override - public boolean usesBlockLight() { - return this.usesBlockLight; - } - - @Override - public TextureAtlasSprite getParticleIcon() { - return this.particle; - } - - @NotNull - @Override - public ItemTransforms getTransforms() { - return this.transforms; - } - - @NotNull - @Override - public ChunkRenderTypeSet getRenderTypes(@NotNull BlockState state, @NotNull RandomSource rand, @NotNull ModelData data) { - return this.blockRenderTypes != null ? this.blockRenderTypes : IDynamicBakedModel.super.getRenderTypes(state, rand, data); - } - - @Override - public RenderType getRenderType(ItemStack stack) { - return this.itemRenderType != null ? this.itemRenderType : IDynamicBakedModel.super.getRenderType(stack); - } - public enum ExtraDirection implements StringRepresentable { DOWN("down", 0, 1, 0), UP("up", 1, 0, 1), @@ -220,8 +213,7 @@ public enum ExtraDirection implements StringRepresentable { SOUTH_WEST("south_west", 17, 16, 14), SOUTH_EAST("south_east", 16, 17, 15); - @SuppressWarnings("deprecation") - public static final EnumCodec CODEC = StringRepresentable.fromEnum(ExtraDirection::values); + public static final EnumCodec<@NotNull ExtraDirection> CODEC = StringRepresentable.fromEnum(ExtraDirection::values); private final String name; private final int xAxisMirror; private final int yAxisMirror; @@ -248,7 +240,7 @@ public ExtraDirection mirrored(Direction.Axis axis) { } @Nullable - public static ExtraDirection byName(@Nullable String name) { + public static ExtraDirection byName(String name) { return CODEC.byName(name); } } diff --git a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java index 67a6b97846..7fefd69044 100644 --- a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java +++ b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java @@ -5,13 +5,9 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.mojang.datafixers.util.Pair; -import net.minecraft.client.renderer.block.model.BlockElement; -import net.minecraft.client.renderer.block.model.BlockElementFace; -import net.minecraft.client.renderer.block.model.BlockElementRotation; -import net.minecraft.client.renderer.block.model.BlockFaceUV; import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.util.Mth; import net.neoforged.neoforge.client.model.ExtraFaceData; import net.neoforged.neoforge.client.model.generators.template.CustomLoaderBuilder; @@ -26,7 +22,6 @@ import java.util.stream.Collectors; public class ForceFieldModelBuilder extends CustomLoaderBuilder { - private boolean defaultShade = true; private int brightnessOverride = 0; private int tint = -1; @@ -79,9 +74,8 @@ protected CustomLoaderBuilder copyInternal() { public JsonObject toJson(JsonObject json) { json = super.toJson(json); if (!this.elements.isEmpty()) { - JsonArray elements = new JsonArray(); + JsonArray elementsArray = new JsonArray(); this.elements.forEach(forceFieldElementBuilder -> { - BlockElement part = forceFieldElementBuilder.build(); JsonObject partObj = new JsonObject(); if (forceFieldElementBuilder.condition != null) { @@ -98,55 +92,63 @@ public JsonObject toJson(JsonObject json) { partObj.add("condition", condition); } - partObj.add("from", serializeVector3f(part.from)); - partObj.add("to", serializeVector3f(part.to)); + partObj.add("from", serializeVector3f(forceFieldElementBuilder.from)); + partObj.add("to", serializeVector3f(forceFieldElementBuilder.to)); - if (part.rotation != null) { + if (forceFieldElementBuilder.rotation != null) { JsonObject rotation = new JsonObject(); - rotation.add("origin", serializeVector3f(part.rotation.origin())); - rotation.addProperty("axis", part.rotation.axis().getSerializedName()); - rotation.addProperty("angle", part.rotation.angle()); - if (part.rotation.rescale()) { + rotation.add("origin", serializeVector3f(forceFieldElementBuilder.rotation.origin)); + rotation.addProperty("axis", forceFieldElementBuilder.rotation.axis.getSerializedName()); + rotation.addProperty("angle", forceFieldElementBuilder.rotation.angle); + if (forceFieldElementBuilder.rotation.rescale) { rotation.addProperty("rescale", true); } partObj.add("rotation", rotation); } - if (!part.shade) { - partObj.addProperty("shade", part.shade); + if (!forceFieldElementBuilder.shade) { + partObj.addProperty("shade", forceFieldElementBuilder.shade); } - if (part.lightEmission != 0) { - partObj.addProperty("light_emission", part.lightEmission); + if (forceFieldElementBuilder.light != 0) { + partObj.addProperty("light", forceFieldElementBuilder.light); } - JsonObject faces = new JsonObject(); - for (Direction dir : Direction.values()) { - BlockElementFace face = part.faces.get(dir); - if (face == null) continue; + JsonObject facesObj = new JsonObject(); + + for (net.minecraft.core.Direction dir : net.minecraft.core.Direction.values()) { + var faceBuilder = forceFieldElementBuilder.faces.get(dir); + if (faceBuilder == null) continue; JsonObject faceObj = new JsonObject(); - faceObj.addProperty("texture", serializeLocOrKey(face.texture())); - if (!Arrays.equals(face.uv().uvs, part.uvsByFace(dir))) { - faceObj.add("uv", new Gson().toJsonTree(face.uv().uvs)); + + faceObj.addProperty("texture", serializeLocOrKey(faceBuilder.texture)); + + if (faceBuilder.uvs != null) { + faceObj.add("uvs", new Gson().toJsonTree(faceBuilder.uvs)); } - if (face.cullForDirection() != null) { - faceObj.addProperty("cullface", face.cullForDirection().getSerializedName()); + + if (faceBuilder.cullface != null) { + faceObj.addProperty("cullface", faceBuilder.cullface.getSerializedName()); } - if (face.uv().rotation != 0) { - faceObj.addProperty("rotation", face.uv().rotation); + + if (faceBuilder.rotation.rotation != 0) { + faceObj.addProperty("rotation", faceBuilder.rotation.rotation); } - if (face.tintIndex() != -1) { - faceObj.addProperty("tintindex", face.tintIndex()); + + if (faceBuilder.tintindex != -1) { + faceObj.addProperty("tintindex", faceBuilder.tintindex); } - faces.add(dir.getSerializedName(), faceObj); + + facesObj.add(dir.getSerializedName(), faceObj); } - if (!part.faces.isEmpty()) { - partObj.add("faces", faces); + + if (!forceFieldElementBuilder.faces.isEmpty()) { + partObj.add("faces", facesObj); } - elements.add(partObj); + elementsArray.add(partObj); }); - json.add("elements", elements); + json.add("elements", elementsArray); } return json; } @@ -155,7 +157,7 @@ private static String serializeLocOrKey(String tex) { if (tex.charAt(0) == '#') { return tex; } - return ResourceLocation.parse(tex).toString(); + return Identifier.parse(tex).toString(); } private static JsonArray serializeVector3f(Vector3f vec) { @@ -288,14 +290,6 @@ private BiConsumer addTexture(S return (direction, builder) -> builder.texture(texture); } - BlockElement build() { - Map faces = this.faces.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().build(), (direction, face) -> { - throw new IllegalArgumentException(); - }, LinkedHashMap::new)); - return new BlockElement(this.from, this.to, faces, this.rotation == null ? null : this.rotation.build(), this.shade, this.light, ExtraFaceData.DEFAULT); - } - public ForceFieldModelBuilder end() { return self(); } @@ -340,13 +334,6 @@ public ForceFieldElementBuilder.FaceBuilder rotation(FaceRotation rot) { return this; } - BlockElementFace build() { - if (this.texture == null) { - throw new IllegalStateException("A model face must have a texture"); - } - return new BlockElementFace(this.cullface, this.tintindex, this.texture, new BlockFaceUV(this.uvs, this.rotation.rotation), ExtraFaceData.DEFAULT, new MutableObject<>()); - } - public ForceFieldElementBuilder end() { return ForceFieldElementBuilder.this; } @@ -384,12 +371,6 @@ public ForceFieldElementBuilder.RotationBuilder rescale(boolean rescale) { return this; } - BlockElementRotation build() { - Preconditions.checkNotNull(this.origin, "No origin specified"); - Preconditions.checkNotNull(this.axis, "No axis specified"); - return new BlockElementRotation(this.origin, this.axis, this.angle, this.rescale); - } - public ForceFieldElementBuilder end() { return ForceFieldElementBuilder.this; } diff --git a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java index 46bb236fb5..7588ceae6f 100644 --- a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java +++ b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java @@ -4,9 +4,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import net.minecraft.client.renderer.block.model.BlockElement; import net.minecraft.util.GsonHelper; -import net.neoforged.neoforge.client.model.NeoForgeModelProperties; import net.neoforged.neoforge.client.model.StandardModelParameters; import net.neoforged.neoforge.client.model.UnbakedModelLoader; import org.jetbrains.annotations.Nullable; @@ -23,10 +21,10 @@ public class ForceFieldModelLoader implements UnbakedModelLoader elementsAndConditions = new HashMap<>(); + Map elementsAndConditions = new HashMap<>(); if (json.has("elements")) { + int elementIndex = 0; for (JsonElement jsonElement : GsonHelper.getAsJsonArray(json, "elements")) { ExtraDirection direction = null; boolean b = false; @@ -40,8 +38,12 @@ public UnbakedForceFieldModel read(JsonObject json, JsonDeserializationContext c parents.add(ForceFieldModel.ExtraDirection.byName(parentElement.getAsString())); } } + + String elementName = element.has("name") ? GsonHelper.getAsString(element, "name") : "element_" + elementIndex; + + elementsAndConditions.put(elementName, new Condition(direction, b, parents)); + elementIndex++; } - elementsAndConditions.put(context.deserialize(jsonElement, BlockElement.class), new Condition(direction, b, parents)); } } diff --git a/src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java b/src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java index 4c2cf16f46..0f725785d6 100644 --- a/src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java +++ b/src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java @@ -1,28 +1,30 @@ package twilightforest.client.model.block.forcefield; -import net.minecraft.client.renderer.block.model.BlockElement; -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.renderer.block.model.TextureSlots; -import net.minecraft.client.resources.model.*; -import net.minecraft.util.context.ContextMap; -import net.neoforged.neoforge.client.RenderTypeGroup; +import net.minecraft.client.renderer.rendertype.RenderTypes; +import net.minecraft.client.resources.model.cuboid.ItemTransforms; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; import net.neoforged.neoforge.client.model.AbstractUnbakedModel; -import net.neoforged.neoforge.client.model.ExtendedUnbakedModel; import net.neoforged.neoforge.client.model.StandardModelParameters; - import java.util.Map; public class UnbakedForceFieldModel extends AbstractUnbakedModel { - private final Map elementsAndConditions; + private final Map elementsAndConditions; - public UnbakedForceFieldModel(Map elementsAndConditions, StandardModelParameters parameters) { + public UnbakedForceFieldModel(Map elementsAndConditions, StandardModelParameters parameters) { super(parameters); this.elementsAndConditions = elementsAndConditions; } @Override - public BakedModel bake(TextureSlots textures, ModelBaker baker, ModelState modelState, boolean useAmbientOcclusion, boolean usesBlockLight, ItemTransforms itemTransforms, ContextMap additionalProperties) { - return new ForceFieldModel(this.elementsAndConditions, s -> baker.findSprite(textures, s), useAmbientOcclusion, usesBlockLight, itemTransforms, this.parameters.renderTypeGroup()); + public UnbakedGeometry geometry() { + return new ForceFieldModel( + this.elementsAndConditions, + (String textureKey) -> textureKey, + Boolean.TRUE.equals(this.parameters.ambientOcclusion()), + this.parameters.guiLight().lightLikeBlock(), + ItemTransforms.NO_TRANSFORMS, + java.util.Set.of(RenderTypes.translucentMovingBlock()) + ); } } diff --git a/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockBuilder.java b/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockBuilder.java index a8ecaa1d0a..9cc3b3f04a 100644 --- a/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockBuilder.java +++ b/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockBuilder.java @@ -1,5 +1,6 @@ package twilightforest.client.model.block.giantblock; +import com.google.gson.JsonObject; import net.neoforged.neoforge.client.model.generators.template.CustomLoaderBuilder; import twilightforest.TwilightForestMod; @@ -17,4 +18,18 @@ public GiantBlockBuilder() { protected CustomLoaderBuilder copyInternal() { return new GiantBlockBuilder(); } + + @Override + public JsonObject toJson(JsonObject json) { + JsonObject mainJson = super.toJson(json); + + if (mainJson.has("loader")) { + mainJson.remove("loader"); + } + if (mainJson.has("type")) { + mainJson.remove("type"); + } + + return mainJson; + } } diff --git a/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockModel.java b/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockModel.java index ddf913910a..f1c830fd0c 100644 --- a/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockModel.java +++ b/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockModel.java @@ -14,7 +14,6 @@ import java.util.List; public class GiantBlockModel implements BlockStateModel, DynamicBlockStateModel { - private final BlockStateModel[] voxels; public GiantBlockModel(BlockStateModel[] voxels) { diff --git a/src/main/java/twilightforest/client/model/block/patch/PatchBuilder.java b/src/main/java/twilightforest/client/model/block/patch/PatchBuilder.java index 5160a6db0c..ff7cfc8c09 100644 --- a/src/main/java/twilightforest/client/model/block/patch/PatchBuilder.java +++ b/src/main/java/twilightforest/client/model/block/patch/PatchBuilder.java @@ -1,12 +1,10 @@ package twilightforest.client.model.block.patch; -import com.google.gson.JsonArray; import com.google.gson.JsonObject; import net.neoforged.neoforge.client.model.generators.template.CustomLoaderBuilder; import twilightforest.TwilightForestMod; public class PatchBuilder extends CustomLoaderBuilder { - private boolean shaggify = false; public PatchBuilder() { diff --git a/src/main/java/twilightforest/client/model/block/patch/PatchModel.java b/src/main/java/twilightforest/client/model/block/patch/PatchModel.java index 76cc54a379..95892beeb5 100644 --- a/src/main/java/twilightforest/client/model/block/patch/PatchModel.java +++ b/src/main/java/twilightforest/client/model/block/patch/PatchModel.java @@ -1,64 +1,39 @@ package twilightforest.client.model.block.patch; import com.google.common.collect.ImmutableList; -import com.mojang.math.Transformation; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.block.model.*; +import net.minecraft.client.renderer.block.dispatch.ModelState; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelBaker; +import net.minecraft.client.resources.model.ModelDebugName; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.geometry.QuadCollection; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.resources.model.sprite.TextureSlots; import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; import net.minecraft.util.RandomSource; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.structure.BoundingBox; -import net.neoforged.neoforge.client.ChunkRenderTypeSet; -import net.neoforged.neoforge.client.RenderTypeGroup; -import net.neoforged.neoforge.client.model.IDynamicBakedModel; -import net.neoforged.neoforge.client.model.SimpleModelState; -import net.neoforged.neoforge.client.model.StandardModelParameters; -import net.neoforged.neoforge.client.model.data.ModelData; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.joml.Vector3f; +import net.neoforged.neoforge.client.model.quad.MutableQuad; import twilightforest.block.PatchBlock; -import twilightforest.client.model.block.connected.UnbakedConnectedTextureModel; -import twilightforest.init.TFBlocks; import java.util.ArrayList; import java.util.List; -public class PatchModel implements BakedModel { - - private final TextureAtlasSprite texture; +public class PatchModel implements UnbakedGeometry { private final boolean shaggify; - private final TextureAtlasSprite particle; - private final boolean usesAO; - private final boolean usesBlockLight; - private final ItemTransforms transforms; - @Nullable - private final ChunkRenderTypeSet blockRenderTypes; - @Nullable - private final RenderType itemRenderType; - - public PatchModel(TextureAtlasSprite texture, boolean shaggify, TextureAtlasSprite particle, boolean usesAO, boolean usesBlockLight, ItemTransforms transforms, RenderTypeGroup group) { + + private TextureAtlasSprite texture; + private boolean usesAO; + private boolean usesBlockLight; + + public PatchModel(boolean shaggify) { + this.shaggify = shaggify; + } + + public PatchModel(TextureAtlasSprite texture, boolean shaggify, boolean usesAO, boolean usesBlockLight) { this.texture = texture; this.shaggify = shaggify; - this.particle = particle; this.usesAO = usesAO; this.usesBlockLight = usesBlockLight; - this.transforms = transforms; - this.blockRenderTypes = !group.isEmpty() ? ChunkRenderTypeSet.of(group.block()) : null; - this.itemRenderType = !group.isEmpty() ? group.entity() : null; - } - - @Override - public List getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource random) { - if (state == null) - return this.getQuads(false, false, false, false, random); - else - return this.getQuads(state.getValue(PatchBlock.NORTH), state.getValue(PatchBlock.EAST), state.getValue(PatchBlock.SOUTH), state.getValue(PatchBlock.WEST), random); } private List getQuads(boolean north, boolean east, boolean south, boolean west, RandomSource posRandom) { @@ -173,50 +148,50 @@ private void quadsFromAABB(List quads, float minX, float minY, float } private BakedQuad quadFromVectors(Direction direction, float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { - BlockElementFace face = new BlockElementFace(null, 0, this.texture.atlasLocation().toString(), switch (direction) { - case NORTH -> new BlockFaceUV(new float[]{maxX, minZ + 1f, minX, minZ}, 0); - case EAST -> new BlockFaceUV(new float[]{maxX, minZ, maxX - 1f, maxZ}, 90); - case SOUTH -> new BlockFaceUV(new float[]{minX, maxZ, maxX, maxZ - 1f}, 0); - case WEST -> new BlockFaceUV(new float[]{minX, maxZ, minX + 1f, minZ}, 90); - default -> new BlockFaceUV(new float[]{minX, minZ, maxX, maxZ}, 0); - }); - - return FaceBakery.bakeQuad(new Vector3f(minX, minY, minZ), new Vector3f(maxX, maxY, maxZ), face, this.texture, direction, new SimpleModelState(Transformation.identity()), null, true, 0); - } + MutableQuad mutableQuad = new MutableQuad(); - @Override - public boolean useAmbientOcclusion() { - return this.usesAO; - } + mutableQuad.setDirection(direction); + mutableQuad.setShade(this.usesAO); - @Override - public boolean isGui3d() { - return false; - } + if (this.usesBlockLight) { + mutableQuad.setLightEmission(15); + } - @Override - public boolean usesBlockLight() { - return this.usesBlockLight; - } + for (int v = 0; v < 4; v++) { + float x = (v == 1 || v == 2) ? maxX / 16.0f : minX / 16.0f; + float y = (v == 2 || v == 3) ? maxY / 16.0f : minY / 16.0f; + float z = (direction.getAxis() == net.minecraft.core.Direction.Axis.Z) ? maxZ / 16.0f : minZ / 16.0f; - @Override - public ItemTransforms getTransforms() { - return this.transforms; - } + mutableQuad.setPosition(v, new org.joml.Vector3f(x, y, z)); - @Override - public TextureAtlasSprite getParticleIcon() { - return this.particle; - } + float u = this.texture.getU(x * 16.0f); + float vCoord = this.texture.getV(y * 16.0f); - @NotNull - @Override - public ChunkRenderTypeSet getRenderTypes(@NotNull BlockState state, @NotNull RandomSource rand, @NotNull ModelData data) { - return this.blockRenderTypes != null ? this.blockRenderTypes : BakedModel.super.getRenderTypes(state, rand, data); + if (direction == net.minecraft.core.Direction.EAST || direction == net.minecraft.core.Direction.WEST) { + mutableQuad.setUv(v, vCoord, u); + } else { + mutableQuad.setUv(v, u, vCoord); + } + } + + return mutableQuad.toBakedQuad(); } @Override - public RenderType getRenderType(ItemStack stack) { - return this.itemRenderType != null ? this.itemRenderType : BakedModel.super.getRenderType(stack); + public QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName modelDebugName) { + QuadCollection.Builder builder = new QuadCollection.Builder(); + + RandomSource staticRandom = RandomSource.create(42L); + List myPatchQuads = this.getQuads(false, false, false, false, staticRandom); + + for (BakedQuad quad : myPatchQuads) { + if (quad.direction() != null) { + builder.addCulledFace(quad.direction(), quad); + } else { + builder.addUnculledFace(quad); + } + } + + return builder.build(); } } diff --git a/src/main/java/twilightforest/client/model/block/patch/PatchModelLoader.java b/src/main/java/twilightforest/client/model/block/patch/PatchModelLoader.java index 0d6db0059c..0a4e1f04c2 100644 --- a/src/main/java/twilightforest/client/model/block/patch/PatchModelLoader.java +++ b/src/main/java/twilightforest/client/model/block/patch/PatchModelLoader.java @@ -4,12 +4,11 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.mojang.realmsclient.util.JsonUtils; -import net.minecraft.resources.ResourceLocation; -import net.neoforged.neoforge.client.model.NeoForgeModelProperties; import net.neoforged.neoforge.client.model.StandardModelParameters; import net.neoforged.neoforge.client.model.UnbakedModelLoader; +import org.jetbrains.annotations.NotNull; -public final class PatchModelLoader implements UnbakedModelLoader { +public final class PatchModelLoader implements UnbakedModelLoader<@NotNull UnbakedPatchModel> { public static final PatchModelLoader INSTANCE = new PatchModelLoader(); private PatchModelLoader() { diff --git a/src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java b/src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java index 0def27c9a2..a82445d6a7 100644 --- a/src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java +++ b/src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java @@ -1,15 +1,10 @@ package twilightforest.client.model.block.patch; -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.renderer.block.model.TextureSlots; -import net.minecraft.client.resources.model.*; -import net.minecraft.util.context.ContextMap; -import net.neoforged.neoforge.client.RenderTypeGroup; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; import net.neoforged.neoforge.client.model.AbstractUnbakedModel; import net.neoforged.neoforge.client.model.StandardModelParameters; public class UnbakedPatchModel extends AbstractUnbakedModel { - private final boolean shaggify; public UnbakedPatchModel(boolean shaggify, StandardModelParameters parameters) { @@ -18,7 +13,7 @@ public UnbakedPatchModel(boolean shaggify, StandardModelParameters parameters) { } @Override - public BakedModel bake(TextureSlots textureSlots, ModelBaker baker, ModelState modelState, boolean hasAmbientOcclusion, boolean useBlockLight, ItemTransforms transforms, ContextMap additionalProperties) { - return new PatchModel(baker.findSprite(textureSlots, "texture"), this.shaggify, baker.findSprite(textureSlots, "particle"), hasAmbientOcclusion, useBlockLight, transforms, this.parameters.renderTypeGroup()); + public UnbakedGeometry geometry() { + return new PatchModel(this.shaggify); } } diff --git a/src/main/java/twilightforest/client/model/entity/HostileWolfModel.java b/src/main/java/twilightforest/client/model/entity/HostileWolfModel.java index a810bb836c..fabf39059e 100644 --- a/src/main/java/twilightforest/client/model/entity/HostileWolfModel.java +++ b/src/main/java/twilightforest/client/model/entity/HostileWolfModel.java @@ -7,11 +7,11 @@ import net.minecraft.client.renderer.rendertype.RenderTypes; import net.minecraft.resources.Identifier; import net.minecraft.util.Mth; +import org.jetbrains.annotations.NotNull; import java.util.function.Function; -public class HostileWolfModel extends EntityModel { - +public class HostileWolfModel extends EntityModel<@NotNull T> { private final ModelPart head; private final ModelPart body; private final ModelPart rightHindLeg; @@ -26,7 +26,7 @@ public HostileWolfModel(ModelPart root) { } public HostileWolfModel(Function type, ModelPart root) { - super(type, false, 5.0F, 2.0F, 2.0F, 2.0F, 24.0F); + super(root, type); this.head = root.getChild("head"); this.body = root.getChild("body"); this.upperBody = root.getChild("upper_body"); diff --git a/src/main/java/twilightforest/client/model/entity/LichMinionModel.java b/src/main/java/twilightforest/client/model/entity/LichMinionModel.java deleted file mode 100644 index 6e5fd76ba0..0000000000 --- a/src/main/java/twilightforest/client/model/entity/LichMinionModel.java +++ /dev/null @@ -1,32 +0,0 @@ -package twilightforest.client.model.entity; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import net.minecraft.client.model.ZombieModel; -import net.minecraft.client.model.geom.ModelPart; -import net.minecraft.util.FastColor; -import net.minecraft.world.effect.MobEffects; -import twilightforest.entity.monster.LichMinion; - -public class LichMinionModel extends ZombieModel { - - private boolean hasStrength; - - public LichMinionModel(ModelPart root) { - super(root); - } - - @Override - public void prepareMobModel(LichMinion entity, float limbSwing, float limbSwingAmount, float partialTicks) { - this.hasStrength = entity.getEffect(MobEffects.DAMAGE_BOOST) != null; - } - - @Override - public void renderToBuffer(PoseStack stack, VertexConsumer builder, int light, int overlay, int color) { - if (this.hasStrength) { - super.renderToBuffer(stack, builder, light, overlay, FastColor.ARGB32.color(FastColor.ARGB32.alpha(color), (int) (FastColor.ARGB32.red(color) * 0.25F), FastColor.ARGB32.green(color), (int) (FastColor.ARGB32.blue(color) * 0.25F))); - } else { - super.renderToBuffer(stack, builder, light, overlay, FastColor.ARGB32.color(FastColor.ARGB32.alpha(color), (int) (FastColor.ARGB32.red(color) * 0.5F), FastColor.ARGB32.green(color), (int) (FastColor.ARGB32.blue(color) * 0.5F))); - } - } -} diff --git a/src/main/java/twilightforest/client/model/entity/LowerGoblinKnightModel.java b/src/main/java/twilightforest/client/model/entity/LowerGoblinKnightModel.java index dd29842f78..38c67fc211 100644 --- a/src/main/java/twilightforest/client/model/entity/LowerGoblinKnightModel.java +++ b/src/main/java/twilightforest/client/model/entity/LowerGoblinKnightModel.java @@ -6,9 +6,10 @@ import net.minecraft.client.model.geom.PartPose; import net.minecraft.client.model.geom.builders.*; import net.minecraft.util.Mth; +import org.jetbrains.annotations.NotNull; import twilightforest.client.state.entity.LowerGoblinKnightRenderState; -public class LowerGoblinKnightModel extends HumanoidModel { +public class LowerGoblinKnightModel extends HumanoidModel<@NotNull LowerGoblinKnightRenderState> { private final ModelPart tunic; diff --git a/src/main/java/twilightforest/client/model/entity/LoyalZombieModel.java b/src/main/java/twilightforest/client/model/entity/LoyalZombieModel.java index b03f722c97..4b4d385f21 100644 --- a/src/main/java/twilightforest/client/model/entity/LoyalZombieModel.java +++ b/src/main/java/twilightforest/client/model/entity/LoyalZombieModel.java @@ -5,25 +5,22 @@ import net.minecraft.client.model.AnimationUtils; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.geom.ModelPart; -import net.minecraft.util.FastColor; +import net.minecraft.util.ARGB; import net.minecraft.util.Mth; -import twilightforest.entity.monster.LoyalZombie; - -/** - * [VanillaCopy] {@link net.minecraft.client.model.AbstractZombieModel} due to generic restrictions - */ -public class LoyalZombieModel extends HumanoidModel { +import net.minecraft.client.renderer.entity.state.HumanoidRenderState; +import org.jetbrains.annotations.NotNull; +public class LoyalZombieModel extends HumanoidModel { public LoyalZombieModel(ModelPart part) { super(part); } @Override - public void setupAnim(LoyalZombie e, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) { - super.setupAnim(e, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch); - boolean flag = e.isAggressive(); - float f = Mth.sin(this.attackTime * Mth.PI); - float f1 = Mth.sin((1.0F - (1.0F - this.attackTime) * (1.0F - this.attackTime)) * Mth.PI); + public void setupAnim(LoyalZombieRenderState state) { + super.setupAnim(state); + boolean flag = state.isAggressive; + float f = Mth.sin(state.attackTime * Mth.PI); + float f1 = Mth.sin((1.0F - (1.0F - state.attackTime) * (1.0F - state.attackTime)) * Mth.PI); this.rightArm.zRot = 0.0F; this.leftArm.zRot = 0.0F; this.rightArm.yRot = -(0.1F - f * 0.6F); @@ -33,12 +30,16 @@ public void setupAnim(LoyalZombie e, float limbSwing, float limbSwingAmount, flo this.leftArm.xRot = f2; this.rightArm.xRot += f * 1.2F - f1 * 0.4F; this.leftArm.xRot += f * 1.2F - f1 * 0.4F; - AnimationUtils.bobArms(this.rightArm, this.leftArm, ageInTicks); + AnimationUtils.bobArms(this.rightArm, this.leftArm, state.ageScale); } @Override public void renderToBuffer(PoseStack stack, VertexConsumer builder, int light, int overlay, int color) { - // GREEEEN - super.renderToBuffer(stack, builder, light, overlay, FastColor.ARGB32.color(FastColor.ARGB32.alpha(color), (int) (FastColor.ARGB32.red(color) * 0.25F), FastColor.ARGB32.green(color), (int) (FastColor.ARGB32.blue(color) * 0.25F))); + int greenColor = ARGB.color(ARGB.alpha(color), (int) (ARGB.red(color) * 0.25F), ARGB.green(color), (int) (ARGB.blue(color) * 0.25F)); + super.renderToBuffer(stack, builder, light, overlay, greenColor); + } + + public static class LoyalZombieRenderState extends HumanoidRenderState { + public boolean isAggressive; } } diff --git a/src/main/java/twilightforest/client/model/entity/UpperGoblinKnightModel.java b/src/main/java/twilightforest/client/model/entity/UpperGoblinKnightModel.java index 30634c0a45..b410af5c1f 100644 --- a/src/main/java/twilightforest/client/model/entity/UpperGoblinKnightModel.java +++ b/src/main/java/twilightforest/client/model/entity/UpperGoblinKnightModel.java @@ -9,10 +9,10 @@ import net.minecraft.client.model.geom.builders.MeshDefinition; import net.minecraft.client.model.geom.builders.PartDefinition; import net.minecraft.util.Mth; +import org.jetbrains.annotations.NotNull; import twilightforest.client.state.entity.UpperGoblinKnightRenderState; -public class UpperGoblinKnightModel extends HumanoidModel { - +public class UpperGoblinKnightModel extends HumanoidModel<@NotNull UpperGoblinKnightRenderState> { private final ModelPart breastplate; private final ModelPart shield; @@ -26,9 +26,11 @@ public static LayerDefinition create() { MeshDefinition meshdefinition = new MeshDefinition(); PartDefinition partdefinition = meshdefinition.getRoot(); - partdefinition.addOrReplaceChild("head", CubeListBuilder.create(), + var head = partdefinition.addOrReplaceChild("head", CubeListBuilder.create(), PartPose.offset(0.0F, 12.0F, 0.0F)); + head.addOrReplaceChild("hat", CubeListBuilder.create(), PartPose.ZERO); + var hat = partdefinition.addOrReplaceChild("hat", CubeListBuilder.create(), PartPose.offset(0.0F, 12.0F, 0.0F)); diff --git a/src/main/java/twilightforest/client/model/item/TrollsteinnModel.java b/src/main/java/twilightforest/client/model/item/TrollsteinnModel.java deleted file mode 100644 index d880eab3e9..0000000000 --- a/src/main/java/twilightforest/client/model/item/TrollsteinnModel.java +++ /dev/null @@ -1,50 +0,0 @@ -package twilightforest.client.model.item; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.renderer.block.model.ItemOverrides; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.ModelResourceLocation; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.item.ItemStack; -import net.neoforged.neoforge.client.model.BakedModelWrapper; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import twilightforest.TwilightForestMod; -import twilightforest.block.TrollsteinnBlock; - -public class TrollsteinnModel extends BakedModelWrapper { - public static final ModelResourceLocation LIT_TROLLSTEINN = ModelResourceLocation.standalone(TwilightForestMod.prefix("item/trollsteinn_light")); - @Nullable - private BakedModel litTrollsteinnModel; - private final ItemOverrides overrides = new ItemOverrides() { - @Override - public BakedModel resolve(@NotNull BakedModel model, @NotNull ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed) { - if (TrollsteinnModel.this.litTrollsteinnModel == null) - TrollsteinnModel.this.litTrollsteinnModel = Minecraft.getInstance().getModelManager().getModel(LIT_TROLLSTEINN); - - Entity itemEntity = (entity == null) ? stack.getEntityRepresentation() : entity; - - if (level == null || itemEntity == null) { - return super.resolve(TrollsteinnModel.this.originalModel, stack, level, entity, seed); - } - - int brightness = level.getMaxLocalRawBrightness(itemEntity.blockPosition(), level.getSkyDarken()); - if (brightness > TrollsteinnBlock.LIGHT_THRESHOLD) { - return super.resolve(TrollsteinnModel.this.litTrollsteinnModel, stack, level, entity, seed); - } else { - return super.resolve(TrollsteinnModel.this.originalModel, stack, level, entity, seed); - } - } - }; - - public TrollsteinnModel(BakedModel originalModel) { - super(originalModel); - } - - @Override - public ItemOverrides getOverrides() { - return overrides; - } -} From 6e1e25690f385d7fd189a064096598258c487cb1 Mon Sep 17 00:00:00 2001 From: Albazavr Date: Sun, 5 Jul 2026 03:25:00 +0300 Subject: [PATCH 02/18] Removed every @NotNull and unnecessary line change --- .../twilightforest/client/model/armor/TFArmorModel.java | 4 ++-- .../client/model/armor/TravellersWingsModel.java | 3 +-- .../client/model/block/carpet/RoyalRagsModelLoader.java | 3 +-- .../model/block/connected/ConnectedTextureBuilder.java | 6 +++--- .../model/block/connected/ConnectedTextureModel.java | 1 + .../model/block/connected/ConnectedTextureModelLoader.java | 3 +-- .../block/connected/UnbakedConnectedTextureModel.java | 1 + .../client/model/block/forcefield/ForceFieldModel.java | 5 ++--- .../model/block/forcefield/ForceFieldModelBuilder.java | 4 +--- .../model/block/forcefield/ForceFieldModelLoader.java | 1 + .../model/block/forcefield/UnbakedForceFieldModel.java | 1 + .../client/model/block/giantblock/GiantBlockModel.java | 1 + .../client/model/block/patch/PatchBuilder.java | 1 + .../client/model/block/patch/PatchModel.java | 1 + .../client/model/block/patch/PatchModelLoader.java | 3 +-- .../client/model/block/patch/UnbakedPatchModel.java | 1 + .../client/model/entity/HostileWolfModel.java | 4 ++-- .../client/model/entity/LowerGoblinKnightModel.java | 3 +-- .../client/model/entity/LoyalZombieModel.java | 7 +++++-- .../client/model/entity/UpperGoblinKnightModel.java | 4 ++-- 20 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/main/java/twilightforest/client/model/armor/TFArmorModel.java b/src/main/java/twilightforest/client/model/armor/TFArmorModel.java index be667d4e92..d33c3ceaf9 100644 --- a/src/main/java/twilightforest/client/model/armor/TFArmorModel.java +++ b/src/main/java/twilightforest/client/model/armor/TFArmorModel.java @@ -8,9 +8,9 @@ import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.decoration.ArmorStand; -import org.jetbrains.annotations.NotNull; -public class TFArmorModel extends HumanoidModel<@NotNull HumanoidRenderState> { +public class TFArmorModel extends HumanoidModel { + public TFArmorModel(ModelPart root) { super(root); } diff --git a/src/main/java/twilightforest/client/model/armor/TravellersWingsModel.java b/src/main/java/twilightforest/client/model/armor/TravellersWingsModel.java index 3152e9db63..39bc4002ce 100644 --- a/src/main/java/twilightforest/client/model/armor/TravellersWingsModel.java +++ b/src/main/java/twilightforest/client/model/armor/TravellersWingsModel.java @@ -10,7 +10,6 @@ import net.minecraft.client.renderer.entity.state.HumanoidRenderState; import net.minecraft.util.Mth; import net.minecraft.world.entity.LivingEntity; -import org.jetbrains.annotations.NotNull; import org.joml.Vector3f; import twilightforest.components.entity.TravellersWingsAnimAttachment; import twilightforest.components.entity.TravellersWingsAttachment; @@ -19,7 +18,7 @@ import java.util.List; -public class TravellersWingsModel extends HumanoidModel<@NotNull HumanoidRenderState> { +public class TravellersWingsModel extends HumanoidModel { private static final double TAU = 4; // Time (in ticks) in which distance reduces in e times private static final float ANGLE_10_DEG = Mth.PI / 18; private static final Vector3f SMALL_SWING = new Vector3f(8.0F, 8.0F, 8.0F); diff --git a/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java b/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java index 3b556fc6ec..442739969c 100644 --- a/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java +++ b/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java @@ -1,9 +1,8 @@ package twilightforest.client.model.block.carpet; -import org.jetbrains.annotations.NotNull; import twilightforest.block.GenericModelLoader; -public class RoyalRagsModelLoader extends GenericModelLoader<@NotNull UnbakedRoyalRagsModel> { +public class RoyalRagsModelLoader extends GenericModelLoader { public static final RoyalRagsModelLoader INSTANCE = new RoyalRagsModelLoader(); public RoyalRagsModelLoader() { diff --git a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureBuilder.java b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureBuilder.java index 8776f7e26e..5d2acdb209 100644 --- a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureBuilder.java +++ b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureBuilder.java @@ -8,7 +8,6 @@ import net.minecraft.tags.TagKey; import net.minecraft.world.level.block.Block; import net.neoforged.neoforge.client.model.generators.template.CustomLoaderBuilder; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; import twilightforest.TwilightForestMod; @@ -18,9 +17,10 @@ @SuppressWarnings("unused") public class ConnectedTextureBuilder extends CustomLoaderBuilder { + private List connectedFaces = new ArrayList<>(); private List connectableBlocks = new ArrayList<>(); - private List> connectableTags = new ArrayList<>(); + private List> connectableTags = new ArrayList<>(); @Nullable private Pair element; private boolean renderOverlayOnAllFaces = true; @@ -80,7 +80,7 @@ public final ConnectedTextureBuilder connectsTo(Block... blocks) { @SuppressWarnings("varargs") @SafeVarargs - public final ConnectedTextureBuilder connectsTo(TagKey<@NotNull Block>... blocks) { + public final ConnectedTextureBuilder connectsTo(TagKey... blocks) { this.connectableTags.addAll(List.of(blocks)); return this; } diff --git a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java index 0c3de70e8f..d72ca1e978 100644 --- a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java +++ b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java @@ -19,6 +19,7 @@ import java.util.*; public class ConnectedTextureModel implements UnbakedGeometry { + private final Set connectedFaces; private final Set unculledFaces; private final boolean renderOverlayOnAllFaces; diff --git a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java index a7a8cc13dd..2b4c86be61 100644 --- a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java +++ b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java @@ -12,14 +12,13 @@ import net.minecraft.world.level.block.Blocks; import net.neoforged.neoforge.client.model.StandardModelParameters; import net.neoforged.neoforge.client.model.UnbakedModelLoader; -import org.jetbrains.annotations.NotNull; import org.joml.Vector3f; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; -public class ConnectedTextureModelLoader implements UnbakedModelLoader<@NotNull UnbakedConnectedTextureModel> { +public class ConnectedTextureModelLoader implements UnbakedModelLoader { public static final ConnectedTextureModelLoader INSTANCE = new ConnectedTextureModelLoader(); public ConnectedTextureModelLoader() { diff --git a/src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java b/src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java index 748a5e34ca..cc2e015ab2 100644 --- a/src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java +++ b/src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java @@ -19,6 +19,7 @@ import java.util.*; public class UnbakedConnectedTextureModel extends AbstractUnbakedModel { + protected final boolean renderOverlayOnAllFaces; protected final Set connectedFaces; protected final List connectableBlocks; diff --git a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java index 80e2e99e94..64d94092f7 100644 --- a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java +++ b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java @@ -21,7 +21,6 @@ import net.neoforged.neoforge.client.model.quad.MutableQuad; import net.neoforged.neoforge.model.data.ModelData; import net.neoforged.neoforge.model.data.ModelProperty; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import twilightforest.block.ForceFieldBlock; @@ -128,7 +127,7 @@ protected static boolean skipRender(Map> directi return false; } - public @NotNull ModelData getModelData(@NotNull BlockAndTintGetter level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull ModelData modelData) { + public ModelData getModelData(BlockAndTintGetter level, BlockPos pos, BlockState state, ModelData modelData) { if (modelData == ModelData.EMPTY) { Map> map = new HashMap<>(); for (ExtraDirection extraDirection : getExtraDirections(state, level, pos)) { @@ -213,7 +212,7 @@ public enum ExtraDirection implements StringRepresentable { SOUTH_WEST("south_west", 17, 16, 14), SOUTH_EAST("south_east", 16, 17, 15); - public static final EnumCodec<@NotNull ExtraDirection> CODEC = StringRepresentable.fromEnum(ExtraDirection::values); + public static final EnumCodec CODEC = StringRepresentable.fromEnum(ExtraDirection::values); private final String name; private final int xAxisMirror; private final int yAxisMirror; diff --git a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java index 7fefd69044..02b1d5a494 100644 --- a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java +++ b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java @@ -9,9 +9,7 @@ import net.minecraft.core.Direction; import net.minecraft.resources.Identifier; import net.minecraft.util.Mth; -import net.neoforged.neoforge.client.model.ExtraFaceData; import net.neoforged.neoforge.client.model.generators.template.CustomLoaderBuilder; -import org.apache.commons.lang3.mutable.MutableObject; import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; import twilightforest.TwilightForestMod; @@ -19,9 +17,9 @@ import java.util.*; import java.util.function.BiConsumer; -import java.util.stream.Collectors; public class ForceFieldModelBuilder extends CustomLoaderBuilder { + private boolean defaultShade = true; private int brightnessOverride = 0; private int tint = -1; diff --git a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java index 7588ceae6f..ee251fb99f 100644 --- a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java +++ b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java @@ -21,6 +21,7 @@ public class ForceFieldModelLoader implements UnbakedModelLoader elementsAndConditions = new HashMap<>(); if (json.has("elements")) { diff --git a/src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java b/src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java index 0f725785d6..2bbf4cb784 100644 --- a/src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java +++ b/src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java @@ -5,6 +5,7 @@ import net.minecraft.client.resources.model.geometry.UnbakedGeometry; import net.neoforged.neoforge.client.model.AbstractUnbakedModel; import net.neoforged.neoforge.client.model.StandardModelParameters; + import java.util.Map; public class UnbakedForceFieldModel extends AbstractUnbakedModel { diff --git a/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockModel.java b/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockModel.java index f1c830fd0c..ddf913910a 100644 --- a/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockModel.java +++ b/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockModel.java @@ -14,6 +14,7 @@ import java.util.List; public class GiantBlockModel implements BlockStateModel, DynamicBlockStateModel { + private final BlockStateModel[] voxels; public GiantBlockModel(BlockStateModel[] voxels) { diff --git a/src/main/java/twilightforest/client/model/block/patch/PatchBuilder.java b/src/main/java/twilightforest/client/model/block/patch/PatchBuilder.java index ff7cfc8c09..c60e278071 100644 --- a/src/main/java/twilightforest/client/model/block/patch/PatchBuilder.java +++ b/src/main/java/twilightforest/client/model/block/patch/PatchBuilder.java @@ -5,6 +5,7 @@ import twilightforest.TwilightForestMod; public class PatchBuilder extends CustomLoaderBuilder { + private boolean shaggify = false; public PatchBuilder() { diff --git a/src/main/java/twilightforest/client/model/block/patch/PatchModel.java b/src/main/java/twilightforest/client/model/block/patch/PatchModel.java index 95892beeb5..4681e968ba 100644 --- a/src/main/java/twilightforest/client/model/block/patch/PatchModel.java +++ b/src/main/java/twilightforest/client/model/block/patch/PatchModel.java @@ -19,6 +19,7 @@ import java.util.List; public class PatchModel implements UnbakedGeometry { + private final boolean shaggify; private TextureAtlasSprite texture; diff --git a/src/main/java/twilightforest/client/model/block/patch/PatchModelLoader.java b/src/main/java/twilightforest/client/model/block/patch/PatchModelLoader.java index 0a4e1f04c2..4599a7d9e5 100644 --- a/src/main/java/twilightforest/client/model/block/patch/PatchModelLoader.java +++ b/src/main/java/twilightforest/client/model/block/patch/PatchModelLoader.java @@ -6,9 +6,8 @@ import com.mojang.realmsclient.util.JsonUtils; import net.neoforged.neoforge.client.model.StandardModelParameters; import net.neoforged.neoforge.client.model.UnbakedModelLoader; -import org.jetbrains.annotations.NotNull; -public final class PatchModelLoader implements UnbakedModelLoader<@NotNull UnbakedPatchModel> { +public final class PatchModelLoader implements UnbakedModelLoader { public static final PatchModelLoader INSTANCE = new PatchModelLoader(); private PatchModelLoader() { diff --git a/src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java b/src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java index a82445d6a7..ff875d6fb8 100644 --- a/src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java +++ b/src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java @@ -5,6 +5,7 @@ import net.neoforged.neoforge.client.model.StandardModelParameters; public class UnbakedPatchModel extends AbstractUnbakedModel { + private final boolean shaggify; public UnbakedPatchModel(boolean shaggify, StandardModelParameters parameters) { diff --git a/src/main/java/twilightforest/client/model/entity/HostileWolfModel.java b/src/main/java/twilightforest/client/model/entity/HostileWolfModel.java index fabf39059e..171b98b04a 100644 --- a/src/main/java/twilightforest/client/model/entity/HostileWolfModel.java +++ b/src/main/java/twilightforest/client/model/entity/HostileWolfModel.java @@ -7,11 +7,11 @@ import net.minecraft.client.renderer.rendertype.RenderTypes; import net.minecraft.resources.Identifier; import net.minecraft.util.Mth; -import org.jetbrains.annotations.NotNull; import java.util.function.Function; -public class HostileWolfModel extends EntityModel<@NotNull T> { +public class HostileWolfModel extends EntityModel { + private final ModelPart head; private final ModelPart body; private final ModelPart rightHindLeg; diff --git a/src/main/java/twilightforest/client/model/entity/LowerGoblinKnightModel.java b/src/main/java/twilightforest/client/model/entity/LowerGoblinKnightModel.java index 38c67fc211..dd29842f78 100644 --- a/src/main/java/twilightforest/client/model/entity/LowerGoblinKnightModel.java +++ b/src/main/java/twilightforest/client/model/entity/LowerGoblinKnightModel.java @@ -6,10 +6,9 @@ import net.minecraft.client.model.geom.PartPose; import net.minecraft.client.model.geom.builders.*; import net.minecraft.util.Mth; -import org.jetbrains.annotations.NotNull; import twilightforest.client.state.entity.LowerGoblinKnightRenderState; -public class LowerGoblinKnightModel extends HumanoidModel<@NotNull LowerGoblinKnightRenderState> { +public class LowerGoblinKnightModel extends HumanoidModel { private final ModelPart tunic; diff --git a/src/main/java/twilightforest/client/model/entity/LoyalZombieModel.java b/src/main/java/twilightforest/client/model/entity/LoyalZombieModel.java index 4b4d385f21..d32f6b6c08 100644 --- a/src/main/java/twilightforest/client/model/entity/LoyalZombieModel.java +++ b/src/main/java/twilightforest/client/model/entity/LoyalZombieModel.java @@ -8,9 +8,12 @@ import net.minecraft.util.ARGB; import net.minecraft.util.Mth; import net.minecraft.client.renderer.entity.state.HumanoidRenderState; -import org.jetbrains.annotations.NotNull; -public class LoyalZombieModel extends HumanoidModel { +/** + * [VanillaCopy] {@link net.minecraft.client.model.monster.zombie.AbstractZombieModel} due to generic restrictions + */ +public class LoyalZombieModel extends HumanoidModel { + public LoyalZombieModel(ModelPart part) { super(part); } diff --git a/src/main/java/twilightforest/client/model/entity/UpperGoblinKnightModel.java b/src/main/java/twilightforest/client/model/entity/UpperGoblinKnightModel.java index b410af5c1f..315d2d96c3 100644 --- a/src/main/java/twilightforest/client/model/entity/UpperGoblinKnightModel.java +++ b/src/main/java/twilightforest/client/model/entity/UpperGoblinKnightModel.java @@ -9,10 +9,10 @@ import net.minecraft.client.model.geom.builders.MeshDefinition; import net.minecraft.client.model.geom.builders.PartDefinition; import net.minecraft.util.Mth; -import org.jetbrains.annotations.NotNull; import twilightforest.client.state.entity.UpperGoblinKnightRenderState; -public class UpperGoblinKnightModel extends HumanoidModel<@NotNull UpperGoblinKnightRenderState> { +public class UpperGoblinKnightModel extends HumanoidModel { + private final ModelPart breastplate; private final ModelPart shield; From 7a80ae02eb3050308272694f6f70fc543f5c305b Mon Sep 17 00:00:00 2001 From: Albazavr Date: Fri, 17 Jul 2026 03:21:17 +0300 Subject: [PATCH 03/18] Fixed TFArmorModel --- .../client/model/armor/TFArmorModel.java | 52 +++++++++---------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/src/main/java/twilightforest/client/model/armor/TFArmorModel.java b/src/main/java/twilightforest/client/model/armor/TFArmorModel.java index d33c3ceaf9..36783ea2d9 100644 --- a/src/main/java/twilightforest/client/model/armor/TFArmorModel.java +++ b/src/main/java/twilightforest/client/model/armor/TFArmorModel.java @@ -1,13 +1,10 @@ package twilightforest.client.model.armor; -import net.minecraft.client.Minecraft; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.renderer.entity.state.ArmorStandRenderState; import net.minecraft.client.renderer.entity.state.HumanoidRenderState; import net.minecraft.util.Mth; -import net.minecraft.world.entity.EntitySpawnReason; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.decoration.ArmorStand; public class TFArmorModel extends HumanoidModel { @@ -16,32 +13,31 @@ public TFArmorModel(ModelPart root) { } @Override - public void setupAnim(HumanoidRenderState state) { + public void setupAnim(HumanoidRenderState humanoidRenderState) { // [VanillaCopy] ArmorStandArmorModel // this prevents helmets from always facing south, and the armor "breathing" on the stand - if (state.entityType == EntityType.ARMOR_STAND) { - ArmorStand stand = (ArmorStand) state.entityType.create(Minecraft.getInstance().level, EntitySpawnReason.NATURAL); - this.head.xRot = Mth.DEG_TO_RAD * stand.getHeadPose().x(); - this.head.yRot = Mth.DEG_TO_RAD * stand.getHeadPose().y(); - this.head.zRot = Mth.DEG_TO_RAD * stand.getHeadPose().z(); - this.body.xRot = Mth.DEG_TO_RAD * stand.getBodyPose().x(); - this.body.yRot = Mth.DEG_TO_RAD * stand.getBodyPose().y(); - this.body.zRot = Mth.DEG_TO_RAD * stand.getBodyPose().z(); - this.leftArm.xRot = Mth.DEG_TO_RAD * stand.getLeftArmPose().x(); - this.leftArm.yRot = Mth.DEG_TO_RAD * stand.getLeftArmPose().y(); - this.leftArm.zRot = Mth.DEG_TO_RAD * stand.getLeftArmPose().z(); - this.rightArm.xRot = Mth.DEG_TO_RAD * stand.getRightArmPose().x(); - this.rightArm.yRot = Mth.DEG_TO_RAD * stand.getRightArmPose().y(); - this.rightArm.zRot = Mth.DEG_TO_RAD * stand.getRightArmPose().z(); - this.leftLeg.xRot = Mth.DEG_TO_RAD * stand.getLeftLegPose().x(); - this.leftLeg.yRot = Mth.DEG_TO_RAD * stand.getLeftLegPose().y(); - this.leftLeg.zRot = Mth.DEG_TO_RAD * stand.getLeftLegPose().z(); - this.rightLeg.xRot = Mth.DEG_TO_RAD * stand.getRightLegPose().x(); - this.rightLeg.yRot = Mth.DEG_TO_RAD * stand.getRightLegPose().y(); - this.rightLeg.zRot = Mth.DEG_TO_RAD * stand.getRightLegPose().z(); - this.hat.loadPose(this.head.getInitialPose()); + if (humanoidRenderState instanceof ArmorStandRenderState state) { + this.head.xRot = Mth.DEG_TO_RAD * state.headPose.x(); + this.head.yRot = Mth.DEG_TO_RAD * state.headPose.y(); + this.head.zRot = Mth.DEG_TO_RAD * state.headPose.z(); + this.body.xRot = Mth.DEG_TO_RAD * state.headPose.x(); + this.body.yRot = Mth.DEG_TO_RAD * state.headPose.y(); + this.body.zRot = Mth.DEG_TO_RAD * state.headPose.z(); + this.leftArm.xRot = Mth.DEG_TO_RAD * state.leftArmPose.x(); + this.leftArm.yRot = Mth.DEG_TO_RAD * state.leftArmPose.y(); + this.leftArm.zRot = Mth.DEG_TO_RAD * state.leftArmPose.z(); + this.rightArm.xRot = Mth.DEG_TO_RAD * state.rightArmPose.x(); + this.rightArm.yRot = Mth.DEG_TO_RAD * state.rightArmPose.y(); + this.rightArm.zRot = Mth.DEG_TO_RAD * state.rightArmPose.z(); + this.leftLeg.xRot = Mth.DEG_TO_RAD * state.leftLegPose.x(); + this.leftLeg.yRot = Mth.DEG_TO_RAD * state.leftLegPose.y(); + this.leftLeg.zRot = Mth.DEG_TO_RAD * state.leftLegPose.z(); + this.rightLeg.xRot = Mth.DEG_TO_RAD * state.rightLegPose.x(); + this.rightLeg.yRot = Mth.DEG_TO_RAD * state.rightLegPose.y(); + this.rightLeg.zRot = Mth.DEG_TO_RAD * state.rightLegPose.z(); + this.hat.loadPose(this.head.storePose()); } else { - super.setupAnim(state); - } + super.setupAnim(humanoidRenderState); + } // TF - Defer to super otherwise } } From ca0e423e728c1bb6e328796e4755a0d1e121aea0 Mon Sep 17 00:00:00 2001 From: Albazavr Date: Fri, 17 Jul 2026 03:23:38 +0300 Subject: [PATCH 04/18] Fixed TFArmorModel --- .../twilightforest/client/model/armor/TFArmorModel.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/twilightforest/client/model/armor/TFArmorModel.java b/src/main/java/twilightforest/client/model/armor/TFArmorModel.java index 36783ea2d9..28a3c039f1 100644 --- a/src/main/java/twilightforest/client/model/armor/TFArmorModel.java +++ b/src/main/java/twilightforest/client/model/armor/TFArmorModel.java @@ -20,9 +20,9 @@ public void setupAnim(HumanoidRenderState humanoidRenderState) { this.head.xRot = Mth.DEG_TO_RAD * state.headPose.x(); this.head.yRot = Mth.DEG_TO_RAD * state.headPose.y(); this.head.zRot = Mth.DEG_TO_RAD * state.headPose.z(); - this.body.xRot = Mth.DEG_TO_RAD * state.headPose.x(); - this.body.yRot = Mth.DEG_TO_RAD * state.headPose.y(); - this.body.zRot = Mth.DEG_TO_RAD * state.headPose.z(); + this.body.xRot = Mth.DEG_TO_RAD * state.bodyPose.x(); + this.body.yRot = Mth.DEG_TO_RAD * state.bodyPose.y(); + this.body.zRot = Mth.DEG_TO_RAD * state.bodyPose.z(); this.leftArm.xRot = Mth.DEG_TO_RAD * state.leftArmPose.x(); this.leftArm.yRot = Mth.DEG_TO_RAD * state.leftArmPose.y(); this.leftArm.zRot = Mth.DEG_TO_RAD * state.leftArmPose.z(); From a9c4c6acd2fa2e3570f4a65df4c43bf0ce543ba9 Mon Sep 17 00:00:00 2001 From: Albazavr Date: Fri, 17 Jul 2026 03:48:44 +0300 Subject: [PATCH 05/18] Fixed TravellersWingsModel --- .../client/model/armor/TravellersWingsModel.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/twilightforest/client/model/armor/TravellersWingsModel.java b/src/main/java/twilightforest/client/model/armor/TravellersWingsModel.java index 39bc4002ce..34c576e6d1 100644 --- a/src/main/java/twilightforest/client/model/armor/TravellersWingsModel.java +++ b/src/main/java/twilightforest/client/model/armor/TravellersWingsModel.java @@ -167,9 +167,21 @@ protected static void createBelt(PartDefinition root, float deformation) { ); } - public void setupModelAnimations(LivingEntity entity, double ageInTicks) { + // [VanillaCopy] this method should be removed when IClientItemExtensions fully switches to HumanoidRenderState + private HumanoidRenderState createRendererState(LivingEntity entity, float walkAnimationPos, float walkAnimationSpeed, double ageInTicks, float netHeadYaw, float headPitch) { + HumanoidRenderState state = new HumanoidRenderState(); + state.entityType = entity.getType(); + state.walkAnimationPos = walkAnimationPos; + state.walkAnimationSpeed = walkAnimationSpeed; + state.ageInTicks = (float) ageInTicks; + state.yRot = netHeadYaw; + state.xRot = headPitch; + return state; + } + + public void setupModelAnimations(LivingEntity entity, float walkAnimationPos, float walkAnimationSpeed, double ageInTicks, float netHeadYaw, float headPitch) { this.bodyParts().forEach(modelPart -> modelPart.getAllParts().forEach(ModelPart::resetPose)); - super.setupAnim(new HumanoidRenderState()); + super.setupAnim(createRendererState(entity, walkAnimationPos, walkAnimationSpeed, ageInTicks, netHeadYaw, headPitch)); TravellersWingsAnimAttachment animAttachment = entity.getData(TFDataAttachments.TRAVELLERS_WINGS_ANIM); TravellersWingsAttachment attachment = entity.getData(TFDataAttachments.TRAVELLERS_WINGS); From 286acab29628f271e87d758f4b72bd54d19d5056 Mon Sep 17 00:00:00 2001 From: Albazavr Date: Fri, 17 Jul 2026 03:52:41 +0300 Subject: [PATCH 06/18] Removed diff from NoiseVaryingModelBuilder --- .../block/aurorablock/NoiseVaryingModelBuilder.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/main/java/twilightforest/client/model/block/aurorablock/NoiseVaryingModelBuilder.java b/src/main/java/twilightforest/client/model/block/aurorablock/NoiseVaryingModelBuilder.java index 235cd28a28..74776241bd 100644 --- a/src/main/java/twilightforest/client/model/block/aurorablock/NoiseVaryingModelBuilder.java +++ b/src/main/java/twilightforest/client/model/block/aurorablock/NoiseVaryingModelBuilder.java @@ -38,19 +38,11 @@ protected NoiseVaryingModelBuilder copyInternal() { @Override public JsonObject toJson(JsonObject json) { JsonObject mainJson = super.toJson(json); - JsonArray variants = new JsonArray(); + JsonArray variants = new JsonArray(); this.variants.forEach(Identifier -> variants.add(Identifier.toString())); mainJson.add("variants", variants); - if (mainJson.has("loader")) { - mainJson.remove("loader"); - } - if (mainJson.has("type")) { - mainJson.remove("type"); - } - return mainJson; } - } From 2cb3ae7e2891bef7ad9639b89ea84c95e78627ab Mon Sep 17 00:00:00 2001 From: Albazavr Date: Fri, 17 Jul 2026 03:58:30 +0300 Subject: [PATCH 07/18] Fixed RoyalRagsModelLoader --- .../model/block/carpet/RoyalRagsModelLoader.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java b/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java index 442739969c..7fca73cb5a 100644 --- a/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java +++ b/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java @@ -1,11 +1,18 @@ package twilightforest.client.model.block.carpet; -import twilightforest.block.GenericModelLoader; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import net.neoforged.neoforge.client.model.UnbakedModelLoader; -public class RoyalRagsModelLoader extends GenericModelLoader { +public class RoyalRagsModelLoader implements UnbakedModelLoader { + @Deprecated // FIXME: Generalize alongside with CastleDoor models public static final RoyalRagsModelLoader INSTANCE = new RoyalRagsModelLoader(); public RoyalRagsModelLoader() { - super(UnbakedRoyalRagsModel::new); + } + + public UnbakedRoyalRagsModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) throws JsonParseException { + return new UnbakedRoyalRagsModel(); } } From a40eb89b92fc1aff53868bd9b25a214a69f77e7b Mon Sep 17 00:00:00 2001 From: Albazavr Date: Sun, 19 Jul 2026 15:51:48 +0300 Subject: [PATCH 08/18] Changed ConnectionLogic.remapUVs to use new UVs API --- .../model/block/connected/ConnectionLogic.java | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java b/src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java index b023dcd4df..54a7f70901 100644 --- a/src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java +++ b/src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java @@ -1,6 +1,7 @@ package twilightforest.client.model.block.connected; import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.cuboid.CuboidFace; import net.minecraft.core.Direction; //let the magic begin. @@ -58,17 +59,9 @@ public TextureAtlasSprite chooseTexture(TextureAtlasSprite[] sprites) { return sprites[this.texture]; } - public float[] remapUVs(float[] uvs) { - if (uvs.length == 2) { - return new float[]{this.getU(uvs[0]), this.getV(uvs[1])}; - } - - if (uvs.length >= 4) { - // Fallback - return new float[]{this.getU(uvs[0]), this.getV(uvs[1]), this.getU(uvs[2]), this.getV(uvs[3])}; - } - - return uvs; + public CuboidFace.UVs remapUVs(CuboidFace.UVs uvs) { + if (uvs == null) return new CuboidFace.UVs(0, 0, 0, 0); + return new CuboidFace.UVs(this.getU(uvs.maxU()), this.getV(uvs.minV()), this.getU(uvs.maxU()), this.getV(uvs.maxV())); } public float getU(float delta) { From 31218deef961c1344914aa45d467b8c34e2d8118 Mon Sep 17 00:00:00 2001 From: Albazavr Date: Sun, 19 Jul 2026 15:52:17 +0300 Subject: [PATCH 09/18] Extracted getModelData method from deleted class to ReactorDebrisBlockEntity --- .../block/entity/ReactorDebrisBlockEntity.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/twilightforest/block/entity/ReactorDebrisBlockEntity.java b/src/main/java/twilightforest/block/entity/ReactorDebrisBlockEntity.java index ecd5806385..0dfe1ed52b 100644 --- a/src/main/java/twilightforest/block/entity/ReactorDebrisBlockEntity.java +++ b/src/main/java/twilightforest/block/entity/ReactorDebrisBlockEntity.java @@ -1,6 +1,7 @@ package twilightforest.block.entity; import com.google.common.base.MoreObjects; +import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.core.BlockPos; import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; @@ -17,6 +18,8 @@ import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; +import net.neoforged.neoforge.model.data.ModelData; +import net.neoforged.neoforge.model.data.ModelProperty; import org.joml.Vector3f; import twilightforest.init.TFBlockEntities; @@ -30,6 +33,7 @@ public class ReactorDebrisBlockEntity extends BlockEntity { Identifier.withDefaultNamespace("block/nether_portal"), Identifier.withDefaultNamespace("block/obsidian"), }; + public static final ModelProperty TEXTURE_FOR_PARTICLE = new ModelProperty<>(); public static final Identifier DEFAULT_TEXTURE = TEXTURES[0]; private static final float Z_FIGHTING_MIN = 0.008F; private static final float Z_FIGHTING_MAX = 1 - 0.008F; @@ -153,4 +157,12 @@ public ClientboundBlockEntityDataPacket getUpdatePacket() { public CompoundTag getUpdateTag(HolderLookup.Provider registries) { return this.saveCustomOnly(registries); } + + @Override + public ModelData getModelData() { + if (!(this.level instanceof ClientLevel clientLevel)) + return ModelData.EMPTY.derive().with(TEXTURE_FOR_PARTICLE, ReactorDebrisBlockEntity.DEFAULT_TEXTURE).build(); + final Identifier textureForParticle = this.textures[clientLevel.getRandom().nextInt(this.textures.length)]; + return ModelData.EMPTY.derive().with(TEXTURE_FOR_PARTICLE, textureForParticle).build(); + } } From 64711f747db74a474604409c129bff113eba4f15 Mon Sep 17 00:00:00 2001 From: Albazavr Date: Sun, 19 Jul 2026 21:18:45 +0300 Subject: [PATCH 10/18] Fixed royal rags logic and rendering --- .../block/CoronationCarpetBlock.java | 76 +++++++ .../entity/CoronationCarpetBlockEntity.java | 73 +++++++ .../block/carpet/UnbakedRoyalRagsModel.java | 190 +++++++----------- .../twilightforest/init/TFBlockEntities.java | 2 + .../java/twilightforest/init/TFBlocks.java | 2 +- .../util/UnbakedGeometryUtil.java | 41 ++++ 6 files changed, 269 insertions(+), 115 deletions(-) create mode 100644 src/main/java/twilightforest/block/CoronationCarpetBlock.java create mode 100644 src/main/java/twilightforest/block/entity/CoronationCarpetBlockEntity.java create mode 100644 src/main/java/twilightforest/util/UnbakedGeometryUtil.java diff --git a/src/main/java/twilightforest/block/CoronationCarpetBlock.java b/src/main/java/twilightforest/block/CoronationCarpetBlock.java new file mode 100644 index 0000000000..90a3501765 --- /dev/null +++ b/src/main/java/twilightforest/block/CoronationCarpetBlock.java @@ -0,0 +1,76 @@ +package twilightforest.block; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.ScheduledTickAccess; +import net.minecraft.world.level.block.BaseEntityBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.WoolCarpetBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.jspecify.annotations.Nullable; +import twilightforest.block.entity.CoronationCarpetBlockEntity; +import twilightforest.init.TFBlockEntities; + +// [VanillaCopy] extended WoolCarpetBlock with BlockEntity +public class CoronationCarpetBlock extends BaseEntityBlock { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec((i) -> i.group(DyeColor.CODEC.fieldOf("color").forGetter(CoronationCarpetBlock::getColor), propertiesCodec()).apply(i, CoronationCarpetBlock::new)); + private static final VoxelShape SHAPE = Block.column(16.0D, 0.0D, 1.0D); + + private final DyeColor color; + + public CoronationCarpetBlock(DyeColor color, Properties properties) { + super(properties); + this.color = color; + } + + @Override + protected MapCodec codec() { + return CODEC; + } + + @Override + public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) { + return new CoronationCarpetBlockEntity(blockPos, blockState); + } + + @Override + protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { + return SHAPE; + } + + @Override + protected BlockState updateShape(BlockState state, LevelReader level, ScheduledTickAccess ticks, BlockPos pos, Direction directionToNeighbour, BlockPos neighbourPos, BlockState neighbourState, RandomSource random) { + if (!state.canSurvive(level, pos)) { + return Blocks.AIR.defaultBlockState(); + } + + if (level instanceof Level world && world.isClientSide()) { + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity instanceof CoronationCarpetBlockEntity) { + world.getModelDataManager().requestRefresh(blockEntity); + } + } + + return super.updateShape(state, level, ticks, pos, directionToNeighbour, neighbourPos, neighbourState, random); + } + + @Override + protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) { + return !level.isEmptyBlock(pos.below()); + } + + public DyeColor getColor() { + return color; + } +} diff --git a/src/main/java/twilightforest/block/entity/CoronationCarpetBlockEntity.java b/src/main/java/twilightforest/block/entity/CoronationCarpetBlockEntity.java new file mode 100644 index 0000000000..6cbe86227f --- /dev/null +++ b/src/main/java/twilightforest/block/entity/CoronationCarpetBlockEntity.java @@ -0,0 +1,73 @@ +package twilightforest.block.entity; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.neoforged.neoforge.model.data.ModelData; +import net.neoforged.neoforge.model.data.ModelProperty; +import twilightforest.client.model.block.connected.ConnectionLogic; +import twilightforest.init.TFBlockEntities; +import twilightforest.init.TFBlocks; + +import java.util.Arrays; + +public class CoronationCarpetBlockEntity extends BlockEntity { + private final Block[] validConnectors = {TFBlocks.CORONATION_CARPET.value()}; + private static final ModelProperty DATA = new ModelProperty<>(); + + public CoronationCarpetBlockEntity(BlockPos worldPosition, BlockState blockState) { + super(TFBlockEntities.CORONATION_CARPET.get(), worldPosition, blockState); + } + + @Override + public ModelData getModelData() { + if (this.level == null) { + return ModelData.EMPTY; + } + + LoftyCarpetData data = new LoftyCarpetData(); + + for (Direction face : Direction.values()) { + Direction[] directions = ConnectionLogic.AXIS_PLANE_DIRECTIONS[face.getAxis().ordinal()]; + boolean[] sideStates = new boolean[4]; + + int faceIndex; + for (faceIndex = 0; faceIndex < directions.length; faceIndex++) { + sideStates[faceIndex] = this.shouldConnectSide(this.level, this.worldPosition, face, directions[faceIndex]); + } + + faceIndex = face.get3DDataValue(); + + for (int dir = 0; dir < directions.length; dir++) { + int cornerOffset = (dir + 1) % directions.length; + boolean side1 = sideStates[dir]; + boolean side2 = sideStates[cornerOffset]; + boolean corner = side1 && side2 && this.isCornerBlockPresent(this.level, this.worldPosition, face, directions[dir], directions[cornerOffset]); + data.logic[faceIndex][dir] = dir % 2 == 0 ? ConnectionLogic.of(side1, side2, corner) : ConnectionLogic.of(side2, side1, corner); + } + } + + return ModelData.EMPTY.derive().with(DATA, data).build(); + } + + private boolean shouldConnectSide(BlockGetter getter, BlockPos pos, Direction face, Direction side) { + BlockState neighborState = getter.getBlockState(pos.relative(side)); + return Arrays.stream(this.validConnectors).anyMatch(neighborState::is) && Block.shouldRenderFace(getter, pos, getter.getBlockState(pos), neighborState, face); + } + + private boolean isCornerBlockPresent(BlockGetter getter, BlockPos pos, Direction face, Direction side1, Direction side2) { + BlockState neighborState = getter.getBlockState(pos.relative(side1).relative(side2)); + return Arrays.stream(this.validConnectors).anyMatch(neighborState::is) && Block.shouldRenderFace(getter, pos, getter.getBlockState(pos), neighborState, face); + } + + //we need a class to make model data. Fine, here you go + private static final class LoftyCarpetData { + private final ConnectionLogic[][] logic = new ConnectionLogic[6][4]; + + private LoftyCarpetData() { + } + } +} diff --git a/src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java b/src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java index 9ee617a39c..3ac7de26a5 100644 --- a/src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java +++ b/src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java @@ -1,11 +1,13 @@ package twilightforest.client.model.block.carpet; -import com.mojang.blaze3d.platform.Transparency; +import com.mojang.math.Quadrant; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.block.dispatch.ModelState; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.ModelBaker; import net.minecraft.client.resources.model.ModelDebugName; -import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.client.resources.model.cuboid.CuboidFace; +import net.minecraft.client.resources.model.cuboid.CuboidModelElement; import net.minecraft.client.resources.model.geometry.BakedQuad; import net.minecraft.client.resources.model.geometry.QuadCollection; import net.minecraft.client.resources.model.geometry.UnbakedGeometry; @@ -13,160 +15,120 @@ import net.minecraft.client.resources.model.sprite.TextureSlots; import net.minecraft.core.Direction; import net.minecraft.core.Vec3i; +import net.minecraft.data.AtlasIds; +import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; import twilightforest.client.model.block.connected.ConnectionLogic; +import twilightforest.util.UnbakedGeometryUtil; -import java.awt.*; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; //for now, im keeping this hardcoded to a 2 layer block, with the overlay layer being fullbright and tinted. //It might be worth expanding this in the future to be more flexible for other kinds of blocks (1 layer blocks, determining emissivity and tinting per layer, maybe >2 layer blocks?) but for now, I see no point. //I only wanted this system for castle doors after all! -public class UnbakedRoyalRagsModel implements UnbakedGeometry, UnbakedModel { - private final Vector3f[][][] baseElements; // [horizontal_dir][quad][0 = from, 1 = to] - private final Vector3f[][][][] faceElements; // [up_down_dir][quad][connection_logic][0 = from, 1 = to] +public class UnbakedRoyalRagsModel implements UnbakedGeometry { + + private final CuboidModelElement[][] baseElements; + private final CuboidModelElement[][][] faceElements; public UnbakedRoyalRagsModel() { - // Properly size the arrays to handle the extra [2] dimension at the end for from/to - this.baseElements = new Vector3f[4][4][2]; - this.faceElements = new Vector3f[2][4][5][2]; + //base elements - the side faces without ctm. No Connected Textures on this bit. + //the array is made of horizontal directions (Direction.get2DDataValue) and quads + this.baseElements = new CuboidModelElement[4][4]; + + //face elements - the connected bit of the model. + //the array is made of the directions, quads, and each logic value in the ConnectionLogic class + //Topmost array indexes to up/dpwn directions (Direction.get3DDataValue, down = 0, up = 1) then inside are quads + this.faceElements = new CuboidModelElement[2][4][5]; Vec3i center = new Vec3i(8, 8, 8); for (Direction face : Direction.values()) { Direction[] planeDirections = ConnectionLogic.AXIS_PLANE_DIRECTIONS[face.getAxis().ordinal()]; for (int quad = 0; quad < 4; quad++) { - Vec3i vFace = face.getUnitVec3i(); - Vec3i vP1 = planeDirections[quad].getUnitVec3i(); - Vec3i vP2 = planeDirections[(quad + 1) % 4].getUnitVec3i(); - - int cornerX = (vFace.getX() + vP1.getX() + vP2.getX() + 1) * 8; - int cornerY = (vFace.getY() + vP1.getY() + vP2.getY() + 1) * 8; - int cornerZ = (vFace.getZ() + vP1.getZ() + vP2.getZ() + 1) * 8; - - Vector3f from = new Vector3f( - (float) Math.min(center.getX(), cornerX), - (float) Math.min(center.getY(), cornerY) / 16f, - (float) Math.min(center.getZ(), cornerZ) - ); - - Vector3f to = new Vector3f( - (float) Math.max(center.getX(), cornerX), - (float) Math.max(center.getY(), cornerY) / 16f, - (float) Math.max(center.getZ(), cornerZ) - ); + Vec3i corner = face.getUnitVec3i().offset(planeDirections[quad].getUnitVec3i()).offset(planeDirections[(quad + 1) % 4].getUnitVec3i()).offset(1, 1, 1).multiply(8); + CuboidModelElement element = new CuboidModelElement(new Vector3f((float) Math.min(center.getX(), corner.getX()), (float) Math.min(center.getY(), corner.getY()) / 16f, (float) Math.min(center.getZ(), corner.getZ())), new Vector3f((float) Math.max(center.getX(), corner.getX()), (float) Math.max(center.getY(), corner.getY()) / 16f, (float) Math.max(center.getZ(), corner.getZ())), Map.of()); if (face.getAxis().isHorizontal()) { - this.baseElements[face.get2DDataValue()][quad][0] = from; - this.baseElements[face.get2DDataValue()][quad][1] = to; + this.baseElements[face.get2DDataValue()][quad] = new CuboidModelElement(element.from(), element.to(), Map.of(face, new CuboidFace(face, -1, "", ConnectionLogic.NONE.remapUVs(UnbakedGeometryUtil.uvsByFace(face, element)), Quadrant.R0))); } else { for (ConnectionLogic connectionType : ConnectionLogic.values()) { - this.faceElements[face.get3DDataValue()][quad][connectionType.ordinal()][0] = from; - this.faceElements[face.get3DDataValue()][quad][connectionType.ordinal()][1] = to; + this.faceElements[face.get3DDataValue()][quad][connectionType.ordinal()] = new CuboidModelElement(element.from(), element.to(), Map.of(face, new CuboidFace(face, 0, "", connectionType.remapUVs(UnbakedGeometryUtil.uvsByFace(face, element)), Quadrant.R0))); } } } } } + public QuadCollection getQuads(@Nullable Direction side, List[] baseQuads, BakedQuad[][][] quads) { + if (side != null) { + QuadCollection.Builder builder = new QuadCollection.Builder(); + if (side.getAxis().isHorizontal()) { + if (baseQuads != null) { + for (BakedQuad bakedQuad : baseQuads[side.get2DDataValue()]) { + builder.addCulledFace(side, bakedQuad); + } + } + } else { + int faceIndex = side.get3DDataValue(); + for (int quad = 0; quad < 4; ++quad) { + ConnectionLogic connectionType = ConnectionLogic.NONE; + builder.addCulledFace(side, quads[faceIndex][quad][connectionType.ordinal()]); + } + } + + return builder.build(); + } else { + return QuadCollection.EMPTY; + } + } + @Override public QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName modelDebugName) { - QuadCollection.Builder builder = new QuadCollection.Builder(); + //making an array list like this is cursed, would not recommend + @SuppressWarnings("unchecked") //this is fine, I hope + List[] baseQuads = (List[]) Array.newInstance(List.class, 4); + Material baseMaterial = textureSlots.getMaterial("wool"); + TextureAtlasSprite baseTexture = Minecraft.getInstance().getAtlasManager().getAtlasOrThrow(AtlasIds.BLOCKS).getSprite(baseMaterial.sprite()); + Material.Baked baseBakedMaterial = new Material.Baked(baseTexture, baseMaterial.forceTranslucent()); - TextureAtlasSprite baseTexture = modelBaker.materials().resolveSlot(textureSlots, "wool", modelDebugName).sprite(); - TextureAtlasSprite ctmTexture = modelBaker.materials().resolveSlot(textureSlots, "wool_ctm", modelDebugName).sprite(); - TextureAtlasSprite[] textures = new TextureAtlasSprite[]{baseTexture, ctmTexture}; + Material ctmMaterial = textureSlots.getMaterial("wool_ctm"); + TextureAtlasSprite ctmTexture = Minecraft.getInstance().getAtlasManager().getAtlasOrThrow(AtlasIds.BLOCKS).getSprite(ctmMaterial.sprite()); for (Direction direction : Direction.Plane.HORIZONTAL) { - int horSideIndex = direction.get2DDataValue(); - - for (int quad = 0; quad < 4; quad++) { - Vector3f from = this.baseElements[horSideIndex][quad][0]; - Vector3f to = this.baseElements[horSideIndex][quad][1]; + baseQuads[direction.get2DDataValue()] = new ArrayList<>(); - if (from == null || to == null) continue; - - Material.Baked material = modelBaker.materials().get(textureSlots.getMaterial("wool"), modelDebugName); - BakedQuad bakedQuad = createModernQuad(from, to, direction, material, baseTexture, -1, baseTexture.transparency()); - builder.addUnculledFace(bakedQuad); + for (CuboidModelElement element : this.baseElements[direction.get2DDataValue()]) { + baseQuads[direction.get2DDataValue()].add(UnbakedGeometryUtil.bakeElementFace(modelBaker, element, element.faces().values().iterator().next(), baseBakedMaterial, direction, modelState)); } } - for (int direction = 0; direction < 2; direction++) { - Direction actualDirection = direction == 0 ? Direction.DOWN: Direction.UP; - - for (int quad = 0; quad < 4; quad++) { - for (int connectionState = 0; connectionState < 5; connectionState++) { - Vector3f from = this.faceElements[direction][quad][connectionState][0]; - Vector3f to = this.faceElements[direction][quad][connectionState][1]; - - if (from == null || to == null) continue; + //we'll use this to figure out which texture to use with the Connected Texture logic + //NONE uses the first one, everything else uses the 2nd one + TextureAtlasSprite[] sprites = new TextureAtlasSprite[]{baseTexture, ctmTexture}; + Material[] materials = new Material[]{baseMaterial, ctmMaterial}; - TextureAtlasSprite chosenTexture = ConnectionLogic.values()[connectionState].chooseTexture(textures); + BakedQuad[][][] quads = new BakedQuad[2][4][5]; - Material.Baked material = modelBaker.materials().get(textureSlots.getMaterial(chosenTexture == baseTexture ? "wool" : "wool_ctm"), modelDebugName); - BakedQuad bakedQuad = createModernQuad(from, to, actualDirection, material, chosenTexture, 0, baseTexture.transparency()); - builder.addCulledFace(actualDirection, bakedQuad); + for (int dir = 0; dir < 2; dir++) { + for (int quad = 0; quad < 4; quad++) { + for (int type = 0; type < 5; type++) { + CuboidModelElement element = this.faceElements[dir][quad][type]; + Material.Baked bakedChoice = UnbakedGeometryUtil.chooseAndBake(ConnectionLogic.values()[type], sprites, materials); + quads[dir][quad][type] = UnbakedGeometryUtil.bakeElementFace(modelBaker, element, element.faces().values().iterator().next(), bakedChoice, Direction.values()[dir], modelState); } } } - return builder.build(); - } + QuadCollection.Builder builder = new QuadCollection.Builder(); - private BakedQuad createModernQuad( - Vector3f from, Vector3f to, - Direction direction, - Material.Baked material, - TextureAtlasSprite activeSprite, - int tintIndex, - Transparency transparency) { - - float x0 = from.x(), y0 = from.y(), z0 = from.z(); - float x1 = to.x(), y1 = to.y(), z1 = to.z(); - - Vector3f p0 = new Vector3f(); - Vector3f p1 = new Vector3f(); - Vector3f p2 = new Vector3f(); - Vector3f p3 = new Vector3f(); - - switch (direction) { - case DOWN -> { - p0.set(x0, y0, z0); p1.set(x1, y0, z0); p2.set(x1, y0, z1); p3.set(x0, y0, z1); - } - case UP -> { - p0.set(x0, y1, z1); p1.set(x1, y1, z1); p2.set(x1, y1, z0); p3.set(x0, y1, z0); - } - case NORTH -> { - p0.set(x1, y1, z0); p1.set(x1, y0, z0); p2.set(x0, y0, z0); p3.set(x0, y1, z0); - } - case SOUTH -> { - p0.set(x0, y1, z1); p1.set(x0, y0, z1); p2.set(x1, y0, z1); p3.set(x1, y1, z1); - } - case WEST -> { - p0.set(x0, y1, z0); p1.set(x0, y0, z0); p2.set(x0, y0, z1); p3.set(x0, y1, z1); - } - case EAST -> { - p0.set(x1, y1, z1); p1.set(x1, y0, z1); p2.set(x1, y0, z0); p3.set(x1, y1, z0); - } + for (Direction value : Direction.values()) { + builder.addAll(getQuads(value, baseQuads, quads)); } - float u0 = activeSprite.getU0(), u1 = activeSprite.getU1(); - float v0 = activeSprite.getV0(), v1 = activeSprite.getV1(); - - long uv0 = ((long) Float.floatToRawIntBits(u0) << 32) | (Float.floatToRawIntBits(v0) & 0xFFFFFFFFL); - long uv1 = ((long) Float.floatToRawIntBits(u1) << 32) | (Float.floatToRawIntBits(v0) & 0xFFFFFFFFL); - long uv2 = ((long) Float.floatToRawIntBits(u1) << 32) | (Float.floatToRawIntBits(v1) & 0xFFFFFFFFL); - long uv3 = ((long) Float.floatToRawIntBits(u0) << 32) | (Float.floatToRawIntBits(v1) & 0xFFFFFFFFL); - - BakedQuad.MaterialInfo materialInfo = BakedQuad.MaterialInfo.of( - material, - transparency, - tintIndex, - true, - 0, - true - ); - - return new BakedQuad(p0, p1, p2, p3, uv0, uv1, uv2, uv3, direction, materialInfo); + return builder.build(); } } \ No newline at end of file diff --git a/src/main/java/twilightforest/init/TFBlockEntities.java b/src/main/java/twilightforest/init/TFBlockEntities.java index 8ebf010cbf..be58af63ee 100644 --- a/src/main/java/twilightforest/init/TFBlockEntities.java +++ b/src/main/java/twilightforest/init/TFBlockEntities.java @@ -68,6 +68,8 @@ public class TFBlockEntities { new BlockEntityType<>(KeepsakeCasketBlockEntity::new, TFBlocks.KEEPSAKE_CASKET.get())); public static final DeferredHolder, BlockEntityType> BRAZIER = BLOCK_ENTITIES.register("brazier", () -> new BlockEntityType<>(BrazierBlockEntity::new, TFBlocks.BRAZIER.get())); + public static final DeferredHolder, BlockEntityType> CORONATION_CARPET = BLOCK_ENTITIES.register("coronation_carpet", () -> + new BlockEntityType<>(CoronationCarpetBlockEntity::new, TFBlocks.CORONATION_CARPET.get())); public static final DeferredHolder, BlockEntityType> TF_CHEST = BLOCK_ENTITIES.register("chest", () -> new BlockEntityType<>(TFChestBlockEntity::new, diff --git a/src/main/java/twilightforest/init/TFBlocks.java b/src/main/java/twilightforest/init/TFBlocks.java index 525d52304e..e053ba27d6 100644 --- a/src/main/java/twilightforest/init/TFBlocks.java +++ b/src/main/java/twilightforest/init/TFBlocks.java @@ -126,7 +126,7 @@ public class TFBlocks { public static final DeferredBlock TERRORCOTTA_ARCS = registerWithItem("terrorcotta_arcs", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(1.5F, 6.0F)); public static final DeferredBlock TERRORCOTTA_CURVES = registerWithItem("terrorcotta_curves", GlazedTerracottaBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(1.5F, 6.0F)); public static final DeferredBlock TERRORCOTTA_LINES = registerWithItem("terrorcotta_lines", BinaryRotatedBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(1.5F, 6.0F)); - public static final DeferredBlock CORONATION_CARPET = registerWithItem("coronation_carpet", properties -> new WoolCarpetBlock(DyeColor.RED, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.RED_CARPET).isValidSpawn(Blocks::always)); + public static final DeferredBlock CORONATION_CARPET = registerWithItem("coronation_carpet", properties -> new CoronationCarpetBlock(DyeColor.RED, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.RED_CARPET).isValidSpawn(Blocks::always)); //ominous public static final DeferredBlock OMINOUS_FIRE = register("ominous_fire", OminousFireBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_PURPLE).replaceable().noCollision().instabreak().lightLevel((state) -> 15).sound(SoundType.WOOL).pushReaction(PushReaction.DESTROY)); diff --git a/src/main/java/twilightforest/util/UnbakedGeometryUtil.java b/src/main/java/twilightforest/util/UnbakedGeometryUtil.java new file mode 100644 index 0000000000..9e09db00e9 --- /dev/null +++ b/src/main/java/twilightforest/util/UnbakedGeometryUtil.java @@ -0,0 +1,41 @@ +package twilightforest.util; + +import net.minecraft.client.renderer.block.dispatch.ModelState; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.ModelBaker; +import net.minecraft.client.resources.model.cuboid.CuboidFace; +import net.minecraft.client.resources.model.cuboid.CuboidModelElement; +import net.minecraft.client.resources.model.cuboid.FaceBakery; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.sprite.Material; +import net.minecraft.core.Direction; +import twilightforest.client.model.block.connected.ConnectionLogic; + +// this class returns back removed methods from the sources +public class UnbakedGeometryUtil { + public static CuboidFace.UVs uvsByFace(Direction face, CuboidModelElement element) { + return switch (face) { + case DOWN -> new CuboidFace.UVs(element.from().x(), 16.0F - element.to().z(), element.to().x(), 16.0F - element.from().z()); + case UP -> new CuboidFace.UVs(element.from().x(), element.from().z(), element.to().x(), element.to().z()); + case SOUTH -> new CuboidFace.UVs(element.from().x(), 16.0F - element.to().y(), element.to().x(), 16.0F - element.from().y()); + case WEST -> new CuboidFace.UVs(element.from().z(), 16.0F - element.to().y(), element.to().z(), 16.0F - element.from().y()); + case EAST -> new CuboidFace.UVs(16.0F - element.to().z(), 16.0F - element.to().y(), 16.0F - element.from().z(), 16.0F - element.from().y()); + default -> new CuboidFace.UVs(16.0F - element.to().x(), 16.0F - element.to().y(), 16.0F - element.from().x(), 16.0F - element.from().y()); + }; + } + + public static BakedQuad bakeElementFace(ModelBaker baker, CuboidModelElement element, CuboidFace face, Material.Baked sprite, Direction direction, ModelState state) { + return FaceBakery.bakeQuad(baker, element.from(), element.to(), face, sprite, direction, state, null, element.shade(), 0); + } + + public static Material.Baked chooseAndBake(ConnectionLogic target, TextureAtlasSprite[] spriteOptions, Material[] materials) { + TextureAtlasSprite unbakedChoice = target.chooseTexture(spriteOptions); + // spriteOptions.length should be equal to materials.length + for (int i = 0; i < spriteOptions.length; i++) { + if (unbakedChoice == spriteOptions[i]) { + return new Material.Baked(spriteOptions[i], materials[i].forceTranslucent()); + } + } + return new Material.Baked(spriteOptions[0], false); + } +} From 2583eabd25ecddd5620d8ba34909e47770b11469 Mon Sep 17 00:00:00 2001 From: Albazavr Date: Sun, 19 Jul 2026 21:52:14 +0300 Subject: [PATCH 11/18] Fixed GiantBlockBuilder --- .../model/block/giantblock/GiantBlockBuilder.java | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockBuilder.java b/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockBuilder.java index 9cc3b3f04a..1ebca90c16 100644 --- a/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockBuilder.java +++ b/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockBuilder.java @@ -18,18 +18,4 @@ public GiantBlockBuilder() { protected CustomLoaderBuilder copyInternal() { return new GiantBlockBuilder(); } - - @Override - public JsonObject toJson(JsonObject json) { - JsonObject mainJson = super.toJson(json); - - if (mainJson.has("loader")) { - mainJson.remove("loader"); - } - if (mainJson.has("type")) { - mainJson.remove("type"); - } - - return mainJson; - } } From dd0c26d3e2ad530c6edcc5dfd9580bdb9cc98cbe Mon Sep 17 00:00:00 2001 From: Albazavr Date: Sun, 19 Jul 2026 21:53:08 +0300 Subject: [PATCH 12/18] Removed unnecessary import from GiantBlockBuilder --- .../block/CoronationCarpetBlock.java | 76 -- .../entity/CoronationCarpetBlockEntity.java | 73 -- .../block/carpet/RoyalRagsModelLoader.java | 18 - .../block/carpet/UnbakedRoyalRagsModel.java | 134 ---- .../connected/ConnectedTextureModel.java | 96 --- .../ConnectedTextureModelLoader.java | 104 --- .../block/connected/ConnectionLogic.java | 74 -- .../UnbakedConnectedTextureModel.java | 187 ----- .../block/forcefield/ForceFieldModel.java | 250 ------ .../forcefield/ForceFieldModelBuilder.java | 390 ---------- .../forcefield/ForceFieldModelLoader.java | 57 -- .../forcefield/UnbakedForceFieldModel.java | 31 - .../block/giantblock/GiantBlockBuilder.java | 1 - .../model/block/patch/PatchBuilder.java | 35 - .../client/model/block/patch/PatchModel.java | 198 ----- .../model/block/patch/PatchModelLoader.java | 23 - .../model/block/patch/UnbakedPatchModel.java | 20 - .../twilightforest/init/TFBlockEntities.java | 148 ---- .../java/twilightforest/init/TFBlocks.java | 713 ------------------ .../util/UnbakedGeometryUtil.java | 41 - 20 files changed, 2669 deletions(-) delete mode 100644 src/main/java/twilightforest/block/CoronationCarpetBlock.java delete mode 100644 src/main/java/twilightforest/block/entity/CoronationCarpetBlockEntity.java delete mode 100644 src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java delete mode 100644 src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java delete mode 100644 src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java delete mode 100644 src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java delete mode 100644 src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java delete mode 100644 src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java delete mode 100644 src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java delete mode 100644 src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java delete mode 100644 src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java delete mode 100644 src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java delete mode 100644 src/main/java/twilightforest/client/model/block/patch/PatchBuilder.java delete mode 100644 src/main/java/twilightforest/client/model/block/patch/PatchModel.java delete mode 100644 src/main/java/twilightforest/client/model/block/patch/PatchModelLoader.java delete mode 100644 src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java delete mode 100644 src/main/java/twilightforest/init/TFBlockEntities.java delete mode 100644 src/main/java/twilightforest/init/TFBlocks.java delete mode 100644 src/main/java/twilightforest/util/UnbakedGeometryUtil.java diff --git a/src/main/java/twilightforest/block/CoronationCarpetBlock.java b/src/main/java/twilightforest/block/CoronationCarpetBlock.java deleted file mode 100644 index 90a3501765..0000000000 --- a/src/main/java/twilightforest/block/CoronationCarpetBlock.java +++ /dev/null @@ -1,76 +0,0 @@ -package twilightforest.block; - -import com.mojang.serialization.MapCodec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.util.RandomSource; -import net.minecraft.world.item.DyeColor; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.ScheduledTickAccess; -import net.minecraft.world.level.block.BaseEntityBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.WoolCarpetBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; -import org.jspecify.annotations.Nullable; -import twilightforest.block.entity.CoronationCarpetBlockEntity; -import twilightforest.init.TFBlockEntities; - -// [VanillaCopy] extended WoolCarpetBlock with BlockEntity -public class CoronationCarpetBlock extends BaseEntityBlock { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec((i) -> i.group(DyeColor.CODEC.fieldOf("color").forGetter(CoronationCarpetBlock::getColor), propertiesCodec()).apply(i, CoronationCarpetBlock::new)); - private static final VoxelShape SHAPE = Block.column(16.0D, 0.0D, 1.0D); - - private final DyeColor color; - - public CoronationCarpetBlock(DyeColor color, Properties properties) { - super(properties); - this.color = color; - } - - @Override - protected MapCodec codec() { - return CODEC; - } - - @Override - public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) { - return new CoronationCarpetBlockEntity(blockPos, blockState); - } - - @Override - protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { - return SHAPE; - } - - @Override - protected BlockState updateShape(BlockState state, LevelReader level, ScheduledTickAccess ticks, BlockPos pos, Direction directionToNeighbour, BlockPos neighbourPos, BlockState neighbourState, RandomSource random) { - if (!state.canSurvive(level, pos)) { - return Blocks.AIR.defaultBlockState(); - } - - if (level instanceof Level world && world.isClientSide()) { - BlockEntity blockEntity = world.getBlockEntity(pos); - if (blockEntity instanceof CoronationCarpetBlockEntity) { - world.getModelDataManager().requestRefresh(blockEntity); - } - } - - return super.updateShape(state, level, ticks, pos, directionToNeighbour, neighbourPos, neighbourState, random); - } - - @Override - protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) { - return !level.isEmptyBlock(pos.below()); - } - - public DyeColor getColor() { - return color; - } -} diff --git a/src/main/java/twilightforest/block/entity/CoronationCarpetBlockEntity.java b/src/main/java/twilightforest/block/entity/CoronationCarpetBlockEntity.java deleted file mode 100644 index 6cbe86227f..0000000000 --- a/src/main/java/twilightforest/block/entity/CoronationCarpetBlockEntity.java +++ /dev/null @@ -1,73 +0,0 @@ -package twilightforest.block.entity; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.neoforged.neoforge.model.data.ModelData; -import net.neoforged.neoforge.model.data.ModelProperty; -import twilightforest.client.model.block.connected.ConnectionLogic; -import twilightforest.init.TFBlockEntities; -import twilightforest.init.TFBlocks; - -import java.util.Arrays; - -public class CoronationCarpetBlockEntity extends BlockEntity { - private final Block[] validConnectors = {TFBlocks.CORONATION_CARPET.value()}; - private static final ModelProperty DATA = new ModelProperty<>(); - - public CoronationCarpetBlockEntity(BlockPos worldPosition, BlockState blockState) { - super(TFBlockEntities.CORONATION_CARPET.get(), worldPosition, blockState); - } - - @Override - public ModelData getModelData() { - if (this.level == null) { - return ModelData.EMPTY; - } - - LoftyCarpetData data = new LoftyCarpetData(); - - for (Direction face : Direction.values()) { - Direction[] directions = ConnectionLogic.AXIS_PLANE_DIRECTIONS[face.getAxis().ordinal()]; - boolean[] sideStates = new boolean[4]; - - int faceIndex; - for (faceIndex = 0; faceIndex < directions.length; faceIndex++) { - sideStates[faceIndex] = this.shouldConnectSide(this.level, this.worldPosition, face, directions[faceIndex]); - } - - faceIndex = face.get3DDataValue(); - - for (int dir = 0; dir < directions.length; dir++) { - int cornerOffset = (dir + 1) % directions.length; - boolean side1 = sideStates[dir]; - boolean side2 = sideStates[cornerOffset]; - boolean corner = side1 && side2 && this.isCornerBlockPresent(this.level, this.worldPosition, face, directions[dir], directions[cornerOffset]); - data.logic[faceIndex][dir] = dir % 2 == 0 ? ConnectionLogic.of(side1, side2, corner) : ConnectionLogic.of(side2, side1, corner); - } - } - - return ModelData.EMPTY.derive().with(DATA, data).build(); - } - - private boolean shouldConnectSide(BlockGetter getter, BlockPos pos, Direction face, Direction side) { - BlockState neighborState = getter.getBlockState(pos.relative(side)); - return Arrays.stream(this.validConnectors).anyMatch(neighborState::is) && Block.shouldRenderFace(getter, pos, getter.getBlockState(pos), neighborState, face); - } - - private boolean isCornerBlockPresent(BlockGetter getter, BlockPos pos, Direction face, Direction side1, Direction side2) { - BlockState neighborState = getter.getBlockState(pos.relative(side1).relative(side2)); - return Arrays.stream(this.validConnectors).anyMatch(neighborState::is) && Block.shouldRenderFace(getter, pos, getter.getBlockState(pos), neighborState, face); - } - - //we need a class to make model data. Fine, here you go - private static final class LoftyCarpetData { - private final ConnectionLogic[][] logic = new ConnectionLogic[6][4]; - - private LoftyCarpetData() { - } - } -} diff --git a/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java b/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java deleted file mode 100644 index 7fca73cb5a..0000000000 --- a/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java +++ /dev/null @@ -1,18 +0,0 @@ -package twilightforest.client.model.block.carpet; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import net.neoforged.neoforge.client.model.UnbakedModelLoader; - -public class RoyalRagsModelLoader implements UnbakedModelLoader { - @Deprecated // FIXME: Generalize alongside with CastleDoor models - public static final RoyalRagsModelLoader INSTANCE = new RoyalRagsModelLoader(); - - public RoyalRagsModelLoader() { - } - - public UnbakedRoyalRagsModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) throws JsonParseException { - return new UnbakedRoyalRagsModel(); - } -} diff --git a/src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java b/src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java deleted file mode 100644 index 3ac7de26a5..0000000000 --- a/src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java +++ /dev/null @@ -1,134 +0,0 @@ -package twilightforest.client.model.block.carpet; - -import com.mojang.math.Quadrant; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.block.dispatch.ModelState; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.ModelBaker; -import net.minecraft.client.resources.model.ModelDebugName; -import net.minecraft.client.resources.model.cuboid.CuboidFace; -import net.minecraft.client.resources.model.cuboid.CuboidModelElement; -import net.minecraft.client.resources.model.geometry.BakedQuad; -import net.minecraft.client.resources.model.geometry.QuadCollection; -import net.minecraft.client.resources.model.geometry.UnbakedGeometry; -import net.minecraft.client.resources.model.sprite.Material; -import net.minecraft.client.resources.model.sprite.TextureSlots; -import net.minecraft.core.Direction; -import net.minecraft.core.Vec3i; -import net.minecraft.data.AtlasIds; -import org.jetbrains.annotations.Nullable; -import org.joml.Vector3f; -import twilightforest.client.model.block.connected.ConnectionLogic; -import twilightforest.util.UnbakedGeometryUtil; - -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -//for now, im keeping this hardcoded to a 2 layer block, with the overlay layer being fullbright and tinted. -//It might be worth expanding this in the future to be more flexible for other kinds of blocks (1 layer blocks, determining emissivity and tinting per layer, maybe >2 layer blocks?) but for now, I see no point. -//I only wanted this system for castle doors after all! -public class UnbakedRoyalRagsModel implements UnbakedGeometry { - - private final CuboidModelElement[][] baseElements; - private final CuboidModelElement[][][] faceElements; - - public UnbakedRoyalRagsModel() { - //base elements - the side faces without ctm. No Connected Textures on this bit. - //the array is made of horizontal directions (Direction.get2DDataValue) and quads - this.baseElements = new CuboidModelElement[4][4]; - - //face elements - the connected bit of the model. - //the array is made of the directions, quads, and each logic value in the ConnectionLogic class - //Topmost array indexes to up/dpwn directions (Direction.get3DDataValue, down = 0, up = 1) then inside are quads - this.faceElements = new CuboidModelElement[2][4][5]; - Vec3i center = new Vec3i(8, 8, 8); - - for (Direction face : Direction.values()) { - Direction[] planeDirections = ConnectionLogic.AXIS_PLANE_DIRECTIONS[face.getAxis().ordinal()]; - - for (int quad = 0; quad < 4; quad++) { - Vec3i corner = face.getUnitVec3i().offset(planeDirections[quad].getUnitVec3i()).offset(planeDirections[(quad + 1) % 4].getUnitVec3i()).offset(1, 1, 1).multiply(8); - CuboidModelElement element = new CuboidModelElement(new Vector3f((float) Math.min(center.getX(), corner.getX()), (float) Math.min(center.getY(), corner.getY()) / 16f, (float) Math.min(center.getZ(), corner.getZ())), new Vector3f((float) Math.max(center.getX(), corner.getX()), (float) Math.max(center.getY(), corner.getY()) / 16f, (float) Math.max(center.getZ(), corner.getZ())), Map.of()); - - if (face.getAxis().isHorizontal()) { - this.baseElements[face.get2DDataValue()][quad] = new CuboidModelElement(element.from(), element.to(), Map.of(face, new CuboidFace(face, -1, "", ConnectionLogic.NONE.remapUVs(UnbakedGeometryUtil.uvsByFace(face, element)), Quadrant.R0))); - } else { - for (ConnectionLogic connectionType : ConnectionLogic.values()) { - this.faceElements[face.get3DDataValue()][quad][connectionType.ordinal()] = new CuboidModelElement(element.from(), element.to(), Map.of(face, new CuboidFace(face, 0, "", connectionType.remapUVs(UnbakedGeometryUtil.uvsByFace(face, element)), Quadrant.R0))); - } - } - } - } - } - - public QuadCollection getQuads(@Nullable Direction side, List[] baseQuads, BakedQuad[][][] quads) { - if (side != null) { - QuadCollection.Builder builder = new QuadCollection.Builder(); - if (side.getAxis().isHorizontal()) { - if (baseQuads != null) { - for (BakedQuad bakedQuad : baseQuads[side.get2DDataValue()]) { - builder.addCulledFace(side, bakedQuad); - } - } - } else { - int faceIndex = side.get3DDataValue(); - for (int quad = 0; quad < 4; ++quad) { - ConnectionLogic connectionType = ConnectionLogic.NONE; - builder.addCulledFace(side, quads[faceIndex][quad][connectionType.ordinal()]); - } - } - - return builder.build(); - } else { - return QuadCollection.EMPTY; - } - } - - @Override - public QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName modelDebugName) { - //making an array list like this is cursed, would not recommend - @SuppressWarnings("unchecked") //this is fine, I hope - List[] baseQuads = (List[]) Array.newInstance(List.class, 4); - Material baseMaterial = textureSlots.getMaterial("wool"); - TextureAtlasSprite baseTexture = Minecraft.getInstance().getAtlasManager().getAtlasOrThrow(AtlasIds.BLOCKS).getSprite(baseMaterial.sprite()); - Material.Baked baseBakedMaterial = new Material.Baked(baseTexture, baseMaterial.forceTranslucent()); - - Material ctmMaterial = textureSlots.getMaterial("wool_ctm"); - TextureAtlasSprite ctmTexture = Minecraft.getInstance().getAtlasManager().getAtlasOrThrow(AtlasIds.BLOCKS).getSprite(ctmMaterial.sprite()); - - for (Direction direction : Direction.Plane.HORIZONTAL) { - baseQuads[direction.get2DDataValue()] = new ArrayList<>(); - - for (CuboidModelElement element : this.baseElements[direction.get2DDataValue()]) { - baseQuads[direction.get2DDataValue()].add(UnbakedGeometryUtil.bakeElementFace(modelBaker, element, element.faces().values().iterator().next(), baseBakedMaterial, direction, modelState)); - } - } - - //we'll use this to figure out which texture to use with the Connected Texture logic - //NONE uses the first one, everything else uses the 2nd one - TextureAtlasSprite[] sprites = new TextureAtlasSprite[]{baseTexture, ctmTexture}; - Material[] materials = new Material[]{baseMaterial, ctmMaterial}; - - BakedQuad[][][] quads = new BakedQuad[2][4][5]; - - for (int dir = 0; dir < 2; dir++) { - for (int quad = 0; quad < 4; quad++) { - for (int type = 0; type < 5; type++) { - CuboidModelElement element = this.faceElements[dir][quad][type]; - Material.Baked bakedChoice = UnbakedGeometryUtil.chooseAndBake(ConnectionLogic.values()[type], sprites, materials); - quads[dir][quad][type] = UnbakedGeometryUtil.bakeElementFace(modelBaker, element, element.faces().values().iterator().next(), bakedChoice, Direction.values()[dir], modelState); - } - } - } - - QuadCollection.Builder builder = new QuadCollection.Builder(); - - for (Direction value : Direction.values()) { - builder.addAll(getQuads(value, baseQuads, quads)); - } - - return builder.build(); - } -} \ No newline at end of file diff --git a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java deleted file mode 100644 index d72ca1e978..0000000000 --- a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java +++ /dev/null @@ -1,96 +0,0 @@ -package twilightforest.client.model.block.connected; - -import net.minecraft.client.renderer.block.BlockAndTintGetter; -import net.minecraft.client.renderer.block.dispatch.ModelState; -import net.minecraft.client.resources.model.ModelBaker; -import net.minecraft.client.resources.model.ModelDebugName; -import net.minecraft.client.resources.model.geometry.BakedQuad; -import net.minecraft.client.resources.model.geometry.QuadCollection; -import net.minecraft.client.resources.model.geometry.UnbakedGeometry; -import net.minecraft.client.resources.model.sprite.TextureSlots; -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; -import net.neoforged.neoforge.model.data.ModelData; -import net.neoforged.neoforge.model.data.ModelProperty; -import org.jetbrains.annotations.NotNull; - -import java.util.*; - -public class ConnectedTextureModel implements UnbakedGeometry { - - private final Set connectedFaces; - private final Set unculledFaces; - private final boolean renderOverlayOnAllFaces; - private final Map baseQuads; - private final Map connectedQuads; - private final List validConnectors; - private static final ModelProperty<@NotNull ConnectedTextureData> DATA = new ModelProperty<>(); - - public ConnectedTextureModel(Set connectedFaces, Set unculledFaces, boolean renderOverlayOnAllFaces, List connectableBlocks, Map baseQuads, Map connectedQuads) { - this.connectedFaces = connectedFaces; - this.unculledFaces = unculledFaces; - this.renderOverlayOnAllFaces = renderOverlayOnAllFaces; - this.validConnectors = connectableBlocks; - this.baseQuads = baseQuads; - this.connectedQuads = connectedQuads; - } - - @Override - public QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName modelDebugName) { - QuadCollection.Builder builder = new QuadCollection.Builder(); - - for (Direction direction : this.unculledFaces) { - List unculledQuads = this.getQuadsForFace(direction, ModelData.EMPTY); - for (BakedQuad quad : unculledQuads) { - builder.addUnculledFace(quad); - } - } - - for (Direction direction : Direction.values()) { - List culledQuads = this.getQuadsForFace(direction, ModelData.EMPTY); - for (BakedQuad quad : culledQuads) { - builder.addCulledFace(direction, quad); - } - } - - return builder.build(); - } - - public List getQuadsForFace(Direction side, ModelData extraData) { - BakedQuad[] baseQuads = this.baseQuads.get(side); - ConnectedTextureData data = extraData.get(DATA); - ArrayList quads = new ArrayList<>(4 + (baseQuads != null ? 4 : 0)); - if (baseQuads != null) quads.addAll(List.of(baseQuads)); - - if (this.connectedFaces.contains(side) || this.renderOverlayOnAllFaces) { - for (int quad = 0; quad < 4; ++quad) { - //if our model data is null (happens for items), we can skip connected textures since we dont have the info we need - ConnectionLogic connectionType = data != null && this.connectedFaces.contains(side) ? data.logic[side.get3DDataValue()][quad] : ConnectionLogic.NONE; - quads.add(this.connectedQuads.get(side)[quad][connectionType.ordinal()]); - } - } - - return quads; - } - - private boolean shouldConnectSide(BlockAndTintGetter getter, BlockPos pos, Direction face, Direction side) { - BlockState neighborState = getter.getBlockState(pos.relative(side)); - if (this.unculledFaces.contains(face)) return this.validConnectors.stream().anyMatch(neighborState::is); - return this.validConnectors.stream().anyMatch(neighborState::is) && Block.shouldRenderFace(getter, pos.relative(face), neighborState, getter.getBlockState(pos.relative(face)), face); - } - - private boolean isCornerBlockPresent(BlockAndTintGetter getter, BlockPos pos, Direction face, Direction side1, Direction side2) { - BlockState neighborState = getter.getBlockState(pos.relative(side1).relative(side2)); - if (this.unculledFaces.contains(face)) return this.validConnectors.stream().anyMatch(neighborState::is); - return this.validConnectors.stream().anyMatch(neighborState::is) && Block.shouldRenderFace(getter, pos.relative(face), neighborState, getter.getBlockState(pos.relative(face)), face); - } - - private static final class ConnectedTextureData { - private final ConnectionLogic[][] logic = new ConnectionLogic[6][4]; - - private ConnectedTextureData() { - } - } -} \ No newline at end of file diff --git a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java deleted file mode 100644 index 2b4c86be61..0000000000 --- a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java +++ /dev/null @@ -1,104 +0,0 @@ -package twilightforest.client.model.block.connected; - -import com.google.gson.*; -import com.mojang.datafixers.util.Pair; -import net.minecraft.core.Direction; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.core.registries.Registries; -import net.minecraft.resources.Identifier; -import net.minecraft.tags.TagKey; -import net.minecraft.util.GsonHelper; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.neoforged.neoforge.client.model.StandardModelParameters; -import net.neoforged.neoforge.client.model.UnbakedModelLoader; -import org.joml.Vector3f; - -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; - -public class ConnectedTextureModelLoader implements UnbakedModelLoader { - public static final ConnectedTextureModelLoader INSTANCE = new ConnectedTextureModelLoader(); - - public ConnectedTextureModelLoader() { - } - - @Override - public UnbakedConnectedTextureModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) throws JsonParseException { - JsonObject baseTextureInfo = GsonHelper.getAsJsonObject(jsonObject, "base", new JsonObject()); - int baseTintIndex = GsonHelper.getAsInt(baseTextureInfo, "tint_index", -1); - int baseEmissivity = GsonHelper.getAsInt(baseTextureInfo, "emissivity", 0); - - Pair element; - if (jsonObject.has("element")) { - JsonObject obj = jsonObject.getAsJsonObject("element"); - element = Pair.of(this.deserializeVec(obj, "from"), this.deserializeVec(obj, "to")); - } else { - element = Pair.of(new Vector3f(0, 0, 0), new Vector3f(16, 16, 16)); - } - - JsonObject overlayInfo = GsonHelper.getAsJsonObject(jsonObject, "connected_texture", new JsonObject()); - int tintIndex = GsonHelper.getAsInt(overlayInfo, "tint_index", -1); - int emissivity = GsonHelper.getAsInt(overlayInfo, "emissivity", 0); - boolean renderDisabled = GsonHelper.getAsBoolean(overlayInfo, "always_render_overlay", true); - EnumSet faces = this.parseEnabledFaces(overlayInfo, "faces"); - - List connectables = this.parseConnnectableBlocks(jsonObject); - return new UnbakedConnectedTextureModel(element, faces, renderDisabled, connectables, baseEmissivity, emissivity, StandardModelParameters.parse(jsonObject, deserializationContext)); - } - - private EnumSet parseEnabledFaces(JsonObject object, String key) { - if (!object.has(key)) { - return EnumSet.allOf(Direction.class); - } else { - EnumSet faces = EnumSet.noneOf(Direction.class); - - for (JsonElement element : object.getAsJsonArray(key)) { - Direction face = Direction.byName(element.getAsString()); - if (face == null) { - throw new JsonParseException("Invalid face: " + element.getAsString()); - } - - faces.add(face); - } - - return faces; - } - } - - private List parseConnnectableBlocks(JsonObject object) { - if (!object.has("connectable_blocks")) { - return List.of(); - } else { - List blocks = new ArrayList<>(); - - for (JsonElement element : object.getAsJsonArray("connectable_blocks")) { - if (element.getAsString().startsWith("#")) { - Identifier tag = Identifier.tryParse(element.getAsString().substring(1)); - if (tag != null) { - BuiltInRegistries.BLOCK.getTagOrEmpty(TagKey.create(Registries.BLOCK, tag)).forEach(blockHolder -> blocks.add(blockHolder.value())); - } else { - throw new JsonParseException("Invalid block tag: " + element.getAsString()); - } - } else { - Block block = BuiltInRegistries.BLOCK.getValue(Identifier.tryParse(element.getAsString())); - if (block == Blocks.AIR) { - throw new JsonParseException("Invalid block: " + element.getAsString()); - } - blocks.add(block); - } - } - - return blocks; - } - } - - private Vector3f deserializeVec(JsonObject object, String name) { - JsonArray from = object.getAsJsonArray(name); - if (from.asList().size() == 3) { - return new Vector3f(from.get(0).getAsFloat(), from.get(1).getAsFloat(), from.get(2).getAsFloat()); - } - return new Vector3f(0, 0, 0); - } -} diff --git a/src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java b/src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java deleted file mode 100644 index 54a7f70901..0000000000 --- a/src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java +++ /dev/null @@ -1,74 +0,0 @@ -package twilightforest.client.model.block.connected; - -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.cuboid.CuboidFace; -import net.minecraft.core.Direction; - -//let the magic begin. -//as far as I understand, CTM texture sheets are laid out in 4 pieces: -// - cornerless connections in the top left -// - vertical connections in the top right -// - horizontal connections in the bottom left -// - corner connection in the bottom right -//each quadrant is composed of a 4x4 piece for each rotation that the model can pick based on where on the block the connection is happening. -//to avoid confusion: cornerless means that no corner piece renders. This happens when you have a block horizontally, vertically, and filling that corner space between the 2. -// ** -// ** -//while a corner means that a corner piece will render. This happens when you have a block horizontally and vertically, but theres no block in the corner. -// * -// ** -public enum ConnectionLogic { - - NONE(0, 0, 0, 16, 16), - CORNERLESS(1, 0, 0, 8, 8), - VERTICAL(1, 0, 8, 8, 16), - HORIZONTAL(1, 8, 0, 16, 8), - CORNER(1, 8, 8, 16, 16); - - private final int texture; - private final int u0; - private final int v0; - private final int u1; - private final int v1; - - public static final Direction[][] AXIS_PLANE_DIRECTIONS = new Direction[][]{ - {Direction.UP, Direction.NORTH, Direction.DOWN, Direction.SOUTH}, - {Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST}, - {Direction.UP, Direction.EAST, Direction.DOWN, Direction.WEST} - }; - - ConnectionLogic(int texture, int u0, int v0, int u1, int v1) { - this.texture = texture; - this.u0 = u0; - this.v0 = v0; - this.u1 = u1; - this.v1 = v1; - } - - public static ConnectionLogic of(boolean horizontal, boolean vertical, boolean corner) { - if (corner) { - return CORNERLESS; - } else if (horizontal) { - return vertical ? CORNER : HORIZONTAL; - } else { - return vertical ? VERTICAL : NONE; - } - } - - public TextureAtlasSprite chooseTexture(TextureAtlasSprite[] sprites) { - return sprites[this.texture]; - } - - public CuboidFace.UVs remapUVs(CuboidFace.UVs uvs) { - if (uvs == null) return new CuboidFace.UVs(0, 0, 0, 0); - return new CuboidFace.UVs(this.getU(uvs.maxU()), this.getV(uvs.minV()), this.getU(uvs.maxU()), this.getV(uvs.maxV())); - } - - public float getU(float delta) { - return (float) this.u0 + (float) (this.u1 - this.u0) * (delta / 16.0F); - } - - public float getV(float delta) { - return (float) this.v0 + (float) (this.v1 - this.v0) * (delta / 16.0F); - } -} diff --git a/src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java b/src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java deleted file mode 100644 index cc2e015ab2..0000000000 --- a/src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java +++ /dev/null @@ -1,187 +0,0 @@ -package twilightforest.client.model.block.connected; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.client.renderer.texture.TextureAtlas; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.geometry.BakedQuad; -import net.minecraft.client.resources.model.geometry.UnbakedGeometry; -import net.minecraft.client.resources.model.sprite.Material; -import net.minecraft.core.Direction; -import net.minecraft.resources.Identifier; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.Block; -import net.neoforged.neoforge.client.model.AbstractUnbakedModel; -import net.neoforged.neoforge.client.model.StandardModelParameters; -import net.neoforged.neoforge.client.model.quad.MutableQuad; -import org.jetbrains.annotations.Nullable; -import org.joml.Vector3f; - -import java.util.*; - -public class UnbakedConnectedTextureModel extends AbstractUnbakedModel { - - protected final boolean renderOverlayOnAllFaces; - protected final Set connectedFaces; - protected final List connectableBlocks; - - protected MutableQuad[][] baseElements; - protected MutableQuad[][][] connectedElements; - - - public UnbakedConnectedTextureModel(Pair element, Set connectedFaces, boolean renderOnDisabledFaces, List connectableBlocks, int baseEmissivity, int emissivity, StandardModelParameters parameters) { - super(parameters); - this.connectedFaces = connectedFaces; - this.renderOverlayOnAllFaces = renderOnDisabledFaces; - this.connectableBlocks = connectableBlocks; - - this.baseElements = new MutableQuad[6][4]; - this.connectedElements = new MutableQuad[6][4][5]; - - int center = 8; - - for (Direction face : Direction.values()) { - Direction cull = this.getCullface(face, element.getFirst(), element.getSecond()); - Direction[] planeDirections = ConnectionLogic.AXIS_PLANE_DIRECTIONS[face.getAxis().ordinal()]; - - for (int i = 0; i < 4; ++i) { - net.minecraft.core.Vec3i corner = face.getUnitVec3i().offset(planeDirections[i].getUnitVec3i()).offset(planeDirections[(i + 1) % 4].getUnitVec3i()).offset(1, 1, 1).multiply(8); - - Vector3f from = new Vector3f( - Mth.clamp(Math.min(center - (16 - element.getSecond().x()), corner.getX() + element.getFirst().x()), 0, 16), - Mth.clamp(Math.min(center - (16 - element.getSecond().y()), corner.getY() + element.getFirst().y()), 0, 16), - Mth.clamp(Math.min(center - (16 - element.getSecond().z()), corner.getZ() + element.getFirst().z()), 0, 16) - ); - - Vector3f to = new Vector3f( - element.getSecond().x() < center ? element.getSecond().x() : Math.max(center, corner.getX() - (16 - element.getSecond().x())), - element.getSecond().y() < center ? element.getSecond().y() : Math.max(center, corner.getY() - (16 - element.getSecond().y())), - element.getSecond().z() < center ? element.getSecond().z() : Math.max(center, corner.getZ() - (16 - element.getSecond().z())) - ); - - MutableQuad baseQuad = new MutableQuad(); - baseQuad.setDirection(face); - baseQuad.setShade(true); - baseQuad.setLightEmission(baseEmissivity); - setupQuadVertices(baseQuad, from, to, face); - remapQuadUVs(baseQuad, ConnectionLogic.NONE, face); - - this.baseElements[face.get3DDataValue()][i] = baseQuad; - - for (ConnectionLogic logic : ConnectionLogic.values()) { - MutableQuad connectedQuad = new MutableQuad(); - connectedQuad.setDirection(face); - connectedQuad.setShade(true); - connectedQuad.setLightEmission(emissivity); - setupQuadVertices(connectedQuad, from, to, face); - remapQuadUVs(connectedQuad, logic, face); - - this.connectedElements[face.get3DDataValue()][i][logic.ordinal()] = connectedQuad; - } - } - } - } - - private void setupQuadVertices(MutableQuad quad, org.joml.Vector3f from, org.joml.Vector3f to, Direction face) { - for (int v = 0; v < 4; v++) { - float x = (v == 1 || v == 2) ? to.x() / 16f : from.x() / 16f; - float y = (v == 2 || v == 3) ? to.y() / 16f : from.y() / 16f; - float z = (face.getAxis() == Direction.Axis.Z) ? to.z() / 16f : from.z() / 16f; - quad.setPosition(v, new org.joml.Vector3f(x, y, z)); - } - } - - private void remapQuadUVs(MutableQuad quad, ConnectionLogic logic, Direction face) { - for (int v = 0; v < 4; v++) { - float u = (v == 1 || v == 2) ? 1.0f : 0.0f; - float vCoord = (v == 2 || v == 3) ? 1.0f : 0.0f; - - float[] uvs = new float[]{u, vCoord}; - float[] remapped = logic.remapUVs(uvs); - - quad.setUv(v, remapped[0], remapped[1]); - } - } - - - @Nullable - private Direction getCullface(Direction direction, Vector3f from, Vector3f to) { - boolean cull = switch (direction) { - case DOWN -> from.y() == 0.0F; - case UP -> to.y() == 16.0F; - case NORTH -> from.x() == 0.0F; - case SOUTH -> to.x() == 16.0F; - case WEST -> from.z() == 0.0F; - case EAST -> to.z() == 16.0F; - }; - - return cull ? direction : null; - } - - @Override - public UnbakedGeometry geometry() { - TextureAtlas atlas = net.minecraft.client.Minecraft.getInstance().getAtlasManager().getAtlasOrThrow(TextureAtlas.LOCATION_BLOCKS); - - String modId = "twilightforest"; - - Identifier idBase = Identifier.fromNamespaceAndPath(modId, "block/glass"); - Identifier idOverlay = Identifier.fromNamespaceAndPath(modId, "block/glass_overlay"); - Identifier idConnected = Identifier.fromNamespaceAndPath(modId, "block/glass_overlay_connected"); - - Material matBase = new Material(idBase); - Material matOverlay = new Material(idOverlay); - Material matConnected = new Material(idConnected); - - matBase = matBase.withForceTranslucent(true); - matOverlay = matOverlay.withForceTranslucent(true); - matConnected = matConnected.withForceTranslucent(true); - - TextureAtlasSprite baseTexture = atlas.getSprite(matBase.sprite()); - TextureAtlasSprite overlayTexture = atlas.getSprite(matOverlay.sprite()); - TextureAtlasSprite connectedTexture = atlas.getSprite(matConnected.sprite()); - TextureAtlasSprite particleTexture = overlayTexture; - - TextureAtlasSprite[] sprites = new TextureAtlasSprite[]{overlayTexture, connectedTexture, particleTexture}; - - Map finalBaseQuads = new HashMap<>(); - Map finalConnectedQuads = new HashMap<>(); - Set unculledFaces = new HashSet<>(); - - for (Direction dir : Direction.values()) { - int dirIdx = dir.get3DDataValue(); - - List baseQuadList = new ArrayList<>(); - for (int i = 0; i < 4; i++) { - MutableQuad quad = this.baseElements[dirIdx][i]; - for (int v = 0; v < 4; v++) { - quad.setUv(v, baseTexture.getU(quad.u(v) * 16f), baseTexture.getV(quad.v(v) * 16f)); - } - baseQuadList.add(quad.toBakedQuad()); - } - finalBaseQuads.put(dir, baseQuadList.toArray(new BakedQuad[0])); - - BakedQuad[][] dirQuads = new BakedQuad[4][5]; - for (int quadIdx = 0; quadIdx < 4; quadIdx++) { - for (int typeIdx = 0; typeIdx < 5; typeIdx++) { - MutableQuad quad = this.connectedElements[dirIdx][quadIdx][typeIdx]; - - TextureAtlasSprite chosenSprite = ConnectionLogic.values()[typeIdx].chooseTexture(sprites); - - for (int v = 0; v < 4; v++) { - quad.setUv(v, chosenSprite.getU(quad.u(v) * 16f), chosenSprite.getV(quad.v(v) * 16f)); - } - dirQuads[quadIdx][typeIdx] = quad.toBakedQuad(); - } - } - finalConnectedQuads.put(dir, dirQuads); - } - - return new ConnectedTextureModel( - this.connectedFaces, - unculledFaces, - this.renderOverlayOnAllFaces, - this.connectableBlocks, - finalBaseQuads, - finalConnectedQuads - ); - } -} \ No newline at end of file diff --git a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java deleted file mode 100644 index 64d94092f7..0000000000 --- a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java +++ /dev/null @@ -1,250 +0,0 @@ -package twilightforest.client.model.block.forcefield; - -import net.minecraft.client.renderer.block.BlockAndTintGetter; -import net.minecraft.client.renderer.block.dispatch.ModelState; -import net.minecraft.client.renderer.rendertype.RenderType; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.ModelBaker; -import net.minecraft.client.resources.model.ModelDebugName; -import net.minecraft.client.resources.model.cuboid.ItemTransforms; -import net.minecraft.client.resources.model.geometry.BakedQuad; -import net.minecraft.client.resources.model.geometry.QuadCollection; -import net.minecraft.client.resources.model.geometry.UnbakedGeometry; -import net.minecraft.client.resources.model.sprite.Material; -import net.minecraft.client.resources.model.sprite.TextureSlots; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.resources.Identifier; -import net.minecraft.util.StringRepresentable; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.block.state.BlockState; -import net.neoforged.neoforge.client.model.quad.MutableQuad; -import net.neoforged.neoforge.model.data.ModelData; -import net.neoforged.neoforge.model.data.ModelProperty; -import org.jetbrains.annotations.Nullable; -import twilightforest.block.ForceFieldBlock; - -import java.util.*; -import java.util.function.Function; - -public class ForceFieldModel implements UnbakedGeometry { - private static final ModelProperty DATA = new ModelProperty<>(); - - private final Map parts; - private final Function spriteFunction; - private final boolean usesAO; - private final boolean usesBlockLight; - private final ItemTransforms transforms; - @Nullable - private final Set renderTypes; - - public ForceFieldModel(Map parts, Function spriteFunction, boolean useAmbientOcclusion, boolean usesBlockLight, ItemTransforms itemTransforms, @Nullable Set renderTypes) { - this.parts = parts; - this.spriteFunction = spriteFunction; - this.usesAO = useAmbientOcclusion; - this.usesBlockLight = usesBlockLight; - this.transforms = itemTransforms; - this.renderTypes = renderTypes; - } - - @Override - public QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName modelDebugName) { - QuadCollection.Builder builder = new QuadCollection.Builder(); - - ForceFieldData defaultData = new ForceFieldData(java.util.Collections.emptyMap()); - - List unculledQuads = new java.util.ArrayList<>(); - for (Direction direction : Direction.values()) { - unculledQuads = this.getQuads(unculledQuads, direction, defaultData); - } - for (BakedQuad quad : unculledQuads) { - builder.addUnculledFace(quad); - } - - for (Direction direction : Direction.values()) { - List culledQuads = new java.util.ArrayList<>(); - culledQuads = this.getQuads(culledQuads, direction, defaultData); - for (BakedQuad quad : culledQuads) { - builder.addCulledFace(direction, quad); - } - } - - return builder.build(); - } - - public List getQuads(List quads, Direction side, ForceFieldData data) { - for (Map.Entry entry : this.parts.entrySet()) { - - if (ForceFieldModel.skipRender(data.directions(), entry.getValue().direction(), entry.getValue().b(), entry.getValue().parents(), side)) { - continue; - } - - String texturePath = this.spriteFunction.apply(entry.getKey() + "_" + side.getName()); - - if (texturePath != null) { - Identifier identifier = Identifier.parse(texturePath); - Material material = new Material(identifier); - - material = material.withForceTranslucent(true); - - TextureAtlasSprite sprite = net.minecraft.client.Minecraft.getInstance() - .getAtlasManager().getAtlasOrThrow(net.minecraft.client.renderer.texture.TextureAtlas.LOCATION_BLOCKS) - .getSprite(material.sprite()); - - MutableQuad mutableQuad = new MutableQuad(); - - for (int vertexIndex = 0; vertexIndex < 4; vertexIndex++) { - float x = (vertexIndex == 1 || vertexIndex == 2) ? 1.0f : 0.0f; - float y = (vertexIndex == 2 || vertexIndex == 3) ? 1.0f : 0.0f; - float z = 0.5f; - - mutableQuad.setPosition(vertexIndex, new org.joml.Vector3f(x, y, z)); - - float u = sprite.getU(x * 16.0f); - float v = sprite.getV(y * 16.0f); - mutableQuad.setUv(vertexIndex, u, v); - } - - mutableQuad.setDirection(side); - mutableQuad.setShade(this.usesAO); - - if (this.usesBlockLight) { - mutableQuad.setLightEmission(15); - } - - quads.add(mutableQuad.toBakedQuad()); - } - } - return quads; - } - - protected static boolean skipRender(Map> directions, @Nullable ExtraDirection direction, boolean supposedToBe, List parents, Direction side) { - if (direction == null) return false; - for (ExtraDirection parent : parents) if (!directions.containsKey(parent)) return true; - boolean hasKey = directions.containsKey(direction); - if (hasKey != supposedToBe) return true; - if (hasKey) return directions.get(direction).contains(side); - return false; - } - - public ModelData getModelData(BlockAndTintGetter level, BlockPos pos, BlockState state, ModelData modelData) { - if (modelData == ModelData.EMPTY) { - Map> map = new HashMap<>(); - for (ExtraDirection extraDirection : getExtraDirections(state, level, pos)) { - List directionList = new ArrayList<>(); - for (Direction dir : Direction.values()) { - ExtraDirection mirrored = extraDirection.mirrored(dir.getAxis()); - if (mirrored != extraDirection) { - BlockState other = level.getBlockState(pos.relative(dir)); - if (other.getBlock() instanceof ForceFieldBlock) { - if (getExtraDirections(other, level, pos.relative(dir)).contains(mirrored)) directionList.add(dir); - } - } - } - map.put(extraDirection, directionList); - } - - modelData = ModelData.builder().with(DATA, new ForceFieldData(map)).build(); - } - return modelData; - } - - public static List getExtraDirections(BlockState state, BlockGetter level, BlockPos pos) { - List directions = new ArrayList<>(); - - boolean down = state.getValue(ForceFieldBlock.DOWN); - boolean up = state.getValue(ForceFieldBlock.UP); - boolean north = state.getValue(ForceFieldBlock.NORTH); - boolean south = state.getValue(ForceFieldBlock.SOUTH); - boolean west = state.getValue(ForceFieldBlock.WEST); - boolean east = state.getValue(ForceFieldBlock.EAST); - - if (down) { - directions.add(ExtraDirection.DOWN); - if (north && ForceFieldBlock.cornerConnects(level, pos, Direction.DOWN, Direction.NORTH)) directions.add(ExtraDirection.DOWN_NORTH); - if (south && ForceFieldBlock.cornerConnects(level, pos, Direction.DOWN, Direction.SOUTH)) directions.add(ExtraDirection.DOWN_SOUTH); - if (west && ForceFieldBlock.cornerConnects(level, pos, Direction.DOWN, Direction.WEST)) directions.add(ExtraDirection.DOWN_WEST); - if (east && ForceFieldBlock.cornerConnects(level, pos, Direction.DOWN, Direction.EAST)) directions.add(ExtraDirection.DOWN_EAST); - } - if (up) { - directions.add(ExtraDirection.UP); - if (north && ForceFieldBlock.cornerConnects(level, pos, Direction.UP, Direction.NORTH)) directions.add(ExtraDirection.UP_NORTH); - if (south && ForceFieldBlock.cornerConnects(level, pos, Direction.UP, Direction.SOUTH)) directions.add(ExtraDirection.UP_SOUTH); - if (west && ForceFieldBlock.cornerConnects(level, pos, Direction.UP, Direction.WEST)) directions.add(ExtraDirection.UP_WEST); - if (east && ForceFieldBlock.cornerConnects(level, pos, Direction.UP, Direction.EAST)) directions.add(ExtraDirection.UP_EAST); - } - if (north) { - directions.add(ExtraDirection.NORTH); - if (west && ForceFieldBlock.cornerConnects(level, pos, Direction.NORTH, Direction.WEST)) directions.add(ExtraDirection.NORTH_WEST); - if (east && ForceFieldBlock.cornerConnects(level, pos, Direction.NORTH, Direction.EAST)) directions.add(ExtraDirection.NORTH_EAST); - } - if (south) { - directions.add(ExtraDirection.SOUTH); - if (west && ForceFieldBlock.cornerConnects(level, pos, Direction.SOUTH, Direction.WEST)) directions.add(ExtraDirection.SOUTH_WEST); - if (east && ForceFieldBlock.cornerConnects(level, pos, Direction.SOUTH, Direction.EAST)) directions.add(ExtraDirection.SOUTH_EAST); - } - if (west) directions.add(ExtraDirection.WEST); - if (east) directions.add(ExtraDirection.EAST); - - return directions; - } - - public enum ExtraDirection implements StringRepresentable { - DOWN("down", 0, 1, 0), - UP("up", 1, 0, 1), - NORTH("north", 2, 2, 3), - SOUTH("south", 3, 3, 2), - WEST("west", 5, 4, 4), - EAST("east", 4, 5, 5), - - DOWN_NORTH("down_north", 6, 10, 7), - DOWN_SOUTH("down_south", 7, 11, 6), - DOWN_WEST("down_west", 9, 12, 8), - DOWN_EAST("down_east", 8, 13, 9), - - UP_NORTH("up_north", 10, 6, 11), - UP_SOUTH("up_south", 11, 7, 10), - UP_WEST("up_west", 13, 8, 12), - UP_EAST("up_east", 12, 9, 13), - - NORTH_WEST("north_west", 15, 14, 16), - NORTH_EAST("north_east", 14, 15, 17), - SOUTH_WEST("south_west", 17, 16, 14), - SOUTH_EAST("south_east", 16, 17, 15); - - public static final EnumCodec CODEC = StringRepresentable.fromEnum(ExtraDirection::values); - private final String name; - private final int xAxisMirror; - private final int yAxisMirror; - private final int zAxisMirror; - - ExtraDirection(String name, int xAxisMirror, int yAxisMirror, int zAxisMirror) { - this.name = name; - this.xAxisMirror = xAxisMirror; - this.yAxisMirror = yAxisMirror; - this.zAxisMirror = zAxisMirror; - } - - @Override - public String getSerializedName() { - return this.name; - } - - public ExtraDirection mirrored(Direction.Axis axis) { - return switch (axis) { - case X -> ExtraDirection.values()[this.xAxisMirror]; - case Y -> ExtraDirection.values()[this.yAxisMirror]; - case Z -> ExtraDirection.values()[this.zAxisMirror]; - }; - } - - @Nullable - public static ExtraDirection byName(String name) { - return CODEC.byName(name); - } - } - - //modeldata holder - public record ForceFieldData(Map> directions) { - } -} diff --git a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java deleted file mode 100644 index 02b1d5a494..0000000000 --- a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java +++ /dev/null @@ -1,390 +0,0 @@ -package twilightforest.client.model.block.forcefield; - -import com.google.common.base.Preconditions; -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.mojang.datafixers.util.Pair; -import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; -import net.minecraft.core.Direction; -import net.minecraft.resources.Identifier; -import net.minecraft.util.Mth; -import net.neoforged.neoforge.client.model.generators.template.CustomLoaderBuilder; -import org.jetbrains.annotations.Nullable; -import org.joml.Vector3f; -import twilightforest.TwilightForestMod; -import twilightforest.client.model.block.forcefield.ForceFieldModel.ExtraDirection; - -import java.util.*; -import java.util.function.BiConsumer; - -public class ForceFieldModelBuilder extends CustomLoaderBuilder { - - private boolean defaultShade = true; - private int brightnessOverride = 0; - private int tint = -1; - protected List elements = new ArrayList<>(); - - public static ForceFieldModelBuilder begin() { - return new ForceFieldModelBuilder(); - } - - private ForceFieldModelBuilder self() { - return this; - } - - public ForceFieldModelBuilder() { - super(TwilightForestMod.prefix("force_field"), false); - } - - public ForceFieldElementBuilder forceFieldElement() { - ForceFieldElementBuilder ret = new ForceFieldElementBuilder(this.defaultShade, this.brightnessOverride, this.tint); - this.elements.add(ret); - return ret; - } - - public ForceFieldModelBuilder brightnessOverride(int light) { - this.brightnessOverride = light; - return this; - } - - public ForceFieldModelBuilder disableShade() { - this.defaultShade = false; - return this; - } - - public ForceFieldModelBuilder tintAll(int index) { - this.tint = index; - return this; - } - - @Override - protected CustomLoaderBuilder copyInternal() { - ForceFieldModelBuilder builder = new ForceFieldModelBuilder(); - builder.elements = this.elements; - builder.defaultShade = this.defaultShade; - builder.brightnessOverride = this.brightnessOverride; - builder.tint = this.tint; - return builder; - } - - @Override - public JsonObject toJson(JsonObject json) { - json = super.toJson(json); - if (!this.elements.isEmpty()) { - JsonArray elementsArray = new JsonArray(); - this.elements.forEach(forceFieldElementBuilder -> { - JsonObject partObj = new JsonObject(); - - if (forceFieldElementBuilder.condition != null) { - JsonObject condition = new JsonObject(); - condition.addProperty("if", forceFieldElementBuilder.condition.getSecond()); - condition.addProperty("direction", forceFieldElementBuilder.condition.getFirst().getSerializedName()); - - JsonArray parents = new JsonArray(); - for (ExtraDirection parent : forceFieldElementBuilder.parents) { - parents.add(parent.getSerializedName()); - } - condition.add("parents", parents); - - partObj.add("condition", condition); - } - - partObj.add("from", serializeVector3f(forceFieldElementBuilder.from)); - partObj.add("to", serializeVector3f(forceFieldElementBuilder.to)); - - if (forceFieldElementBuilder.rotation != null) { - JsonObject rotation = new JsonObject(); - rotation.add("origin", serializeVector3f(forceFieldElementBuilder.rotation.origin)); - rotation.addProperty("axis", forceFieldElementBuilder.rotation.axis.getSerializedName()); - rotation.addProperty("angle", forceFieldElementBuilder.rotation.angle); - if (forceFieldElementBuilder.rotation.rescale) { - rotation.addProperty("rescale", true); - } - partObj.add("rotation", rotation); - } - - if (!forceFieldElementBuilder.shade) { - partObj.addProperty("shade", forceFieldElementBuilder.shade); - } - - if (forceFieldElementBuilder.light != 0) { - partObj.addProperty("light", forceFieldElementBuilder.light); - } - - JsonObject facesObj = new JsonObject(); - - for (net.minecraft.core.Direction dir : net.minecraft.core.Direction.values()) { - var faceBuilder = forceFieldElementBuilder.faces.get(dir); - if (faceBuilder == null) continue; - - JsonObject faceObj = new JsonObject(); - - faceObj.addProperty("texture", serializeLocOrKey(faceBuilder.texture)); - - if (faceBuilder.uvs != null) { - faceObj.add("uvs", new Gson().toJsonTree(faceBuilder.uvs)); - } - - if (faceBuilder.cullface != null) { - faceObj.addProperty("cullface", faceBuilder.cullface.getSerializedName()); - } - - if (faceBuilder.rotation.rotation != 0) { - faceObj.addProperty("rotation", faceBuilder.rotation.rotation); - } - - if (faceBuilder.tintindex != -1) { - faceObj.addProperty("tintindex", faceBuilder.tintindex); - } - - facesObj.add(dir.getSerializedName(), faceObj); - } - - if (!forceFieldElementBuilder.faces.isEmpty()) { - partObj.add("faces", facesObj); - } - elementsArray.add(partObj); - }); - json.add("elements", elementsArray); - } - return json; - } - - private static String serializeLocOrKey(String tex) { - if (tex.charAt(0) == '#') { - return tex; - } - return Identifier.parse(tex).toString(); - } - - private static JsonArray serializeVector3f(Vector3f vec) { - JsonArray ret = new JsonArray(); - ret.add(serializeFloat(vec.x())); - ret.add(serializeFloat(vec.y())); - ret.add(serializeFloat(vec.z())); - return ret; - } - - private static Number serializeFloat(float f) { - if ((int) f == f) return (int) f; - return f; - } - - - /** - * Forge copy of ElementBuilder, with some things changed - */ - public class ForceFieldElementBuilder { - private Vector3f from = new Vector3f(); - private Vector3f to = new Vector3f(16, 16, 16); - private final Map faces = new LinkedHashMap<>(); - @Nullable - private ForceFieldElementBuilder.RotationBuilder rotation; - private boolean shade; - private int light; - private int tint; - @Nullable - private Pair condition = null; - private final List parents = new ArrayList<>(); - - private ForceFieldElementBuilder(boolean defaultShade, int brightnessOverride, int tint) { - this.shade = defaultShade; - this.light = brightnessOverride; - this.tint = tint; - } - - private static void validateCoordinate(float coord, char name) { - Preconditions.checkArgument(!(coord < -16.0F) && !(coord > 32.0F), "Position " + name + " out of range, must be within [-16, 32]. Found: %d", coord); - } - - private static void validatePosition(Vector3f pos) { - validateCoordinate(pos.x(), 'x'); - validateCoordinate(pos.y(), 'y'); - validateCoordinate(pos.z(), 'z'); - } - - public ForceFieldElementBuilder from(float x, float y, float z) { - this.from = new Vector3f(x, y, z); - validatePosition(this.from); - return this; - } - - public ForceFieldElementBuilder to(float x, float y, float z) { - this.to = new Vector3f(x, y, z); - validatePosition(this.to); - return this; - } - - public ForceFieldElementBuilder.FaceBuilder face(Direction dir) { - Preconditions.checkNotNull(dir, "Direction must not be null"); - return this.faces.computeIfAbsent(dir, direction -> new FaceBuilder(this.tint)); - } - - public ForceFieldElementBuilder.RotationBuilder rotation() { - if (this.rotation == null) { - this.rotation = new ForceFieldElementBuilder.RotationBuilder(); - } - return this.rotation; - } - - public ForceFieldElementBuilder shade(boolean shade) { - this.shade = shade; - return this; - } - - public ForceFieldElementBuilder allFaces(BiConsumer action) { - Arrays.stream(Direction.values()).forEach(d -> action.accept(d, this.face(d))); - return this; - } - - public ForceFieldElementBuilder faces(BiConsumer action) { - this.faces.forEach(action); - return this; - } - - public ForceFieldElementBuilder textureAll(String texture) { - return this.allFaces(this.addTexture(texture)); - } - - public ForceFieldElementBuilder texture(String texture) { - return this.faces(this.addTexture(texture)); - } - - public ForceFieldElementBuilder cube(String texture) { - return this.allFaces(this.addTexture(texture).andThen((dir, f) -> f.cullface(dir))); - } - - public ForceFieldElementBuilder emissivity(int light) { - this.light = light; - return this; - } - - public ForceFieldElementBuilder ifState(ExtraDirection condition, boolean b) { - this.condition = Pair.of(condition, b); - return this; - } - - // Returns a new ForceFieldElementBuilder that has the same condition - public ForceFieldElementBuilder ifSame() { - ForceFieldElementBuilder newBuilder = this.end().forceFieldElement(); - newBuilder.condition = Pair.of(this.condition.getFirst(), this.condition.getSecond()); - return newBuilder; - } - - // Returns a new ForceFieldElementBuilder that has the opposite condition - public ForceFieldElementBuilder ifElse() { - ForceFieldElementBuilder newBuilder = this.end().forceFieldElement(); - newBuilder.condition = Pair.of(this.condition.getFirst(), !this.condition.getSecond()); - return newBuilder; - } - - public ForceFieldElementBuilder parents(ExtraDirection... parents) { - Collections.addAll(this.parents, parents); - return this; - } - - private BiConsumer addTexture(String texture) { - return (direction, builder) -> builder.texture(texture); - } - - public ForceFieldModelBuilder end() { - return self(); - } - - public class FaceBuilder { - @Nullable - private Direction cullface; - private int tintindex; - @Nullable - private String texture = MissingTextureAtlasSprite.getLocation().toString(); - private float@Nullable[] uvs; - private FaceRotation rotation = FaceRotation.ZERO; - - FaceBuilder(int tint) { - this.tintindex = tint; - } - - public ForceFieldElementBuilder.FaceBuilder cullface(@Nullable Direction dir) { - this.cullface = dir; - return this; - } - - public ForceFieldElementBuilder.FaceBuilder tintindex(int index) { - this.tintindex = index; - return this; - } - - public ForceFieldElementBuilder.FaceBuilder texture(String texture) { - Preconditions.checkNotNull(texture, "Texture must not be null"); - this.texture = texture; - return this; - } - - public ForceFieldElementBuilder.FaceBuilder uvs(float u1, float v1, float u2, float v2) { - this.uvs = new float[]{u1, v1, u2, v2}; - return this; - } - - public ForceFieldElementBuilder.FaceBuilder rotation(FaceRotation rot) { - Preconditions.checkNotNull(rot, "Rotation must not be null"); - this.rotation = rot; - return this; - } - - public ForceFieldElementBuilder end() { - return ForceFieldElementBuilder.this; - } - } - - public class RotationBuilder { - - @Nullable - private Vector3f origin; - @Nullable - private Direction.Axis axis; - private float angle; - private boolean rescale; - - public ForceFieldElementBuilder.RotationBuilder origin(float x, float y, float z) { - this.origin = new Vector3f(x, y, z); - return this; - } - - public ForceFieldElementBuilder.RotationBuilder axis(Direction.Axis axis) { - Preconditions.checkNotNull(axis, "Axis must not be null"); - this.axis = axis; - return this; - } - - public ForceFieldElementBuilder.RotationBuilder angle(float angle) { - // Same logic from BlockPart.Deserializer#parseAngle - Preconditions.checkArgument(angle == 0.0F || Mth.abs(angle) == 22.5F || Mth.abs(angle) == 45.0F, "Invalid rotation %f found, only -45/-22.5/0/22.5/45 allowed", angle); - this.angle = angle; - return this; - } - - public ForceFieldElementBuilder.RotationBuilder rescale(boolean rescale) { - this.rescale = rescale; - return this; - } - - public ForceFieldElementBuilder end() { - return ForceFieldElementBuilder.this; - } - } - } - - public enum FaceRotation { - ZERO(0), - CLOCKWISE_90(90), - UPSIDE_DOWN(180), - COUNTERCLOCKWISE_90(270); - - final int rotation; - - FaceRotation(int rotation) { - this.rotation = rotation; - } - } -} diff --git a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java deleted file mode 100644 index ee251fb99f..0000000000 --- a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java +++ /dev/null @@ -1,57 +0,0 @@ -package twilightforest.client.model.block.forcefield; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import net.minecraft.util.GsonHelper; -import net.neoforged.neoforge.client.model.StandardModelParameters; -import net.neoforged.neoforge.client.model.UnbakedModelLoader; -import org.jetbrains.annotations.Nullable; -import twilightforest.client.model.block.forcefield.ForceFieldModel.ExtraDirection; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class ForceFieldModelLoader implements UnbakedModelLoader { - public static final ForceFieldModelLoader INSTANCE = new ForceFieldModelLoader(); - - @Override - @SuppressWarnings("ConstantConditions") - public UnbakedForceFieldModel read(JsonObject json, JsonDeserializationContext context) throws JsonParseException { - - Map elementsAndConditions = new HashMap<>(); - - if (json.has("elements")) { - int elementIndex = 0; - for (JsonElement jsonElement : GsonHelper.getAsJsonArray(json, "elements")) { - ExtraDirection direction = null; - boolean b = false; - List parents = new ArrayList<>(); - - if (jsonElement instanceof JsonObject element) { - if (element.get("condition") instanceof JsonObject condition) { - direction = ForceFieldModel.ExtraDirection.byName(GsonHelper.getAsString(condition, "direction", "up")); - b = GsonHelper.getAsBoolean(condition, "if", true); - for (JsonElement parentElement : GsonHelper.getAsJsonArray(condition, "parents")) { - parents.add(ForceFieldModel.ExtraDirection.byName(parentElement.getAsString())); - } - } - - String elementName = element.has("name") ? GsonHelper.getAsString(element, "name") : "element_" + elementIndex; - - elementsAndConditions.put(elementName, new Condition(direction, b, parents)); - elementIndex++; - } - } - } - - return new UnbakedForceFieldModel(elementsAndConditions, StandardModelParameters.parse(json, context)); - } - - public record Condition(@Nullable ExtraDirection direction, boolean b, List parents) { - - } -} diff --git a/src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java b/src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java deleted file mode 100644 index 2bbf4cb784..0000000000 --- a/src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java +++ /dev/null @@ -1,31 +0,0 @@ -package twilightforest.client.model.block.forcefield; - -import net.minecraft.client.renderer.rendertype.RenderTypes; -import net.minecraft.client.resources.model.cuboid.ItemTransforms; -import net.minecraft.client.resources.model.geometry.UnbakedGeometry; -import net.neoforged.neoforge.client.model.AbstractUnbakedModel; -import net.neoforged.neoforge.client.model.StandardModelParameters; - -import java.util.Map; - -public class UnbakedForceFieldModel extends AbstractUnbakedModel { - - private final Map elementsAndConditions; - - public UnbakedForceFieldModel(Map elementsAndConditions, StandardModelParameters parameters) { - super(parameters); - this.elementsAndConditions = elementsAndConditions; - } - - @Override - public UnbakedGeometry geometry() { - return new ForceFieldModel( - this.elementsAndConditions, - (String textureKey) -> textureKey, - Boolean.TRUE.equals(this.parameters.ambientOcclusion()), - this.parameters.guiLight().lightLikeBlock(), - ItemTransforms.NO_TRANSFORMS, - java.util.Set.of(RenderTypes.translucentMovingBlock()) - ); - } -} diff --git a/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockBuilder.java b/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockBuilder.java index 1ebca90c16..a8ecaa1d0a 100644 --- a/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockBuilder.java +++ b/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockBuilder.java @@ -1,6 +1,5 @@ package twilightforest.client.model.block.giantblock; -import com.google.gson.JsonObject; import net.neoforged.neoforge.client.model.generators.template.CustomLoaderBuilder; import twilightforest.TwilightForestMod; diff --git a/src/main/java/twilightforest/client/model/block/patch/PatchBuilder.java b/src/main/java/twilightforest/client/model/block/patch/PatchBuilder.java deleted file mode 100644 index c60e278071..0000000000 --- a/src/main/java/twilightforest/client/model/block/patch/PatchBuilder.java +++ /dev/null @@ -1,35 +0,0 @@ -package twilightforest.client.model.block.patch; - -import com.google.gson.JsonObject; -import net.neoforged.neoforge.client.model.generators.template.CustomLoaderBuilder; -import twilightforest.TwilightForestMod; - -public class PatchBuilder extends CustomLoaderBuilder { - - private boolean shaggify = false; - - public PatchBuilder() { - super(TwilightForestMod.prefix("patch"), false); - } - - public PatchBuilder shaggify() { - this.shaggify = true; - return this; - } - - @Override - protected CustomLoaderBuilder copyInternal() { - PatchBuilder builder = new PatchBuilder(); - builder.shaggify = this.shaggify; - return builder; - } - - @Override - public JsonObject toJson(JsonObject json) { - JsonObject mainJson = super.toJson(json); - - mainJson.addProperty("shaggify", this.shaggify); - - return mainJson; - } -} diff --git a/src/main/java/twilightforest/client/model/block/patch/PatchModel.java b/src/main/java/twilightforest/client/model/block/patch/PatchModel.java deleted file mode 100644 index 4681e968ba..0000000000 --- a/src/main/java/twilightforest/client/model/block/patch/PatchModel.java +++ /dev/null @@ -1,198 +0,0 @@ -package twilightforest.client.model.block.patch; - -import com.google.common.collect.ImmutableList; -import net.minecraft.client.renderer.block.dispatch.ModelState; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.ModelBaker; -import net.minecraft.client.resources.model.ModelDebugName; -import net.minecraft.client.resources.model.geometry.BakedQuad; -import net.minecraft.client.resources.model.geometry.QuadCollection; -import net.minecraft.client.resources.model.geometry.UnbakedGeometry; -import net.minecraft.client.resources.model.sprite.TextureSlots; -import net.minecraft.core.Direction; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.levelgen.structure.BoundingBox; -import net.neoforged.neoforge.client.model.quad.MutableQuad; -import twilightforest.block.PatchBlock; - -import java.util.ArrayList; -import java.util.List; - -public class PatchModel implements UnbakedGeometry { - - private final boolean shaggify; - - private TextureAtlasSprite texture; - private boolean usesAO; - private boolean usesBlockLight; - - public PatchModel(boolean shaggify) { - this.shaggify = shaggify; - } - - public PatchModel(TextureAtlasSprite texture, boolean shaggify, boolean usesAO, boolean usesBlockLight) { - this.texture = texture; - this.shaggify = shaggify; - this.usesAO = usesAO; - this.usesBlockLight = usesBlockLight; - } - - private List getQuads(boolean north, boolean east, boolean south, boolean west, RandomSource posRandom) { - List list = new ArrayList<>(); - - BoundingBox bb = PatchBlock.AABBFromRandom(posRandom); - - this.quadsFromAABB(list, west ? 0 : bb.minX(), bb.minY(), north ? 0 : bb.minZ(), east ? 16 : bb.maxX(), bb.maxY(), south ? 16 : bb.maxZ()); - - if (!this.shaggify) - return ImmutableList.copyOf(list); - - // Poll these seeds before entering branching code, otherwise placing neighbors will cause odd changes - long westSeed = posRandom.nextLong(); - long eastSeed = posRandom.nextLong(); - long northSeed = posRandom.nextLong(); - long southSeed = posRandom.nextLong(); - - int minY = bb.minY(); - int maxY = bb.maxY(); - - // add on shaggy edges - if (!west) { - long seed = westSeed; - seed = seed * seed * 42317861L + seed * 7L; - - int num0 = (int) (seed >> 12 & 3L) + 1; - int num1 = (int) (seed >> 15 & 3L) + 1; - int num2 = (int) (seed >> 18 & 3L) + 1; - int num3 = (int) (seed >> 21 & 3L) + 1; - - int minZ = bb.minZ() + num0; - int maxZ = bb.maxZ(); - - if (maxZ - ((num1 + num2 + num3)) > minZ) { - // draw two blobs - int innerZ = bb.maxZ() - num2; - this.quadsFromAABB(list, bb.minX() - 1, minY, minZ, bb.minX(), maxY, minZ + num1); - this.quadsFromAABB(list, bb.minX() - 1, minY, innerZ - num3, bb.minX(), maxY, innerZ); - } else { - //draw one blob - this.quadsFromAABB(list, bb.minX() - 1, minY, minZ, bb.minX(), maxY, maxZ - num2); - } - } - - if (!east) { - long seed = eastSeed; - seed = seed * seed * 42317861L + seed * 17L; - - int num0 = (int) (seed >> 12 & 3L) + 1; - int num1 = (int) (seed >> 15 & 3L) + 1; - int num2 = (int) (seed >> 18 & 3L) + 1; - int num3 = (int) (seed >> 21 & 3L) + 1; - - int minZ = bb.minZ() + num0; - int maxZ = bb.maxZ(); - - if (maxZ - ((num1 + num2 + num3)) > minZ) { - // draw two blobs - int innerZ = maxZ - num2; - this.quadsFromAABB(list, bb.maxX(), minY, minZ, bb.maxX() + 1, maxY, minZ + num1); - this.quadsFromAABB(list, bb.maxX(), minY, innerZ - num3, bb.maxX() + 1, maxY, innerZ); - } else { - //draw one blob - this.quadsFromAABB(list, bb.maxX(), minY, minZ, bb.maxX() + 1, maxY, maxZ - num2); - } - } - - if (!north) { - long seed = northSeed; - seed = seed * seed * 42317861L + seed * 23L; - - int num0 = (int) (seed >> 12 & 3L) + 1; - int num1 = (int) (seed >> 15 & 3L) + 1; - int num2 = (int) (seed >> 18 & 3L) + 1; - int num3 = (int) (seed >> 21 & 3L) + 1; - - int minX = bb.minX() + num0; - int innerX = minX + num1; - int maxX = bb.maxX() - num2; - - this.quadsFromAABB(list, minX, minY, bb.minZ() - 1, innerX, maxY, bb.minZ()); - this.quadsFromAABB(list, maxX - num3, minY, bb.minZ() - 1, maxX, maxY, bb.minZ()); - } - - if (!south) { - long seed = southSeed; - seed = seed * seed * 42317861L + seed * 11L; - - int num0 = (int) (seed >> 12 & 3L) + 1; - int num1 = (int) (seed >> 15 & 3L) + 1; - int num2 = (int) (seed >> 18 & 3L) + 1; - int num3 = (int) (seed >> 21 & 3L) + 1; - - int minX = bb.minX() + num0; - int maxX = bb.maxX() - num2; - - this.quadsFromAABB(list, minX, minY, bb.maxZ(), minX + num1, maxY, bb.maxZ() + 1); - this.quadsFromAABB(list, maxX - num3, minY, bb.maxZ(), maxX, maxY, bb.maxZ() + 1); - } - - return ImmutableList.copyOf(list); - } - - private void quadsFromAABB(List quads, float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { - quads.add(this.quadFromVectors(Direction.UP, minX, minY, minZ, maxX, maxY, maxZ)); - quads.add(this.quadFromVectors(Direction.NORTH, minX, minY, minZ, maxX, maxY, maxZ)); - quads.add(this.quadFromVectors(Direction.EAST, minX, minY, minZ, maxX, maxY, maxZ)); - quads.add(this.quadFromVectors(Direction.SOUTH, minX, minY, minZ, maxX, maxY, maxZ)); - quads.add(this.quadFromVectors(Direction.WEST, minX, minY, minZ, maxX, maxY, maxZ)); - quads.add(this.quadFromVectors(Direction.DOWN, minX, minY, minZ, maxX, maxY, maxZ)); - } - - private BakedQuad quadFromVectors(Direction direction, float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { - MutableQuad mutableQuad = new MutableQuad(); - - mutableQuad.setDirection(direction); - mutableQuad.setShade(this.usesAO); - - if (this.usesBlockLight) { - mutableQuad.setLightEmission(15); - } - - for (int v = 0; v < 4; v++) { - float x = (v == 1 || v == 2) ? maxX / 16.0f : minX / 16.0f; - float y = (v == 2 || v == 3) ? maxY / 16.0f : minY / 16.0f; - float z = (direction.getAxis() == net.minecraft.core.Direction.Axis.Z) ? maxZ / 16.0f : minZ / 16.0f; - - mutableQuad.setPosition(v, new org.joml.Vector3f(x, y, z)); - - float u = this.texture.getU(x * 16.0f); - float vCoord = this.texture.getV(y * 16.0f); - - if (direction == net.minecraft.core.Direction.EAST || direction == net.minecraft.core.Direction.WEST) { - mutableQuad.setUv(v, vCoord, u); - } else { - mutableQuad.setUv(v, u, vCoord); - } - } - - return mutableQuad.toBakedQuad(); - } - - @Override - public QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName modelDebugName) { - QuadCollection.Builder builder = new QuadCollection.Builder(); - - RandomSource staticRandom = RandomSource.create(42L); - List myPatchQuads = this.getQuads(false, false, false, false, staticRandom); - - for (BakedQuad quad : myPatchQuads) { - if (quad.direction() != null) { - builder.addCulledFace(quad.direction(), quad); - } else { - builder.addUnculledFace(quad); - } - } - - return builder.build(); - } -} diff --git a/src/main/java/twilightforest/client/model/block/patch/PatchModelLoader.java b/src/main/java/twilightforest/client/model/block/patch/PatchModelLoader.java deleted file mode 100644 index 4599a7d9e5..0000000000 --- a/src/main/java/twilightforest/client/model/block/patch/PatchModelLoader.java +++ /dev/null @@ -1,23 +0,0 @@ -package twilightforest.client.model.block.patch; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.mojang.realmsclient.util.JsonUtils; -import net.neoforged.neoforge.client.model.StandardModelParameters; -import net.neoforged.neoforge.client.model.UnbakedModelLoader; - -public final class PatchModelLoader implements UnbakedModelLoader { - public static final PatchModelLoader INSTANCE = new PatchModelLoader(); - - private PatchModelLoader() { - } - - @Override - public UnbakedPatchModel read(JsonObject object, JsonDeserializationContext deserializationContext) throws JsonParseException { -// if (!object.has("texture")) -// throw new JsonParseException("Patch model missing value for 'texture'."); - - return new UnbakedPatchModel(JsonUtils.getBooleanOr("shaggify", object, false), StandardModelParameters.parse(object, deserializationContext)); - } -} diff --git a/src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java b/src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java deleted file mode 100644 index ff875d6fb8..0000000000 --- a/src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java +++ /dev/null @@ -1,20 +0,0 @@ -package twilightforest.client.model.block.patch; - -import net.minecraft.client.resources.model.geometry.UnbakedGeometry; -import net.neoforged.neoforge.client.model.AbstractUnbakedModel; -import net.neoforged.neoforge.client.model.StandardModelParameters; - -public class UnbakedPatchModel extends AbstractUnbakedModel { - - private final boolean shaggify; - - public UnbakedPatchModel(boolean shaggify, StandardModelParameters parameters) { - super(parameters); - this.shaggify = shaggify; - } - - @Override - public UnbakedGeometry geometry() { - return new PatchModel(this.shaggify); - } -} diff --git a/src/main/java/twilightforest/init/TFBlockEntities.java b/src/main/java/twilightforest/init/TFBlockEntities.java deleted file mode 100644 index be58af63ee..0000000000 --- a/src/main/java/twilightforest/init/TFBlockEntities.java +++ /dev/null @@ -1,148 +0,0 @@ -package twilightforest.init; - -import net.minecraft.core.registries.Registries; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.neoforged.neoforge.registries.DeferredHolder; -import net.neoforged.neoforge.registries.DeferredRegister; -import twilightforest.TwilightForestMod; -import twilightforest.block.entity.*; -import twilightforest.block.entity.bookshelf.ChiseledCanopyShelfBlockEntity; -import twilightforest.block.entity.spawner.*; - -@SuppressWarnings("DataFlowIssue") -public class TFBlockEntities { - - public static final DeferredRegister> BLOCK_ENTITIES = DeferredRegister.create(Registries.BLOCK_ENTITY_TYPE, TwilightForestMod.ID); - - public static final DeferredHolder, BlockEntityType> ANTIBUILDER = BLOCK_ENTITIES.register("antibuilder", () -> - new BlockEntityType<>(AntibuilderBlockEntity::new, TFBlocks.ANTIBUILDER.get())); - public static final DeferredHolder, BlockEntityType> CINDER_FURNACE = BLOCK_ENTITIES.register("cinder_furnace", () -> - new BlockEntityType<>(CinderFurnaceBlockEntity::new, TFBlocks.CINDER_FURNACE.get())); - public static final DeferredHolder, BlockEntityType> CARMINITE_REACTOR = BLOCK_ENTITIES.register("carminite_reactor", () -> - new BlockEntityType<>(CarminiteReactorBlockEntity::new, TFBlocks.CARMINITE_REACTOR.get())); - public static final DeferredHolder, BlockEntityType> REACTOR_DEBRIS = BLOCK_ENTITIES.register("reactor_debris", () -> - new BlockEntityType<>(ReactorDebrisBlockEntity::new, TFBlocks.REACTOR_DEBRIS.get())); - public static final DeferredHolder, BlockEntityType> FLAME_JET = BLOCK_ENTITIES.register("flame_jet", () -> - new BlockEntityType<>(FireJetBlockEntity::new, TFBlocks.FIRE_JET.get(), TFBlocks.ENCASED_FIRE_JET.get())); - public static final DeferredHolder, BlockEntityType> GHAST_TRAP = BLOCK_ENTITIES.register("ghast_trap", () -> - new BlockEntityType<>(GhastTrapBlockEntity::new, TFBlocks.GHAST_TRAP.get())); - public static final DeferredHolder, BlockEntityType> SMOKER = BLOCK_ENTITIES.register("smoker", () -> - new BlockEntityType<>(TFSmokerBlockEntity::new, TFBlocks.SMOKER.get(), TFBlocks.ENCASED_SMOKER.get())); - public static final DeferredHolder, BlockEntityType> TOWER_BUILDER = BLOCK_ENTITIES.register("tower_builder", () -> - new BlockEntityType<>(CarminiteBuilderBlockEntity::new, TFBlocks.CARMINITE_BUILDER.get())); - public static final DeferredHolder, BlockEntityType> TROPHY = BLOCK_ENTITIES.register("trophy", () -> - new BlockEntityType<>(TrophyBlockEntity::new, TFBlocks.NAGA_TROPHY.get(), TFBlocks.LICH_TROPHY.get(), TFBlocks.MINOSHROOM_TROPHY.get(), - TFBlocks.HYDRA_TROPHY.get(), TFBlocks.KNIGHT_PHANTOM_TROPHY.get(), TFBlocks.UR_GHAST_TROPHY.get(), TFBlocks.ALPHA_YETI_TROPHY.get(), - TFBlocks.SNOW_QUEEN_TROPHY.get(), TFBlocks.QUEST_RAM_TROPHY.get(), TFBlocks.NAGA_WALL_TROPHY.get(), TFBlocks.LICH_WALL_TROPHY.get(), - TFBlocks.MINOSHROOM_WALL_TROPHY.get(), TFBlocks.HYDRA_WALL_TROPHY.get(), TFBlocks.KNIGHT_PHANTOM_WALL_TROPHY.get(), TFBlocks.UR_GHAST_WALL_TROPHY.get(), - TFBlocks.ALPHA_YETI_WALL_TROPHY.get(), TFBlocks.SNOW_QUEEN_WALL_TROPHY.get(), TFBlocks.QUEST_RAM_WALL_TROPHY.get())); - public static final DeferredHolder, BlockEntityType> ALPHA_YETI_SPAWNER = BLOCK_ENTITIES.register("alpha_yeti_spawner", () -> - new BlockEntityType<>(AlphaYetiSpawnerBlockEntity::new, TFBlocks.ALPHA_YETI_BOSS_SPAWNER.get())); - public static final DeferredHolder, BlockEntityType> FINAL_BOSS_SPAWNER = BLOCK_ENTITIES.register("final_boss_spawner", () -> - new BlockEntityType<>(FinalBossSpawnerBlockEntity::new, TFBlocks.FINAL_BOSS_BOSS_SPAWNER.get())); - public static final DeferredHolder, BlockEntityType> HYDRA_SPAWNER = BLOCK_ENTITIES.register("hydra_boss_spawner", () -> - new BlockEntityType<>(HydraSpawnerBlockEntity::new, TFBlocks.HYDRA_BOSS_SPAWNER.get())); - public static final DeferredHolder, BlockEntityType> KNIGHT_PHANTOM_SPAWNER = BLOCK_ENTITIES.register("knight_phantom_spawner", () -> - new BlockEntityType<>(KnightPhantomSpawnerBlockEntity::new, TFBlocks.KNIGHT_PHANTOM_BOSS_SPAWNER.get())); - public static final DeferredHolder, BlockEntityType> LICH_SPAWNER = BLOCK_ENTITIES.register("lich_spawner", () -> - new BlockEntityType<>(LichSpawnerBlockEntity::new, TFBlocks.LICH_BOSS_SPAWNER.get())); - public static final DeferredHolder, BlockEntityType> MINOSHROOM_SPAWNER = BLOCK_ENTITIES.register("minoshroom_spawner", () -> - new BlockEntityType<>(MinoshroomSpawnerBlockEntity::new, TFBlocks.MINOSHROOM_BOSS_SPAWNER.get())); - public static final DeferredHolder, BlockEntityType> NAGA_SPAWNER = BLOCK_ENTITIES.register("naga_spawner", () -> - new BlockEntityType<>(NagaSpawnerBlockEntity::new, TFBlocks.NAGA_BOSS_SPAWNER.get())); - public static final DeferredHolder, BlockEntityType> SNOW_QUEEN_SPAWNER = BLOCK_ENTITIES.register("snow_queen_spawner", () -> - new BlockEntityType<>(SnowQueenSpawnerBlockEntity::new, TFBlocks.SNOW_QUEEN_BOSS_SPAWNER.get())); - public static final DeferredHolder, BlockEntityType> UR_GHAST_SPAWNER = BLOCK_ENTITIES.register("tower_boss_spawner", () -> - new BlockEntityType<>(UrGhastSpawnerBlockEntity::new, TFBlocks.UR_GHAST_BOSS_SPAWNER.get())); - - public static final DeferredHolder, BlockEntityType> CICADA = BLOCK_ENTITIES.register("cicada", () -> - new BlockEntityType<>(CicadaBlockEntity::new, TFBlocks.CICADA.get())); - public static final DeferredHolder, BlockEntityType> FIREFLY = BLOCK_ENTITIES.register("firefly", () -> - new BlockEntityType<>(FireflyBlockEntity::new, TFBlocks.FIREFLY.get())); - public static final DeferredHolder, BlockEntityType> MOONWORM = BLOCK_ENTITIES.register("moonworm", () -> - new BlockEntityType<>(MoonwormBlockEntity::new, TFBlocks.MOONWORM.get())); - - public static final DeferredHolder, BlockEntityType> SKULL_CHEST = BLOCK_ENTITIES.register("skull_chest", () -> - new BlockEntityType<>(SkullChestBlockEntity::new, TFBlocks.SKULL_CHEST.get())); - public static final DeferredHolder, BlockEntityType> KEEPSAKE_CASKET = BLOCK_ENTITIES.register("keepsake_casket", () -> - new BlockEntityType<>(KeepsakeCasketBlockEntity::new, TFBlocks.KEEPSAKE_CASKET.get())); - public static final DeferredHolder, BlockEntityType> BRAZIER = BLOCK_ENTITIES.register("brazier", () -> - new BlockEntityType<>(BrazierBlockEntity::new, TFBlocks.BRAZIER.get())); - public static final DeferredHolder, BlockEntityType> CORONATION_CARPET = BLOCK_ENTITIES.register("coronation_carpet", () -> - new BlockEntityType<>(CoronationCarpetBlockEntity::new, TFBlocks.CORONATION_CARPET.get())); - - public static final DeferredHolder, BlockEntityType> TF_CHEST = BLOCK_ENTITIES.register("chest", () -> - new BlockEntityType<>(TFChestBlockEntity::new, - TFBlocks.TWILIGHT_OAK_CHEST.get(), TFBlocks.CANOPY_CHEST.get(), TFBlocks.MANGROVE_CHEST.get(), - TFBlocks.DARK_CHEST.get(), TFBlocks.TIME_CHEST.get(), TFBlocks.TRANSFORMATION_CHEST.get(), - TFBlocks.MINING_CHEST.get(), TFBlocks.SORTING_CHEST.get())); - - public static final DeferredHolder, BlockEntityType> TF_TRAPPED_CHEST = BLOCK_ENTITIES.register("trapped_chest", () -> - new BlockEntityType<>(TFTrappedChestBlockEntity::new, - TFBlocks.TWILIGHT_OAK_TRAPPED_CHEST.get(), TFBlocks.CANOPY_TRAPPED_CHEST.get(), TFBlocks.MANGROVE_TRAPPED_CHEST.get(), - TFBlocks.DARK_TRAPPED_CHEST.get(), TFBlocks.TIME_TRAPPED_CHEST.get(), TFBlocks.TRANSFORMATION_TRAPPED_CHEST.get(), - TFBlocks.MINING_TRAPPED_CHEST.get(), TFBlocks.SORTING_TRAPPED_CHEST.get())); - - public static final DeferredHolder, BlockEntityType> SKULL_CANDLE = BLOCK_ENTITIES.register("skull_candle", () -> - new BlockEntityType<>(SkullCandleBlockEntity::new, - TFBlocks.ZOMBIE_SKULL_CANDLE.get(), TFBlocks.ZOMBIE_WALL_SKULL_CANDLE.get(), - TFBlocks.SKELETON_SKULL_CANDLE.get(), TFBlocks.SKELETON_WALL_SKULL_CANDLE.get(), - TFBlocks.WITHER_SKELE_SKULL_CANDLE.get(), TFBlocks.WITHER_SKELE_WALL_SKULL_CANDLE.get(), - TFBlocks.CREEPER_SKULL_CANDLE.get(), TFBlocks.CREEPER_WALL_SKULL_CANDLE.get(), - TFBlocks.PLAYER_SKULL_CANDLE.get(), TFBlocks.PLAYER_WALL_SKULL_CANDLE.get(), - TFBlocks.PIGLIN_SKULL_CANDLE.get(), TFBlocks.PIGLIN_WALL_SKULL_CANDLE.get())); - - public static final DeferredHolder, BlockEntityType> CHISELED_CANOPY_BOOKSHELF = BLOCK_ENTITIES.register("chiseled_canopy_bookshelf", () -> - new BlockEntityType<>(ChiseledCanopyShelfBlockEntity::new, TFBlocks.CHISELED_CANOPY_BOOKSHELF.get())); - - public static final DeferredHolder, BlockEntityType> BEANSTALK_GROWER = BLOCK_ENTITIES.register("beanstalk_grower", () -> - new BlockEntityType<>(GrowingBeanstalkBlockEntity::new, TFBlocks.BEANSTALK_GROWER.get())); - - public static final DeferredHolder, BlockEntityType> RED_THREAD = BLOCK_ENTITIES.register("red_thread", () -> - new BlockEntityType<>(RedThreadBlockEntity::new, TFBlocks.RED_THREAD.get())); - - public static final DeferredHolder, BlockEntityType> CANDELABRA = BLOCK_ENTITIES.register("candelabra", () -> - new BlockEntityType<>(CandelabraBlockEntity::new, TFBlocks.CANDELABRA.get())); - - public static final DeferredHolder, BlockEntityType> JAR = BLOCK_ENTITIES.register("jar", () -> - new BlockEntityType<>(JarBlockEntity::new, TFBlocks.FIREFLY_JAR.get(), TFBlocks.CICADA_JAR.get())); - - public static final DeferredHolder, BlockEntityType> MASON_JAR = BLOCK_ENTITIES.register("mason_jar", () -> - new BlockEntityType<>(MasonJarBlockEntity::new, TFBlocks.MASON_JAR.get())); - - public static final DeferredHolder, BlockEntityType> SINISTER_SPAWNER = BLOCK_ENTITIES.register("sinister_spawner", () -> - new BlockEntityType<>(SinisterSpawnerBlockEntity::new, TFBlocks.SINISTER_SPAWNER.get())); - - public static final DeferredHolder, BlockEntityType> DRYING_RACK = BLOCK_ENTITIES.register("drying_rack", () -> - new BlockEntityType<>(DryingRackBlockEntity::new, - TFBlocks.OAK_DRYING_RACK.get(), TFBlocks.SPRUCE_DRYING_RACK.get(), - TFBlocks.BIRCH_DRYING_RACK.get(), TFBlocks.JUNGLE_DRYING_RACK.get(), - TFBlocks.ACACIA_DRYING_RACK.get(), TFBlocks.DARK_OAK_DRYING_RACK.get(), - TFBlocks.CRIMSON_DRYING_RACK.get(), TFBlocks.WARPED_DRYING_RACK.get(), - TFBlocks.VANGROVE_DRYING_RACK.get(), TFBlocks.BAMBOO_DRYING_RACK.get(), - TFBlocks.CHERRY_DRYING_RACK.get(), TFBlocks.PALE_OAK_DRYING_RACK.get(), - TFBlocks.TWILIGHT_OAK_DRYING_RACK.get(), TFBlocks.CANOPY_DRYING_RACK.get(), - TFBlocks.MANGROVE_DRYING_RACK.get(), TFBlocks.DARK_DRYING_RACK.get(), - TFBlocks.TIME_DRYING_RACK.get(), TFBlocks.TRANSFORMATION_DRYING_RACK.get(), - TFBlocks.MINING_DRYING_RACK.get(), TFBlocks.SORTING_DRYING_RACK.get())); - - public static final DeferredHolder, BlockEntityType> OMINOUS_CANDLE = BLOCK_ENTITIES.register("ominous_candle", () -> - new BlockEntityType<>(OminousCandleBlockEntity::new, - TFBlocks.OMINOUS_CANDLE.get(), - TFBlocks.OMINOUS_WHITE_CANDLE.get(), - TFBlocks.OMINOUS_ORANGE_CANDLE.get(), - TFBlocks.OMINOUS_MAGENTA_CANDLE.get(), - TFBlocks.OMINOUS_LIGHT_BLUE_CANDLE.get(), - TFBlocks.OMINOUS_YELLOW_CANDLE.get(), - TFBlocks.OMINOUS_LIME_CANDLE.get(), - TFBlocks.OMINOUS_PINK_CANDLE.get(), - TFBlocks.OMINOUS_GRAY_CANDLE.get(), - TFBlocks.OMINOUS_LIGHT_GRAY_CANDLE.get(), - TFBlocks.OMINOUS_CYAN_CANDLE.get(), - TFBlocks.OMINOUS_PURPLE_CANDLE.get(), - TFBlocks.OMINOUS_BLUE_CANDLE.get(), - TFBlocks.OMINOUS_BROWN_CANDLE.get(), - TFBlocks.OMINOUS_GREEN_CANDLE.get(), - TFBlocks.OMINOUS_RED_CANDLE.get(), - TFBlocks.OMINOUS_BLACK_CANDLE.get())); -} diff --git a/src/main/java/twilightforest/init/TFBlocks.java b/src/main/java/twilightforest/init/TFBlocks.java deleted file mode 100644 index e053ba27d6..0000000000 --- a/src/main/java/twilightforest/init/TFBlocks.java +++ /dev/null @@ -1,713 +0,0 @@ -package twilightforest.init; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.registries.Registries; -import net.minecraft.resources.ResourceKey; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.item.*; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.*; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; -import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; -import net.minecraft.world.level.material.MapColor; -import net.minecraft.world.level.material.PushReaction; -import net.neoforged.neoforge.registries.DeferredBlock; -import net.neoforged.neoforge.registries.DeferredRegister; -import twilightforest.TwilightForestMod; -import twilightforest.block.*; -import twilightforest.enums.BlockLoggingEnum; -import twilightforest.enums.BossVariant; -import twilightforest.enums.FireJetVariant; -import twilightforest.enums.TowerDeviceVariant; -import twilightforest.loot.TFLootTables; -import twilightforest.util.woods.TFWoodTypes; -import twilightforest.world.components.feature.trees.growers.TFTreeGrowers; - -import java.util.function.Function; -import java.util.function.Supplier; - -public class TFBlocks { - public static final DeferredRegister.Blocks BLOCKS = DeferredRegister.createBlocks(TwilightForestMod.ID); - - public static final DeferredBlock TWILIGHT_PORTAL = register("twilight_portal", TFPortalBlock::new, () -> BlockBehaviour.Properties.of().pushReaction(PushReaction.BLOCK).strength(-1.0F).sound(SoundType.GLASS).lightLevel((state) -> 11).noCollision().noOcclusion().noLootTable()); - - //misc. - public static final DeferredBlock HEDGE = registerWithItem("hedge", HedgeBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).sound(SoundType.GRASS).strength(2.0F, 6.0F)); - public static final DeferredBlock MASON_JAR = register("mason_jar", MasonJarBlock::new, () -> BlockBehaviour.Properties.of().noOcclusion().noTerrainParticles().randomTicks().sound(TFSoundTypes.JAR).strength(0.3F, 3.0F)); - public static final DeferredBlock FIREFLY_JAR = register("firefly_jar", FireflyJarBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> 15).noOcclusion().noTerrainParticles().sound(TFSoundTypes.JAR).strength(0.3F, 3.0F)); - public static final DeferredBlock FIREFLY_SPAWNER = registerWithItem("firefly_particle_spawner", FireflySpawnerBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> 15).noOcclusion().noTerrainParticles().sound(TFSoundTypes.JAR).strength(0.3F, 3.0F)); - public static final DeferredBlock CICADA_JAR = register("cicada_jar", CicadaJarBlock::new, () -> BlockBehaviour.Properties.of().noOcclusion().noTerrainParticles().randomTicks().sound(TFSoundTypes.JAR).strength(0.3F, 3.0F)); - public static final DeferredBlock MOSS_PATCH = registerWithItem("moss_patch", MossPatchBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instabreak().mapColor(MapColor.PLANT).noCollision().noOcclusion().pushReaction(PushReaction.DESTROY).sound(SoundType.MOSS)); - public static final DeferredBlock MAYAPPLE = registerWithItem("mayapple", MayappleBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instabreak().mapColor(MapColor.PLANT).noCollision().noOcclusion().pushReaction(PushReaction.DESTROY).sound(SoundType.GRASS)); - public static final DeferredBlock CLOVER_PATCH = registerWithItem("clover_patch", PatchBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().noCollision().noOcclusion().instabreak().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).sound(SoundType.GRASS)); - public static final DeferredBlock FIDDLEHEAD = registerWithItem("fiddlehead", FiddleheadBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instabreak().mapColor(MapColor.PLANT).noCollision().noOcclusion().pushReaction(PushReaction.DESTROY).replaceable().sound(SoundType.GRASS)); - public static final DeferredBlock MUSHGLOOM = registerWithItem("mushgloom", MushgloomBlock::new, () -> BlockBehaviour.Properties.of().instabreak().lightLevel((state) -> 3).noCollision().noOcclusion().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).sound(SoundType.FUNGUS)); - public static final DeferredBlock TORCHBERRY_PLANT = registerWithItem("torchberry_plant", TorchberryPlantBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instabreak().lightLevel(value -> value.getValue(TorchberryPlantBlock.HAS_BERRIES) ? 7 : 1).noCollision().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).sound(SoundType.HANGING_ROOTS)); - public static final DeferredBlock ROOT_STRAND = registerWithItem("root_strand", RootStrandBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instabreak().mapColor(MapColor.PLANT).noCollision().noOcclusion().pushReaction(PushReaction.DESTROY).sound(SoundType.HANGING_ROOTS)); - public static final DeferredBlock FALLEN_LEAVES = register("fallen_leaves", FallenLeavesBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instabreak().mapColor(MapColor.PLANT).noCollision().noOcclusion().replaceable().pushReaction(PushReaction.DESTROY).sound(SoundType.AZALEA_LEAVES)); - public static final DeferredBlock ROOT_BLOCK = registerWithItem("root", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.WOOD).sound(SoundType.WOOD).strength(2.0F, 3.0F)); - public static final DeferredBlock LIVEROOT_BLOCK = registerWithItem("liveroot_block", LiverootBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.COLOR_LIGHT_GREEN).sound(SoundType.WOOD).strength(2.0F, 3.0F)); - public static final DeferredBlock UNCRAFTING_TABLE = registerWithItem("uncrafting_table", UncraftingTableBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.FIRE).sound(SoundType.WOOD).strength(2.5F)); - public static final DeferredBlock SMOKER = registerWithItem("smoker", TFSmokerBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.GRASS).sound(SoundType.GRASS).strength(1.5F, 6.0F)); - public static final DeferredBlock ENCASED_SMOKER = registerWithItem("encased_smoker", EncasedSmokerBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.SAND).requiresCorrectToolForDrops().sound(SoundType.WOOD).strength(1.5F, 6.0F)); - public static final DeferredBlock FIRE_JET = registerWithItem("fire_jet", FireJetBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> state.getValue(FireJetBlock.STATE) != FireJetVariant.FLAME ? 0 : 15).mapColor(MapColor.GRASS).randomTicks().sound(SoundType.GRASS).strength(1.5F, 6.0F)); - public static final DeferredBlock ENCASED_FIRE_JET = registerWithItem("encased_fire_jet", EncasedFireJetBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().lightLevel((state) -> state.getValue(FireJetBlock.STATE) != FireJetVariant.FLAME ? 0 : 15).mapColor(MapColor.SAND).requiresCorrectToolForDrops().sound(SoundType.WOOD).strength(1.5F, 6.0F)); - public static final DeferredBlock FIREFLY = registerWithItem("firefly", FireflyBlock::new, () -> BlockBehaviour.Properties.of().instabreak().lightLevel((state) -> 15).noCollision().noTerrainParticles().pushReaction(PushReaction.DESTROY).sound(SoundType.SLIME_BLOCK)); - public static final DeferredBlock CICADA = registerWithItem("cicada", CicadaBlock::new, () -> BlockBehaviour.Properties.of().instabreak().noCollision().noTerrainParticles().pushReaction(PushReaction.DESTROY).sound(SoundType.SLIME_BLOCK)); - public static final DeferredBlock MOONWORM = registerWithItem("moonworm", MoonwormBlock::new, () -> BlockBehaviour.Properties.of().forceSolidOff().instabreak().lightLevel((state) -> 14).noCollision().noTerrainParticles().pushReaction(PushReaction.DESTROY).sound(SoundType.SLIME_BLOCK)); - public static final DeferredBlock HUGE_LILY_PAD = register("huge_lily_pad", HugeLilyPadBlock::new, () -> BlockBehaviour.Properties.of().instabreak().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).sound(SoundType.LILY_PAD)); - public static final DeferredBlock HUGE_WATER_LILY = register("huge_water_lily", HugeWaterLilyBlock::new, () -> BlockBehaviour.Properties.of().instabreak().mapColor(MapColor.PLANT).noCollision().pushReaction(PushReaction.DESTROY).sound(SoundType.LILY_PAD)); - public static final DeferredBlock SLIDER = registerWithItem("slider", SliderBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.DIRT).noLootTable().noOcclusion().randomTicks().strength(2.0F, 10.0F)); - public static final DeferredBlock IRON_LADDER = registerWithItem("iron_ladder", IronLadderBlock::new, () -> BlockBehaviour.Properties.of().forceSolidOff().noOcclusion().pushReaction(PushReaction.DESTROY).requiresCorrectToolForDrops().sound(SoundType.METAL).strength(5.0F, 6.0F)); - public static final DeferredBlock ROPE = register("rope", RopeBlock::new, () -> BlockBehaviour.Properties.of().forceSolidOff().noOcclusion().pushReaction(PushReaction.DESTROY).sound(SoundType.WOOL).strength(0.3F, 3.0F)); - public static final DeferredBlock CANOPY_WINDOW = registerWithItem("canopy_window", TransparentBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.HAT).strength(0.3F).sound(SoundType.GLASS).noOcclusion().isValidSpawn((pState, pLevel, pPos, pValue) -> false).isRedstoneConductor((pState, pLevel, pPos) -> false).isSuffocating((pState, pLevel, pPos) -> false).isViewBlocking((pState, pLevel, pPos) -> false)); - public static final DeferredBlock CANOPY_WINDOW_PANE = registerWithItem("canopy_window_pane", IronBarsBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.HAT).strength(0.3F).sound(SoundType.GLASS).noOcclusion()); - public static final DeferredBlock SINISTER_SPAWNER = registerWithItem("sinister_spawner", SinisterSpawnerBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.SPAWNER).noLootTable()); - public static final DeferredBlock BRAZIER = registerWithItem("brazier", BrazierBlock::new, () -> BlockBehaviour.Properties.of().sound(SoundType.WOOD).lightLevel(state -> state.getValue(BrazierBlock.HALF) == DoubleBlockHalf.UPPER ? state.getValue(BrazierBlock.LIGHT).getLight() : 0).pushReaction(PushReaction.DESTROY)); - - // bushes - public static final DeferredBlock IRON_OREBERRY_BUSH = registerWithItem("iron_oreberry_bush", properties -> new OreBerryBushBlock(false, TFLootTables.IRON_OREBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.METAL).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); - public static final DeferredBlock GOLD_OREBERRY_BUSH = registerWithItem("gold_oreberry_bush", properties -> new OreBerryBushBlock(false, TFLootTables.GOLD_OREBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.METAL).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); - public static final DeferredBlock COPPER_OREBERRY_BUSH = registerWithItem("copper_oreberry_bush", properties -> new OreBerryBushBlock(false, TFLootTables.COPPER_OREBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.METAL).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); - public static final DeferredBlock ESSENCE_OREBERRY_BUSH = registerWithItem("essence_oreberry_bush", properties -> new OreBerryBushBlock(true, TFLootTables.ESSENCE_BERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.METAL).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); - public static final DeferredBlock RASPBERRY_BUSH = registerWithItem("raspberry_bush", properties -> new BerryBushBlock(TFLootTables.RASPBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.GRASS).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); - public static final DeferredBlock BLUEBERRY_BUSH = registerWithItem("blueberry_bush", properties -> new BerryBushBlock(TFLootTables.BLUEBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.GRASS).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); - public static final DeferredBlock BLACKBERRY_BUSH = registerWithItem("blackberry_bush", properties -> new BerryBushBlock(TFLootTables.BLACKBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.GRASS).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); - public static final DeferredBlock MALOBERRY_BUSH = registerWithItem("maloberry_bush", properties -> new BerryBushBlock(TFLootTables.MALOBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.GRASS).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); - public static final DeferredBlock BLIGHTBERRY_BUSH = registerWithItem("blightberry_bush", properties -> new DarkTowerBerryBushBlock(TFLootTables.BLIGHTBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.GRASS).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); - public static final DeferredBlock DUSKBERRY_BUSH = registerWithItem("duskberry_bush", properties -> new DarkTowerBerryBushBlock(TFLootTables.DUSKBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.GRASS).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); - public static final DeferredBlock SKYBERRY_BUSH = registerWithItem("skyberry_bush", properties -> new DarkTowerBerryBushBlock(TFLootTables.SKYBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.GRASS).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); - public static final DeferredBlock STINGBERRY_BUSH = registerWithItem("stingberry_bush", properties -> new DarkTowerBerryBushBlock(TFLootTables.STINGBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.GRASS).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); - - //naga courtyard - public static final DeferredBlock NAGASTONE_HEAD = registerWithItem("nagastone_head", TFHorizontalBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); - public static final DeferredBlock NAGASTONE = registerWithItem("nagastone", NagastoneBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); - public static final DeferredBlock SPIRAL_BRICKS = registerWithItem("spiral_bricks", SpiralBrickBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).noOcclusion().requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); - public static final DeferredBlock ETCHED_NAGASTONE = registerWithItem("etched_nagastone", EtchedNagastoneBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); - public static final DeferredBlock NAGASTONE_PILLAR = registerWithItem("nagastone_pillar", DirectionalRotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); - public static final DeferredBlock NAGASTONE_STAIRS_LEFT = registerWithItem("nagastone_stairs_left", properties -> new StairBlock(ETCHED_NAGASTONE.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(ETCHED_NAGASTONE.get())); - public static final DeferredBlock NAGASTONE_STAIRS_RIGHT = registerWithItem("nagastone_stairs_right", properties -> new StairBlock(ETCHED_NAGASTONE.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(ETCHED_NAGASTONE.get())); - public static final DeferredBlock MOSSY_ETCHED_NAGASTONE = registerWithItem("mossy_etched_nagastone", EtchedNagastoneBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); - public static final DeferredBlock MOSSY_NAGASTONE_PILLAR = registerWithItem("mossy_nagastone_pillar", DirectionalRotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); - public static final DeferredBlock MOSSY_NAGASTONE_STAIRS_LEFT = registerWithItem("mossy_nagastone_stairs_left", properties -> new StairBlock(MOSSY_ETCHED_NAGASTONE.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(MOSSY_ETCHED_NAGASTONE.get())); - public static final DeferredBlock MOSSY_NAGASTONE_STAIRS_RIGHT = registerWithItem("mossy_nagastone_stairs_right", properties -> new StairBlock(MOSSY_ETCHED_NAGASTONE.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(MOSSY_ETCHED_NAGASTONE.get())); - public static final DeferredBlock CRACKED_ETCHED_NAGASTONE = registerWithItem("cracked_etched_nagastone", EtchedNagastoneBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); - public static final DeferredBlock CRACKED_NAGASTONE_PILLAR = registerWithItem("cracked_nagastone_pillar", DirectionalRotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); - public static final DeferredBlock CRACKED_NAGASTONE_STAIRS_LEFT = registerWithItem("cracked_nagastone_stairs_left", properties -> new StairBlock(CRACKED_ETCHED_NAGASTONE.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(CRACKED_ETCHED_NAGASTONE.get())); - public static final DeferredBlock CRACKED_NAGASTONE_STAIRS_RIGHT = registerWithItem("cracked_nagastone_stairs_right", properties -> new StairBlock(CRACKED_ETCHED_NAGASTONE.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(CRACKED_ETCHED_NAGASTONE.get())); - - //lich tower - public static final DeferredBlock TWISTED_STONE = registerWithItem("twisted_stone", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); - public static final DeferredBlock TWISTED_STONE_PILLAR = registerWithItem("twisted_stone_pillar", properties -> new WallPillarBlock(12, 16, properties), () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).noOcclusion().requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); - public static final DeferredBlock SKULL_CHEST = registerWithItem("skull_chest", SkullChestBlock::new, () -> BlockBehaviour.Properties.of().lightLevel(state -> state.getValue(BlockLoggingEnum.MULTILOGGED) == BlockLoggingEnum.LAVA ? 15 : 0).mapColor(MapColor.COLOR_LIGHT_GRAY).noOcclusion().pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.NETHERITE_BLOCK).strength(3.0F, 100.0F)); - public static final DeferredBlock KEEPSAKE_CASKET = register("keepsake_casket", KeepsakeCasketBlock::new, () -> BlockBehaviour.Properties.of().lightLevel(state -> state.getValue(BlockLoggingEnum.MULTILOGGED) == BlockLoggingEnum.LAVA ? 15 : 0).mapColor(MapColor.COLOR_BLACK).noOcclusion().pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.NETHERITE_BLOCK).strength(5.0F, 1200.0F)); - public static final DeferredBlock BOLD_STONE_PILLAR = registerWithItem("bold_stone_pillar", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); - public static final DeferredBlock CHISELED_CANOPY_BOOKSHELF = registerWithItem("chiseled_canopy_bookshelf", ChiseledCanopyShelfBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.COLOR_BROWN).sound(SoundType.CHISELED_BOOKSHELF).strength(2.5F)); - public static final DeferredBlock CANDELABRA = registerWithItem("candelabra", CandelabraBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).strength(1.5F)); - public static final DeferredBlock ZOMBIE_SKULL_CANDLE = register("zombie_skull_candle", properties -> new SkullCandleBlock(SkullBlock.Types.ZOMBIE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.ZOMBIE_HEAD)); - public static final DeferredBlock ZOMBIE_WALL_SKULL_CANDLE = register("zombie_wall_skull_candle", properties -> new WallSkullCandleBlock(SkullBlock.Types.ZOMBIE, properties), () -> BlockBehaviour.Properties.of().strength(1.0F).pushReaction(PushReaction.DESTROY).overrideLootTable(ZOMBIE_SKULL_CANDLE.get().getLootTable()).overrideDescription(ZOMBIE_SKULL_CANDLE.get().getDescriptionId())); - public static final DeferredBlock SKELETON_SKULL_CANDLE = register("skeleton_skull_candle", properties -> new SkullCandleBlock(SkullBlock.Types.SKELETON, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.SKELETON_SKULL)); - public static final DeferredBlock SKELETON_WALL_SKULL_CANDLE = register("skeleton_wall_skull_candle", properties -> new WallSkullCandleBlock(SkullBlock.Types.SKELETON, properties), () -> BlockBehaviour.Properties.of().strength(1.0F).pushReaction(PushReaction.DESTROY).overrideLootTable(SKELETON_SKULL_CANDLE.get().getLootTable()).overrideDescription(SKELETON_SKULL_CANDLE.get().getDescriptionId())); - public static final DeferredBlock WITHER_SKELE_SKULL_CANDLE = register("wither_skeleton_skull_candle", properties -> new SkullCandleBlock(SkullBlock.Types.WITHER_SKELETON, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.WITHER_SKELETON_SKULL)); - public static final DeferredBlock WITHER_SKELE_WALL_SKULL_CANDLE = register("wither_skeleton_wall_skull_candle", properties -> new WallSkullCandleBlock(SkullBlock.Types.WITHER_SKELETON, properties), () -> BlockBehaviour.Properties.of().strength(1.0F).pushReaction(PushReaction.DESTROY).overrideLootTable(WITHER_SKELE_SKULL_CANDLE.get().getLootTable()).overrideDescription(WITHER_SKELE_SKULL_CANDLE.get().getDescriptionId())); - public static final DeferredBlock CREEPER_SKULL_CANDLE = register("creeper_skull_candle", properties -> new SkullCandleBlock(SkullBlock.Types.CREEPER, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.CREEPER_HEAD)); - public static final DeferredBlock CREEPER_WALL_SKULL_CANDLE = register("creeper_wall_skull_candle", properties -> new WallSkullCandleBlock(SkullBlock.Types.CREEPER, properties), () -> BlockBehaviour.Properties.of().strength(1.0F).pushReaction(PushReaction.DESTROY).overrideLootTable(CREEPER_SKULL_CANDLE.get().getLootTable()).overrideDescription(CREEPER_SKULL_CANDLE.get().getDescriptionId())); - public static final DeferredBlock PLAYER_SKULL_CANDLE = register("player_skull_candle", properties -> new SkullCandleBlock(SkullBlock.Types.PLAYER, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.PLAYER_HEAD)); - public static final DeferredBlock PLAYER_WALL_SKULL_CANDLE = register("player_wall_skull_candle", properties -> new WallSkullCandleBlock(SkullBlock.Types.PLAYER, properties), () -> BlockBehaviour.Properties.of().strength(1.0F).pushReaction(PushReaction.DESTROY).overrideLootTable(PLAYER_SKULL_CANDLE.get().getLootTable()).overrideDescription(PLAYER_SKULL_CANDLE.get().getDescriptionId())); - public static final DeferredBlock PIGLIN_SKULL_CANDLE = register("piglin_skull_candle", properties -> new SkullCandleBlock(SkullBlock.Types.PIGLIN, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.PIGLIN_HEAD)); - public static final DeferredBlock PIGLIN_WALL_SKULL_CANDLE = register("piglin_wall_skull_candle", properties -> new WallSkullCandleBlock(SkullBlock.Types.PIGLIN, properties), () -> BlockBehaviour.Properties.of().strength(1.0F).pushReaction(PushReaction.DESTROY).overrideLootTable(PIGLIN_SKULL_CANDLE.get().getLootTable()).overrideDescription(PIGLIN_SKULL_CANDLE.get().getDescriptionId())); - public static final DeferredBlock WROUGHT_IRON_FENCE = register("wrought_iron_fence", WroughtIronFenceBlock::new, () -> BlockBehaviour.Properties.of().strength(8.0F, 20.0F).sound(SoundType.METAL).requiresCorrectToolForDrops().noOcclusion()); - public static final DeferredBlock TERRORCOTTA_ARCS = registerWithItem("terrorcotta_arcs", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(1.5F, 6.0F)); - public static final DeferredBlock TERRORCOTTA_CURVES = registerWithItem("terrorcotta_curves", GlazedTerracottaBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(1.5F, 6.0F)); - public static final DeferredBlock TERRORCOTTA_LINES = registerWithItem("terrorcotta_lines", BinaryRotatedBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(1.5F, 6.0F)); - public static final DeferredBlock CORONATION_CARPET = registerWithItem("coronation_carpet", properties -> new CoronationCarpetBlock(DyeColor.RED, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.RED_CARPET).isValidSpawn(Blocks::always)); - - //ominous - public static final DeferredBlock OMINOUS_FIRE = register("ominous_fire", OminousFireBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_PURPLE).replaceable().noCollision().instabreak().lightLevel((state) -> 15).sound(SoundType.WOOL).pushReaction(PushReaction.DESTROY)); - public static final DeferredBlock OMINOUS_CANDLE = ominousCandle("ominous_candle", MapColor.SAND, Blocks.CANDLE); - public static final DeferredBlock OMINOUS_WHITE_CANDLE = ominousCandle("ominous_white_candle", MapColor.WOOL, Blocks.WHITE_CANDLE); - public static final DeferredBlock OMINOUS_ORANGE_CANDLE = ominousCandle("ominous_orange_candle", MapColor.COLOR_ORANGE, Blocks.ORANGE_CANDLE); - public static final DeferredBlock OMINOUS_MAGENTA_CANDLE = ominousCandle("ominous_magenta_candle", MapColor.COLOR_MAGENTA, Blocks.MAGENTA_CANDLE); - public static final DeferredBlock OMINOUS_LIGHT_BLUE_CANDLE = ominousCandle("ominous_light_blue_candle", MapColor.COLOR_LIGHT_BLUE, Blocks.LIGHT_BLUE_CANDLE); - public static final DeferredBlock OMINOUS_YELLOW_CANDLE = ominousCandle("ominous_yellow_candle", MapColor.COLOR_YELLOW, Blocks.YELLOW_CANDLE); - public static final DeferredBlock OMINOUS_LIME_CANDLE = ominousCandle("ominous_lime_candle", MapColor.COLOR_LIGHT_GREEN, Blocks.LIME_CANDLE); - public static final DeferredBlock OMINOUS_PINK_CANDLE = ominousCandle("ominous_pink_candle", MapColor.COLOR_PINK, Blocks.PINK_CANDLE); - public static final DeferredBlock OMINOUS_GRAY_CANDLE = ominousCandle("ominous_gray_candle", MapColor.COLOR_GRAY, Blocks.GRAY_CANDLE); - public static final DeferredBlock OMINOUS_LIGHT_GRAY_CANDLE = ominousCandle("ominous_light_gray_candle", MapColor.COLOR_LIGHT_GRAY, Blocks.LIGHT_GRAY_CANDLE); - public static final DeferredBlock OMINOUS_CYAN_CANDLE = ominousCandle("ominous_cyan_candle", MapColor.COLOR_CYAN, Blocks.CYAN_CANDLE); - public static final DeferredBlock OMINOUS_PURPLE_CANDLE = ominousCandle("ominous_purple_candle", MapColor.COLOR_PURPLE, Blocks.PURPLE_CANDLE); - public static final DeferredBlock OMINOUS_BLUE_CANDLE = ominousCandle("ominous_blue_candle", MapColor.COLOR_BLUE, Blocks.BLUE_CANDLE); - public static final DeferredBlock OMINOUS_BROWN_CANDLE = ominousCandle("ominous_brown_candle", MapColor.COLOR_BROWN, Blocks.BROWN_CANDLE); - public static final DeferredBlock OMINOUS_GREEN_CANDLE = ominousCandle("ominous_green_candle", MapColor.COLOR_GREEN, Blocks.GREEN_CANDLE); - public static final DeferredBlock OMINOUS_RED_CANDLE = ominousCandle("ominous_red_candle", MapColor.COLOR_RED, Blocks.RED_CANDLE); - public static final DeferredBlock OMINOUS_BLACK_CANDLE = ominousCandle("ominous_black_candle", MapColor.COLOR_BLACK, Blocks.BLACK_CANDLE); - - //labyrinth - public static final DeferredBlock MAZESTONE = registerWithItem("mazestone", Block::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(100.0F, 5.0F)); - public static final DeferredBlock MAZESTONE_BRICK = registerWithItem("mazestone_brick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(MAZESTONE.get())); - public static final DeferredBlock CUT_MAZESTONE = registerWithItem("cut_mazestone", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(MAZESTONE.get())); - public static final DeferredBlock DECORATIVE_MAZESTONE = registerWithItem("decorative_mazestone", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(MAZESTONE.get())); - public static final DeferredBlock CRACKED_MAZESTONE = registerWithItem("cracked_mazestone", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(MAZESTONE.get())); - public static final DeferredBlock MOSSY_MAZESTONE = registerWithItem("mossy_mazestone", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(MAZESTONE.get())); - public static final DeferredBlock MAZESTONE_MOSAIC = registerWithItem("mazestone_mosaic", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(MAZESTONE.get())); - public static final DeferredBlock MAZESTONE_BORDER = registerWithItem("mazestone_border", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(MAZESTONE.get())); - public static final DeferredBlock RED_THREAD = registerWithItem("red_thread", RedThreadBlock::new, () -> BlockBehaviour.Properties.of().instabreak().mapColor(MapColor.FIRE).isValidSpawn(TFBlocks::noSpawning).noCollision().noOcclusion().noTerrainParticles().pushReaction(PushReaction.DESTROY)); - public static final DeferredBlock MAZE_SLIME_BLOCK = registerWithItem("maze_slime_block", MazeSlimeBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.SLIME_BLOCK).mapColor(MapColor.STONE)); - - //stronghold - public static final DeferredBlock STRONGHOLD_SHIELD = registerWithItem("stronghold_shield", StrongholdShieldBlock::new, () -> BlockBehaviour.Properties.of().noLootTable().mapColor(MapColor.STONE).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.METAL).strength(-1.0F, 6000000.0F)); - public static final DeferredBlock TROPHY_PEDESTAL = registerWithItem("trophy_pedestal", TrophyPedestalBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(2.0F, 2000.0F)); - public static final DeferredBlock UNDERBRICK = registerWithItem("underbrick", Block::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).requiresCorrectToolForDrops().sound(SoundType.DEEPSLATE_BRICKS).strength(1.5F, 6.0F)); - public static final DeferredBlock MOSSY_UNDERBRICK = registerWithItem("mossy_underbrick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(UNDERBRICK.get())); - public static final DeferredBlock CRACKED_UNDERBRICK = registerWithItem("cracked_underbrick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(UNDERBRICK.get())); - public static final DeferredBlock UNDERBRICK_FLOOR = registerWithItem("underbrick_floor", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(UNDERBRICK.get())); - - //dark tower - public static final DeferredBlock TOWERWOOD = registerWithItem("towerwood", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.COLOR_ORANGE).strength(40.0F, 6.0F).sound(SoundType.WOOD)); - public static final DeferredBlock ENCASED_TOWERWOOD = registerWithItem("encased_towerwood", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(TOWERWOOD.get()).mapColor(MapColor.SAND)); - public static final DeferredBlock CRACKED_TOWERWOOD = registerWithItem("cracked_towerwood", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(TOWERWOOD.get())); - public static final DeferredBlock MOSSY_TOWERWOOD = registerWithItem("mossy_towerwood", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(TOWERWOOD.get())); - public static final DeferredBlock INFESTED_TOWERWOOD = registerWithItem("infested_towerwood", InfestedTowerwoodBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TOWERWOOD.get()).instrument(NoteBlockInstrument.FLUTE).noLootTable().strength(2.0F, 6.0F)); - public static final DeferredBlock REAPPEARING_BLOCK = registerWithItem("reappearing_block", ReappearingBlock::new, () -> BlockBehaviour.Properties.of().forceSolidOn().lightLevel((state) -> 4).mapColor(MapColor.SAND).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.WOOD).strength(10.0F, 35.0F)); - public static final DeferredBlock VANISHING_BLOCK = registerWithItem("vanishing_block", VanishingBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> state.getValue(VanishingBlock.ACTIVE) ? 4 : 0).mapColor(MapColor.SAND).pushReaction(PushReaction.BLOCK).sound(SoundType.WOOD).strength(10.0F, 35.0F)); - public static final DeferredBlock UNBREAKABLE_VANISHING_BLOCK = register("unbreakable_vanishing_block", VanishingBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(VANISHING_BLOCK.get()).noLootTable().strength(-1.0F, 6000000.0F)); - public static final DeferredBlock LOCKED_VANISHING_BLOCK = registerWithItem("locked_vanishing_block", LockedVanishingBlock::new, () -> BlockBehaviour.Properties.of().pushReaction(PushReaction.BLOCK).mapColor(MapColor.SAND).sound(SoundType.WOOD).strength(-1.0F, 2000.0F)); - public static final DeferredBlock CARMINITE_BUILDER = registerWithItem("carminite_builder", BuilderBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> state.getValue(BuilderBlock.STATE) == TowerDeviceVariant.BUILDER_ACTIVE ? 4 : 0).mapColor(MapColor.SAND).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.WOOD).strength(10.0F, 6.0F)); - public static final DeferredBlock BUILT_BLOCK = register("built_block", TranslucentBuiltBlock::new, () -> BlockBehaviour.Properties.of().noLootTable().noOcclusion().pushReaction(PushReaction.BLOCK).sound(SoundType.WOOD).strength(50.0F, 2000.0F)); - public static final DeferredBlock ANTIBUILDER = registerWithItem("antibuilder", AntibuilderBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> 10).noLootTable().pushReaction(PushReaction.BLOCK).mapColor(MapColor.SAND).requiresCorrectToolForDrops().sound(SoundType.WOOD).strength(10.0F, 6.0F)); - public static final DeferredBlock ANTIBUILT_BLOCK = register("antibuilt_block", Block::new, () -> BlockBehaviour.Properties.of().noLootTable().noOcclusion().pushReaction(PushReaction.BLOCK).sound(SoundType.WOOD).strength(0.3F, 2000.0F)); - public static final DeferredBlock GHAST_TRAP = registerWithItem("ghast_trap", GhastTrapBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> state.getValue(GhastTrapBlock.ACTIVE) ? 15 : 0).mapColor(MapColor.SAND).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.WOOD).strength(10.0F, 6.0F)); - public static final DeferredBlock CARMINITE_REACTOR = registerWithItem("carminite_reactor", CarminiteReactorBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> state.getValue(CarminiteReactorBlock.ACTIVE) ? 15 : 0).mapColor(MapColor.SAND).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.WOOD).strength(10.0F, 6.0F)); - public static final DeferredBlock REACTOR_DEBRIS = register("reactor_debris", ReactorDebrisBlock::new, () -> BlockBehaviour.Properties.of().noLootTable().noOcclusion().pushReaction(PushReaction.BLOCK).sound(SoundType.ANCIENT_DEBRIS).strength(0.3F, 2000.0F)); - public static final DeferredBlock FAKE_GOLD = register("fake_gold", Block::new, () -> BlockBehaviour.Properties.of().noLootTable().pushReaction(PushReaction.BLOCK).sound(SoundType.METAL).strength(50.0F, 2000.0F)); - public static final DeferredBlock FAKE_DIAMOND = register("fake_diamond", Block::new, () -> BlockBehaviour.Properties.of().noLootTable().pushReaction(PushReaction.BLOCK).sound(SoundType.METAL).strength(50.0F, 2000.0F)); - public static final DeferredBlock EXPERIMENT_115 = register("experiment_115", Experiment115Block::new, () -> BlockBehaviour.Properties.of().noLootTable().pushReaction(PushReaction.DESTROY).randomTicks().sound(SoundType.WOOL).strength(0.5F)); - - //aurora palace - public static final DeferredBlock AURORA_BLOCK = registerWithItem("aurora_block", AuroraBrickBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.CHIME).mapColor(MapColor.ICE).strength(10.0F, 6.0F)); - public static final DeferredBlock AURORA_PILLAR = registerWithItem("aurora_pillar", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.CHIME).mapColor(MapColor.ICE).requiresCorrectToolForDrops().strength(2.0F, 6.0F)); - public static final DeferredBlock AURORA_SLAB = registerWithItem("aurora_slab", SlabBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.CHIME).mapColor(MapColor.ICE).requiresCorrectToolForDrops().strength(2.0F, 6.0F)); - public static final DeferredBlock AURORALIZED_GLASS = registerWithItem("auroralized_glass", AuroralizedGlassBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.GLASS)); - - //highlands/thornlands - public static final DeferredBlock BROWN_THORNS = registerWithItem("brown_thorns", ThornsBlock::new, () -> BlockBehaviour.Properties.of().noLootTable().mapColor(MapColor.PODZOL).pushReaction(PushReaction.BLOCK).sound(SoundType.WOOD).strength(50.0F, 2000.0F)); - public static final DeferredBlock GREEN_THORNS = registerWithItem("green_thorns", ThornsBlock::new, () -> BlockBehaviour.Properties.of().noLootTable().mapColor(MapColor.PLANT).pushReaction(PushReaction.BLOCK).sound(SoundType.WOOD).strength(50.0F, 2000.0F)); - public static final DeferredBlock BURNT_THORNS = registerWithItem("burnt_thorns", BurntThornsBlock::new, () -> BlockBehaviour.Properties.of().instabreak().noLootTable().mapColor(MapColor.STONE).pushReaction(PushReaction.DESTROY).sound(SoundType.SAND)); - public static final DeferredBlock THORN_ROSE = registerWithItem("thorn_rose", ThornRoseBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).noCollision().pushReaction(PushReaction.DESTROY).sound(SoundType.GRASS).strength(10.0F, 0.0F)); - public static final DeferredBlock THORN_LEAVES = registerWithItem("thorn_leaves", properties -> new SpecialStemLeavesBlock(state -> state.is(TFBlocks.BROWN_THORNS) || state.is(TFBlocks.GREEN_THORNS), properties), () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.PLANT).noOcclusion().pushReaction(PushReaction.DESTROY).randomTicks().sound(SoundType.AZALEA_LEAVES).strength(0.2F).isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); - public static final DeferredBlock BEANSTALK_LEAVES = registerWithItem("beanstalk_leaves", properties -> new SpecialStemLeavesBlock(state -> state.is(TFBlocks.HUGE_STALK), properties), () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.PLANT).noOcclusion().pushReaction(PushReaction.DESTROY).randomTicks().sound(SoundType.AZALEA_LEAVES).strength(0.2F).isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); - public static final DeferredBlock DEADROCK = registerWithItem("deadrock", Block::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(100.0F, 6000000.0F)); - public static final DeferredBlock CRACKED_DEADROCK = registerWithItem("cracked_deadrock", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(DEADROCK.get())); - public static final DeferredBlock WEATHERED_DEADROCK = registerWithItem("weathered_deadrock", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(DEADROCK.get())); - public static final DeferredBlock TROLLSTEINN = registerWithItem("trollsteinn", TrollsteinnBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).randomTicks().requiresCorrectToolForDrops().sound(SoundType.STONE).strength(2.0F, 6.0F)); - - public static final DeferredBlock WISPY_CLOUD = registerWithItem("wispy_cloud", properties -> new WispyCloudBlock(Biome.Precipitation.NONE, properties), () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.HAT).mapColor(MapColor.SNOW).noOcclusion().pushReaction(PushReaction.DESTROY).replaceable().sound(SoundType.WOOL).strength(0.3F, 0.0F).forceSolidOff()); - public static final DeferredBlock FLUFFY_CLOUD = registerWithItem("fluffy_cloud", properties -> new CloudBlock(null, properties), () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.HAT).mapColor(MapColor.ICE).pushReaction(PushReaction.DESTROY).sound(SoundType.WOOL).strength(0.8F, 0.0F).randomTicks()); - public static final DeferredBlock RAINY_CLOUD = registerWithItem("rainy_cloud", properties -> new CloudBlock(Biome.Precipitation.RAIN, properties), () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.HAT).mapColor(MapColor.ICE).pushReaction(PushReaction.DESTROY).sound(SoundType.WOOL).strength(0.8F, 0.0F).randomTicks()); - public static final DeferredBlock SNOWY_CLOUD = registerWithItem("snowy_cloud", properties -> new CloudBlock(Biome.Precipitation.SNOW, properties), () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.HAT).mapColor(MapColor.ICE).pushReaction(PushReaction.DESTROY).sound(SoundType.WOOL).strength(0.8F, 0.0F).randomTicks()); - - public static final DeferredBlock GIANT_COBBLESTONE = registerWithItem("giant_cobblestone", GiantBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.COBBLESTONE).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(128.0F, 50.0F)); - public static final DeferredBlock GIANT_LOG = registerWithItem("giant_log", GiantBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_PLANKS).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(128.0F, 30.0F)); - public static final DeferredBlock GIANT_LEAVES = registerWithItem("giant_leaves", GiantLeavesBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_LEAVES).noOcclusion().pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.AZALEA_LEAVES).strength(0.2F * 64.0F, 15.0F).isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isValidSpawn(TFBlocks::noSpawning).isRedstoneConductor((state, level, pos) -> false)); - public static final DeferredBlock GIANT_OBSIDIAN = registerWithItem("giant_obsidian", GiantBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.OBSIDIAN).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(50.0F * 64.0F * 64.0F, 2000.0F * 64.0F * 64.0F).isValidSpawn(TFBlocks::noSpawning)); - public static final DeferredBlock UBEROUS_SOIL = registerWithItem("uberous_soil", UberousSoilBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.DIRT).sound(SoundType.GRAVEL).strength(0.6F)); - public static final DeferredBlock HUGE_STALK = registerWithItem("huge_stalk", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.PLANT).sound(SoundType.STEM).strength(1.5F, 3.0F)); - public static final DeferredBlock BEANSTALK_GROWER = register("beanstalk_grower", GrowingBeanstalkBlock::new, () -> BlockBehaviour.Properties.of().noCollision().noLootTable().noOcclusion().noTerrainParticles().strength(-1.0F, 6000000.0F)); - public static final DeferredBlock HUGE_MUSHGLOOM = registerWithItem("huge_mushgloom", HugeMushroomBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().lightLevel((state) -> 5).mapColor(MapColor.COLOR_ORANGE).sound(SoundType.SHROOMLIGHT).strength(0.2F)); - public static final DeferredBlock HUGE_MUSHGLOOM_STEM = registerWithItem("huge_mushgloom_stem", HugeMushroomBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().lightLevel((state) -> 5).mapColor(MapColor.COLOR_ORANGE).sound(SoundType.NYLIUM).strength(0.2F)); - public static final DeferredBlock TROLLVIDR = registerWithItem("trollvidr", TrollRootBlock::new, () -> BlockBehaviour.Properties.of().instabreak().mapColor(MapColor.PLANT).noCollision().pushReaction(PushReaction.DESTROY).sound(SoundType.FLOWERING_AZALEA)); - public static final DeferredBlock UNRIPE_TROLLBER = registerWithItem("unripe_trollber", UnripeTorchClusterBlock::new, () -> BlockBehaviour.Properties.of().instabreak().mapColor(MapColor.PLANT).noCollision().pushReaction(PushReaction.DESTROY).randomTicks().sound(SoundType.FLOWERING_AZALEA)); - public static final DeferredBlock TROLLBER = registerWithItem("trollber", TrollRootBlock::new, () -> BlockBehaviour.Properties.of().instabreak().lightLevel((state) -> 15).mapColor(MapColor.PLANT).noCollision().pushReaction(PushReaction.DESTROY).sound(SoundType.FLOWERING_AZALEA)); - - //plateau castle - public static final DeferredBlock CASTLE_BRICK = registerWithItem("castle_brick", Block::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.QUARTZ).requiresCorrectToolForDrops().sound(SoundType.DEEPSLATE_TILES).strength(100.0F, 50.0F)); - public static final DeferredBlock WORN_CASTLE_BRICK = registerWithItem("worn_castle_brick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get())); - public static final DeferredBlock CRACKED_CASTLE_BRICK = registerWithItem("cracked_castle_brick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get())); - public static final DeferredBlock CASTLE_ROOF_TILE = registerWithItem("castle_roof_tile", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get()).mapColor(MapColor.COLOR_GRAY)); - public static final DeferredBlock MOSSY_CASTLE_BRICK = registerWithItem("mossy_castle_brick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get())); - public static final DeferredBlock THICK_CASTLE_BRICK = registerWithItem("thick_castle_brick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get())); - public static final DeferredBlock ENCASED_CASTLE_BRICK_PILLAR = registerWithItem("encased_castle_brick_pillar", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get())); - public static final DeferredBlock ENCASED_CASTLE_BRICK_TILE = registerWithItem("encased_castle_brick_tile", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get())); - public static final DeferredBlock BOLD_CASTLE_BRICK_PILLAR = registerWithItem("bold_castle_brick_pillar", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get())); - public static final DeferredBlock BOLD_CASTLE_BRICK_TILE = registerWithItem("bold_castle_brick_tile", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get())); - public static final DeferredBlock CASTLE_BRICK_STAIRS = registerWithItem("castle_brick_stairs", properties -> new StairBlock(CASTLE_BRICK.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get())); - public static final DeferredBlock WORN_CASTLE_BRICK_STAIRS = registerWithItem("worn_castle_brick_stairs", properties -> new StairBlock(WORN_CASTLE_BRICK.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(WORN_CASTLE_BRICK.get())); - public static final DeferredBlock CRACKED_CASTLE_BRICK_STAIRS = registerWithItem("cracked_castle_brick_stairs", properties -> new StairBlock(CRACKED_CASTLE_BRICK.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(CRACKED_CASTLE_BRICK.get())); - public static final DeferredBlock MOSSY_CASTLE_BRICK_STAIRS = registerWithItem("mossy_castle_brick_stairs", properties -> new StairBlock(MOSSY_CASTLE_BRICK.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(MOSSY_CASTLE_BRICK.get())); - public static final DeferredBlock ENCASED_CASTLE_BRICK_STAIRS = registerWithItem("encased_castle_brick_stairs", properties -> new StairBlock(ENCASED_CASTLE_BRICK_PILLAR.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(ENCASED_CASTLE_BRICK_PILLAR.get())); - public static final DeferredBlock BOLD_CASTLE_BRICK_STAIRS = registerWithItem("bold_castle_brick_stairs", properties -> new StairBlock(BOLD_CASTLE_BRICK_PILLAR.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(BOLD_CASTLE_BRICK_PILLAR.get())); - public static final DeferredBlock PINK_CASTLE_RUNE_BRICK = registerWithItem("pink_castle_rune_brick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get()).mapColor(DyeColor.MAGENTA)); - public static final DeferredBlock BLUE_CASTLE_RUNE_BRICK = registerWithItem("blue_castle_rune_brick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get()).mapColor(DyeColor.LIGHT_BLUE)); - public static final DeferredBlock YELLOW_CASTLE_RUNE_BRICK = registerWithItem("yellow_castle_rune_brick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get()).mapColor(DyeColor.YELLOW)); - public static final DeferredBlock VIOLET_CASTLE_RUNE_BRICK = registerWithItem("violet_castle_rune_brick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get()).mapColor(DyeColor.PURPLE)); - public static final DeferredBlock VIOLET_FORCE_FIELD = registerWithItem("violet_force_field", ForceFieldBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> 2).mapColor(DyeColor.PURPLE).noLootTable().noOcclusion().pushReaction(PushReaction.BLOCK).strength(-1.0F, 3600000.8F)); - public static final DeferredBlock PINK_FORCE_FIELD = registerWithItem("pink_force_field", ForceFieldBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> 2).mapColor(DyeColor.MAGENTA).noLootTable().noOcclusion().pushReaction(PushReaction.BLOCK).strength(-1.0F, 3600000.8F)); - public static final DeferredBlock ORANGE_FORCE_FIELD = registerWithItem("orange_force_field", ForceFieldBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> 2).mapColor(DyeColor.ORANGE).noLootTable().noOcclusion().pushReaction(PushReaction.BLOCK).strength(-1.0F, 3600000.8F)); - public static final DeferredBlock GREEN_FORCE_FIELD = registerWithItem("green_force_field", ForceFieldBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> 2).mapColor(DyeColor.GREEN).noLootTable().noOcclusion().pushReaction(PushReaction.BLOCK).strength(-1.0F, 3600000.8F)); - public static final DeferredBlock BLUE_FORCE_FIELD = registerWithItem("blue_force_field", ForceFieldBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> 2).mapColor(DyeColor.LIGHT_BLUE).noLootTable().noOcclusion().pushReaction(PushReaction.BLOCK).strength(-1.0F, 3600000.8F)); - public static final DeferredBlock CINDER_FURNACE = registerWithItem("cinder_furnace", CinderFurnaceBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).requiresCorrectToolForDrops().strength(7.0F).lightLevel((state) -> 15)); - public static final DeferredBlock CINDER_LOG = registerWithItem("cinder_log", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.COLOR_GRAY).strength(1.0F)); - public static final DeferredBlock CINDER_WOOD = registerWithItem("cinder_wood", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.COLOR_GRAY).strength(1.0F)); - public static final DeferredBlock YELLOW_CASTLE_DOOR = registerWithItem("yellow_castle_door", CastleDoorBlock::new, () -> BlockBehaviour.Properties.of().forceSolidOn().mapColor((state) -> state.getValue(CastleDoorBlock.VANISHED) ? MapColor.NONE : DyeColor.YELLOW.getMapColor()).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.DEEPSLATE_TILES).strength(100.0F, 100.0F)); - public static final DeferredBlock VIOLET_CASTLE_DOOR = registerWithItem("violet_castle_door", CastleDoorBlock::new, () -> BlockBehaviour.Properties.of().forceSolidOn().mapColor((state) -> state.getValue(CastleDoorBlock.VANISHED) ? MapColor.NONE : DyeColor.LIGHT_BLUE.getMapColor()).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.DEEPSLATE_TILES).strength(100.0F, 100.0F)); - public static final DeferredBlock PINK_CASTLE_DOOR = registerWithItem("pink_castle_door", CastleDoorBlock::new, () -> BlockBehaviour.Properties.of().forceSolidOn().mapColor((state) -> state.getValue(CastleDoorBlock.VANISHED) ? MapColor.NONE : DyeColor.MAGENTA.getMapColor()).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.DEEPSLATE_TILES).strength(100.0F, 100.0F)); - public static final DeferredBlock BLUE_CASTLE_DOOR = registerWithItem("blue_castle_door", CastleDoorBlock::new, () -> BlockBehaviour.Properties.of().forceSolidOn().mapColor((state) -> state.getValue(CastleDoorBlock.VANISHED) ? MapColor.NONE : DyeColor.PURPLE.getMapColor()).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.DEEPSLATE_TILES).strength(100.0F, 100.0F)); - - //mini structures - public static final DeferredBlock TWILIGHT_PORTAL_MINIATURE_STRUCTURE = registerWithItem("twilight_portal_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.of().noCollision().noOcclusion().requiresCorrectToolForDrops().strength(0.75F)); - // public static final DeferredBlock HEDGE_MAZE_MINIATURE_STRUCTURE = register("hedge_maze_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); -// public static final DeferredBlock HOLLOW_HILL_MINIATURE_STRUCTURE = register("hollow_hill_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); -// public static final DeferredBlock QUEST_GROVE_MINIATURE_STRUCTURE = register("quest_grove_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); -// public static final DeferredBlock MUSHROOM_TOWER_MINIATURE_STRUCTURE = register("mushroom_tower_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); - public static final DeferredBlock NAGA_COURTYARD_MINIATURE_STRUCTURE = registerWithItem("naga_courtyard_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); - public static final DeferredBlock LICH_TOWER_MINIATURE_STRUCTURE = registerWithItem("lich_tower_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); - public static final DeferredBlock MINOTAUR_LABYRINTH_MINIATURE_STRUCTURE = register("minotaur_labyrinth_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); -// public static final DeferredBlock HYDRA_LAIR_MINIATURE_STRUCTURE = register("hydra_lair_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); -// public static final DeferredBlock GOBLIN_STRONGHOLD_MINIATURE_STRUCTURE = register("goblin_stronghold_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); - public static final DeferredBlock DARK_TOWER_MINIATURE_STRUCTURE = register("dark_tower_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); -// public static final DeferredBlock YETI_CAVE_MINIATURE_STRUCTURE = register("yeti_cave_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); -// public static final DeferredBlock AURORA_PALACE_MINIATURE_STRUCTURE = register("aurora_palace_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); -// public static final DeferredBlock TROLL_CAVE_COTTAGE_MINIATURE_STRUCTURE = register("troll_cave_cottage_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); -// public static final DeferredBlock FINAL_CASTLE_MINIATURE_STRUCTURE = register("final_castle_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); - - //storage blocks - public static final DeferredBlock KNIGHTMETAL_BLOCK = registerWithItem("knightmetal_block", KnightmetalBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.METAL).requiresCorrectToolForDrops().sound(SoundType.NETHERITE_BLOCK).strength(5.0F, 40.0F)); - public static final DeferredBlock IRONWOOD_BLOCK = registerWithItem("ironwood_block", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.WOOD).sound(SoundType.WOOD).strength(5.0F, 6.0F)); - public static final DeferredBlock FIERY_BLOCK = registerWithItem("fiery_block", FieryBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).noOcclusion().requiresCorrectToolForDrops().sound(SoundType.METAL).strength(5.0F, 6.0F).emissiveRendering((state, world, pos) -> true), () -> new Item.Properties().fireResistant()); - public static final DeferredBlock STEELEAF_BLOCK = registerWithItem("steeleaf_block", Block::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).sound(SoundType.NETHERITE_BLOCK).strength(5.0F, 6.0F)); - public static final DeferredBlock ARCTIC_FUR_BLOCK = registerWithItem("arctic_fur_block", ArcticFurBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.WOOL).sound(SoundType.WOOL).strength(0.8F)); - public static final DeferredBlock CARMINITE_BLOCK = registerWithItem("carminite_block", Block::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_RED).strength(1.5F, 10.0F).requiresCorrectToolForDrops().sound(SoundType.METAL)); - - //boss trophies and spawners - public static final DeferredBlock NAGA_BOSS_SPAWNER = registerWithItem("naga_boss_spawner", properties -> new BossSpawnerBlock(BossVariant.NAGA, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).noLootTable().sound(SoundType.METAL).noOcclusion().strength(-1.0F, 3600000.8F)); - public static final DeferredBlock LICH_BOSS_SPAWNER = registerWithItem("lich_boss_spawner", properties -> new BossSpawnerBlock(BossVariant.LICH, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).noLootTable().sound(SoundType.METAL).noOcclusion().strength(-1.0F, 3600000.8F)); - public static final DeferredBlock HYDRA_BOSS_SPAWNER = registerWithItem("hydra_boss_spawner", properties -> new BossSpawnerBlock(BossVariant.HYDRA, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).noLootTable().sound(SoundType.METAL).noOcclusion().strength(-1.0F, 3600000.8F)); - public static final DeferredBlock UR_GHAST_BOSS_SPAWNER = registerWithItem("ur_ghast_boss_spawner", properties -> new BossSpawnerBlock(BossVariant.UR_GHAST, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).noLootTable().sound(SoundType.METAL).noOcclusion().strength(-1.0F, 3600000.8F)); - public static final DeferredBlock KNIGHT_PHANTOM_BOSS_SPAWNER = registerWithItem("knight_phantom_boss_spawner", properties -> new BossSpawnerBlock(BossVariant.KNIGHT_PHANTOM, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).noLootTable().sound(SoundType.METAL).noOcclusion().strength(-1.0F, 3600000.8F)); - public static final DeferredBlock SNOW_QUEEN_BOSS_SPAWNER = registerWithItem("snow_queen_boss_spawner", properties -> new BossSpawnerBlock(BossVariant.SNOW_QUEEN, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).noLootTable().sound(SoundType.METAL).noOcclusion().strength(-1.0F, 3600000.8F)); - public static final DeferredBlock MINOSHROOM_BOSS_SPAWNER = registerWithItem("minoshroom_boss_spawner", properties -> new BossSpawnerBlock(BossVariant.MINOSHROOM, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).noLootTable().sound(SoundType.METAL).noOcclusion().strength(-1.0F, 3600000.8F)); - public static final DeferredBlock ALPHA_YETI_BOSS_SPAWNER = registerWithItem("alpha_yeti_boss_spawner", properties -> new BossSpawnerBlock(BossVariant.ALPHA_YETI, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).noLootTable().sound(SoundType.METAL).noOcclusion().strength(-1.0F, 3600000.8F)); - public static final DeferredBlock FINAL_BOSS_BOSS_SPAWNER = registerWithItem("final_boss_boss_spawner", properties -> new BossSpawnerBlock(BossVariant.FINAL_BOSS, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).noLootTable().sound(SoundType.METAL).noOcclusion().strength(-1.0F, 3600000.8F)); - public static final DeferredBlock NAGA_TROPHY = register("naga_trophy", properties -> new TrophyBlock(BossVariant.NAGA, 5, properties), () -> BlockBehaviour.Properties.of().instabreak()); - public static final DeferredBlock LICH_TROPHY = register("lich_trophy", properties -> new TrophyBlock(BossVariant.LICH, 6, properties), () -> BlockBehaviour.Properties.of().instabreak()); - public static final DeferredBlock HYDRA_TROPHY = register("hydra_trophy", properties -> new TrophyBlock(BossVariant.HYDRA, 12, properties), () -> BlockBehaviour.Properties.of().instabreak()); - public static final DeferredBlock UR_GHAST_TROPHY = register("ur_ghast_trophy", properties -> new TrophyBlock(BossVariant.UR_GHAST, 13, properties), () -> BlockBehaviour.Properties.of().instabreak()); - public static final DeferredBlock KNIGHT_PHANTOM_TROPHY = register("knight_phantom_trophy", properties -> new TrophyBlock(BossVariant.KNIGHT_PHANTOM, 8, properties), () -> BlockBehaviour.Properties.of().instabreak()); - public static final DeferredBlock SNOW_QUEEN_TROPHY = register("snow_queen_trophy", properties -> new TrophyBlock(BossVariant.SNOW_QUEEN, 14, properties), () -> BlockBehaviour.Properties.of().instabreak()); - public static final DeferredBlock MINOSHROOM_TROPHY = register("minoshroom_trophy", properties -> new TrophyBlock(BossVariant.MINOSHROOM, 7, properties), () -> BlockBehaviour.Properties.of().instabreak()); - public static final DeferredBlock ALPHA_YETI_TROPHY = register("alpha_yeti_trophy", properties -> new TrophyBlock(BossVariant.ALPHA_YETI, 9, properties), () -> BlockBehaviour.Properties.of().instabreak()); - public static final DeferredBlock QUEST_RAM_TROPHY = register("quest_ram_trophy", properties -> new TrophyBlock(BossVariant.QUEST_RAM, 1, properties), () -> BlockBehaviour.Properties.of().instabreak()); - public static final DeferredBlock NAGA_WALL_TROPHY = register("naga_wall_trophy", properties -> new TrophyWallBlock(BossVariant.NAGA, properties), () -> BlockBehaviour.Properties.of().instabreak().pushReaction(PushReaction.DESTROY).overrideLootTable(NAGA_TROPHY.get().getLootTable()).overrideDescription(NAGA_TROPHY.get().getDescriptionId())); - public static final DeferredBlock LICH_WALL_TROPHY = register("lich_wall_trophy", properties -> new TrophyWallBlock(BossVariant.LICH, properties), () -> BlockBehaviour.Properties.of().instabreak().pushReaction(PushReaction.DESTROY).overrideLootTable(LICH_TROPHY.get().getLootTable()).overrideDescription(LICH_TROPHY.get().getDescriptionId())); - public static final DeferredBlock HYDRA_WALL_TROPHY = register("hydra_wall_trophy", properties -> new TrophyWallBlock(BossVariant.HYDRA, properties), () -> BlockBehaviour.Properties.of().instabreak().pushReaction(PushReaction.DESTROY).overrideLootTable(HYDRA_TROPHY.get().getLootTable()).overrideDescription(HYDRA_TROPHY.get().getDescriptionId())); - public static final DeferredBlock UR_GHAST_WALL_TROPHY = register("ur_ghast_wall_trophy", properties -> new TrophyWallBlock(BossVariant.UR_GHAST, properties), () -> BlockBehaviour.Properties.of().instabreak().pushReaction(PushReaction.DESTROY).overrideLootTable(UR_GHAST_TROPHY.get().getLootTable()).overrideDescription(UR_GHAST_TROPHY.get().getDescriptionId())); - public static final DeferredBlock KNIGHT_PHANTOM_WALL_TROPHY = register("knight_phantom_wall_trophy", properties -> new TrophyWallBlock(BossVariant.KNIGHT_PHANTOM, properties), () -> BlockBehaviour.Properties.of().instabreak().pushReaction(PushReaction.DESTROY).overrideLootTable(KNIGHT_PHANTOM_TROPHY.get().getLootTable()).overrideDescription(KNIGHT_PHANTOM_TROPHY.get().getDescriptionId())); - public static final DeferredBlock SNOW_QUEEN_WALL_TROPHY = register("snow_queen_wall_trophy", properties -> new TrophyWallBlock(BossVariant.SNOW_QUEEN, properties), () -> BlockBehaviour.Properties.of().instabreak().pushReaction(PushReaction.DESTROY).overrideLootTable(SNOW_QUEEN_TROPHY.get().getLootTable()).overrideDescription(SNOW_QUEEN_TROPHY.get().getDescriptionId())); - public static final DeferredBlock MINOSHROOM_WALL_TROPHY = register("minoshroom_wall_trophy", properties -> new TrophyWallBlock(BossVariant.MINOSHROOM, properties), () -> BlockBehaviour.Properties.of().instabreak().pushReaction(PushReaction.DESTROY).overrideLootTable(MINOSHROOM_TROPHY.get().getLootTable()).overrideDescription(MINOSHROOM_TROPHY.get().getDescriptionId())); - public static final DeferredBlock ALPHA_YETI_WALL_TROPHY = register("alpha_yeti_wall_trophy", properties -> new TrophyWallBlock(BossVariant.ALPHA_YETI, properties), () -> BlockBehaviour.Properties.of().instabreak().pushReaction(PushReaction.DESTROY).overrideLootTable(ALPHA_YETI_TROPHY.get().getLootTable()).overrideDescription(ALPHA_YETI_TROPHY.get().getDescriptionId())); - public static final DeferredBlock QUEST_RAM_WALL_TROPHY = register("quest_ram_wall_trophy", properties -> new TrophyWallBlock(BossVariant.QUEST_RAM, properties), () -> BlockBehaviour.Properties.of().instabreak().pushReaction(PushReaction.DESTROY).overrideLootTable(QUEST_RAM_TROPHY.get().getLootTable()).overrideDescription(QUEST_RAM_TROPHY.get().getDescriptionId())); - - // TODO Enumify all of the dang tree stuff - - //all tree related stuff - public static final DeferredBlock OAK_BANISTER = registerWithItem("oak_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_PLANKS)); - public static final DeferredBlock SPRUCE_BANISTER = registerWithItem("spruce_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.SPRUCE_PLANKS)); - public static final DeferredBlock BIRCH_BANISTER = registerWithItem("birch_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.BIRCH_PLANKS)); - public static final DeferredBlock JUNGLE_BANISTER = registerWithItem("jungle_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.JUNGLE_PLANKS)); - public static final DeferredBlock ACACIA_BANISTER = registerWithItem("acacia_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.ACACIA_PLANKS)); - public static final DeferredBlock DARK_OAK_BANISTER = registerWithItem("dark_oak_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.DARK_OAK_PLANKS)); - public static final DeferredBlock CRIMSON_BANISTER = registerWithItem("crimson_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.CRIMSON_PLANKS)); - public static final DeferredBlock WARPED_BANISTER = registerWithItem("warped_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.WARPED_PLANKS)); - public static final DeferredBlock VANGROVE_BANISTER = registerWithItem("vangrove_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.MANGROVE_PLANKS)); - public static final DeferredBlock BAMBOO_BANISTER = registerWithItem("bamboo_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.BAMBOO_PLANKS)); - public static final DeferredBlock CHERRY_BANISTER = registerWithItem("cherry_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.CHERRY_PLANKS)); - public static final DeferredBlock PALE_OAK_BANISTER = registerWithItem("pale_oak_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.PALE_OAK_PLANKS)); - - public static final DeferredBlock OAK_DRYING_RACK = register("oak_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.OAK_SLAB, 0.5F)); - public static final DeferredBlock SPRUCE_DRYING_RACK = register("spruce_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.SPRUCE_SLAB, 0.5F)); - public static final DeferredBlock BIRCH_DRYING_RACK = register("birch_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.BIRCH_SLAB, 0.5F)); - public static final DeferredBlock JUNGLE_DRYING_RACK = register("jungle_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.JUNGLE_SLAB, 0.5F)); - public static final DeferredBlock ACACIA_DRYING_RACK = register("acacia_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.ACACIA_SLAB, 0.5F)); - public static final DeferredBlock DARK_OAK_DRYING_RACK = register("dark_oak_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.DARK_OAK_SLAB, 0.5F)); - public static final DeferredBlock CRIMSON_DRYING_RACK = register("crimson_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.CRIMSON_SLAB, 0.5F)); - public static final DeferredBlock WARPED_DRYING_RACK = register("warped_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.WARPED_SLAB, 0.5F)); - public static final DeferredBlock VANGROVE_DRYING_RACK = register("vangrove_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.MANGROVE_SLAB, 0.5F)); - public static final DeferredBlock BAMBOO_DRYING_RACK = register("bamboo_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.BAMBOO_SLAB, 0.5F)); - public static final DeferredBlock CHERRY_DRYING_RACK = register("cherry_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.CHERRY_SLAB, 0.5F)); - public static final DeferredBlock PALE_OAK_DRYING_RACK = register("pale_oak_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.CHERRY_SLAB, 0.5F)); - - public static final BlockBehaviour.Properties TWILIGHT_OAK_LOG_PROPS = logProperties(MapColor.WOOD, MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties CANOPY_LOG_PROPS = logProperties(MapColor.PODZOL, MapColor.COLOR_BROWN).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties MANGROVE_LOG_PROPS = logProperties(MapColor.DIRT, MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties DARK_LOG_PROPS = logProperties(MapColor.COLOR_BROWN, MapColor.STONE).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties TIME_LOG_PROPS = logProperties(MapColor.DIRT, MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties TRANSFORMATION_LOG_PROPS = logProperties(MapColor.WOOD, MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties MINING_LOG_PROPS = logProperties(MapColor.SAND, MapColor.QUARTZ).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties SORTING_LOG_PROPS = logProperties(MapColor.PODZOL, MapColor.COLOR_BROWN).strength(2.0F).sound(SoundType.WOOD); - - public static final BlockBehaviour.Properties TWILIGHT_OAK_BARK_PROPS = logProperties(MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties CANOPY_BARK_PROPS = logProperties(MapColor.COLOR_BROWN).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties MANGROVE_BARK_PROPS = logProperties(MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties DARK_BARK_PROPS = logProperties(MapColor.STONE).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties TIME_BARK_PROPS = logProperties(MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties TRANSFORMATION_BARK_PROPS = logProperties(MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties MINING_BARK_PROPS = logProperties(MapColor.QUARTZ).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties SORTING_BARK_PROPS = logProperties(MapColor.COLOR_BROWN).strength(2.0F).sound(SoundType.WOOD); - - public static final BlockBehaviour.Properties TWILIGHT_OAK_STRIPPED_PROPS = logProperties(MapColor.WOOD).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties CANOPY_STRIPPED_PROPS = logProperties(MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties MANGROVE_STRIPPED_PROPS = logProperties(MapColor.DIRT).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties DARK_STRIPPED_PROPS = logProperties(MapColor.COLOR_BROWN).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties TIME_STRIPPED_PROPS = logProperties(MapColor.DIRT).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties TRANSFORMATION_STRIPPED_PROPS = logProperties(MapColor.WOOD).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties MINING_STRIPPED_PROPS = logProperties(MapColor.SAND).strength(2.0F).sound(SoundType.WOOD); - public static final BlockBehaviour.Properties SORTING_STRIPPED_PROPS = logProperties(MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); - - public static final DeferredBlock TWILIGHT_OAK_LOG = registerWithItem("twilight_oak_log", RotatedPillarBlock::new, () -> TWILIGHT_OAK_LOG_PROPS); - public static final DeferredBlock CANOPY_LOG = registerWithItem("canopy_log", RotatedPillarBlock::new, () -> CANOPY_LOG_PROPS); - public static final DeferredBlock MANGROVE_LOG = registerWithItem("mangrove_log", RotatedPillarBlock::new, () -> MANGROVE_LOG_PROPS); - public static final DeferredBlock DARK_LOG = registerWithItem("dark_log", RotatedPillarBlock::new, () -> DARK_LOG_PROPS); - public static final DeferredBlock TIME_LOG = registerWithItem("time_log", RotatedPillarBlock::new, () -> TIME_LOG_PROPS); - public static final DeferredBlock TRANSFORMATION_LOG = registerWithItem("transformation_log", RotatedPillarBlock::new, () -> TRANSFORMATION_LOG_PROPS); - public static final DeferredBlock MINING_LOG = registerWithItem("mining_log", RotatedPillarBlock::new, () -> MINING_LOG_PROPS); - public static final DeferredBlock SORTING_LOG = registerWithItem("sorting_log", RotatedPillarBlock::new, () -> SORTING_LOG_PROPS); - - public static final DeferredBlock HOLLOW_TWILIGHT_OAK_LOG_HORIZONTAL = registerCustomID("hollow_twilight_oak_log_horizontal", HorizontalHollowLogBlock::new, () -> TWILIGHT_OAK_BARK_PROPS, "hollow_twilight_oak_log"); - public static final DeferredBlock HOLLOW_CANOPY_LOG_HORIZONTAL = registerCustomID("hollow_canopy_log_horizontal", HorizontalHollowLogBlock::new, () -> CANOPY_BARK_PROPS, "hollow_canopy_log"); - public static final DeferredBlock HOLLOW_MANGROVE_LOG_HORIZONTAL = registerCustomID("hollow_mangrove_log_horizontal", HorizontalHollowLogBlock::new, () -> MANGROVE_BARK_PROPS, "hollow_mangrove_log"); - public static final DeferredBlock HOLLOW_DARK_LOG_HORIZONTAL = registerCustomID("hollow_dark_log_horizontal", HorizontalHollowLogBlock::new, () -> DARK_BARK_PROPS, "hollow_dark_log"); - public static final DeferredBlock HOLLOW_TIME_LOG_HORIZONTAL = registerCustomID("hollow_time_log_horizontal", HorizontalHollowLogBlock::new, () -> TIME_BARK_PROPS, "hollow_time_log"); - public static final DeferredBlock HOLLOW_TRANSFORMATION_LOG_HORIZONTAL = registerCustomID("hollow_transformation_log_horizontal", HorizontalHollowLogBlock::new, () -> TRANSFORMATION_BARK_PROPS, "hollow_transformation_log"); - public static final DeferredBlock HOLLOW_MINING_LOG_HORIZONTAL = registerCustomID("hollow_mining_log_horizontal", HorizontalHollowLogBlock::new, () -> MINING_BARK_PROPS, "hollow_mining_log"); - public static final DeferredBlock HOLLOW_SORTING_LOG_HORIZONTAL = registerCustomID("hollow_sorting_log_horizontal", HorizontalHollowLogBlock::new, () -> SORTING_BARK_PROPS, "hollow_sorting_log"); - - public static final DeferredBlock HOLLOW_TWILIGHT_OAK_LOG_VERTICAL = registerCustomID("hollow_twilight_oak_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_TWILIGHT_OAK_LOG_CLIMBABLE, properties), () -> TWILIGHT_OAK_STRIPPED_PROPS, "hollow_twilight_oak_log"); - public static final DeferredBlock HOLLOW_CANOPY_LOG_VERTICAL = registerCustomID("hollow_canopy_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_CANOPY_LOG_CLIMBABLE, properties), () -> CANOPY_STRIPPED_PROPS, "hollow_canopy_log"); - public static final DeferredBlock HOLLOW_MANGROVE_LOG_VERTICAL = registerCustomID("hollow_mangrove_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_MANGROVE_LOG_CLIMBABLE, properties), () -> MANGROVE_STRIPPED_PROPS, "hollow_mangrove_log"); - public static final DeferredBlock HOLLOW_DARK_LOG_VERTICAL = registerCustomID("hollow_dark_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_DARK_LOG_CLIMBABLE, properties), () -> DARK_STRIPPED_PROPS, "hollow_dark_log"); - public static final DeferredBlock HOLLOW_TIME_LOG_VERTICAL = registerCustomID("hollow_time_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_TIME_LOG_CLIMBABLE, properties), () -> TIME_STRIPPED_PROPS, "hollow_time_log"); - public static final DeferredBlock HOLLOW_TRANSFORMATION_LOG_VERTICAL = registerCustomID("hollow_transformation_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_TRANSFORMATION_LOG_CLIMBABLE, properties), () -> TRANSFORMATION_STRIPPED_PROPS, "hollow_transformation_log"); - public static final DeferredBlock HOLLOW_MINING_LOG_VERTICAL = registerCustomID("hollow_mining_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_MINING_LOG_CLIMBABLE, properties), () -> MINING_STRIPPED_PROPS, "hollow_mining_log"); - public static final DeferredBlock HOLLOW_SORTING_LOG_VERTICAL = registerCustomID("hollow_sorting_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_SORTING_LOG_CLIMBABLE, properties), () -> SORTING_STRIPPED_PROPS, "hollow_sorting_log"); - - public static final DeferredBlock HOLLOW_TWILIGHT_OAK_LOG_CLIMBABLE = registerCustomID("hollow_twilight_oak_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_TWILIGHT_OAK_LOG_VERTICAL, properties), () -> TWILIGHT_OAK_STRIPPED_PROPS, "hollow_twilight_oak_log"); - public static final DeferredBlock HOLLOW_CANOPY_LOG_CLIMBABLE = registerCustomID("hollow_canopy_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_CANOPY_LOG_VERTICAL, properties), () -> CANOPY_STRIPPED_PROPS, "hollow_canopy_log"); - public static final DeferredBlock HOLLOW_MANGROVE_LOG_CLIMBABLE = registerCustomID("hollow_mangrove_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_MANGROVE_LOG_VERTICAL, properties), () -> MANGROVE_STRIPPED_PROPS, "hollow_mangrove_log"); - public static final DeferredBlock HOLLOW_DARK_LOG_CLIMBABLE = registerCustomID("hollow_dark_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_DARK_LOG_VERTICAL, properties), () -> DARK_STRIPPED_PROPS, "hollow_dark_log"); - public static final DeferredBlock HOLLOW_TIME_LOG_CLIMBABLE = registerCustomID("hollow_time_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_TIME_LOG_VERTICAL, properties), () -> TIME_STRIPPED_PROPS, "hollow_time_log"); - public static final DeferredBlock HOLLOW_TRANSFORMATION_LOG_CLIMBABLE = registerCustomID("hollow_transformation_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_TRANSFORMATION_LOG_VERTICAL, properties), () -> TRANSFORMATION_STRIPPED_PROPS, "hollow_transformation_log"); - public static final DeferredBlock HOLLOW_MINING_LOG_CLIMBABLE = registerCustomID("hollow_mining_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_MINING_LOG_VERTICAL, properties), () -> MINING_STRIPPED_PROPS, "hollow_mining_log"); - public static final DeferredBlock HOLLOW_SORTING_LOG_CLIMBABLE = registerCustomID("hollow_sorting_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_SORTING_LOG_VERTICAL, properties), () -> SORTING_STRIPPED_PROPS, "hollow_sorting_log"); - - public static final DeferredBlock HOLLOW_OAK_LOG_HORIZONTAL = registerCustomID("hollow_oak_log_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_WOOD), "hollow_twilight_oak_log"); - public static final DeferredBlock HOLLOW_SPRUCE_LOG_HORIZONTAL = registerCustomID("hollow_spruce_log_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.SPRUCE_WOOD), "hollow_spruce_log"); - public static final DeferredBlock HOLLOW_BIRCH_LOG_HORIZONTAL = registerCustomID("hollow_birch_log_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.BIRCH_WOOD), "hollow_birch_log"); - public static final DeferredBlock HOLLOW_JUNGLE_LOG_HORIZONTAL = registerCustomID("hollow_jungle_log_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.JUNGLE_WOOD), "hollow_jungle_log"); - public static final DeferredBlock HOLLOW_ACACIA_LOG_HORIZONTAL = registerCustomID("hollow_acacia_log_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.ACACIA_WOOD), "hollow_acacia_log"); - public static final DeferredBlock HOLLOW_DARK_OAK_LOG_HORIZONTAL = registerCustomID("hollow_dark_oak_log_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.DARK_OAK_WOOD), "hollow_dark_oak_log"); - public static final DeferredBlock HOLLOW_CRIMSON_STEM_HORIZONTAL = registerCustomID("hollow_crimson_stem_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.CRIMSON_HYPHAE), "hollow_crimson_stem"); - public static final DeferredBlock HOLLOW_WARPED_STEM_HORIZONTAL = registerCustomID("hollow_warped_stem_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.WARPED_HYPHAE), "hollow_warped_stem"); - public static final DeferredBlock HOLLOW_VANGROVE_LOG_HORIZONTAL = registerCustomID("hollow_vangrove_log_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.MANGROVE_WOOD), "hollow_vangrove_log"); - public static final DeferredBlock HOLLOW_CHERRY_LOG_HORIZONTAL = registerCustomID("hollow_cherry_log_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.CHERRY_WOOD), "hollow_cherry_log"); - public static final DeferredBlock HOLLOW_PALE_OAK_LOG_HORIZONTAL = registerCustomID("hollow_pale_oak_log_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.PALE_OAK_WOOD), "hollow_pale_oak_log"); - - public static final DeferredBlock HOLLOW_OAK_LOG_VERTICAL = registerCustomID("hollow_oak_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_OAK_LOG_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_OAK_WOOD), "hollow_twilight_oak_log"); - public static final DeferredBlock HOLLOW_SPRUCE_LOG_VERTICAL = registerCustomID("hollow_spruce_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_SPRUCE_LOG_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_SPRUCE_WOOD), "hollow_spruce_log"); - public static final DeferredBlock HOLLOW_BIRCH_LOG_VERTICAL = registerCustomID("hollow_birch_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_BIRCH_LOG_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_BIRCH_WOOD), "hollow_birch_log"); - public static final DeferredBlock HOLLOW_JUNGLE_LOG_VERTICAL = registerCustomID("hollow_jungle_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_JUNGLE_LOG_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_JUNGLE_WOOD), "hollow_jungle_log"); - public static final DeferredBlock HOLLOW_ACACIA_LOG_VERTICAL = registerCustomID("hollow_acacia_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_ACACIA_LOG_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_ACACIA_WOOD), "hollow_acacia_log"); - public static final DeferredBlock HOLLOW_DARK_OAK_LOG_VERTICAL = registerCustomID("hollow_dark_oak_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_DARK_OAK_LOG_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_DARK_OAK_WOOD), "hollow_dark_oak_log"); - public static final DeferredBlock HOLLOW_CRIMSON_STEM_VERTICAL = registerCustomID("hollow_crimson_stem_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_CRIMSON_STEM_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_CRIMSON_HYPHAE), "hollow_crimson_stem"); - public static final DeferredBlock HOLLOW_WARPED_STEM_VERTICAL = registerCustomID("hollow_warped_stem_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_WARPED_STEM_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_WARPED_HYPHAE), "hollow_warped_stem"); - // wanna see a funny crash? Use () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_MANGROVE_WOOD) instead of the BlockBehaviour.Properties.of(...) - // I still legit have no idea why it happens but it does - public static final DeferredBlock HOLLOW_VANGROVE_LOG_VERTICAL = registerCustomID("hollow_vangrove_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_VANGROVE_LOG_CLIMBABLE, properties), () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.COLOR_RED).strength(2.0F).sound(SoundType.WOOD), "hollow_vangrove_log"); - public static final DeferredBlock HOLLOW_CHERRY_LOG_VERTICAL = registerCustomID("hollow_cherry_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_CHERRY_LOG_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_CHERRY_WOOD), "hollow_cherry_log"); - public static final DeferredBlock HOLLOW_PALE_OAK_LOG_VERTICAL = registerCustomID("hollow_pale_oak_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_PALE_OAK_LOG_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_PALE_OAK_WOOD), "hollow_pale_oak_log"); - - public static final DeferredBlock HOLLOW_OAK_LOG_CLIMBABLE = registerCustomID("hollow_oak_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_OAK_LOG_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_OAK_WOOD), "hollow_twilight_oak_log"); - public static final DeferredBlock HOLLOW_SPRUCE_LOG_CLIMBABLE = registerCustomID("hollow_spruce_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_SPRUCE_LOG_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_SPRUCE_WOOD), "hollow_spruce_log"); - public static final DeferredBlock HOLLOW_BIRCH_LOG_CLIMBABLE = registerCustomID("hollow_birch_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_BIRCH_LOG_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_BIRCH_WOOD), "hollow_birch_log"); - public static final DeferredBlock HOLLOW_JUNGLE_LOG_CLIMBABLE = registerCustomID("hollow_jungle_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_JUNGLE_LOG_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_JUNGLE_WOOD), "hollow_jungle_log"); - public static final DeferredBlock HOLLOW_ACACIA_LOG_CLIMBABLE = registerCustomID("hollow_acacia_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_ACACIA_LOG_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_ACACIA_WOOD), "hollow_acacia_log"); - public static final DeferredBlock HOLLOW_DARK_OAK_LOG_CLIMBABLE = registerCustomID("hollow_dark_oak_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_DARK_OAK_LOG_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_DARK_OAK_WOOD), "hollow_dark_oak_log"); - public static final DeferredBlock HOLLOW_CRIMSON_STEM_CLIMBABLE = registerCustomID("hollow_crimson_stem_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_CRIMSON_STEM_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_CRIMSON_HYPHAE), "hollow_crimson_stem"); - public static final DeferredBlock HOLLOW_WARPED_STEM_CLIMBABLE = registerCustomID("hollow_warped_stem_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_WARPED_STEM_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_WARPED_HYPHAE), "hollow_warped_stem"); - public static final DeferredBlock HOLLOW_VANGROVE_LOG_CLIMBABLE = registerCustomID("hollow_vangrove_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_VANGROVE_LOG_VERTICAL, properties), () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.COLOR_RED).strength(2.0F).sound(SoundType.WOOD), "hollow_vangrove_log"); - public static final DeferredBlock HOLLOW_CHERRY_LOG_CLIMBABLE = registerCustomID("hollow_cherry_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_CHERRY_LOG_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_CHERRY_WOOD), "hollow_cherry_log"); - public static final DeferredBlock HOLLOW_PALE_OAK_LOG_CLIMBABLE = registerCustomID("hollow_pale_oak_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_PALE_OAK_LOG_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_PALE_OAK_WOOD), "hollow_pale_oak_log"); - - public static final DeferredBlock STRIPPED_TWILIGHT_OAK_LOG = registerWithItem("stripped_twilight_oak_log", RotatedPillarBlock::new, () -> TWILIGHT_OAK_STRIPPED_PROPS); - public static final DeferredBlock STRIPPED_CANOPY_LOG = registerWithItem("stripped_canopy_log", RotatedPillarBlock::new, () -> CANOPY_STRIPPED_PROPS); - public static final DeferredBlock STRIPPED_MANGROVE_LOG = registerWithItem("stripped_mangrove_log", RotatedPillarBlock::new, () -> MANGROVE_STRIPPED_PROPS); - public static final DeferredBlock STRIPPED_DARK_LOG = registerWithItem("stripped_dark_log", RotatedPillarBlock::new, () -> DARK_STRIPPED_PROPS); - public static final DeferredBlock STRIPPED_TIME_LOG = registerWithItem("stripped_time_log", RotatedPillarBlock::new, () -> TIME_STRIPPED_PROPS); - public static final DeferredBlock STRIPPED_TRANSFORMATION_LOG = registerWithItem("stripped_transformation_log", RotatedPillarBlock::new, () -> TRANSFORMATION_STRIPPED_PROPS); - public static final DeferredBlock STRIPPED_MINING_LOG = registerWithItem("stripped_mining_log", RotatedPillarBlock::new, () -> MINING_STRIPPED_PROPS); - public static final DeferredBlock STRIPPED_SORTING_LOG = registerWithItem("stripped_sorting_log", RotatedPillarBlock::new, () -> SORTING_STRIPPED_PROPS); - - public static final DeferredBlock TWILIGHT_OAK_WOOD = registerWithItem("twilight_oak_wood", RotatedPillarBlock::new, () -> TWILIGHT_OAK_BARK_PROPS); - public static final DeferredBlock CANOPY_WOOD = registerWithItem("canopy_wood", RotatedPillarBlock::new, () -> CANOPY_BARK_PROPS); - public static final DeferredBlock MANGROVE_WOOD = registerWithItem("mangrove_wood", RotatedPillarBlock::new, () -> MANGROVE_BARK_PROPS); - public static final DeferredBlock DARK_WOOD = registerWithItem("dark_wood", RotatedPillarBlock::new, () -> DARK_BARK_PROPS); - public static final DeferredBlock TIME_WOOD = registerWithItem("time_wood", RotatedPillarBlock::new, () -> TIME_BARK_PROPS); - public static final DeferredBlock TRANSFORMATION_WOOD = registerWithItem("transformation_wood", RotatedPillarBlock::new, () -> TRANSFORMATION_BARK_PROPS); - public static final DeferredBlock MINING_WOOD = registerWithItem("mining_wood", RotatedPillarBlock::new, () -> MINING_BARK_PROPS); - public static final DeferredBlock SORTING_WOOD = registerWithItem("sorting_wood", RotatedPillarBlock::new, () -> SORTING_BARK_PROPS); - - public static final DeferredBlock STRIPPED_TWILIGHT_OAK_WOOD = registerWithItem("stripped_twilight_oak_wood", RotatedPillarBlock::new, () -> TWILIGHT_OAK_STRIPPED_PROPS); - public static final DeferredBlock STRIPPED_CANOPY_WOOD = registerWithItem("stripped_canopy_wood", RotatedPillarBlock::new, () -> CANOPY_STRIPPED_PROPS); - public static final DeferredBlock STRIPPED_MANGROVE_WOOD = registerWithItem("stripped_mangrove_wood", RotatedPillarBlock::new, () -> MANGROVE_STRIPPED_PROPS); - public static final DeferredBlock STRIPPED_DARK_WOOD = registerWithItem("stripped_dark_wood", RotatedPillarBlock::new, () -> DARK_STRIPPED_PROPS); - public static final DeferredBlock STRIPPED_TIME_WOOD = registerWithItem("stripped_time_wood", RotatedPillarBlock::new, () -> TIME_STRIPPED_PROPS); - public static final DeferredBlock STRIPPED_TRANSFORMATION_WOOD = registerWithItem("stripped_transformation_wood", RotatedPillarBlock::new, () -> TRANSFORMATION_STRIPPED_PROPS); - public static final DeferredBlock STRIPPED_MINING_WOOD = registerWithItem("stripped_mining_wood", RotatedPillarBlock::new, () -> MINING_STRIPPED_PROPS); - public static final DeferredBlock STRIPPED_SORTING_WOOD = registerWithItem("stripped_sorting_wood", RotatedPillarBlock::new, () -> SORTING_STRIPPED_PROPS); - - public static final DeferredBlock TIME_LOG_CORE = registerWithItem("time_log_core", TimeLogCoreBlock::new, () -> TIME_LOG_PROPS); - public static final DeferredBlock TRANSFORMATION_LOG_CORE = registerWithItem("transformation_log_core", TransLogCoreBlock::new, () -> TRANSFORMATION_LOG_PROPS); - public static final DeferredBlock MINING_LOG_CORE = registerWithItem("mining_log_core", MineLogCoreBlock::new, () -> MINING_LOG_PROPS); - public static final DeferredBlock SORTING_LOG_CORE = registerWithItem("sorting_log_core", SortLogCoreBlock::new, () -> SORTING_LOG_PROPS); - - public static final DeferredBlock MANGROVE_ROOT = registerWithItem("mangrove_root", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.STONE).sound(SoundType.WOOD).strength(2.0F)); - - public static final DeferredBlock TWILIGHT_OAK_LEAVES = registerWithItem("twilight_oak_leaves", properties -> new TintedParticleLeavesBlock(0.01F, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(0.2F).randomTicks().noOcclusion().sound(SoundType.AZALEA_LEAVES).isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); - public static final DeferredBlock CANOPY_LEAVES = registerWithItem("canopy_leaves", properties -> new TintedParticleLeavesBlock(0.01F, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(0.2F).randomTicks().noOcclusion().sound(SoundType.AZALEA_LEAVES).isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); - public static final DeferredBlock MANGROVE_LEAVES = registerWithItem("mangrove_leaves", properties -> new TintedParticleLeavesBlock(0.01F, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(0.2F).randomTicks().noOcclusion().sound(SoundType.AZALEA_LEAVES).isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); - public static final DeferredBlock DARK_LEAVES = registerWithItem("dark_leaves", DarkLeavesBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(2.0F, 10.0F).sound(SoundType.AZALEA_LEAVES).isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); - public static final DeferredBlock HARDENED_DARK_LEAVES = register("hardened_dark_leaves", HardenedDarkLeavesBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(2.0F, 10.0F).sound(SoundType.AZALEA_LEAVES).isValidSpawn(TFBlocks::noSpawning).isRedstoneConductor((state, level, pos) -> false)); - public static final DeferredBlock RAINBOW_OAK_LEAVES = registerWithItem("rainbow_oak_leaves", properties -> new TintedParticleLeavesBlock(0.01F, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(0.2F).randomTicks().noOcclusion().sound(SoundType.AZALEA_LEAVES).isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); - public static final DeferredBlock TIME_LEAVES = registerWithItem("time_leaves", properties -> new TintedParticleLeavesBlock(0.01F, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(0.2F).sound(SoundType.AZALEA_LEAVES).randomTicks().noOcclusion().isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); - public static final DeferredBlock TRANSFORMATION_LEAVES = registerWithItem("transformation_leaves", TransformationLeavesBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(0.2F).sound(SoundType.AZALEA_LEAVES).randomTicks().noOcclusion().isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); - public static final DeferredBlock MINING_LEAVES = registerWithItem("mining_leaves", properties -> new TintedParticleLeavesBlock(0.01F, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(0.2F).sound(SoundType.AZALEA_LEAVES).randomTicks().noOcclusion().isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); - public static final DeferredBlock SORTING_LEAVES = registerWithItem("sorting_leaves", properties -> new TintedParticleLeavesBlock(0.01F, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(0.2F).sound(SoundType.AZALEA_LEAVES).randomTicks().noOcclusion().isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); - - public static final DeferredBlock TWILIGHT_OAK_SAPLING = registerWithItem("twilight_oak_sapling", properties -> new SaplingBlock(TFTreeGrowers.TWILIGHT_OAK, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); - public static final DeferredBlock CANOPY_SAPLING = registerWithItem("canopy_sapling", properties -> new SaplingBlock(TFTreeGrowers.CANOPY, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); - public static final DeferredBlock MANGROVE_SAPLING = registerWithItem("mangrove_sapling", properties -> new MangroveSaplingBlock(TFTreeGrowers.MANGROVE, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); - public static final DeferredBlock DARKWOOD_SAPLING = registerWithItem("darkwood_sapling", properties -> new SaplingBlock(TFTreeGrowers.DARK, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); - public static final DeferredBlock HOLLOW_OAK_SAPLING = registerWithItem("hollow_oak_sapling", properties -> new SaplingBlock(TFTreeGrowers.HOLLOW_OAK, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); - public static final DeferredBlock TIME_SAPLING = registerWithItem("time_sapling", properties -> new SaplingBlock(TFTreeGrowers.TIME, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); - public static final DeferredBlock TRANSFORMATION_SAPLING = registerWithItem("transformation_sapling", properties -> new SaplingBlock(TFTreeGrowers.TRANSFORMATION, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); - public static final DeferredBlock MINING_SAPLING = registerWithItem("mining_sapling", properties -> new SaplingBlock(TFTreeGrowers.MINING, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); - public static final DeferredBlock SORTING_SAPLING = registerWithItem("sorting_sapling", properties -> new SaplingBlock(TFTreeGrowers.SORTING, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); - public static final DeferredBlock RAINBOW_OAK_SAPLING = registerWithItem("rainbow_oak_sapling", properties -> new SaplingBlock(TFTreeGrowers.RAINBOW_OAK, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); - - public static final DeferredBlock TWILIGHT_OAK_PLANKS = registerWithItem("twilight_oak_planks", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.WOOD).strength(2.0F, 3.0F).sound(SoundType.WOOD)); - public static final DeferredBlock TWILIGHT_OAK_STAIRS = registerWithItem("twilight_oak_stairs", properties -> new StairBlock(TWILIGHT_OAK_PLANKS.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get())); - public static final DeferredBlock TWILIGHT_OAK_SLAB = registerWithItem("twilight_oak_slab", SlabBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get())); - public static final DeferredBlock TWILIGHT_OAK_BUTTON = registerWithItem("twilight_oak_button", properties -> new ButtonBlock(TFWoodTypes.TWILIGHT_OAK_SET, 30, properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).noCollision().strength(0.5F)); - public static final DeferredBlock TWILIGHT_OAK_FENCE = registerWithItem("twilight_oak_fence", FenceBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get())); - public static final DeferredBlock TWILIGHT_OAK_GATE = registerWithItem("twilight_oak_fence_gate", properties -> new FenceGateBlock(TFWoodTypes.TWILIGHT_OAK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).forceSolidOn()); - public static final DeferredBlock TWILIGHT_OAK_PLATE = registerWithItem("twilight_oak_pressure_plate", properties -> new PressurePlateBlock(TFWoodTypes.TWILIGHT_OAK_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).forceSolidOn().noCollision().strength(0.5F)); - public static final DeferredBlock TWILIGHT_OAK_DOOR = registerWithItem("twilight_oak_door", properties -> new DoorBlock(TFWoodTypes.TWILIGHT_OAK_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).strength(3.0F).sound(SoundType.WOOD).noOcclusion()); - public static final DeferredBlock TWILIGHT_OAK_TRAPDOOR = registerWithItem("twilight_oak_trapdoor", properties -> new TrapDoorBlock(TFWoodTypes.TWILIGHT_OAK_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).strength(3.0F).noOcclusion()); - public static final DeferredBlock TWILIGHT_OAK_SIGN = register("twilight_oak_sign", properties -> new StandingSignBlock(TFWoodTypes.TWILIGHT_OAK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).strength(3.0F).noOcclusion().noCollision()); - public static final DeferredBlock TWILIGHT_WALL_SIGN = register("twilight_wall_sign", properties -> new WallSignBlock(TFWoodTypes.TWILIGHT_OAK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).strength(3.0F).noOcclusion().noCollision().overrideLootTable(TWILIGHT_OAK_SIGN.get().getLootTable()).overrideDescription(TWILIGHT_OAK_SIGN.get().getDescriptionId())); - public static final DeferredBlock TWILIGHT_OAK_HANGING_SIGN = register("twilight_oak_hanging_sign", properties -> new CeilingHangingSignBlock(TFWoodTypes.TWILIGHT_OAK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).noCollision().strength(1.0F)); - public static final DeferredBlock TWILIGHT_OAK_WALL_HANGING_SIGN = register("twilight_oak_wall_hanging_sign", properties -> new WallHangingSignBlock(TFWoodTypes.TWILIGHT_OAK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).noCollision().strength(1.0F).overrideLootTable(TWILIGHT_OAK_HANGING_SIGN.get().getLootTable()).overrideDescription(TWILIGHT_OAK_HANGING_SIGN.get().getDescriptionId())); - public static final DeferredBlock TWILIGHT_OAK_BANISTER = registerWithItem("twilight_oak_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get())); - public static final DeferredBlock TWILIGHT_OAK_DRYING_RACK = register("twilight_oak_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(TWILIGHT_OAK_SLAB.get(), 0.5F)); - - public static final DeferredBlock CANOPY_PLANKS = registerWithItem("canopy_planks", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.PODZOL).strength(2.0F, 3.0F).sound(SoundType.WOOD)); - public static final DeferredBlock CANOPY_STAIRS = registerWithItem("canopy_stairs", properties -> new StairBlock(CANOPY_PLANKS.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get())); - public static final DeferredBlock CANOPY_SLAB = registerWithItem("canopy_slab", SlabBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get())); - public static final DeferredBlock CANOPY_BUTTON = registerWithItem("canopy_button", properties -> new ButtonBlock(TFWoodTypes.CANOPY_WOOD_SET, 30, properties), () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).noCollision().strength(0.5F)); - public static final DeferredBlock CANOPY_FENCE = registerWithItem("canopy_fence", FenceBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get())); - public static final DeferredBlock CANOPY_GATE = registerWithItem("canopy_fence_gate", properties -> new FenceGateBlock(TFWoodTypes.CANOPY_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).forceSolidOn()); - public static final DeferredBlock CANOPY_PLATE = registerWithItem("canopy_pressure_plate", properties -> new PressurePlateBlock(TFWoodTypes.CANOPY_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).forceSolidOn().noCollision().strength(0.5F)); - public static final DeferredBlock CANOPY_DOOR = registerWithItem("canopy_door", properties -> new DoorBlock(TFWoodTypes.CANOPY_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).strength(3.0F).noOcclusion()); - public static final DeferredBlock CANOPY_TRAPDOOR = registerWithItem("canopy_trapdoor", properties -> new TrapDoorBlock(TFWoodTypes.CANOPY_WOOD_SET, properties), () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.SAND).strength(3.0F).sound(SoundType.WOOD).noOcclusion()); - public static final DeferredBlock CANOPY_SIGN = register("canopy_sign", properties -> new StandingSignBlock(TFWoodTypes.CANOPY_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).strength(1.0F).noOcclusion().noCollision()); - public static final DeferredBlock CANOPY_WALL_SIGN = register("canopy_wall_sign", properties -> new WallSignBlock(TFWoodTypes.CANOPY_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).strength(1.0F).noOcclusion().noCollision().overrideLootTable(CANOPY_SIGN.get().getLootTable()).overrideDescription(CANOPY_SIGN.get().getDescriptionId())); - public static final DeferredBlock CANOPY_BOOKSHELF = registerWithItem("canopy_bookshelf", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).strength(1.5F)); - public static final DeferredBlock CANOPY_HANGING_SIGN = register("canopy_hanging_sign", properties -> new CeilingHangingSignBlock(TFWoodTypes.CANOPY_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).noCollision().strength(1.0F)); - public static final DeferredBlock CANOPY_WALL_HANGING_SIGN = register("canopy_wall_hanging_sign", properties -> new WallHangingSignBlock(TFWoodTypes.CANOPY_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).noCollision().strength(1.0F).overrideLootTable(CANOPY_HANGING_SIGN.get().getLootTable()).overrideDescription(CANOPY_HANGING_SIGN.get().getDescriptionId())); - public static final DeferredBlock CANOPY_BANISTER = registerWithItem("canopy_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get())); - public static final DeferredBlock CANOPY_DRYING_RACK = register("canopy_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(CANOPY_SLAB.get(), 0.5F)); - - public static final DeferredBlock MANGROVE_PLANKS = registerWithItem("mangrove_planks", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.DIRT).strength(2.0F, 3.0F).sound(SoundType.WOOD)); - public static final DeferredBlock MANGROVE_STAIRS = registerWithItem("mangrove_stairs", properties -> new StairBlock(MANGROVE_PLANKS.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get())); - public static final DeferredBlock MANGROVE_SLAB = registerWithItem("mangrove_slab", SlabBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get())); - public static final DeferredBlock MANGROVE_BUTTON = registerWithItem("mangrove_button", properties -> new ButtonBlock(TFWoodTypes.MANGROVE_WOOD_SET, 30, properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).noCollision().strength(0.5F)); - public static final DeferredBlock MANGROVE_FENCE = registerWithItem("mangrove_fence", FenceBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get())); - public static final DeferredBlock MANGROVE_GATE = registerWithItem("mangrove_fence_gate", properties -> new FenceGateBlock(TFWoodTypes.MANGROVE_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).forceSolidOn()); - public static final DeferredBlock MANGROVE_PLATE = registerWithItem("mangrove_pressure_plate", properties -> new PressurePlateBlock(TFWoodTypes.MANGROVE_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).forceSolidOn().noCollision().strength(0.5F)); - public static final DeferredBlock MANGROVE_DOOR = registerWithItem("mangrove_door", properties -> new DoorBlock(TFWoodTypes.MANGROVE_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).strength(3.0F).noOcclusion()); - public static final DeferredBlock MANGROVE_TRAPDOOR = registerWithItem("mangrove_trapdoor", properties -> new TrapDoorBlock(TFWoodTypes.MANGROVE_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).strength(3.0F).noOcclusion()); - public static final DeferredBlock MANGROVE_SIGN = register("mangrove_sign", properties -> new StandingSignBlock(TFWoodTypes.MANGROVE_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).strength(1.0F).noOcclusion().noCollision()); - public static final DeferredBlock MANGROVE_WALL_SIGN = register("mangrove_wall_sign", properties -> new WallSignBlock(TFWoodTypes.MANGROVE_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).strength(1.0F).noOcclusion().noCollision().overrideLootTable(MANGROVE_SIGN.get().getLootTable()).overrideDescription(MANGROVE_SIGN.get().getDescriptionId())); - public static final DeferredBlock MANGROVE_HANGING_SIGN = register("mangrove_hanging_sign", properties -> new CeilingHangingSignBlock(TFWoodTypes.MANGROVE_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).noCollision().strength(1.0F)); - public static final DeferredBlock MANGROVE_WALL_HANGING_SIGN = register("mangrove_wall_hanging_sign", properties -> new WallHangingSignBlock(TFWoodTypes.MANGROVE_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).noCollision().strength(1.0F).overrideLootTable(MANGROVE_HANGING_SIGN.get().getLootTable()).overrideDescription(MANGROVE_HANGING_SIGN.get().getDescriptionId())); - public static final DeferredBlock MANGROVE_BANISTER = registerWithItem("mangrove_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get())); - public static final DeferredBlock MANGROVE_DRYING_RACK = register("mangrove_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(MANGROVE_SLAB.get(), 0.5F)); - - public static final DeferredBlock DARK_PLANKS = registerWithItem("dark_planks", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.COLOR_ORANGE).strength(2.0F, 3.0F).sound(SoundType.WOOD)); - public static final DeferredBlock DARK_STAIRS = registerWithItem("dark_stairs", properties -> new StairBlock(DARK_PLANKS.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get())); - public static final DeferredBlock DARK_SLAB = registerWithItem("dark_slab", SlabBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).sound(SoundType.WOOD)); - public static final DeferredBlock DARK_BUTTON = registerWithItem("dark_button", properties -> new ButtonBlock(TFWoodTypes.DARK_WOOD_SET, 30, properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).noCollision().strength(0.5F)); - public static final DeferredBlock DARK_FENCE = registerWithItem("dark_fence", FenceBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get())); - public static final DeferredBlock DARK_GATE = registerWithItem("dark_fence_gate", properties -> new FenceGateBlock(TFWoodTypes.DARK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).forceSolidOn()); - public static final DeferredBlock DARK_PLATE = registerWithItem("dark_pressure_plate", properties -> new PressurePlateBlock(TFWoodTypes.DARK_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).forceSolidOn().noCollision().strength(0.5F)); - public static final DeferredBlock DARK_DOOR = registerWithItem("dark_door", properties -> new DoorBlock(TFWoodTypes.DARK_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).strength(3.0F).sound(SoundType.WOOD).noOcclusion()); - public static final DeferredBlock DARK_TRAPDOOR = registerWithItem("dark_trapdoor", properties -> new TrapDoorBlock(TFWoodTypes.DARK_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).strength(3.0F).noOcclusion()); - public static final DeferredBlock DARK_SIGN = register("dark_sign", properties -> new StandingSignBlock(TFWoodTypes.DARK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).strength(1.0F).noOcclusion().noCollision()); - public static final DeferredBlock DARK_WALL_SIGN = register("dark_wall_sign", properties -> new WallSignBlock(TFWoodTypes.DARK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).strength(1.0F).noOcclusion().noCollision().overrideLootTable(DARK_SIGN.get().getLootTable()).overrideDescription(DARK_SIGN.get().getDescriptionId())); - public static final DeferredBlock DARK_HANGING_SIGN = register("dark_hanging_sign", properties -> new CeilingHangingSignBlock(TFWoodTypes.DARK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).noCollision().strength(1.0F)); - public static final DeferredBlock DARK_WALL_HANGING_SIGN = register("dark_wall_hanging_sign", properties -> new WallHangingSignBlock(TFWoodTypes.DARK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).noCollision().strength(1.0F).overrideLootTable(DARK_HANGING_SIGN.get().getLootTable()).overrideDescription(DARK_HANGING_SIGN.get().getDescriptionId())); - public static final DeferredBlock DARK_BANISTER = registerWithItem("dark_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get())); - public static final DeferredBlock DARK_DRYING_RACK = register("dark_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(DARK_SLAB.get(), 0.5F)); - - public static final DeferredBlock TIME_PLANKS = registerWithItem("time_planks", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.DIRT).strength(2.0F, 3.0F).sound(SoundType.WOOD)); - public static final DeferredBlock TIME_STAIRS = registerWithItem("time_stairs", properties -> new StairBlock(TIME_PLANKS.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get())); - public static final DeferredBlock TIME_SLAB = registerWithItem("time_slab", SlabBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).sound(SoundType.WOOD)); - public static final DeferredBlock TIME_BUTTON = registerWithItem("time_button", properties -> new ButtonBlock(TFWoodTypes.TIME_WOOD_SET, 30, properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).noCollision().strength(0.5F)); - public static final DeferredBlock TIME_FENCE = registerWithItem("time_fence", FenceBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get())); - public static final DeferredBlock TIME_GATE = registerWithItem("time_fence_gate", properties -> new FenceGateBlock(TFWoodTypes.TIME_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).forceSolidOn()); - public static final DeferredBlock TIME_PLATE = registerWithItem("time_pressure_plate", properties -> new PressurePlateBlock(TFWoodTypes.TIME_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).forceSolidOn().noCollision().strength(0.5F)); - public static final DeferredBlock TIME_DOOR = registerWithItem("time_door", properties -> new DoorBlock(TFWoodTypes.TIME_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).strength(3.0F).sound(SoundType.WOOD).noOcclusion()); - public static final DeferredBlock TIME_TRAPDOOR = registerWithItem("time_trapdoor", properties -> new TrapDoorBlock(TFWoodTypes.TIME_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).strength(3.0F).noOcclusion()); - public static final DeferredBlock TIME_SIGN = register("time_sign", properties -> new StandingSignBlock(TFWoodTypes.TIME_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).strength(1.0F).noOcclusion().noCollision()); - public static final DeferredBlock TIME_WALL_SIGN = register("time_wall_sign", properties -> new WallSignBlock(TFWoodTypes.TIME_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).strength(1.0F).noOcclusion().noCollision().overrideLootTable(TIME_SIGN.get().getLootTable()).overrideDescription(TIME_SIGN.get().getDescriptionId())); - public static final DeferredBlock TIME_HANGING_SIGN = register("time_hanging_sign", properties -> new CeilingHangingSignBlock(TFWoodTypes.TIME_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).noCollision().strength(1.0F)); - public static final DeferredBlock TIME_WALL_HANGING_SIGN = register("time_wall_hanging_sign", properties -> new WallHangingSignBlock(TFWoodTypes.TIME_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).noCollision().strength(1.0F).overrideLootTable(TIME_HANGING_SIGN.get().getLootTable()).overrideDescription(TIME_HANGING_SIGN.get().getDescriptionId())); - public static final DeferredBlock TIME_BANISTER = registerWithItem("time_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get())); - public static final DeferredBlock TIME_DRYING_RACK = register("time_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(TIME_SLAB.get(), 0.5F)); - - public static final DeferredBlock TRANSFORMATION_PLANKS = registerWithItem("transformation_planks", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.WOOD).strength(2.0F, 3.0F).sound(SoundType.WOOD)); - public static final DeferredBlock TRANSFORMATION_STAIRS = registerWithItem("transformation_stairs", properties -> new StairBlock(TRANSFORMATION_PLANKS.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get())); - public static final DeferredBlock TRANSFORMATION_SLAB = registerWithItem("transformation_slab", SlabBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get())); - public static final DeferredBlock TRANSFORMATION_BUTTON = registerWithItem("transformation_button", properties -> new ButtonBlock(TFWoodTypes.TRANSFORMATION_WOOD_SET, 30, properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).noCollision().strength(0.5F)); - public static final DeferredBlock TRANSFORMATION_FENCE = registerWithItem("transformation_fence", FenceBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get())); - public static final DeferredBlock TRANSFORMATION_GATE = registerWithItem("transformation_fence_gate", properties -> new FenceGateBlock(TFWoodTypes.TRANSFORMATION_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).forceSolidOn()); - public static final DeferredBlock TRANSFORMATION_PLATE = registerWithItem("transformation_pressure_plate", properties -> new PressurePlateBlock(TFWoodTypes.TRANSFORMATION_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).forceSolidOn().noCollision().strength(0.5F)); - public static final DeferredBlock TRANSFORMATION_DOOR = registerWithItem("transformation_door", properties -> new DoorBlock(TFWoodTypes.TRANSFORMATION_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).strength(3.0F).noOcclusion()); - public static final DeferredBlock TRANSFORMATION_TRAPDOOR = registerWithItem("transformation_trapdoor", properties -> new TrapDoorBlock(TFWoodTypes.TRANSFORMATION_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).strength(3.0F).noOcclusion()); - public static final DeferredBlock TRANSFORMATION_SIGN = register("transformation_sign", properties -> new StandingSignBlock(TFWoodTypes.TRANSFORMATION_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).strength(1.0F).noOcclusion().noCollision()); - public static final DeferredBlock TRANSFORMATION_WALL_SIGN = register("transformation_wall_sign", properties -> new WallSignBlock(TFWoodTypes.TRANSFORMATION_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).strength(1.0F).noOcclusion().noCollision().overrideLootTable(TRANSFORMATION_SIGN.get().getLootTable()).overrideDescription(TRANSFORMATION_SIGN.get().getDescriptionId())); - public static final DeferredBlock TRANSFORMATION_HANGING_SIGN = register("transformation_hanging_sign", properties -> new CeilingHangingSignBlock(TFWoodTypes.TRANSFORMATION_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).noCollision().strength(1.0F)); - public static final DeferredBlock TRANSFORMATION_WALL_HANGING_SIGN = register("transformation_wall_hanging_sign", properties -> new WallHangingSignBlock(TFWoodTypes.TRANSFORMATION_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).noCollision().strength(1.0F).overrideLootTable(TRANSFORMATION_HANGING_SIGN.get().getLootTable()).overrideDescription(TRANSFORMATION_HANGING_SIGN.get().getDescriptionId())); - public static final DeferredBlock TRANSFORMATION_BANISTER = registerWithItem("transformation_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get())); - public static final DeferredBlock TRANSFORMATION_DRYING_RACK = register("transformation_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(TRANSFORMATION_SLAB.get(), 0.5F)); - - public static final DeferredBlock MINING_PLANKS = registerWithItem("mining_planks", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.SAND).strength(2.0F, 3.0F).sound(SoundType.WOOD)); - public static final DeferredBlock MINING_STAIRS = registerWithItem("mining_stairs", properties -> new StairBlock(MINING_PLANKS.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get())); - public static final DeferredBlock MINING_SLAB = registerWithItem("mining_slab", SlabBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get())); - public static final DeferredBlock MINING_BUTTON = registerWithItem("mining_button", properties -> new ButtonBlock(TFWoodTypes.MINING_WOOD_SET, 30, properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).noCollision().strength(0.5F)); - public static final DeferredBlock MINING_FENCE = registerWithItem("mining_fence", FenceBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get())); - public static final DeferredBlock MINING_GATE = registerWithItem("mining_fence_gate", properties -> new FenceGateBlock(TFWoodTypes.MINING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).forceSolidOn()); - public static final DeferredBlock MINING_PLATE = registerWithItem("mining_pressure_plate", properties -> new PressurePlateBlock(TFWoodTypes.MINING_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).forceSolidOn().noCollision().strength(0.5F)); - public static final DeferredBlock MINING_DOOR = registerWithItem("mining_door", properties -> new DoorBlock(TFWoodTypes.MINING_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).strength(3.0F).noOcclusion()); - public static final DeferredBlock MINING_TRAPDOOR = registerWithItem("mining_trapdoor", properties -> new TrapDoorBlock(TFWoodTypes.MINING_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).strength(3.0F).noOcclusion()); - public static final DeferredBlock MINING_SIGN = register("mining_sign", properties -> new StandingSignBlock(TFWoodTypes.MINING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).strength(1.0F).noOcclusion().noCollision()); - public static final DeferredBlock MINING_WALL_SIGN = register("mining_wall_sign", properties -> new WallSignBlock(TFWoodTypes.MINING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).strength(1.0F).noOcclusion().noCollision().overrideLootTable(MINING_SIGN.get().getLootTable()).overrideDescription(MINING_SIGN.get().getDescriptionId())); - public static final DeferredBlock MINING_HANGING_SIGN = register("mining_hanging_sign", properties -> new CeilingHangingSignBlock(TFWoodTypes.MINING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).noCollision().strength(1.0F)); - public static final DeferredBlock MINING_WALL_HANGING_SIGN = register("mining_wall_hanging_sign", properties -> new WallHangingSignBlock(TFWoodTypes.MINING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).noCollision().strength(1.0F).overrideLootTable(MINING_HANGING_SIGN.get().getLootTable()).overrideDescription(MINING_HANGING_SIGN.get().getDescriptionId())); - public static final DeferredBlock MINING_BANISTER = registerWithItem("mining_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get())); - public static final DeferredBlock MINING_DRYING_RACK = register("mining_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(MINING_SLAB.get(), 0.5F)); - - public static final DeferredBlock SORTING_PLANKS = registerWithItem("sorting_planks", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.PODZOL).strength(2.0F, 3.0F).sound(SoundType.WOOD)); - public static final DeferredBlock SORTING_STAIRS = registerWithItem("sorting_stairs", properties -> new StairBlock(SORTING_PLANKS.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get())); - public static final DeferredBlock SORTING_SLAB = registerWithItem("sorting_slab", SlabBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get())); - public static final DeferredBlock SORTING_BUTTON = registerWithItem("sorting_button", properties -> new ButtonBlock(TFWoodTypes.SORTING_WOOD_SET, 30, properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).noCollision().strength(0.5F)); - public static final DeferredBlock SORTING_FENCE = registerWithItem("sorting_fence", FenceBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get())); - public static final DeferredBlock SORTING_GATE = registerWithItem("sorting_fence_gate", properties -> new FenceGateBlock(TFWoodTypes.SORTING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).forceSolidOn()); - public static final DeferredBlock SORTING_PLATE = registerWithItem("sorting_pressure_plate", properties -> new PressurePlateBlock(TFWoodTypes.SORTING_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).forceSolidOn().noCollision().strength(0.5F)); - public static final DeferredBlock SORTING_DOOR = registerWithItem("sorting_door", properties -> new DoorBlock(TFWoodTypes.SORTING_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).strength(3.0F).noOcclusion()); - public static final DeferredBlock SORTING_TRAPDOOR = registerWithItem("sorting_trapdoor", properties -> new TrapDoorBlock(TFWoodTypes.SORTING_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).strength(3.0F).noOcclusion()); - public static final DeferredBlock SORTING_SIGN = register("sorting_sign", properties -> new StandingSignBlock(TFWoodTypes.SORTING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).strength(1.0F).noOcclusion().noCollision()); - public static final DeferredBlock SORTING_WALL_SIGN = register("sorting_wall_sign", properties -> new WallSignBlock(TFWoodTypes.SORTING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).strength(1.0F).noOcclusion().noCollision().overrideLootTable(SORTING_SIGN.get().getLootTable()).overrideDescription(SORTING_SIGN.get().getDescriptionId())); - public static final DeferredBlock SORTING_HANGING_SIGN = register("sorting_hanging_sign", properties -> new CeilingHangingSignBlock(TFWoodTypes.SORTING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).noCollision().strength(1.0F)); - public static final DeferredBlock SORTING_WALL_HANGING_SIGN = register("sorting_wall_hanging_sign", properties -> new WallHangingSignBlock(TFWoodTypes.SORTING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).noCollision().strength(1.0F).overrideLootTable(SORTING_HANGING_SIGN.get().getLootTable()).overrideDescription(SORTING_HANGING_SIGN.get().getDescriptionId())); - public static final DeferredBlock SORTING_BANISTER = registerWithItem("sorting_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get())); - public static final DeferredBlock SORTING_DRYING_RACK = register("sorting_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(SORTING_SLAB.get(), 0.5F)); - - public static final DeferredBlock TWILIGHT_OAK_CHEST = registerWithItem("twilight_oak_chest", TFChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).strength(2.5F)); - public static final DeferredBlock CANOPY_CHEST = registerWithItem("canopy_chest", TFChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).strength(2.5F)); - public static final DeferredBlock MANGROVE_CHEST = registerWithItem("mangrove_chest", TFChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).strength(2.5F)); - public static final DeferredBlock DARK_CHEST = registerWithItem("dark_chest", TFChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).strength(2.5F)); - public static final DeferredBlock TIME_CHEST = registerWithItem("time_chest", TFChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).strength(2.5F)); - public static final DeferredBlock TRANSFORMATION_CHEST = registerWithItem("transformation_chest", TFChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).strength(2.5F)); - public static final DeferredBlock MINING_CHEST = registerWithItem("mining_chest", TFChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).strength(2.5F)); - public static final DeferredBlock SORTING_CHEST = registerWithItem("sorting_chest", TFChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).strength(2.5F)); - - public static final DeferredBlock TWILIGHT_OAK_TRAPPED_CHEST = registerWithItem("twilight_oak_trapped_chest", TFTrappedChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).strength(2.5F)); - public static final DeferredBlock CANOPY_TRAPPED_CHEST = registerWithItem("canopy_trapped_chest", TFTrappedChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).strength(2.5F)); - public static final DeferredBlock MANGROVE_TRAPPED_CHEST = registerWithItem("mangrove_trapped_chest", TFTrappedChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).strength(2.5F)); - public static final DeferredBlock DARK_TRAPPED_CHEST = registerWithItem("dark_trapped_chest", TFTrappedChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).strength(2.5F)); - public static final DeferredBlock TIME_TRAPPED_CHEST = registerWithItem("time_trapped_chest", TFTrappedChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).strength(2.5F)); - public static final DeferredBlock TRANSFORMATION_TRAPPED_CHEST = registerWithItem("transformation_trapped_chest", TFTrappedChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).strength(2.5F)); - public static final DeferredBlock MINING_TRAPPED_CHEST = registerWithItem("mining_trapped_chest", TFTrappedChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).strength(2.5F)); - public static final DeferredBlock SORTING_TRAPPED_CHEST = registerWithItem("sorting_trapped_chest", TFTrappedChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).strength(2.5F)); - - //Flower Pots - public static final DeferredBlock POTTED_TWILIGHT_OAK_SAPLING = register("potted_twilight_oak_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, TWILIGHT_OAK_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); - public static final DeferredBlock POTTED_CANOPY_SAPLING = register("potted_canopy_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, CANOPY_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); - public static final DeferredBlock POTTED_MANGROVE_SAPLING = register("potted_mangrove_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, MANGROVE_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); - public static final DeferredBlock POTTED_DARKWOOD_SAPLING = register("potted_darkwood_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, DARKWOOD_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); - public static final DeferredBlock POTTED_HOLLOW_OAK_SAPLING = register("potted_hollow_oak_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, HOLLOW_OAK_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); - public static final DeferredBlock POTTED_RAINBOW_OAK_SAPLING = register("potted_rainbow_oak_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, RAINBOW_OAK_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); - public static final DeferredBlock POTTED_TIME_SAPLING = register("potted_time_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, TIME_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); - public static final DeferredBlock POTTED_TRANSFORMATION_SAPLING = register("potted_transformation_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, TRANSFORMATION_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); - public static final DeferredBlock POTTED_MINING_SAPLING = register("potted_mining_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, MINING_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); - public static final DeferredBlock POTTED_SORTING_SAPLING = register("potted_sorting_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, SORTING_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); - public static final DeferredBlock POTTED_MAYAPPLE = register("potted_mayapple", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, MAYAPPLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); - public static final DeferredBlock POTTED_FIDDLEHEAD = register("potted_fiddlehead", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, FIDDLEHEAD, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); - public static final DeferredBlock POTTED_MUSHGLOOM = register("potted_mushgloom", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, MUSHGLOOM, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); - public static final DeferredBlock POTTED_THORN = register("potted_thorn", properties -> new SpecialFlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, BROWN_THORNS, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); - public static final DeferredBlock POTTED_GREEN_THORN = register("potted_green_thorn", properties -> new SpecialFlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, GREEN_THORNS, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); - public static final DeferredBlock POTTED_DEAD_THORN = register("potted_dead_thorn", properties -> new SpecialFlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, BURNT_THORNS, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); - - public static DeferredBlock register(String name, Function block, Supplier properties) { - return BLOCKS.register(name, () -> block.apply(properties.get().setId(ResourceKey.create(Registries.BLOCK, TwilightForestMod.prefix(name))))); - } - - public static DeferredBlock registerCustomID(String name, Function block, Supplier properties, String id) { - return BLOCKS.register(name, () -> block.apply(properties.get().setId(ResourceKey.create(Registries.BLOCK, TwilightForestMod.prefix(name))).overrideDescription("block.twilightforest." + id))); - } - - public static DeferredBlock registerWithItem(String name, Function block, Supplier properties) { - return registerWithItem(name, block, properties, Item.Properties::new); - } - - public static DeferredBlock registerWithItem(String name, Function block, Supplier properties, Supplier itemProperties) { - DeferredBlock ret = register(name, block, properties); - TFItems.register(name, itemProps -> new BlockItem(ret.get(), itemProps.useBlockDescriptionPrefix()), itemProperties); - return ret; - } - - public static DeferredBlock ominousCandle(String name, MapColor mapColor, Block candle) { - return BLOCKS.register(name, () -> new OminousCandleBlock(candle, - BlockBehaviour.Properties.of() - .mapColor(mapColor) - .noOcclusion() - .strength(0.1F) - .sound(SoundType.CANDLE) - .lightLevel(state -> 2 * state.getValue(OminousCandleBlock.CANDLES)) - .pushReaction(PushReaction.DESTROY) - )); - } - - private static BlockBehaviour.Properties logProperties(MapColor color) { - return BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(color); - } - - private static BlockBehaviour.Properties logProperties(MapColor top, MapColor side) { - return BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor((state) -> state.getValue(RotatedPillarBlock.AXIS) == Direction.Axis.Y ? top : side); - } - - public static BlockBehaviour.Properties copyAndScaleProperties(BlockBehaviour blockBehaviour, float scale) { - BlockBehaviour.Properties properties = BlockBehaviour.Properties.ofFullCopy(blockBehaviour); - return properties.destroyTime(blockBehaviour.defaultDestroyTime() * scale).explosionResistance(properties.explosionResistance * scale); - } - - private static boolean noSpawning(BlockState pState, BlockGetter pLevel, BlockPos pPos, EntityType pValue) { - return false; - } -} diff --git a/src/main/java/twilightforest/util/UnbakedGeometryUtil.java b/src/main/java/twilightforest/util/UnbakedGeometryUtil.java deleted file mode 100644 index 9e09db00e9..0000000000 --- a/src/main/java/twilightforest/util/UnbakedGeometryUtil.java +++ /dev/null @@ -1,41 +0,0 @@ -package twilightforest.util; - -import net.minecraft.client.renderer.block.dispatch.ModelState; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.ModelBaker; -import net.minecraft.client.resources.model.cuboid.CuboidFace; -import net.minecraft.client.resources.model.cuboid.CuboidModelElement; -import net.minecraft.client.resources.model.cuboid.FaceBakery; -import net.minecraft.client.resources.model.geometry.BakedQuad; -import net.minecraft.client.resources.model.sprite.Material; -import net.minecraft.core.Direction; -import twilightforest.client.model.block.connected.ConnectionLogic; - -// this class returns back removed methods from the sources -public class UnbakedGeometryUtil { - public static CuboidFace.UVs uvsByFace(Direction face, CuboidModelElement element) { - return switch (face) { - case DOWN -> new CuboidFace.UVs(element.from().x(), 16.0F - element.to().z(), element.to().x(), 16.0F - element.from().z()); - case UP -> new CuboidFace.UVs(element.from().x(), element.from().z(), element.to().x(), element.to().z()); - case SOUTH -> new CuboidFace.UVs(element.from().x(), 16.0F - element.to().y(), element.to().x(), 16.0F - element.from().y()); - case WEST -> new CuboidFace.UVs(element.from().z(), 16.0F - element.to().y(), element.to().z(), 16.0F - element.from().y()); - case EAST -> new CuboidFace.UVs(16.0F - element.to().z(), 16.0F - element.to().y(), 16.0F - element.from().z(), 16.0F - element.from().y()); - default -> new CuboidFace.UVs(16.0F - element.to().x(), 16.0F - element.to().y(), 16.0F - element.from().x(), 16.0F - element.from().y()); - }; - } - - public static BakedQuad bakeElementFace(ModelBaker baker, CuboidModelElement element, CuboidFace face, Material.Baked sprite, Direction direction, ModelState state) { - return FaceBakery.bakeQuad(baker, element.from(), element.to(), face, sprite, direction, state, null, element.shade(), 0); - } - - public static Material.Baked chooseAndBake(ConnectionLogic target, TextureAtlasSprite[] spriteOptions, Material[] materials) { - TextureAtlasSprite unbakedChoice = target.chooseTexture(spriteOptions); - // spriteOptions.length should be equal to materials.length - for (int i = 0; i < spriteOptions.length; i++) { - if (unbakedChoice == spriteOptions[i]) { - return new Material.Baked(spriteOptions[i], materials[i].forceTranslucent()); - } - } - return new Material.Baked(spriteOptions[0], false); - } -} From 6e3f393b6ae7fd789849448291bb276273b82492 Mon Sep 17 00:00:00 2001 From: Albazavr Date: Mon, 20 Jul 2026 01:37:12 +0300 Subject: [PATCH 13/18] Removed wrong fixed --- .../block/CoronationCarpetBlock.java | 76 ++ .../entity/CoronationCarpetBlockEntity.java | 73 ++ .../block/carpet/RoyalRagsModelLoader.java | 18 + .../block/carpet/UnbakedRoyalRagsModel.java | 134 ++++ .../connected/ConnectedTextureModel.java | 96 +++ .../ConnectedTextureModelLoader.java | 104 +++ .../block/connected/ConnectionLogic.java | 74 ++ .../UnbakedConnectedTextureModel.java | 187 +++++ .../block/forcefield/ForceFieldModel.java | 250 ++++++ .../forcefield/ForceFieldModelBuilder.java | 390 ++++++++++ .../forcefield/ForceFieldModelLoader.java | 57 ++ .../forcefield/UnbakedForceFieldModel.java | 31 + .../model/block/patch/PatchBuilder.java | 35 + .../client/model/block/patch/PatchModel.java | 198 +++++ .../model/block/patch/PatchModelLoader.java | 23 + .../model/block/patch/UnbakedPatchModel.java | 20 + .../twilightforest/init/TFBlockEntities.java | 148 ++++ .../java/twilightforest/init/TFBlocks.java | 713 ++++++++++++++++++ .../util/UnbakedGeometryUtil.java | 41 + 19 files changed, 2668 insertions(+) create mode 100644 src/main/java/twilightforest/block/CoronationCarpetBlock.java create mode 100644 src/main/java/twilightforest/block/entity/CoronationCarpetBlockEntity.java create mode 100644 src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java create mode 100644 src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java create mode 100644 src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java create mode 100644 src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java create mode 100644 src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java create mode 100644 src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java create mode 100644 src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java create mode 100644 src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java create mode 100644 src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java create mode 100644 src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java create mode 100644 src/main/java/twilightforest/client/model/block/patch/PatchBuilder.java create mode 100644 src/main/java/twilightforest/client/model/block/patch/PatchModel.java create mode 100644 src/main/java/twilightforest/client/model/block/patch/PatchModelLoader.java create mode 100644 src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java create mode 100644 src/main/java/twilightforest/init/TFBlockEntities.java create mode 100644 src/main/java/twilightforest/init/TFBlocks.java create mode 100644 src/main/java/twilightforest/util/UnbakedGeometryUtil.java diff --git a/src/main/java/twilightforest/block/CoronationCarpetBlock.java b/src/main/java/twilightforest/block/CoronationCarpetBlock.java new file mode 100644 index 0000000000..90a3501765 --- /dev/null +++ b/src/main/java/twilightforest/block/CoronationCarpetBlock.java @@ -0,0 +1,76 @@ +package twilightforest.block; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.ScheduledTickAccess; +import net.minecraft.world.level.block.BaseEntityBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.WoolCarpetBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.jspecify.annotations.Nullable; +import twilightforest.block.entity.CoronationCarpetBlockEntity; +import twilightforest.init.TFBlockEntities; + +// [VanillaCopy] extended WoolCarpetBlock with BlockEntity +public class CoronationCarpetBlock extends BaseEntityBlock { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec((i) -> i.group(DyeColor.CODEC.fieldOf("color").forGetter(CoronationCarpetBlock::getColor), propertiesCodec()).apply(i, CoronationCarpetBlock::new)); + private static final VoxelShape SHAPE = Block.column(16.0D, 0.0D, 1.0D); + + private final DyeColor color; + + public CoronationCarpetBlock(DyeColor color, Properties properties) { + super(properties); + this.color = color; + } + + @Override + protected MapCodec codec() { + return CODEC; + } + + @Override + public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) { + return new CoronationCarpetBlockEntity(blockPos, blockState); + } + + @Override + protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { + return SHAPE; + } + + @Override + protected BlockState updateShape(BlockState state, LevelReader level, ScheduledTickAccess ticks, BlockPos pos, Direction directionToNeighbour, BlockPos neighbourPos, BlockState neighbourState, RandomSource random) { + if (!state.canSurvive(level, pos)) { + return Blocks.AIR.defaultBlockState(); + } + + if (level instanceof Level world && world.isClientSide()) { + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity instanceof CoronationCarpetBlockEntity) { + world.getModelDataManager().requestRefresh(blockEntity); + } + } + + return super.updateShape(state, level, ticks, pos, directionToNeighbour, neighbourPos, neighbourState, random); + } + + @Override + protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) { + return !level.isEmptyBlock(pos.below()); + } + + public DyeColor getColor() { + return color; + } +} diff --git a/src/main/java/twilightforest/block/entity/CoronationCarpetBlockEntity.java b/src/main/java/twilightforest/block/entity/CoronationCarpetBlockEntity.java new file mode 100644 index 0000000000..6cbe86227f --- /dev/null +++ b/src/main/java/twilightforest/block/entity/CoronationCarpetBlockEntity.java @@ -0,0 +1,73 @@ +package twilightforest.block.entity; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.neoforged.neoforge.model.data.ModelData; +import net.neoforged.neoforge.model.data.ModelProperty; +import twilightforest.client.model.block.connected.ConnectionLogic; +import twilightforest.init.TFBlockEntities; +import twilightforest.init.TFBlocks; + +import java.util.Arrays; + +public class CoronationCarpetBlockEntity extends BlockEntity { + private final Block[] validConnectors = {TFBlocks.CORONATION_CARPET.value()}; + private static final ModelProperty DATA = new ModelProperty<>(); + + public CoronationCarpetBlockEntity(BlockPos worldPosition, BlockState blockState) { + super(TFBlockEntities.CORONATION_CARPET.get(), worldPosition, blockState); + } + + @Override + public ModelData getModelData() { + if (this.level == null) { + return ModelData.EMPTY; + } + + LoftyCarpetData data = new LoftyCarpetData(); + + for (Direction face : Direction.values()) { + Direction[] directions = ConnectionLogic.AXIS_PLANE_DIRECTIONS[face.getAxis().ordinal()]; + boolean[] sideStates = new boolean[4]; + + int faceIndex; + for (faceIndex = 0; faceIndex < directions.length; faceIndex++) { + sideStates[faceIndex] = this.shouldConnectSide(this.level, this.worldPosition, face, directions[faceIndex]); + } + + faceIndex = face.get3DDataValue(); + + for (int dir = 0; dir < directions.length; dir++) { + int cornerOffset = (dir + 1) % directions.length; + boolean side1 = sideStates[dir]; + boolean side2 = sideStates[cornerOffset]; + boolean corner = side1 && side2 && this.isCornerBlockPresent(this.level, this.worldPosition, face, directions[dir], directions[cornerOffset]); + data.logic[faceIndex][dir] = dir % 2 == 0 ? ConnectionLogic.of(side1, side2, corner) : ConnectionLogic.of(side2, side1, corner); + } + } + + return ModelData.EMPTY.derive().with(DATA, data).build(); + } + + private boolean shouldConnectSide(BlockGetter getter, BlockPos pos, Direction face, Direction side) { + BlockState neighborState = getter.getBlockState(pos.relative(side)); + return Arrays.stream(this.validConnectors).anyMatch(neighborState::is) && Block.shouldRenderFace(getter, pos, getter.getBlockState(pos), neighborState, face); + } + + private boolean isCornerBlockPresent(BlockGetter getter, BlockPos pos, Direction face, Direction side1, Direction side2) { + BlockState neighborState = getter.getBlockState(pos.relative(side1).relative(side2)); + return Arrays.stream(this.validConnectors).anyMatch(neighborState::is) && Block.shouldRenderFace(getter, pos, getter.getBlockState(pos), neighborState, face); + } + + //we need a class to make model data. Fine, here you go + private static final class LoftyCarpetData { + private final ConnectionLogic[][] logic = new ConnectionLogic[6][4]; + + private LoftyCarpetData() { + } + } +} diff --git a/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java b/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java new file mode 100644 index 0000000000..7fca73cb5a --- /dev/null +++ b/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java @@ -0,0 +1,18 @@ +package twilightforest.client.model.block.carpet; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import net.neoforged.neoforge.client.model.UnbakedModelLoader; + +public class RoyalRagsModelLoader implements UnbakedModelLoader { + @Deprecated // FIXME: Generalize alongside with CastleDoor models + public static final RoyalRagsModelLoader INSTANCE = new RoyalRagsModelLoader(); + + public RoyalRagsModelLoader() { + } + + public UnbakedRoyalRagsModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) throws JsonParseException { + return new UnbakedRoyalRagsModel(); + } +} diff --git a/src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java b/src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java new file mode 100644 index 0000000000..3ac7de26a5 --- /dev/null +++ b/src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java @@ -0,0 +1,134 @@ +package twilightforest.client.model.block.carpet; + +import com.mojang.math.Quadrant; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.dispatch.ModelState; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.ModelBaker; +import net.minecraft.client.resources.model.ModelDebugName; +import net.minecraft.client.resources.model.cuboid.CuboidFace; +import net.minecraft.client.resources.model.cuboid.CuboidModelElement; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.geometry.QuadCollection; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.resources.model.sprite.Material; +import net.minecraft.client.resources.model.sprite.TextureSlots; +import net.minecraft.core.Direction; +import net.minecraft.core.Vec3i; +import net.minecraft.data.AtlasIds; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; +import twilightforest.client.model.block.connected.ConnectionLogic; +import twilightforest.util.UnbakedGeometryUtil; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +//for now, im keeping this hardcoded to a 2 layer block, with the overlay layer being fullbright and tinted. +//It might be worth expanding this in the future to be more flexible for other kinds of blocks (1 layer blocks, determining emissivity and tinting per layer, maybe >2 layer blocks?) but for now, I see no point. +//I only wanted this system for castle doors after all! +public class UnbakedRoyalRagsModel implements UnbakedGeometry { + + private final CuboidModelElement[][] baseElements; + private final CuboidModelElement[][][] faceElements; + + public UnbakedRoyalRagsModel() { + //base elements - the side faces without ctm. No Connected Textures on this bit. + //the array is made of horizontal directions (Direction.get2DDataValue) and quads + this.baseElements = new CuboidModelElement[4][4]; + + //face elements - the connected bit of the model. + //the array is made of the directions, quads, and each logic value in the ConnectionLogic class + //Topmost array indexes to up/dpwn directions (Direction.get3DDataValue, down = 0, up = 1) then inside are quads + this.faceElements = new CuboidModelElement[2][4][5]; + Vec3i center = new Vec3i(8, 8, 8); + + for (Direction face : Direction.values()) { + Direction[] planeDirections = ConnectionLogic.AXIS_PLANE_DIRECTIONS[face.getAxis().ordinal()]; + + for (int quad = 0; quad < 4; quad++) { + Vec3i corner = face.getUnitVec3i().offset(planeDirections[quad].getUnitVec3i()).offset(planeDirections[(quad + 1) % 4].getUnitVec3i()).offset(1, 1, 1).multiply(8); + CuboidModelElement element = new CuboidModelElement(new Vector3f((float) Math.min(center.getX(), corner.getX()), (float) Math.min(center.getY(), corner.getY()) / 16f, (float) Math.min(center.getZ(), corner.getZ())), new Vector3f((float) Math.max(center.getX(), corner.getX()), (float) Math.max(center.getY(), corner.getY()) / 16f, (float) Math.max(center.getZ(), corner.getZ())), Map.of()); + + if (face.getAxis().isHorizontal()) { + this.baseElements[face.get2DDataValue()][quad] = new CuboidModelElement(element.from(), element.to(), Map.of(face, new CuboidFace(face, -1, "", ConnectionLogic.NONE.remapUVs(UnbakedGeometryUtil.uvsByFace(face, element)), Quadrant.R0))); + } else { + for (ConnectionLogic connectionType : ConnectionLogic.values()) { + this.faceElements[face.get3DDataValue()][quad][connectionType.ordinal()] = new CuboidModelElement(element.from(), element.to(), Map.of(face, new CuboidFace(face, 0, "", connectionType.remapUVs(UnbakedGeometryUtil.uvsByFace(face, element)), Quadrant.R0))); + } + } + } + } + } + + public QuadCollection getQuads(@Nullable Direction side, List[] baseQuads, BakedQuad[][][] quads) { + if (side != null) { + QuadCollection.Builder builder = new QuadCollection.Builder(); + if (side.getAxis().isHorizontal()) { + if (baseQuads != null) { + for (BakedQuad bakedQuad : baseQuads[side.get2DDataValue()]) { + builder.addCulledFace(side, bakedQuad); + } + } + } else { + int faceIndex = side.get3DDataValue(); + for (int quad = 0; quad < 4; ++quad) { + ConnectionLogic connectionType = ConnectionLogic.NONE; + builder.addCulledFace(side, quads[faceIndex][quad][connectionType.ordinal()]); + } + } + + return builder.build(); + } else { + return QuadCollection.EMPTY; + } + } + + @Override + public QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName modelDebugName) { + //making an array list like this is cursed, would not recommend + @SuppressWarnings("unchecked") //this is fine, I hope + List[] baseQuads = (List[]) Array.newInstance(List.class, 4); + Material baseMaterial = textureSlots.getMaterial("wool"); + TextureAtlasSprite baseTexture = Minecraft.getInstance().getAtlasManager().getAtlasOrThrow(AtlasIds.BLOCKS).getSprite(baseMaterial.sprite()); + Material.Baked baseBakedMaterial = new Material.Baked(baseTexture, baseMaterial.forceTranslucent()); + + Material ctmMaterial = textureSlots.getMaterial("wool_ctm"); + TextureAtlasSprite ctmTexture = Minecraft.getInstance().getAtlasManager().getAtlasOrThrow(AtlasIds.BLOCKS).getSprite(ctmMaterial.sprite()); + + for (Direction direction : Direction.Plane.HORIZONTAL) { + baseQuads[direction.get2DDataValue()] = new ArrayList<>(); + + for (CuboidModelElement element : this.baseElements[direction.get2DDataValue()]) { + baseQuads[direction.get2DDataValue()].add(UnbakedGeometryUtil.bakeElementFace(modelBaker, element, element.faces().values().iterator().next(), baseBakedMaterial, direction, modelState)); + } + } + + //we'll use this to figure out which texture to use with the Connected Texture logic + //NONE uses the first one, everything else uses the 2nd one + TextureAtlasSprite[] sprites = new TextureAtlasSprite[]{baseTexture, ctmTexture}; + Material[] materials = new Material[]{baseMaterial, ctmMaterial}; + + BakedQuad[][][] quads = new BakedQuad[2][4][5]; + + for (int dir = 0; dir < 2; dir++) { + for (int quad = 0; quad < 4; quad++) { + for (int type = 0; type < 5; type++) { + CuboidModelElement element = this.faceElements[dir][quad][type]; + Material.Baked bakedChoice = UnbakedGeometryUtil.chooseAndBake(ConnectionLogic.values()[type], sprites, materials); + quads[dir][quad][type] = UnbakedGeometryUtil.bakeElementFace(modelBaker, element, element.faces().values().iterator().next(), bakedChoice, Direction.values()[dir], modelState); + } + } + } + + QuadCollection.Builder builder = new QuadCollection.Builder(); + + for (Direction value : Direction.values()) { + builder.addAll(getQuads(value, baseQuads, quads)); + } + + return builder.build(); + } +} \ No newline at end of file diff --git a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java new file mode 100644 index 0000000000..d72ca1e978 --- /dev/null +++ b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java @@ -0,0 +1,96 @@ +package twilightforest.client.model.block.connected; + +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.dispatch.ModelState; +import net.minecraft.client.resources.model.ModelBaker; +import net.minecraft.client.resources.model.ModelDebugName; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.geometry.QuadCollection; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.resources.model.sprite.TextureSlots; +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; +import net.neoforged.neoforge.model.data.ModelData; +import net.neoforged.neoforge.model.data.ModelProperty; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +public class ConnectedTextureModel implements UnbakedGeometry { + + private final Set connectedFaces; + private final Set unculledFaces; + private final boolean renderOverlayOnAllFaces; + private final Map baseQuads; + private final Map connectedQuads; + private final List validConnectors; + private static final ModelProperty<@NotNull ConnectedTextureData> DATA = new ModelProperty<>(); + + public ConnectedTextureModel(Set connectedFaces, Set unculledFaces, boolean renderOverlayOnAllFaces, List connectableBlocks, Map baseQuads, Map connectedQuads) { + this.connectedFaces = connectedFaces; + this.unculledFaces = unculledFaces; + this.renderOverlayOnAllFaces = renderOverlayOnAllFaces; + this.validConnectors = connectableBlocks; + this.baseQuads = baseQuads; + this.connectedQuads = connectedQuads; + } + + @Override + public QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName modelDebugName) { + QuadCollection.Builder builder = new QuadCollection.Builder(); + + for (Direction direction : this.unculledFaces) { + List unculledQuads = this.getQuadsForFace(direction, ModelData.EMPTY); + for (BakedQuad quad : unculledQuads) { + builder.addUnculledFace(quad); + } + } + + for (Direction direction : Direction.values()) { + List culledQuads = this.getQuadsForFace(direction, ModelData.EMPTY); + for (BakedQuad quad : culledQuads) { + builder.addCulledFace(direction, quad); + } + } + + return builder.build(); + } + + public List getQuadsForFace(Direction side, ModelData extraData) { + BakedQuad[] baseQuads = this.baseQuads.get(side); + ConnectedTextureData data = extraData.get(DATA); + ArrayList quads = new ArrayList<>(4 + (baseQuads != null ? 4 : 0)); + if (baseQuads != null) quads.addAll(List.of(baseQuads)); + + if (this.connectedFaces.contains(side) || this.renderOverlayOnAllFaces) { + for (int quad = 0; quad < 4; ++quad) { + //if our model data is null (happens for items), we can skip connected textures since we dont have the info we need + ConnectionLogic connectionType = data != null && this.connectedFaces.contains(side) ? data.logic[side.get3DDataValue()][quad] : ConnectionLogic.NONE; + quads.add(this.connectedQuads.get(side)[quad][connectionType.ordinal()]); + } + } + + return quads; + } + + private boolean shouldConnectSide(BlockAndTintGetter getter, BlockPos pos, Direction face, Direction side) { + BlockState neighborState = getter.getBlockState(pos.relative(side)); + if (this.unculledFaces.contains(face)) return this.validConnectors.stream().anyMatch(neighborState::is); + return this.validConnectors.stream().anyMatch(neighborState::is) && Block.shouldRenderFace(getter, pos.relative(face), neighborState, getter.getBlockState(pos.relative(face)), face); + } + + private boolean isCornerBlockPresent(BlockAndTintGetter getter, BlockPos pos, Direction face, Direction side1, Direction side2) { + BlockState neighborState = getter.getBlockState(pos.relative(side1).relative(side2)); + if (this.unculledFaces.contains(face)) return this.validConnectors.stream().anyMatch(neighborState::is); + return this.validConnectors.stream().anyMatch(neighborState::is) && Block.shouldRenderFace(getter, pos.relative(face), neighborState, getter.getBlockState(pos.relative(face)), face); + } + + private static final class ConnectedTextureData { + private final ConnectionLogic[][] logic = new ConnectionLogic[6][4]; + + private ConnectedTextureData() { + } + } +} \ No newline at end of file diff --git a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java new file mode 100644 index 0000000000..2b4c86be61 --- /dev/null +++ b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java @@ -0,0 +1,104 @@ +package twilightforest.client.model.block.connected; + +import com.google.gson.*; +import com.mojang.datafixers.util.Pair; +import net.minecraft.core.Direction; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.Identifier; +import net.minecraft.tags.TagKey; +import net.minecraft.util.GsonHelper; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.neoforged.neoforge.client.model.StandardModelParameters; +import net.neoforged.neoforge.client.model.UnbakedModelLoader; +import org.joml.Vector3f; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; + +public class ConnectedTextureModelLoader implements UnbakedModelLoader { + public static final ConnectedTextureModelLoader INSTANCE = new ConnectedTextureModelLoader(); + + public ConnectedTextureModelLoader() { + } + + @Override + public UnbakedConnectedTextureModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) throws JsonParseException { + JsonObject baseTextureInfo = GsonHelper.getAsJsonObject(jsonObject, "base", new JsonObject()); + int baseTintIndex = GsonHelper.getAsInt(baseTextureInfo, "tint_index", -1); + int baseEmissivity = GsonHelper.getAsInt(baseTextureInfo, "emissivity", 0); + + Pair element; + if (jsonObject.has("element")) { + JsonObject obj = jsonObject.getAsJsonObject("element"); + element = Pair.of(this.deserializeVec(obj, "from"), this.deserializeVec(obj, "to")); + } else { + element = Pair.of(new Vector3f(0, 0, 0), new Vector3f(16, 16, 16)); + } + + JsonObject overlayInfo = GsonHelper.getAsJsonObject(jsonObject, "connected_texture", new JsonObject()); + int tintIndex = GsonHelper.getAsInt(overlayInfo, "tint_index", -1); + int emissivity = GsonHelper.getAsInt(overlayInfo, "emissivity", 0); + boolean renderDisabled = GsonHelper.getAsBoolean(overlayInfo, "always_render_overlay", true); + EnumSet faces = this.parseEnabledFaces(overlayInfo, "faces"); + + List connectables = this.parseConnnectableBlocks(jsonObject); + return new UnbakedConnectedTextureModel(element, faces, renderDisabled, connectables, baseEmissivity, emissivity, StandardModelParameters.parse(jsonObject, deserializationContext)); + } + + private EnumSet parseEnabledFaces(JsonObject object, String key) { + if (!object.has(key)) { + return EnumSet.allOf(Direction.class); + } else { + EnumSet faces = EnumSet.noneOf(Direction.class); + + for (JsonElement element : object.getAsJsonArray(key)) { + Direction face = Direction.byName(element.getAsString()); + if (face == null) { + throw new JsonParseException("Invalid face: " + element.getAsString()); + } + + faces.add(face); + } + + return faces; + } + } + + private List parseConnnectableBlocks(JsonObject object) { + if (!object.has("connectable_blocks")) { + return List.of(); + } else { + List blocks = new ArrayList<>(); + + for (JsonElement element : object.getAsJsonArray("connectable_blocks")) { + if (element.getAsString().startsWith("#")) { + Identifier tag = Identifier.tryParse(element.getAsString().substring(1)); + if (tag != null) { + BuiltInRegistries.BLOCK.getTagOrEmpty(TagKey.create(Registries.BLOCK, tag)).forEach(blockHolder -> blocks.add(blockHolder.value())); + } else { + throw new JsonParseException("Invalid block tag: " + element.getAsString()); + } + } else { + Block block = BuiltInRegistries.BLOCK.getValue(Identifier.tryParse(element.getAsString())); + if (block == Blocks.AIR) { + throw new JsonParseException("Invalid block: " + element.getAsString()); + } + blocks.add(block); + } + } + + return blocks; + } + } + + private Vector3f deserializeVec(JsonObject object, String name) { + JsonArray from = object.getAsJsonArray(name); + if (from.asList().size() == 3) { + return new Vector3f(from.get(0).getAsFloat(), from.get(1).getAsFloat(), from.get(2).getAsFloat()); + } + return new Vector3f(0, 0, 0); + } +} diff --git a/src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java b/src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java new file mode 100644 index 0000000000..54a7f70901 --- /dev/null +++ b/src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java @@ -0,0 +1,74 @@ +package twilightforest.client.model.block.connected; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.cuboid.CuboidFace; +import net.minecraft.core.Direction; + +//let the magic begin. +//as far as I understand, CTM texture sheets are laid out in 4 pieces: +// - cornerless connections in the top left +// - vertical connections in the top right +// - horizontal connections in the bottom left +// - corner connection in the bottom right +//each quadrant is composed of a 4x4 piece for each rotation that the model can pick based on where on the block the connection is happening. +//to avoid confusion: cornerless means that no corner piece renders. This happens when you have a block horizontally, vertically, and filling that corner space between the 2. +// ** +// ** +//while a corner means that a corner piece will render. This happens when you have a block horizontally and vertically, but theres no block in the corner. +// * +// ** +public enum ConnectionLogic { + + NONE(0, 0, 0, 16, 16), + CORNERLESS(1, 0, 0, 8, 8), + VERTICAL(1, 0, 8, 8, 16), + HORIZONTAL(1, 8, 0, 16, 8), + CORNER(1, 8, 8, 16, 16); + + private final int texture; + private final int u0; + private final int v0; + private final int u1; + private final int v1; + + public static final Direction[][] AXIS_PLANE_DIRECTIONS = new Direction[][]{ + {Direction.UP, Direction.NORTH, Direction.DOWN, Direction.SOUTH}, + {Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST}, + {Direction.UP, Direction.EAST, Direction.DOWN, Direction.WEST} + }; + + ConnectionLogic(int texture, int u0, int v0, int u1, int v1) { + this.texture = texture; + this.u0 = u0; + this.v0 = v0; + this.u1 = u1; + this.v1 = v1; + } + + public static ConnectionLogic of(boolean horizontal, boolean vertical, boolean corner) { + if (corner) { + return CORNERLESS; + } else if (horizontal) { + return vertical ? CORNER : HORIZONTAL; + } else { + return vertical ? VERTICAL : NONE; + } + } + + public TextureAtlasSprite chooseTexture(TextureAtlasSprite[] sprites) { + return sprites[this.texture]; + } + + public CuboidFace.UVs remapUVs(CuboidFace.UVs uvs) { + if (uvs == null) return new CuboidFace.UVs(0, 0, 0, 0); + return new CuboidFace.UVs(this.getU(uvs.maxU()), this.getV(uvs.minV()), this.getU(uvs.maxU()), this.getV(uvs.maxV())); + } + + public float getU(float delta) { + return (float) this.u0 + (float) (this.u1 - this.u0) * (delta / 16.0F); + } + + public float getV(float delta) { + return (float) this.v0 + (float) (this.v1 - this.v0) * (delta / 16.0F); + } +} diff --git a/src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java b/src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java new file mode 100644 index 0000000000..cc2e015ab2 --- /dev/null +++ b/src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java @@ -0,0 +1,187 @@ +package twilightforest.client.model.block.connected; + +import com.mojang.datafixers.util.Pair; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.resources.model.sprite.Material; +import net.minecraft.core.Direction; +import net.minecraft.resources.Identifier; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.Block; +import net.neoforged.neoforge.client.model.AbstractUnbakedModel; +import net.neoforged.neoforge.client.model.StandardModelParameters; +import net.neoforged.neoforge.client.model.quad.MutableQuad; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; + +import java.util.*; + +public class UnbakedConnectedTextureModel extends AbstractUnbakedModel { + + protected final boolean renderOverlayOnAllFaces; + protected final Set connectedFaces; + protected final List connectableBlocks; + + protected MutableQuad[][] baseElements; + protected MutableQuad[][][] connectedElements; + + + public UnbakedConnectedTextureModel(Pair element, Set connectedFaces, boolean renderOnDisabledFaces, List connectableBlocks, int baseEmissivity, int emissivity, StandardModelParameters parameters) { + super(parameters); + this.connectedFaces = connectedFaces; + this.renderOverlayOnAllFaces = renderOnDisabledFaces; + this.connectableBlocks = connectableBlocks; + + this.baseElements = new MutableQuad[6][4]; + this.connectedElements = new MutableQuad[6][4][5]; + + int center = 8; + + for (Direction face : Direction.values()) { + Direction cull = this.getCullface(face, element.getFirst(), element.getSecond()); + Direction[] planeDirections = ConnectionLogic.AXIS_PLANE_DIRECTIONS[face.getAxis().ordinal()]; + + for (int i = 0; i < 4; ++i) { + net.minecraft.core.Vec3i corner = face.getUnitVec3i().offset(planeDirections[i].getUnitVec3i()).offset(planeDirections[(i + 1) % 4].getUnitVec3i()).offset(1, 1, 1).multiply(8); + + Vector3f from = new Vector3f( + Mth.clamp(Math.min(center - (16 - element.getSecond().x()), corner.getX() + element.getFirst().x()), 0, 16), + Mth.clamp(Math.min(center - (16 - element.getSecond().y()), corner.getY() + element.getFirst().y()), 0, 16), + Mth.clamp(Math.min(center - (16 - element.getSecond().z()), corner.getZ() + element.getFirst().z()), 0, 16) + ); + + Vector3f to = new Vector3f( + element.getSecond().x() < center ? element.getSecond().x() : Math.max(center, corner.getX() - (16 - element.getSecond().x())), + element.getSecond().y() < center ? element.getSecond().y() : Math.max(center, corner.getY() - (16 - element.getSecond().y())), + element.getSecond().z() < center ? element.getSecond().z() : Math.max(center, corner.getZ() - (16 - element.getSecond().z())) + ); + + MutableQuad baseQuad = new MutableQuad(); + baseQuad.setDirection(face); + baseQuad.setShade(true); + baseQuad.setLightEmission(baseEmissivity); + setupQuadVertices(baseQuad, from, to, face); + remapQuadUVs(baseQuad, ConnectionLogic.NONE, face); + + this.baseElements[face.get3DDataValue()][i] = baseQuad; + + for (ConnectionLogic logic : ConnectionLogic.values()) { + MutableQuad connectedQuad = new MutableQuad(); + connectedQuad.setDirection(face); + connectedQuad.setShade(true); + connectedQuad.setLightEmission(emissivity); + setupQuadVertices(connectedQuad, from, to, face); + remapQuadUVs(connectedQuad, logic, face); + + this.connectedElements[face.get3DDataValue()][i][logic.ordinal()] = connectedQuad; + } + } + } + } + + private void setupQuadVertices(MutableQuad quad, org.joml.Vector3f from, org.joml.Vector3f to, Direction face) { + for (int v = 0; v < 4; v++) { + float x = (v == 1 || v == 2) ? to.x() / 16f : from.x() / 16f; + float y = (v == 2 || v == 3) ? to.y() / 16f : from.y() / 16f; + float z = (face.getAxis() == Direction.Axis.Z) ? to.z() / 16f : from.z() / 16f; + quad.setPosition(v, new org.joml.Vector3f(x, y, z)); + } + } + + private void remapQuadUVs(MutableQuad quad, ConnectionLogic logic, Direction face) { + for (int v = 0; v < 4; v++) { + float u = (v == 1 || v == 2) ? 1.0f : 0.0f; + float vCoord = (v == 2 || v == 3) ? 1.0f : 0.0f; + + float[] uvs = new float[]{u, vCoord}; + float[] remapped = logic.remapUVs(uvs); + + quad.setUv(v, remapped[0], remapped[1]); + } + } + + + @Nullable + private Direction getCullface(Direction direction, Vector3f from, Vector3f to) { + boolean cull = switch (direction) { + case DOWN -> from.y() == 0.0F; + case UP -> to.y() == 16.0F; + case NORTH -> from.x() == 0.0F; + case SOUTH -> to.x() == 16.0F; + case WEST -> from.z() == 0.0F; + case EAST -> to.z() == 16.0F; + }; + + return cull ? direction : null; + } + + @Override + public UnbakedGeometry geometry() { + TextureAtlas atlas = net.minecraft.client.Minecraft.getInstance().getAtlasManager().getAtlasOrThrow(TextureAtlas.LOCATION_BLOCKS); + + String modId = "twilightforest"; + + Identifier idBase = Identifier.fromNamespaceAndPath(modId, "block/glass"); + Identifier idOverlay = Identifier.fromNamespaceAndPath(modId, "block/glass_overlay"); + Identifier idConnected = Identifier.fromNamespaceAndPath(modId, "block/glass_overlay_connected"); + + Material matBase = new Material(idBase); + Material matOverlay = new Material(idOverlay); + Material matConnected = new Material(idConnected); + + matBase = matBase.withForceTranslucent(true); + matOverlay = matOverlay.withForceTranslucent(true); + matConnected = matConnected.withForceTranslucent(true); + + TextureAtlasSprite baseTexture = atlas.getSprite(matBase.sprite()); + TextureAtlasSprite overlayTexture = atlas.getSprite(matOverlay.sprite()); + TextureAtlasSprite connectedTexture = atlas.getSprite(matConnected.sprite()); + TextureAtlasSprite particleTexture = overlayTexture; + + TextureAtlasSprite[] sprites = new TextureAtlasSprite[]{overlayTexture, connectedTexture, particleTexture}; + + Map finalBaseQuads = new HashMap<>(); + Map finalConnectedQuads = new HashMap<>(); + Set unculledFaces = new HashSet<>(); + + for (Direction dir : Direction.values()) { + int dirIdx = dir.get3DDataValue(); + + List baseQuadList = new ArrayList<>(); + for (int i = 0; i < 4; i++) { + MutableQuad quad = this.baseElements[dirIdx][i]; + for (int v = 0; v < 4; v++) { + quad.setUv(v, baseTexture.getU(quad.u(v) * 16f), baseTexture.getV(quad.v(v) * 16f)); + } + baseQuadList.add(quad.toBakedQuad()); + } + finalBaseQuads.put(dir, baseQuadList.toArray(new BakedQuad[0])); + + BakedQuad[][] dirQuads = new BakedQuad[4][5]; + for (int quadIdx = 0; quadIdx < 4; quadIdx++) { + for (int typeIdx = 0; typeIdx < 5; typeIdx++) { + MutableQuad quad = this.connectedElements[dirIdx][quadIdx][typeIdx]; + + TextureAtlasSprite chosenSprite = ConnectionLogic.values()[typeIdx].chooseTexture(sprites); + + for (int v = 0; v < 4; v++) { + quad.setUv(v, chosenSprite.getU(quad.u(v) * 16f), chosenSprite.getV(quad.v(v) * 16f)); + } + dirQuads[quadIdx][typeIdx] = quad.toBakedQuad(); + } + } + finalConnectedQuads.put(dir, dirQuads); + } + + return new ConnectedTextureModel( + this.connectedFaces, + unculledFaces, + this.renderOverlayOnAllFaces, + this.connectableBlocks, + finalBaseQuads, + finalConnectedQuads + ); + } +} \ No newline at end of file diff --git a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java new file mode 100644 index 0000000000..64d94092f7 --- /dev/null +++ b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java @@ -0,0 +1,250 @@ +package twilightforest.client.model.block.forcefield; + +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.dispatch.ModelState; +import net.minecraft.client.renderer.rendertype.RenderType; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.ModelBaker; +import net.minecraft.client.resources.model.ModelDebugName; +import net.minecraft.client.resources.model.cuboid.ItemTransforms; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.geometry.QuadCollection; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.resources.model.sprite.Material; +import net.minecraft.client.resources.model.sprite.TextureSlots; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.resources.Identifier; +import net.minecraft.util.StringRepresentable; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.state.BlockState; +import net.neoforged.neoforge.client.model.quad.MutableQuad; +import net.neoforged.neoforge.model.data.ModelData; +import net.neoforged.neoforge.model.data.ModelProperty; +import org.jetbrains.annotations.Nullable; +import twilightforest.block.ForceFieldBlock; + +import java.util.*; +import java.util.function.Function; + +public class ForceFieldModel implements UnbakedGeometry { + private static final ModelProperty DATA = new ModelProperty<>(); + + private final Map parts; + private final Function spriteFunction; + private final boolean usesAO; + private final boolean usesBlockLight; + private final ItemTransforms transforms; + @Nullable + private final Set renderTypes; + + public ForceFieldModel(Map parts, Function spriteFunction, boolean useAmbientOcclusion, boolean usesBlockLight, ItemTransforms itemTransforms, @Nullable Set renderTypes) { + this.parts = parts; + this.spriteFunction = spriteFunction; + this.usesAO = useAmbientOcclusion; + this.usesBlockLight = usesBlockLight; + this.transforms = itemTransforms; + this.renderTypes = renderTypes; + } + + @Override + public QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName modelDebugName) { + QuadCollection.Builder builder = new QuadCollection.Builder(); + + ForceFieldData defaultData = new ForceFieldData(java.util.Collections.emptyMap()); + + List unculledQuads = new java.util.ArrayList<>(); + for (Direction direction : Direction.values()) { + unculledQuads = this.getQuads(unculledQuads, direction, defaultData); + } + for (BakedQuad quad : unculledQuads) { + builder.addUnculledFace(quad); + } + + for (Direction direction : Direction.values()) { + List culledQuads = new java.util.ArrayList<>(); + culledQuads = this.getQuads(culledQuads, direction, defaultData); + for (BakedQuad quad : culledQuads) { + builder.addCulledFace(direction, quad); + } + } + + return builder.build(); + } + + public List getQuads(List quads, Direction side, ForceFieldData data) { + for (Map.Entry entry : this.parts.entrySet()) { + + if (ForceFieldModel.skipRender(data.directions(), entry.getValue().direction(), entry.getValue().b(), entry.getValue().parents(), side)) { + continue; + } + + String texturePath = this.spriteFunction.apply(entry.getKey() + "_" + side.getName()); + + if (texturePath != null) { + Identifier identifier = Identifier.parse(texturePath); + Material material = new Material(identifier); + + material = material.withForceTranslucent(true); + + TextureAtlasSprite sprite = net.minecraft.client.Minecraft.getInstance() + .getAtlasManager().getAtlasOrThrow(net.minecraft.client.renderer.texture.TextureAtlas.LOCATION_BLOCKS) + .getSprite(material.sprite()); + + MutableQuad mutableQuad = new MutableQuad(); + + for (int vertexIndex = 0; vertexIndex < 4; vertexIndex++) { + float x = (vertexIndex == 1 || vertexIndex == 2) ? 1.0f : 0.0f; + float y = (vertexIndex == 2 || vertexIndex == 3) ? 1.0f : 0.0f; + float z = 0.5f; + + mutableQuad.setPosition(vertexIndex, new org.joml.Vector3f(x, y, z)); + + float u = sprite.getU(x * 16.0f); + float v = sprite.getV(y * 16.0f); + mutableQuad.setUv(vertexIndex, u, v); + } + + mutableQuad.setDirection(side); + mutableQuad.setShade(this.usesAO); + + if (this.usesBlockLight) { + mutableQuad.setLightEmission(15); + } + + quads.add(mutableQuad.toBakedQuad()); + } + } + return quads; + } + + protected static boolean skipRender(Map> directions, @Nullable ExtraDirection direction, boolean supposedToBe, List parents, Direction side) { + if (direction == null) return false; + for (ExtraDirection parent : parents) if (!directions.containsKey(parent)) return true; + boolean hasKey = directions.containsKey(direction); + if (hasKey != supposedToBe) return true; + if (hasKey) return directions.get(direction).contains(side); + return false; + } + + public ModelData getModelData(BlockAndTintGetter level, BlockPos pos, BlockState state, ModelData modelData) { + if (modelData == ModelData.EMPTY) { + Map> map = new HashMap<>(); + for (ExtraDirection extraDirection : getExtraDirections(state, level, pos)) { + List directionList = new ArrayList<>(); + for (Direction dir : Direction.values()) { + ExtraDirection mirrored = extraDirection.mirrored(dir.getAxis()); + if (mirrored != extraDirection) { + BlockState other = level.getBlockState(pos.relative(dir)); + if (other.getBlock() instanceof ForceFieldBlock) { + if (getExtraDirections(other, level, pos.relative(dir)).contains(mirrored)) directionList.add(dir); + } + } + } + map.put(extraDirection, directionList); + } + + modelData = ModelData.builder().with(DATA, new ForceFieldData(map)).build(); + } + return modelData; + } + + public static List getExtraDirections(BlockState state, BlockGetter level, BlockPos pos) { + List directions = new ArrayList<>(); + + boolean down = state.getValue(ForceFieldBlock.DOWN); + boolean up = state.getValue(ForceFieldBlock.UP); + boolean north = state.getValue(ForceFieldBlock.NORTH); + boolean south = state.getValue(ForceFieldBlock.SOUTH); + boolean west = state.getValue(ForceFieldBlock.WEST); + boolean east = state.getValue(ForceFieldBlock.EAST); + + if (down) { + directions.add(ExtraDirection.DOWN); + if (north && ForceFieldBlock.cornerConnects(level, pos, Direction.DOWN, Direction.NORTH)) directions.add(ExtraDirection.DOWN_NORTH); + if (south && ForceFieldBlock.cornerConnects(level, pos, Direction.DOWN, Direction.SOUTH)) directions.add(ExtraDirection.DOWN_SOUTH); + if (west && ForceFieldBlock.cornerConnects(level, pos, Direction.DOWN, Direction.WEST)) directions.add(ExtraDirection.DOWN_WEST); + if (east && ForceFieldBlock.cornerConnects(level, pos, Direction.DOWN, Direction.EAST)) directions.add(ExtraDirection.DOWN_EAST); + } + if (up) { + directions.add(ExtraDirection.UP); + if (north && ForceFieldBlock.cornerConnects(level, pos, Direction.UP, Direction.NORTH)) directions.add(ExtraDirection.UP_NORTH); + if (south && ForceFieldBlock.cornerConnects(level, pos, Direction.UP, Direction.SOUTH)) directions.add(ExtraDirection.UP_SOUTH); + if (west && ForceFieldBlock.cornerConnects(level, pos, Direction.UP, Direction.WEST)) directions.add(ExtraDirection.UP_WEST); + if (east && ForceFieldBlock.cornerConnects(level, pos, Direction.UP, Direction.EAST)) directions.add(ExtraDirection.UP_EAST); + } + if (north) { + directions.add(ExtraDirection.NORTH); + if (west && ForceFieldBlock.cornerConnects(level, pos, Direction.NORTH, Direction.WEST)) directions.add(ExtraDirection.NORTH_WEST); + if (east && ForceFieldBlock.cornerConnects(level, pos, Direction.NORTH, Direction.EAST)) directions.add(ExtraDirection.NORTH_EAST); + } + if (south) { + directions.add(ExtraDirection.SOUTH); + if (west && ForceFieldBlock.cornerConnects(level, pos, Direction.SOUTH, Direction.WEST)) directions.add(ExtraDirection.SOUTH_WEST); + if (east && ForceFieldBlock.cornerConnects(level, pos, Direction.SOUTH, Direction.EAST)) directions.add(ExtraDirection.SOUTH_EAST); + } + if (west) directions.add(ExtraDirection.WEST); + if (east) directions.add(ExtraDirection.EAST); + + return directions; + } + + public enum ExtraDirection implements StringRepresentable { + DOWN("down", 0, 1, 0), + UP("up", 1, 0, 1), + NORTH("north", 2, 2, 3), + SOUTH("south", 3, 3, 2), + WEST("west", 5, 4, 4), + EAST("east", 4, 5, 5), + + DOWN_NORTH("down_north", 6, 10, 7), + DOWN_SOUTH("down_south", 7, 11, 6), + DOWN_WEST("down_west", 9, 12, 8), + DOWN_EAST("down_east", 8, 13, 9), + + UP_NORTH("up_north", 10, 6, 11), + UP_SOUTH("up_south", 11, 7, 10), + UP_WEST("up_west", 13, 8, 12), + UP_EAST("up_east", 12, 9, 13), + + NORTH_WEST("north_west", 15, 14, 16), + NORTH_EAST("north_east", 14, 15, 17), + SOUTH_WEST("south_west", 17, 16, 14), + SOUTH_EAST("south_east", 16, 17, 15); + + public static final EnumCodec CODEC = StringRepresentable.fromEnum(ExtraDirection::values); + private final String name; + private final int xAxisMirror; + private final int yAxisMirror; + private final int zAxisMirror; + + ExtraDirection(String name, int xAxisMirror, int yAxisMirror, int zAxisMirror) { + this.name = name; + this.xAxisMirror = xAxisMirror; + this.yAxisMirror = yAxisMirror; + this.zAxisMirror = zAxisMirror; + } + + @Override + public String getSerializedName() { + return this.name; + } + + public ExtraDirection mirrored(Direction.Axis axis) { + return switch (axis) { + case X -> ExtraDirection.values()[this.xAxisMirror]; + case Y -> ExtraDirection.values()[this.yAxisMirror]; + case Z -> ExtraDirection.values()[this.zAxisMirror]; + }; + } + + @Nullable + public static ExtraDirection byName(String name) { + return CODEC.byName(name); + } + } + + //modeldata holder + public record ForceFieldData(Map> directions) { + } +} diff --git a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java new file mode 100644 index 0000000000..02b1d5a494 --- /dev/null +++ b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java @@ -0,0 +1,390 @@ +package twilightforest.client.model.block.forcefield; + +import com.google.common.base.Preconditions; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.mojang.datafixers.util.Pair; +import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; +import net.minecraft.core.Direction; +import net.minecraft.resources.Identifier; +import net.minecraft.util.Mth; +import net.neoforged.neoforge.client.model.generators.template.CustomLoaderBuilder; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; +import twilightforest.TwilightForestMod; +import twilightforest.client.model.block.forcefield.ForceFieldModel.ExtraDirection; + +import java.util.*; +import java.util.function.BiConsumer; + +public class ForceFieldModelBuilder extends CustomLoaderBuilder { + + private boolean defaultShade = true; + private int brightnessOverride = 0; + private int tint = -1; + protected List elements = new ArrayList<>(); + + public static ForceFieldModelBuilder begin() { + return new ForceFieldModelBuilder(); + } + + private ForceFieldModelBuilder self() { + return this; + } + + public ForceFieldModelBuilder() { + super(TwilightForestMod.prefix("force_field"), false); + } + + public ForceFieldElementBuilder forceFieldElement() { + ForceFieldElementBuilder ret = new ForceFieldElementBuilder(this.defaultShade, this.brightnessOverride, this.tint); + this.elements.add(ret); + return ret; + } + + public ForceFieldModelBuilder brightnessOverride(int light) { + this.brightnessOverride = light; + return this; + } + + public ForceFieldModelBuilder disableShade() { + this.defaultShade = false; + return this; + } + + public ForceFieldModelBuilder tintAll(int index) { + this.tint = index; + return this; + } + + @Override + protected CustomLoaderBuilder copyInternal() { + ForceFieldModelBuilder builder = new ForceFieldModelBuilder(); + builder.elements = this.elements; + builder.defaultShade = this.defaultShade; + builder.brightnessOverride = this.brightnessOverride; + builder.tint = this.tint; + return builder; + } + + @Override + public JsonObject toJson(JsonObject json) { + json = super.toJson(json); + if (!this.elements.isEmpty()) { + JsonArray elementsArray = new JsonArray(); + this.elements.forEach(forceFieldElementBuilder -> { + JsonObject partObj = new JsonObject(); + + if (forceFieldElementBuilder.condition != null) { + JsonObject condition = new JsonObject(); + condition.addProperty("if", forceFieldElementBuilder.condition.getSecond()); + condition.addProperty("direction", forceFieldElementBuilder.condition.getFirst().getSerializedName()); + + JsonArray parents = new JsonArray(); + for (ExtraDirection parent : forceFieldElementBuilder.parents) { + parents.add(parent.getSerializedName()); + } + condition.add("parents", parents); + + partObj.add("condition", condition); + } + + partObj.add("from", serializeVector3f(forceFieldElementBuilder.from)); + partObj.add("to", serializeVector3f(forceFieldElementBuilder.to)); + + if (forceFieldElementBuilder.rotation != null) { + JsonObject rotation = new JsonObject(); + rotation.add("origin", serializeVector3f(forceFieldElementBuilder.rotation.origin)); + rotation.addProperty("axis", forceFieldElementBuilder.rotation.axis.getSerializedName()); + rotation.addProperty("angle", forceFieldElementBuilder.rotation.angle); + if (forceFieldElementBuilder.rotation.rescale) { + rotation.addProperty("rescale", true); + } + partObj.add("rotation", rotation); + } + + if (!forceFieldElementBuilder.shade) { + partObj.addProperty("shade", forceFieldElementBuilder.shade); + } + + if (forceFieldElementBuilder.light != 0) { + partObj.addProperty("light", forceFieldElementBuilder.light); + } + + JsonObject facesObj = new JsonObject(); + + for (net.minecraft.core.Direction dir : net.minecraft.core.Direction.values()) { + var faceBuilder = forceFieldElementBuilder.faces.get(dir); + if (faceBuilder == null) continue; + + JsonObject faceObj = new JsonObject(); + + faceObj.addProperty("texture", serializeLocOrKey(faceBuilder.texture)); + + if (faceBuilder.uvs != null) { + faceObj.add("uvs", new Gson().toJsonTree(faceBuilder.uvs)); + } + + if (faceBuilder.cullface != null) { + faceObj.addProperty("cullface", faceBuilder.cullface.getSerializedName()); + } + + if (faceBuilder.rotation.rotation != 0) { + faceObj.addProperty("rotation", faceBuilder.rotation.rotation); + } + + if (faceBuilder.tintindex != -1) { + faceObj.addProperty("tintindex", faceBuilder.tintindex); + } + + facesObj.add(dir.getSerializedName(), faceObj); + } + + if (!forceFieldElementBuilder.faces.isEmpty()) { + partObj.add("faces", facesObj); + } + elementsArray.add(partObj); + }); + json.add("elements", elementsArray); + } + return json; + } + + private static String serializeLocOrKey(String tex) { + if (tex.charAt(0) == '#') { + return tex; + } + return Identifier.parse(tex).toString(); + } + + private static JsonArray serializeVector3f(Vector3f vec) { + JsonArray ret = new JsonArray(); + ret.add(serializeFloat(vec.x())); + ret.add(serializeFloat(vec.y())); + ret.add(serializeFloat(vec.z())); + return ret; + } + + private static Number serializeFloat(float f) { + if ((int) f == f) return (int) f; + return f; + } + + + /** + * Forge copy of ElementBuilder, with some things changed + */ + public class ForceFieldElementBuilder { + private Vector3f from = new Vector3f(); + private Vector3f to = new Vector3f(16, 16, 16); + private final Map faces = new LinkedHashMap<>(); + @Nullable + private ForceFieldElementBuilder.RotationBuilder rotation; + private boolean shade; + private int light; + private int tint; + @Nullable + private Pair condition = null; + private final List parents = new ArrayList<>(); + + private ForceFieldElementBuilder(boolean defaultShade, int brightnessOverride, int tint) { + this.shade = defaultShade; + this.light = brightnessOverride; + this.tint = tint; + } + + private static void validateCoordinate(float coord, char name) { + Preconditions.checkArgument(!(coord < -16.0F) && !(coord > 32.0F), "Position " + name + " out of range, must be within [-16, 32]. Found: %d", coord); + } + + private static void validatePosition(Vector3f pos) { + validateCoordinate(pos.x(), 'x'); + validateCoordinate(pos.y(), 'y'); + validateCoordinate(pos.z(), 'z'); + } + + public ForceFieldElementBuilder from(float x, float y, float z) { + this.from = new Vector3f(x, y, z); + validatePosition(this.from); + return this; + } + + public ForceFieldElementBuilder to(float x, float y, float z) { + this.to = new Vector3f(x, y, z); + validatePosition(this.to); + return this; + } + + public ForceFieldElementBuilder.FaceBuilder face(Direction dir) { + Preconditions.checkNotNull(dir, "Direction must not be null"); + return this.faces.computeIfAbsent(dir, direction -> new FaceBuilder(this.tint)); + } + + public ForceFieldElementBuilder.RotationBuilder rotation() { + if (this.rotation == null) { + this.rotation = new ForceFieldElementBuilder.RotationBuilder(); + } + return this.rotation; + } + + public ForceFieldElementBuilder shade(boolean shade) { + this.shade = shade; + return this; + } + + public ForceFieldElementBuilder allFaces(BiConsumer action) { + Arrays.stream(Direction.values()).forEach(d -> action.accept(d, this.face(d))); + return this; + } + + public ForceFieldElementBuilder faces(BiConsumer action) { + this.faces.forEach(action); + return this; + } + + public ForceFieldElementBuilder textureAll(String texture) { + return this.allFaces(this.addTexture(texture)); + } + + public ForceFieldElementBuilder texture(String texture) { + return this.faces(this.addTexture(texture)); + } + + public ForceFieldElementBuilder cube(String texture) { + return this.allFaces(this.addTexture(texture).andThen((dir, f) -> f.cullface(dir))); + } + + public ForceFieldElementBuilder emissivity(int light) { + this.light = light; + return this; + } + + public ForceFieldElementBuilder ifState(ExtraDirection condition, boolean b) { + this.condition = Pair.of(condition, b); + return this; + } + + // Returns a new ForceFieldElementBuilder that has the same condition + public ForceFieldElementBuilder ifSame() { + ForceFieldElementBuilder newBuilder = this.end().forceFieldElement(); + newBuilder.condition = Pair.of(this.condition.getFirst(), this.condition.getSecond()); + return newBuilder; + } + + // Returns a new ForceFieldElementBuilder that has the opposite condition + public ForceFieldElementBuilder ifElse() { + ForceFieldElementBuilder newBuilder = this.end().forceFieldElement(); + newBuilder.condition = Pair.of(this.condition.getFirst(), !this.condition.getSecond()); + return newBuilder; + } + + public ForceFieldElementBuilder parents(ExtraDirection... parents) { + Collections.addAll(this.parents, parents); + return this; + } + + private BiConsumer addTexture(String texture) { + return (direction, builder) -> builder.texture(texture); + } + + public ForceFieldModelBuilder end() { + return self(); + } + + public class FaceBuilder { + @Nullable + private Direction cullface; + private int tintindex; + @Nullable + private String texture = MissingTextureAtlasSprite.getLocation().toString(); + private float@Nullable[] uvs; + private FaceRotation rotation = FaceRotation.ZERO; + + FaceBuilder(int tint) { + this.tintindex = tint; + } + + public ForceFieldElementBuilder.FaceBuilder cullface(@Nullable Direction dir) { + this.cullface = dir; + return this; + } + + public ForceFieldElementBuilder.FaceBuilder tintindex(int index) { + this.tintindex = index; + return this; + } + + public ForceFieldElementBuilder.FaceBuilder texture(String texture) { + Preconditions.checkNotNull(texture, "Texture must not be null"); + this.texture = texture; + return this; + } + + public ForceFieldElementBuilder.FaceBuilder uvs(float u1, float v1, float u2, float v2) { + this.uvs = new float[]{u1, v1, u2, v2}; + return this; + } + + public ForceFieldElementBuilder.FaceBuilder rotation(FaceRotation rot) { + Preconditions.checkNotNull(rot, "Rotation must not be null"); + this.rotation = rot; + return this; + } + + public ForceFieldElementBuilder end() { + return ForceFieldElementBuilder.this; + } + } + + public class RotationBuilder { + + @Nullable + private Vector3f origin; + @Nullable + private Direction.Axis axis; + private float angle; + private boolean rescale; + + public ForceFieldElementBuilder.RotationBuilder origin(float x, float y, float z) { + this.origin = new Vector3f(x, y, z); + return this; + } + + public ForceFieldElementBuilder.RotationBuilder axis(Direction.Axis axis) { + Preconditions.checkNotNull(axis, "Axis must not be null"); + this.axis = axis; + return this; + } + + public ForceFieldElementBuilder.RotationBuilder angle(float angle) { + // Same logic from BlockPart.Deserializer#parseAngle + Preconditions.checkArgument(angle == 0.0F || Mth.abs(angle) == 22.5F || Mth.abs(angle) == 45.0F, "Invalid rotation %f found, only -45/-22.5/0/22.5/45 allowed", angle); + this.angle = angle; + return this; + } + + public ForceFieldElementBuilder.RotationBuilder rescale(boolean rescale) { + this.rescale = rescale; + return this; + } + + public ForceFieldElementBuilder end() { + return ForceFieldElementBuilder.this; + } + } + } + + public enum FaceRotation { + ZERO(0), + CLOCKWISE_90(90), + UPSIDE_DOWN(180), + COUNTERCLOCKWISE_90(270); + + final int rotation; + + FaceRotation(int rotation) { + this.rotation = rotation; + } + } +} diff --git a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java new file mode 100644 index 0000000000..ee251fb99f --- /dev/null +++ b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java @@ -0,0 +1,57 @@ +package twilightforest.client.model.block.forcefield; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import net.minecraft.util.GsonHelper; +import net.neoforged.neoforge.client.model.StandardModelParameters; +import net.neoforged.neoforge.client.model.UnbakedModelLoader; +import org.jetbrains.annotations.Nullable; +import twilightforest.client.model.block.forcefield.ForceFieldModel.ExtraDirection; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ForceFieldModelLoader implements UnbakedModelLoader { + public static final ForceFieldModelLoader INSTANCE = new ForceFieldModelLoader(); + + @Override + @SuppressWarnings("ConstantConditions") + public UnbakedForceFieldModel read(JsonObject json, JsonDeserializationContext context) throws JsonParseException { + + Map elementsAndConditions = new HashMap<>(); + + if (json.has("elements")) { + int elementIndex = 0; + for (JsonElement jsonElement : GsonHelper.getAsJsonArray(json, "elements")) { + ExtraDirection direction = null; + boolean b = false; + List parents = new ArrayList<>(); + + if (jsonElement instanceof JsonObject element) { + if (element.get("condition") instanceof JsonObject condition) { + direction = ForceFieldModel.ExtraDirection.byName(GsonHelper.getAsString(condition, "direction", "up")); + b = GsonHelper.getAsBoolean(condition, "if", true); + for (JsonElement parentElement : GsonHelper.getAsJsonArray(condition, "parents")) { + parents.add(ForceFieldModel.ExtraDirection.byName(parentElement.getAsString())); + } + } + + String elementName = element.has("name") ? GsonHelper.getAsString(element, "name") : "element_" + elementIndex; + + elementsAndConditions.put(elementName, new Condition(direction, b, parents)); + elementIndex++; + } + } + } + + return new UnbakedForceFieldModel(elementsAndConditions, StandardModelParameters.parse(json, context)); + } + + public record Condition(@Nullable ExtraDirection direction, boolean b, List parents) { + + } +} diff --git a/src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java b/src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java new file mode 100644 index 0000000000..2bbf4cb784 --- /dev/null +++ b/src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java @@ -0,0 +1,31 @@ +package twilightforest.client.model.block.forcefield; + +import net.minecraft.client.renderer.rendertype.RenderTypes; +import net.minecraft.client.resources.model.cuboid.ItemTransforms; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.neoforged.neoforge.client.model.AbstractUnbakedModel; +import net.neoforged.neoforge.client.model.StandardModelParameters; + +import java.util.Map; + +public class UnbakedForceFieldModel extends AbstractUnbakedModel { + + private final Map elementsAndConditions; + + public UnbakedForceFieldModel(Map elementsAndConditions, StandardModelParameters parameters) { + super(parameters); + this.elementsAndConditions = elementsAndConditions; + } + + @Override + public UnbakedGeometry geometry() { + return new ForceFieldModel( + this.elementsAndConditions, + (String textureKey) -> textureKey, + Boolean.TRUE.equals(this.parameters.ambientOcclusion()), + this.parameters.guiLight().lightLikeBlock(), + ItemTransforms.NO_TRANSFORMS, + java.util.Set.of(RenderTypes.translucentMovingBlock()) + ); + } +} diff --git a/src/main/java/twilightforest/client/model/block/patch/PatchBuilder.java b/src/main/java/twilightforest/client/model/block/patch/PatchBuilder.java new file mode 100644 index 0000000000..c60e278071 --- /dev/null +++ b/src/main/java/twilightforest/client/model/block/patch/PatchBuilder.java @@ -0,0 +1,35 @@ +package twilightforest.client.model.block.patch; + +import com.google.gson.JsonObject; +import net.neoforged.neoforge.client.model.generators.template.CustomLoaderBuilder; +import twilightforest.TwilightForestMod; + +public class PatchBuilder extends CustomLoaderBuilder { + + private boolean shaggify = false; + + public PatchBuilder() { + super(TwilightForestMod.prefix("patch"), false); + } + + public PatchBuilder shaggify() { + this.shaggify = true; + return this; + } + + @Override + protected CustomLoaderBuilder copyInternal() { + PatchBuilder builder = new PatchBuilder(); + builder.shaggify = this.shaggify; + return builder; + } + + @Override + public JsonObject toJson(JsonObject json) { + JsonObject mainJson = super.toJson(json); + + mainJson.addProperty("shaggify", this.shaggify); + + return mainJson; + } +} diff --git a/src/main/java/twilightforest/client/model/block/patch/PatchModel.java b/src/main/java/twilightforest/client/model/block/patch/PatchModel.java new file mode 100644 index 0000000000..4681e968ba --- /dev/null +++ b/src/main/java/twilightforest/client/model/block/patch/PatchModel.java @@ -0,0 +1,198 @@ +package twilightforest.client.model.block.patch; + +import com.google.common.collect.ImmutableList; +import net.minecraft.client.renderer.block.dispatch.ModelState; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.ModelBaker; +import net.minecraft.client.resources.model.ModelDebugName; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.geometry.QuadCollection; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.resources.model.sprite.TextureSlots; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.neoforged.neoforge.client.model.quad.MutableQuad; +import twilightforest.block.PatchBlock; + +import java.util.ArrayList; +import java.util.List; + +public class PatchModel implements UnbakedGeometry { + + private final boolean shaggify; + + private TextureAtlasSprite texture; + private boolean usesAO; + private boolean usesBlockLight; + + public PatchModel(boolean shaggify) { + this.shaggify = shaggify; + } + + public PatchModel(TextureAtlasSprite texture, boolean shaggify, boolean usesAO, boolean usesBlockLight) { + this.texture = texture; + this.shaggify = shaggify; + this.usesAO = usesAO; + this.usesBlockLight = usesBlockLight; + } + + private List getQuads(boolean north, boolean east, boolean south, boolean west, RandomSource posRandom) { + List list = new ArrayList<>(); + + BoundingBox bb = PatchBlock.AABBFromRandom(posRandom); + + this.quadsFromAABB(list, west ? 0 : bb.minX(), bb.minY(), north ? 0 : bb.minZ(), east ? 16 : bb.maxX(), bb.maxY(), south ? 16 : bb.maxZ()); + + if (!this.shaggify) + return ImmutableList.copyOf(list); + + // Poll these seeds before entering branching code, otherwise placing neighbors will cause odd changes + long westSeed = posRandom.nextLong(); + long eastSeed = posRandom.nextLong(); + long northSeed = posRandom.nextLong(); + long southSeed = posRandom.nextLong(); + + int minY = bb.minY(); + int maxY = bb.maxY(); + + // add on shaggy edges + if (!west) { + long seed = westSeed; + seed = seed * seed * 42317861L + seed * 7L; + + int num0 = (int) (seed >> 12 & 3L) + 1; + int num1 = (int) (seed >> 15 & 3L) + 1; + int num2 = (int) (seed >> 18 & 3L) + 1; + int num3 = (int) (seed >> 21 & 3L) + 1; + + int minZ = bb.minZ() + num0; + int maxZ = bb.maxZ(); + + if (maxZ - ((num1 + num2 + num3)) > minZ) { + // draw two blobs + int innerZ = bb.maxZ() - num2; + this.quadsFromAABB(list, bb.minX() - 1, minY, minZ, bb.minX(), maxY, minZ + num1); + this.quadsFromAABB(list, bb.minX() - 1, minY, innerZ - num3, bb.minX(), maxY, innerZ); + } else { + //draw one blob + this.quadsFromAABB(list, bb.minX() - 1, minY, minZ, bb.minX(), maxY, maxZ - num2); + } + } + + if (!east) { + long seed = eastSeed; + seed = seed * seed * 42317861L + seed * 17L; + + int num0 = (int) (seed >> 12 & 3L) + 1; + int num1 = (int) (seed >> 15 & 3L) + 1; + int num2 = (int) (seed >> 18 & 3L) + 1; + int num3 = (int) (seed >> 21 & 3L) + 1; + + int minZ = bb.minZ() + num0; + int maxZ = bb.maxZ(); + + if (maxZ - ((num1 + num2 + num3)) > minZ) { + // draw two blobs + int innerZ = maxZ - num2; + this.quadsFromAABB(list, bb.maxX(), minY, minZ, bb.maxX() + 1, maxY, minZ + num1); + this.quadsFromAABB(list, bb.maxX(), minY, innerZ - num3, bb.maxX() + 1, maxY, innerZ); + } else { + //draw one blob + this.quadsFromAABB(list, bb.maxX(), minY, minZ, bb.maxX() + 1, maxY, maxZ - num2); + } + } + + if (!north) { + long seed = northSeed; + seed = seed * seed * 42317861L + seed * 23L; + + int num0 = (int) (seed >> 12 & 3L) + 1; + int num1 = (int) (seed >> 15 & 3L) + 1; + int num2 = (int) (seed >> 18 & 3L) + 1; + int num3 = (int) (seed >> 21 & 3L) + 1; + + int minX = bb.minX() + num0; + int innerX = minX + num1; + int maxX = bb.maxX() - num2; + + this.quadsFromAABB(list, minX, minY, bb.minZ() - 1, innerX, maxY, bb.minZ()); + this.quadsFromAABB(list, maxX - num3, minY, bb.minZ() - 1, maxX, maxY, bb.minZ()); + } + + if (!south) { + long seed = southSeed; + seed = seed * seed * 42317861L + seed * 11L; + + int num0 = (int) (seed >> 12 & 3L) + 1; + int num1 = (int) (seed >> 15 & 3L) + 1; + int num2 = (int) (seed >> 18 & 3L) + 1; + int num3 = (int) (seed >> 21 & 3L) + 1; + + int minX = bb.minX() + num0; + int maxX = bb.maxX() - num2; + + this.quadsFromAABB(list, minX, minY, bb.maxZ(), minX + num1, maxY, bb.maxZ() + 1); + this.quadsFromAABB(list, maxX - num3, minY, bb.maxZ(), maxX, maxY, bb.maxZ() + 1); + } + + return ImmutableList.copyOf(list); + } + + private void quadsFromAABB(List quads, float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { + quads.add(this.quadFromVectors(Direction.UP, minX, minY, minZ, maxX, maxY, maxZ)); + quads.add(this.quadFromVectors(Direction.NORTH, minX, minY, minZ, maxX, maxY, maxZ)); + quads.add(this.quadFromVectors(Direction.EAST, minX, minY, minZ, maxX, maxY, maxZ)); + quads.add(this.quadFromVectors(Direction.SOUTH, minX, minY, minZ, maxX, maxY, maxZ)); + quads.add(this.quadFromVectors(Direction.WEST, minX, minY, minZ, maxX, maxY, maxZ)); + quads.add(this.quadFromVectors(Direction.DOWN, minX, minY, minZ, maxX, maxY, maxZ)); + } + + private BakedQuad quadFromVectors(Direction direction, float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { + MutableQuad mutableQuad = new MutableQuad(); + + mutableQuad.setDirection(direction); + mutableQuad.setShade(this.usesAO); + + if (this.usesBlockLight) { + mutableQuad.setLightEmission(15); + } + + for (int v = 0; v < 4; v++) { + float x = (v == 1 || v == 2) ? maxX / 16.0f : minX / 16.0f; + float y = (v == 2 || v == 3) ? maxY / 16.0f : minY / 16.0f; + float z = (direction.getAxis() == net.minecraft.core.Direction.Axis.Z) ? maxZ / 16.0f : minZ / 16.0f; + + mutableQuad.setPosition(v, new org.joml.Vector3f(x, y, z)); + + float u = this.texture.getU(x * 16.0f); + float vCoord = this.texture.getV(y * 16.0f); + + if (direction == net.minecraft.core.Direction.EAST || direction == net.minecraft.core.Direction.WEST) { + mutableQuad.setUv(v, vCoord, u); + } else { + mutableQuad.setUv(v, u, vCoord); + } + } + + return mutableQuad.toBakedQuad(); + } + + @Override + public QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName modelDebugName) { + QuadCollection.Builder builder = new QuadCollection.Builder(); + + RandomSource staticRandom = RandomSource.create(42L); + List myPatchQuads = this.getQuads(false, false, false, false, staticRandom); + + for (BakedQuad quad : myPatchQuads) { + if (quad.direction() != null) { + builder.addCulledFace(quad.direction(), quad); + } else { + builder.addUnculledFace(quad); + } + } + + return builder.build(); + } +} diff --git a/src/main/java/twilightforest/client/model/block/patch/PatchModelLoader.java b/src/main/java/twilightforest/client/model/block/patch/PatchModelLoader.java new file mode 100644 index 0000000000..4599a7d9e5 --- /dev/null +++ b/src/main/java/twilightforest/client/model/block/patch/PatchModelLoader.java @@ -0,0 +1,23 @@ +package twilightforest.client.model.block.patch; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.mojang.realmsclient.util.JsonUtils; +import net.neoforged.neoforge.client.model.StandardModelParameters; +import net.neoforged.neoforge.client.model.UnbakedModelLoader; + +public final class PatchModelLoader implements UnbakedModelLoader { + public static final PatchModelLoader INSTANCE = new PatchModelLoader(); + + private PatchModelLoader() { + } + + @Override + public UnbakedPatchModel read(JsonObject object, JsonDeserializationContext deserializationContext) throws JsonParseException { +// if (!object.has("texture")) +// throw new JsonParseException("Patch model missing value for 'texture'."); + + return new UnbakedPatchModel(JsonUtils.getBooleanOr("shaggify", object, false), StandardModelParameters.parse(object, deserializationContext)); + } +} diff --git a/src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java b/src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java new file mode 100644 index 0000000000..ff875d6fb8 --- /dev/null +++ b/src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java @@ -0,0 +1,20 @@ +package twilightforest.client.model.block.patch; + +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.neoforged.neoforge.client.model.AbstractUnbakedModel; +import net.neoforged.neoforge.client.model.StandardModelParameters; + +public class UnbakedPatchModel extends AbstractUnbakedModel { + + private final boolean shaggify; + + public UnbakedPatchModel(boolean shaggify, StandardModelParameters parameters) { + super(parameters); + this.shaggify = shaggify; + } + + @Override + public UnbakedGeometry geometry() { + return new PatchModel(this.shaggify); + } +} diff --git a/src/main/java/twilightforest/init/TFBlockEntities.java b/src/main/java/twilightforest/init/TFBlockEntities.java new file mode 100644 index 0000000000..be58af63ee --- /dev/null +++ b/src/main/java/twilightforest/init/TFBlockEntities.java @@ -0,0 +1,148 @@ +package twilightforest.init; + +import net.minecraft.core.registries.Registries; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; +import twilightforest.TwilightForestMod; +import twilightforest.block.entity.*; +import twilightforest.block.entity.bookshelf.ChiseledCanopyShelfBlockEntity; +import twilightforest.block.entity.spawner.*; + +@SuppressWarnings("DataFlowIssue") +public class TFBlockEntities { + + public static final DeferredRegister> BLOCK_ENTITIES = DeferredRegister.create(Registries.BLOCK_ENTITY_TYPE, TwilightForestMod.ID); + + public static final DeferredHolder, BlockEntityType> ANTIBUILDER = BLOCK_ENTITIES.register("antibuilder", () -> + new BlockEntityType<>(AntibuilderBlockEntity::new, TFBlocks.ANTIBUILDER.get())); + public static final DeferredHolder, BlockEntityType> CINDER_FURNACE = BLOCK_ENTITIES.register("cinder_furnace", () -> + new BlockEntityType<>(CinderFurnaceBlockEntity::new, TFBlocks.CINDER_FURNACE.get())); + public static final DeferredHolder, BlockEntityType> CARMINITE_REACTOR = BLOCK_ENTITIES.register("carminite_reactor", () -> + new BlockEntityType<>(CarminiteReactorBlockEntity::new, TFBlocks.CARMINITE_REACTOR.get())); + public static final DeferredHolder, BlockEntityType> REACTOR_DEBRIS = BLOCK_ENTITIES.register("reactor_debris", () -> + new BlockEntityType<>(ReactorDebrisBlockEntity::new, TFBlocks.REACTOR_DEBRIS.get())); + public static final DeferredHolder, BlockEntityType> FLAME_JET = BLOCK_ENTITIES.register("flame_jet", () -> + new BlockEntityType<>(FireJetBlockEntity::new, TFBlocks.FIRE_JET.get(), TFBlocks.ENCASED_FIRE_JET.get())); + public static final DeferredHolder, BlockEntityType> GHAST_TRAP = BLOCK_ENTITIES.register("ghast_trap", () -> + new BlockEntityType<>(GhastTrapBlockEntity::new, TFBlocks.GHAST_TRAP.get())); + public static final DeferredHolder, BlockEntityType> SMOKER = BLOCK_ENTITIES.register("smoker", () -> + new BlockEntityType<>(TFSmokerBlockEntity::new, TFBlocks.SMOKER.get(), TFBlocks.ENCASED_SMOKER.get())); + public static final DeferredHolder, BlockEntityType> TOWER_BUILDER = BLOCK_ENTITIES.register("tower_builder", () -> + new BlockEntityType<>(CarminiteBuilderBlockEntity::new, TFBlocks.CARMINITE_BUILDER.get())); + public static final DeferredHolder, BlockEntityType> TROPHY = BLOCK_ENTITIES.register("trophy", () -> + new BlockEntityType<>(TrophyBlockEntity::new, TFBlocks.NAGA_TROPHY.get(), TFBlocks.LICH_TROPHY.get(), TFBlocks.MINOSHROOM_TROPHY.get(), + TFBlocks.HYDRA_TROPHY.get(), TFBlocks.KNIGHT_PHANTOM_TROPHY.get(), TFBlocks.UR_GHAST_TROPHY.get(), TFBlocks.ALPHA_YETI_TROPHY.get(), + TFBlocks.SNOW_QUEEN_TROPHY.get(), TFBlocks.QUEST_RAM_TROPHY.get(), TFBlocks.NAGA_WALL_TROPHY.get(), TFBlocks.LICH_WALL_TROPHY.get(), + TFBlocks.MINOSHROOM_WALL_TROPHY.get(), TFBlocks.HYDRA_WALL_TROPHY.get(), TFBlocks.KNIGHT_PHANTOM_WALL_TROPHY.get(), TFBlocks.UR_GHAST_WALL_TROPHY.get(), + TFBlocks.ALPHA_YETI_WALL_TROPHY.get(), TFBlocks.SNOW_QUEEN_WALL_TROPHY.get(), TFBlocks.QUEST_RAM_WALL_TROPHY.get())); + public static final DeferredHolder, BlockEntityType> ALPHA_YETI_SPAWNER = BLOCK_ENTITIES.register("alpha_yeti_spawner", () -> + new BlockEntityType<>(AlphaYetiSpawnerBlockEntity::new, TFBlocks.ALPHA_YETI_BOSS_SPAWNER.get())); + public static final DeferredHolder, BlockEntityType> FINAL_BOSS_SPAWNER = BLOCK_ENTITIES.register("final_boss_spawner", () -> + new BlockEntityType<>(FinalBossSpawnerBlockEntity::new, TFBlocks.FINAL_BOSS_BOSS_SPAWNER.get())); + public static final DeferredHolder, BlockEntityType> HYDRA_SPAWNER = BLOCK_ENTITIES.register("hydra_boss_spawner", () -> + new BlockEntityType<>(HydraSpawnerBlockEntity::new, TFBlocks.HYDRA_BOSS_SPAWNER.get())); + public static final DeferredHolder, BlockEntityType> KNIGHT_PHANTOM_SPAWNER = BLOCK_ENTITIES.register("knight_phantom_spawner", () -> + new BlockEntityType<>(KnightPhantomSpawnerBlockEntity::new, TFBlocks.KNIGHT_PHANTOM_BOSS_SPAWNER.get())); + public static final DeferredHolder, BlockEntityType> LICH_SPAWNER = BLOCK_ENTITIES.register("lich_spawner", () -> + new BlockEntityType<>(LichSpawnerBlockEntity::new, TFBlocks.LICH_BOSS_SPAWNER.get())); + public static final DeferredHolder, BlockEntityType> MINOSHROOM_SPAWNER = BLOCK_ENTITIES.register("minoshroom_spawner", () -> + new BlockEntityType<>(MinoshroomSpawnerBlockEntity::new, TFBlocks.MINOSHROOM_BOSS_SPAWNER.get())); + public static final DeferredHolder, BlockEntityType> NAGA_SPAWNER = BLOCK_ENTITIES.register("naga_spawner", () -> + new BlockEntityType<>(NagaSpawnerBlockEntity::new, TFBlocks.NAGA_BOSS_SPAWNER.get())); + public static final DeferredHolder, BlockEntityType> SNOW_QUEEN_SPAWNER = BLOCK_ENTITIES.register("snow_queen_spawner", () -> + new BlockEntityType<>(SnowQueenSpawnerBlockEntity::new, TFBlocks.SNOW_QUEEN_BOSS_SPAWNER.get())); + public static final DeferredHolder, BlockEntityType> UR_GHAST_SPAWNER = BLOCK_ENTITIES.register("tower_boss_spawner", () -> + new BlockEntityType<>(UrGhastSpawnerBlockEntity::new, TFBlocks.UR_GHAST_BOSS_SPAWNER.get())); + + public static final DeferredHolder, BlockEntityType> CICADA = BLOCK_ENTITIES.register("cicada", () -> + new BlockEntityType<>(CicadaBlockEntity::new, TFBlocks.CICADA.get())); + public static final DeferredHolder, BlockEntityType> FIREFLY = BLOCK_ENTITIES.register("firefly", () -> + new BlockEntityType<>(FireflyBlockEntity::new, TFBlocks.FIREFLY.get())); + public static final DeferredHolder, BlockEntityType> MOONWORM = BLOCK_ENTITIES.register("moonworm", () -> + new BlockEntityType<>(MoonwormBlockEntity::new, TFBlocks.MOONWORM.get())); + + public static final DeferredHolder, BlockEntityType> SKULL_CHEST = BLOCK_ENTITIES.register("skull_chest", () -> + new BlockEntityType<>(SkullChestBlockEntity::new, TFBlocks.SKULL_CHEST.get())); + public static final DeferredHolder, BlockEntityType> KEEPSAKE_CASKET = BLOCK_ENTITIES.register("keepsake_casket", () -> + new BlockEntityType<>(KeepsakeCasketBlockEntity::new, TFBlocks.KEEPSAKE_CASKET.get())); + public static final DeferredHolder, BlockEntityType> BRAZIER = BLOCK_ENTITIES.register("brazier", () -> + new BlockEntityType<>(BrazierBlockEntity::new, TFBlocks.BRAZIER.get())); + public static final DeferredHolder, BlockEntityType> CORONATION_CARPET = BLOCK_ENTITIES.register("coronation_carpet", () -> + new BlockEntityType<>(CoronationCarpetBlockEntity::new, TFBlocks.CORONATION_CARPET.get())); + + public static final DeferredHolder, BlockEntityType> TF_CHEST = BLOCK_ENTITIES.register("chest", () -> + new BlockEntityType<>(TFChestBlockEntity::new, + TFBlocks.TWILIGHT_OAK_CHEST.get(), TFBlocks.CANOPY_CHEST.get(), TFBlocks.MANGROVE_CHEST.get(), + TFBlocks.DARK_CHEST.get(), TFBlocks.TIME_CHEST.get(), TFBlocks.TRANSFORMATION_CHEST.get(), + TFBlocks.MINING_CHEST.get(), TFBlocks.SORTING_CHEST.get())); + + public static final DeferredHolder, BlockEntityType> TF_TRAPPED_CHEST = BLOCK_ENTITIES.register("trapped_chest", () -> + new BlockEntityType<>(TFTrappedChestBlockEntity::new, + TFBlocks.TWILIGHT_OAK_TRAPPED_CHEST.get(), TFBlocks.CANOPY_TRAPPED_CHEST.get(), TFBlocks.MANGROVE_TRAPPED_CHEST.get(), + TFBlocks.DARK_TRAPPED_CHEST.get(), TFBlocks.TIME_TRAPPED_CHEST.get(), TFBlocks.TRANSFORMATION_TRAPPED_CHEST.get(), + TFBlocks.MINING_TRAPPED_CHEST.get(), TFBlocks.SORTING_TRAPPED_CHEST.get())); + + public static final DeferredHolder, BlockEntityType> SKULL_CANDLE = BLOCK_ENTITIES.register("skull_candle", () -> + new BlockEntityType<>(SkullCandleBlockEntity::new, + TFBlocks.ZOMBIE_SKULL_CANDLE.get(), TFBlocks.ZOMBIE_WALL_SKULL_CANDLE.get(), + TFBlocks.SKELETON_SKULL_CANDLE.get(), TFBlocks.SKELETON_WALL_SKULL_CANDLE.get(), + TFBlocks.WITHER_SKELE_SKULL_CANDLE.get(), TFBlocks.WITHER_SKELE_WALL_SKULL_CANDLE.get(), + TFBlocks.CREEPER_SKULL_CANDLE.get(), TFBlocks.CREEPER_WALL_SKULL_CANDLE.get(), + TFBlocks.PLAYER_SKULL_CANDLE.get(), TFBlocks.PLAYER_WALL_SKULL_CANDLE.get(), + TFBlocks.PIGLIN_SKULL_CANDLE.get(), TFBlocks.PIGLIN_WALL_SKULL_CANDLE.get())); + + public static final DeferredHolder, BlockEntityType> CHISELED_CANOPY_BOOKSHELF = BLOCK_ENTITIES.register("chiseled_canopy_bookshelf", () -> + new BlockEntityType<>(ChiseledCanopyShelfBlockEntity::new, TFBlocks.CHISELED_CANOPY_BOOKSHELF.get())); + + public static final DeferredHolder, BlockEntityType> BEANSTALK_GROWER = BLOCK_ENTITIES.register("beanstalk_grower", () -> + new BlockEntityType<>(GrowingBeanstalkBlockEntity::new, TFBlocks.BEANSTALK_GROWER.get())); + + public static final DeferredHolder, BlockEntityType> RED_THREAD = BLOCK_ENTITIES.register("red_thread", () -> + new BlockEntityType<>(RedThreadBlockEntity::new, TFBlocks.RED_THREAD.get())); + + public static final DeferredHolder, BlockEntityType> CANDELABRA = BLOCK_ENTITIES.register("candelabra", () -> + new BlockEntityType<>(CandelabraBlockEntity::new, TFBlocks.CANDELABRA.get())); + + public static final DeferredHolder, BlockEntityType> JAR = BLOCK_ENTITIES.register("jar", () -> + new BlockEntityType<>(JarBlockEntity::new, TFBlocks.FIREFLY_JAR.get(), TFBlocks.CICADA_JAR.get())); + + public static final DeferredHolder, BlockEntityType> MASON_JAR = BLOCK_ENTITIES.register("mason_jar", () -> + new BlockEntityType<>(MasonJarBlockEntity::new, TFBlocks.MASON_JAR.get())); + + public static final DeferredHolder, BlockEntityType> SINISTER_SPAWNER = BLOCK_ENTITIES.register("sinister_spawner", () -> + new BlockEntityType<>(SinisterSpawnerBlockEntity::new, TFBlocks.SINISTER_SPAWNER.get())); + + public static final DeferredHolder, BlockEntityType> DRYING_RACK = BLOCK_ENTITIES.register("drying_rack", () -> + new BlockEntityType<>(DryingRackBlockEntity::new, + TFBlocks.OAK_DRYING_RACK.get(), TFBlocks.SPRUCE_DRYING_RACK.get(), + TFBlocks.BIRCH_DRYING_RACK.get(), TFBlocks.JUNGLE_DRYING_RACK.get(), + TFBlocks.ACACIA_DRYING_RACK.get(), TFBlocks.DARK_OAK_DRYING_RACK.get(), + TFBlocks.CRIMSON_DRYING_RACK.get(), TFBlocks.WARPED_DRYING_RACK.get(), + TFBlocks.VANGROVE_DRYING_RACK.get(), TFBlocks.BAMBOO_DRYING_RACK.get(), + TFBlocks.CHERRY_DRYING_RACK.get(), TFBlocks.PALE_OAK_DRYING_RACK.get(), + TFBlocks.TWILIGHT_OAK_DRYING_RACK.get(), TFBlocks.CANOPY_DRYING_RACK.get(), + TFBlocks.MANGROVE_DRYING_RACK.get(), TFBlocks.DARK_DRYING_RACK.get(), + TFBlocks.TIME_DRYING_RACK.get(), TFBlocks.TRANSFORMATION_DRYING_RACK.get(), + TFBlocks.MINING_DRYING_RACK.get(), TFBlocks.SORTING_DRYING_RACK.get())); + + public static final DeferredHolder, BlockEntityType> OMINOUS_CANDLE = BLOCK_ENTITIES.register("ominous_candle", () -> + new BlockEntityType<>(OminousCandleBlockEntity::new, + TFBlocks.OMINOUS_CANDLE.get(), + TFBlocks.OMINOUS_WHITE_CANDLE.get(), + TFBlocks.OMINOUS_ORANGE_CANDLE.get(), + TFBlocks.OMINOUS_MAGENTA_CANDLE.get(), + TFBlocks.OMINOUS_LIGHT_BLUE_CANDLE.get(), + TFBlocks.OMINOUS_YELLOW_CANDLE.get(), + TFBlocks.OMINOUS_LIME_CANDLE.get(), + TFBlocks.OMINOUS_PINK_CANDLE.get(), + TFBlocks.OMINOUS_GRAY_CANDLE.get(), + TFBlocks.OMINOUS_LIGHT_GRAY_CANDLE.get(), + TFBlocks.OMINOUS_CYAN_CANDLE.get(), + TFBlocks.OMINOUS_PURPLE_CANDLE.get(), + TFBlocks.OMINOUS_BLUE_CANDLE.get(), + TFBlocks.OMINOUS_BROWN_CANDLE.get(), + TFBlocks.OMINOUS_GREEN_CANDLE.get(), + TFBlocks.OMINOUS_RED_CANDLE.get(), + TFBlocks.OMINOUS_BLACK_CANDLE.get())); +} diff --git a/src/main/java/twilightforest/init/TFBlocks.java b/src/main/java/twilightforest/init/TFBlocks.java new file mode 100644 index 0000000000..e053ba27d6 --- /dev/null +++ b/src/main/java/twilightforest/init/TFBlocks.java @@ -0,0 +1,713 @@ +package twilightforest.init; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.*; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.*; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; +import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; +import net.minecraft.world.level.material.MapColor; +import net.minecraft.world.level.material.PushReaction; +import net.neoforged.neoforge.registries.DeferredBlock; +import net.neoforged.neoforge.registries.DeferredRegister; +import twilightforest.TwilightForestMod; +import twilightforest.block.*; +import twilightforest.enums.BlockLoggingEnum; +import twilightforest.enums.BossVariant; +import twilightforest.enums.FireJetVariant; +import twilightforest.enums.TowerDeviceVariant; +import twilightforest.loot.TFLootTables; +import twilightforest.util.woods.TFWoodTypes; +import twilightforest.world.components.feature.trees.growers.TFTreeGrowers; + +import java.util.function.Function; +import java.util.function.Supplier; + +public class TFBlocks { + public static final DeferredRegister.Blocks BLOCKS = DeferredRegister.createBlocks(TwilightForestMod.ID); + + public static final DeferredBlock TWILIGHT_PORTAL = register("twilight_portal", TFPortalBlock::new, () -> BlockBehaviour.Properties.of().pushReaction(PushReaction.BLOCK).strength(-1.0F).sound(SoundType.GLASS).lightLevel((state) -> 11).noCollision().noOcclusion().noLootTable()); + + //misc. + public static final DeferredBlock HEDGE = registerWithItem("hedge", HedgeBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).sound(SoundType.GRASS).strength(2.0F, 6.0F)); + public static final DeferredBlock MASON_JAR = register("mason_jar", MasonJarBlock::new, () -> BlockBehaviour.Properties.of().noOcclusion().noTerrainParticles().randomTicks().sound(TFSoundTypes.JAR).strength(0.3F, 3.0F)); + public static final DeferredBlock FIREFLY_JAR = register("firefly_jar", FireflyJarBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> 15).noOcclusion().noTerrainParticles().sound(TFSoundTypes.JAR).strength(0.3F, 3.0F)); + public static final DeferredBlock FIREFLY_SPAWNER = registerWithItem("firefly_particle_spawner", FireflySpawnerBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> 15).noOcclusion().noTerrainParticles().sound(TFSoundTypes.JAR).strength(0.3F, 3.0F)); + public static final DeferredBlock CICADA_JAR = register("cicada_jar", CicadaJarBlock::new, () -> BlockBehaviour.Properties.of().noOcclusion().noTerrainParticles().randomTicks().sound(TFSoundTypes.JAR).strength(0.3F, 3.0F)); + public static final DeferredBlock MOSS_PATCH = registerWithItem("moss_patch", MossPatchBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instabreak().mapColor(MapColor.PLANT).noCollision().noOcclusion().pushReaction(PushReaction.DESTROY).sound(SoundType.MOSS)); + public static final DeferredBlock MAYAPPLE = registerWithItem("mayapple", MayappleBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instabreak().mapColor(MapColor.PLANT).noCollision().noOcclusion().pushReaction(PushReaction.DESTROY).sound(SoundType.GRASS)); + public static final DeferredBlock CLOVER_PATCH = registerWithItem("clover_patch", PatchBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().noCollision().noOcclusion().instabreak().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).sound(SoundType.GRASS)); + public static final DeferredBlock FIDDLEHEAD = registerWithItem("fiddlehead", FiddleheadBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instabreak().mapColor(MapColor.PLANT).noCollision().noOcclusion().pushReaction(PushReaction.DESTROY).replaceable().sound(SoundType.GRASS)); + public static final DeferredBlock MUSHGLOOM = registerWithItem("mushgloom", MushgloomBlock::new, () -> BlockBehaviour.Properties.of().instabreak().lightLevel((state) -> 3).noCollision().noOcclusion().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).sound(SoundType.FUNGUS)); + public static final DeferredBlock TORCHBERRY_PLANT = registerWithItem("torchberry_plant", TorchberryPlantBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instabreak().lightLevel(value -> value.getValue(TorchberryPlantBlock.HAS_BERRIES) ? 7 : 1).noCollision().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).sound(SoundType.HANGING_ROOTS)); + public static final DeferredBlock ROOT_STRAND = registerWithItem("root_strand", RootStrandBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instabreak().mapColor(MapColor.PLANT).noCollision().noOcclusion().pushReaction(PushReaction.DESTROY).sound(SoundType.HANGING_ROOTS)); + public static final DeferredBlock FALLEN_LEAVES = register("fallen_leaves", FallenLeavesBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instabreak().mapColor(MapColor.PLANT).noCollision().noOcclusion().replaceable().pushReaction(PushReaction.DESTROY).sound(SoundType.AZALEA_LEAVES)); + public static final DeferredBlock ROOT_BLOCK = registerWithItem("root", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.WOOD).sound(SoundType.WOOD).strength(2.0F, 3.0F)); + public static final DeferredBlock LIVEROOT_BLOCK = registerWithItem("liveroot_block", LiverootBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.COLOR_LIGHT_GREEN).sound(SoundType.WOOD).strength(2.0F, 3.0F)); + public static final DeferredBlock UNCRAFTING_TABLE = registerWithItem("uncrafting_table", UncraftingTableBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.FIRE).sound(SoundType.WOOD).strength(2.5F)); + public static final DeferredBlock SMOKER = registerWithItem("smoker", TFSmokerBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.GRASS).sound(SoundType.GRASS).strength(1.5F, 6.0F)); + public static final DeferredBlock ENCASED_SMOKER = registerWithItem("encased_smoker", EncasedSmokerBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.SAND).requiresCorrectToolForDrops().sound(SoundType.WOOD).strength(1.5F, 6.0F)); + public static final DeferredBlock FIRE_JET = registerWithItem("fire_jet", FireJetBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> state.getValue(FireJetBlock.STATE) != FireJetVariant.FLAME ? 0 : 15).mapColor(MapColor.GRASS).randomTicks().sound(SoundType.GRASS).strength(1.5F, 6.0F)); + public static final DeferredBlock ENCASED_FIRE_JET = registerWithItem("encased_fire_jet", EncasedFireJetBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().lightLevel((state) -> state.getValue(FireJetBlock.STATE) != FireJetVariant.FLAME ? 0 : 15).mapColor(MapColor.SAND).requiresCorrectToolForDrops().sound(SoundType.WOOD).strength(1.5F, 6.0F)); + public static final DeferredBlock FIREFLY = registerWithItem("firefly", FireflyBlock::new, () -> BlockBehaviour.Properties.of().instabreak().lightLevel((state) -> 15).noCollision().noTerrainParticles().pushReaction(PushReaction.DESTROY).sound(SoundType.SLIME_BLOCK)); + public static final DeferredBlock CICADA = registerWithItem("cicada", CicadaBlock::new, () -> BlockBehaviour.Properties.of().instabreak().noCollision().noTerrainParticles().pushReaction(PushReaction.DESTROY).sound(SoundType.SLIME_BLOCK)); + public static final DeferredBlock MOONWORM = registerWithItem("moonworm", MoonwormBlock::new, () -> BlockBehaviour.Properties.of().forceSolidOff().instabreak().lightLevel((state) -> 14).noCollision().noTerrainParticles().pushReaction(PushReaction.DESTROY).sound(SoundType.SLIME_BLOCK)); + public static final DeferredBlock HUGE_LILY_PAD = register("huge_lily_pad", HugeLilyPadBlock::new, () -> BlockBehaviour.Properties.of().instabreak().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).sound(SoundType.LILY_PAD)); + public static final DeferredBlock HUGE_WATER_LILY = register("huge_water_lily", HugeWaterLilyBlock::new, () -> BlockBehaviour.Properties.of().instabreak().mapColor(MapColor.PLANT).noCollision().pushReaction(PushReaction.DESTROY).sound(SoundType.LILY_PAD)); + public static final DeferredBlock SLIDER = registerWithItem("slider", SliderBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.DIRT).noLootTable().noOcclusion().randomTicks().strength(2.0F, 10.0F)); + public static final DeferredBlock IRON_LADDER = registerWithItem("iron_ladder", IronLadderBlock::new, () -> BlockBehaviour.Properties.of().forceSolidOff().noOcclusion().pushReaction(PushReaction.DESTROY).requiresCorrectToolForDrops().sound(SoundType.METAL).strength(5.0F, 6.0F)); + public static final DeferredBlock ROPE = register("rope", RopeBlock::new, () -> BlockBehaviour.Properties.of().forceSolidOff().noOcclusion().pushReaction(PushReaction.DESTROY).sound(SoundType.WOOL).strength(0.3F, 3.0F)); + public static final DeferredBlock CANOPY_WINDOW = registerWithItem("canopy_window", TransparentBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.HAT).strength(0.3F).sound(SoundType.GLASS).noOcclusion().isValidSpawn((pState, pLevel, pPos, pValue) -> false).isRedstoneConductor((pState, pLevel, pPos) -> false).isSuffocating((pState, pLevel, pPos) -> false).isViewBlocking((pState, pLevel, pPos) -> false)); + public static final DeferredBlock CANOPY_WINDOW_PANE = registerWithItem("canopy_window_pane", IronBarsBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.HAT).strength(0.3F).sound(SoundType.GLASS).noOcclusion()); + public static final DeferredBlock SINISTER_SPAWNER = registerWithItem("sinister_spawner", SinisterSpawnerBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.SPAWNER).noLootTable()); + public static final DeferredBlock BRAZIER = registerWithItem("brazier", BrazierBlock::new, () -> BlockBehaviour.Properties.of().sound(SoundType.WOOD).lightLevel(state -> state.getValue(BrazierBlock.HALF) == DoubleBlockHalf.UPPER ? state.getValue(BrazierBlock.LIGHT).getLight() : 0).pushReaction(PushReaction.DESTROY)); + + // bushes + public static final DeferredBlock IRON_OREBERRY_BUSH = registerWithItem("iron_oreberry_bush", properties -> new OreBerryBushBlock(false, TFLootTables.IRON_OREBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.METAL).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); + public static final DeferredBlock GOLD_OREBERRY_BUSH = registerWithItem("gold_oreberry_bush", properties -> new OreBerryBushBlock(false, TFLootTables.GOLD_OREBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.METAL).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); + public static final DeferredBlock COPPER_OREBERRY_BUSH = registerWithItem("copper_oreberry_bush", properties -> new OreBerryBushBlock(false, TFLootTables.COPPER_OREBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.METAL).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); + public static final DeferredBlock ESSENCE_OREBERRY_BUSH = registerWithItem("essence_oreberry_bush", properties -> new OreBerryBushBlock(true, TFLootTables.ESSENCE_BERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.METAL).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); + public static final DeferredBlock RASPBERRY_BUSH = registerWithItem("raspberry_bush", properties -> new BerryBushBlock(TFLootTables.RASPBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.GRASS).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); + public static final DeferredBlock BLUEBERRY_BUSH = registerWithItem("blueberry_bush", properties -> new BerryBushBlock(TFLootTables.BLUEBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.GRASS).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); + public static final DeferredBlock BLACKBERRY_BUSH = registerWithItem("blackberry_bush", properties -> new BerryBushBlock(TFLootTables.BLACKBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.GRASS).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); + public static final DeferredBlock MALOBERRY_BUSH = registerWithItem("maloberry_bush", properties -> new BerryBushBlock(TFLootTables.MALOBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.GRASS).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); + public static final DeferredBlock BLIGHTBERRY_BUSH = registerWithItem("blightberry_bush", properties -> new DarkTowerBerryBushBlock(TFLootTables.BLIGHTBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.GRASS).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); + public static final DeferredBlock DUSKBERRY_BUSH = registerWithItem("duskberry_bush", properties -> new DarkTowerBerryBushBlock(TFLootTables.DUSKBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.GRASS).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); + public static final DeferredBlock SKYBERRY_BUSH = registerWithItem("skyberry_bush", properties -> new DarkTowerBerryBushBlock(TFLootTables.SKYBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.GRASS).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); + public static final DeferredBlock STINGBERRY_BUSH = registerWithItem("stingberry_bush", properties -> new DarkTowerBerryBushBlock(TFLootTables.STINGBERRY_BUSH_DROPS, properties), () -> BlockBehaviour.Properties.of().sound(SoundType.GRASS).destroyTime(0.4F).randomTicks().dynamicShape().noOcclusion()); + + //naga courtyard + public static final DeferredBlock NAGASTONE_HEAD = registerWithItem("nagastone_head", TFHorizontalBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); + public static final DeferredBlock NAGASTONE = registerWithItem("nagastone", NagastoneBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); + public static final DeferredBlock SPIRAL_BRICKS = registerWithItem("spiral_bricks", SpiralBrickBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).noOcclusion().requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); + public static final DeferredBlock ETCHED_NAGASTONE = registerWithItem("etched_nagastone", EtchedNagastoneBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); + public static final DeferredBlock NAGASTONE_PILLAR = registerWithItem("nagastone_pillar", DirectionalRotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); + public static final DeferredBlock NAGASTONE_STAIRS_LEFT = registerWithItem("nagastone_stairs_left", properties -> new StairBlock(ETCHED_NAGASTONE.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(ETCHED_NAGASTONE.get())); + public static final DeferredBlock NAGASTONE_STAIRS_RIGHT = registerWithItem("nagastone_stairs_right", properties -> new StairBlock(ETCHED_NAGASTONE.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(ETCHED_NAGASTONE.get())); + public static final DeferredBlock MOSSY_ETCHED_NAGASTONE = registerWithItem("mossy_etched_nagastone", EtchedNagastoneBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); + public static final DeferredBlock MOSSY_NAGASTONE_PILLAR = registerWithItem("mossy_nagastone_pillar", DirectionalRotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); + public static final DeferredBlock MOSSY_NAGASTONE_STAIRS_LEFT = registerWithItem("mossy_nagastone_stairs_left", properties -> new StairBlock(MOSSY_ETCHED_NAGASTONE.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(MOSSY_ETCHED_NAGASTONE.get())); + public static final DeferredBlock MOSSY_NAGASTONE_STAIRS_RIGHT = registerWithItem("mossy_nagastone_stairs_right", properties -> new StairBlock(MOSSY_ETCHED_NAGASTONE.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(MOSSY_ETCHED_NAGASTONE.get())); + public static final DeferredBlock CRACKED_ETCHED_NAGASTONE = registerWithItem("cracked_etched_nagastone", EtchedNagastoneBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); + public static final DeferredBlock CRACKED_NAGASTONE_PILLAR = registerWithItem("cracked_nagastone_pillar", DirectionalRotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); + public static final DeferredBlock CRACKED_NAGASTONE_STAIRS_LEFT = registerWithItem("cracked_nagastone_stairs_left", properties -> new StairBlock(CRACKED_ETCHED_NAGASTONE.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(CRACKED_ETCHED_NAGASTONE.get())); + public static final DeferredBlock CRACKED_NAGASTONE_STAIRS_RIGHT = registerWithItem("cracked_nagastone_stairs_right", properties -> new StairBlock(CRACKED_ETCHED_NAGASTONE.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(CRACKED_ETCHED_NAGASTONE.get())); + + //lich tower + public static final DeferredBlock TWISTED_STONE = registerWithItem("twisted_stone", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); + public static final DeferredBlock TWISTED_STONE_PILLAR = registerWithItem("twisted_stone_pillar", properties -> new WallPillarBlock(12, 16, properties), () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).noOcclusion().requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); + public static final DeferredBlock SKULL_CHEST = registerWithItem("skull_chest", SkullChestBlock::new, () -> BlockBehaviour.Properties.of().lightLevel(state -> state.getValue(BlockLoggingEnum.MULTILOGGED) == BlockLoggingEnum.LAVA ? 15 : 0).mapColor(MapColor.COLOR_LIGHT_GRAY).noOcclusion().pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.NETHERITE_BLOCK).strength(3.0F, 100.0F)); + public static final DeferredBlock KEEPSAKE_CASKET = register("keepsake_casket", KeepsakeCasketBlock::new, () -> BlockBehaviour.Properties.of().lightLevel(state -> state.getValue(BlockLoggingEnum.MULTILOGGED) == BlockLoggingEnum.LAVA ? 15 : 0).mapColor(MapColor.COLOR_BLACK).noOcclusion().pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.NETHERITE_BLOCK).strength(5.0F, 1200.0F)); + public static final DeferredBlock BOLD_STONE_PILLAR = registerWithItem("bold_stone_pillar", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(1.5F, 6.0F)); + public static final DeferredBlock CHISELED_CANOPY_BOOKSHELF = registerWithItem("chiseled_canopy_bookshelf", ChiseledCanopyShelfBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.COLOR_BROWN).sound(SoundType.CHISELED_BOOKSHELF).strength(2.5F)); + public static final DeferredBlock CANDELABRA = registerWithItem("candelabra", CandelabraBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).strength(1.5F)); + public static final DeferredBlock ZOMBIE_SKULL_CANDLE = register("zombie_skull_candle", properties -> new SkullCandleBlock(SkullBlock.Types.ZOMBIE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.ZOMBIE_HEAD)); + public static final DeferredBlock ZOMBIE_WALL_SKULL_CANDLE = register("zombie_wall_skull_candle", properties -> new WallSkullCandleBlock(SkullBlock.Types.ZOMBIE, properties), () -> BlockBehaviour.Properties.of().strength(1.0F).pushReaction(PushReaction.DESTROY).overrideLootTable(ZOMBIE_SKULL_CANDLE.get().getLootTable()).overrideDescription(ZOMBIE_SKULL_CANDLE.get().getDescriptionId())); + public static final DeferredBlock SKELETON_SKULL_CANDLE = register("skeleton_skull_candle", properties -> new SkullCandleBlock(SkullBlock.Types.SKELETON, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.SKELETON_SKULL)); + public static final DeferredBlock SKELETON_WALL_SKULL_CANDLE = register("skeleton_wall_skull_candle", properties -> new WallSkullCandleBlock(SkullBlock.Types.SKELETON, properties), () -> BlockBehaviour.Properties.of().strength(1.0F).pushReaction(PushReaction.DESTROY).overrideLootTable(SKELETON_SKULL_CANDLE.get().getLootTable()).overrideDescription(SKELETON_SKULL_CANDLE.get().getDescriptionId())); + public static final DeferredBlock WITHER_SKELE_SKULL_CANDLE = register("wither_skeleton_skull_candle", properties -> new SkullCandleBlock(SkullBlock.Types.WITHER_SKELETON, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.WITHER_SKELETON_SKULL)); + public static final DeferredBlock WITHER_SKELE_WALL_SKULL_CANDLE = register("wither_skeleton_wall_skull_candle", properties -> new WallSkullCandleBlock(SkullBlock.Types.WITHER_SKELETON, properties), () -> BlockBehaviour.Properties.of().strength(1.0F).pushReaction(PushReaction.DESTROY).overrideLootTable(WITHER_SKELE_SKULL_CANDLE.get().getLootTable()).overrideDescription(WITHER_SKELE_SKULL_CANDLE.get().getDescriptionId())); + public static final DeferredBlock CREEPER_SKULL_CANDLE = register("creeper_skull_candle", properties -> new SkullCandleBlock(SkullBlock.Types.CREEPER, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.CREEPER_HEAD)); + public static final DeferredBlock CREEPER_WALL_SKULL_CANDLE = register("creeper_wall_skull_candle", properties -> new WallSkullCandleBlock(SkullBlock.Types.CREEPER, properties), () -> BlockBehaviour.Properties.of().strength(1.0F).pushReaction(PushReaction.DESTROY).overrideLootTable(CREEPER_SKULL_CANDLE.get().getLootTable()).overrideDescription(CREEPER_SKULL_CANDLE.get().getDescriptionId())); + public static final DeferredBlock PLAYER_SKULL_CANDLE = register("player_skull_candle", properties -> new SkullCandleBlock(SkullBlock.Types.PLAYER, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.PLAYER_HEAD)); + public static final DeferredBlock PLAYER_WALL_SKULL_CANDLE = register("player_wall_skull_candle", properties -> new WallSkullCandleBlock(SkullBlock.Types.PLAYER, properties), () -> BlockBehaviour.Properties.of().strength(1.0F).pushReaction(PushReaction.DESTROY).overrideLootTable(PLAYER_SKULL_CANDLE.get().getLootTable()).overrideDescription(PLAYER_SKULL_CANDLE.get().getDescriptionId())); + public static final DeferredBlock PIGLIN_SKULL_CANDLE = register("piglin_skull_candle", properties -> new SkullCandleBlock(SkullBlock.Types.PIGLIN, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.PIGLIN_HEAD)); + public static final DeferredBlock PIGLIN_WALL_SKULL_CANDLE = register("piglin_wall_skull_candle", properties -> new WallSkullCandleBlock(SkullBlock.Types.PIGLIN, properties), () -> BlockBehaviour.Properties.of().strength(1.0F).pushReaction(PushReaction.DESTROY).overrideLootTable(PIGLIN_SKULL_CANDLE.get().getLootTable()).overrideDescription(PIGLIN_SKULL_CANDLE.get().getDescriptionId())); + public static final DeferredBlock WROUGHT_IRON_FENCE = register("wrought_iron_fence", WroughtIronFenceBlock::new, () -> BlockBehaviour.Properties.of().strength(8.0F, 20.0F).sound(SoundType.METAL).requiresCorrectToolForDrops().noOcclusion()); + public static final DeferredBlock TERRORCOTTA_ARCS = registerWithItem("terrorcotta_arcs", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(1.5F, 6.0F)); + public static final DeferredBlock TERRORCOTTA_CURVES = registerWithItem("terrorcotta_curves", GlazedTerracottaBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(1.5F, 6.0F)); + public static final DeferredBlock TERRORCOTTA_LINES = registerWithItem("terrorcotta_lines", BinaryRotatedBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(1.5F, 6.0F)); + public static final DeferredBlock CORONATION_CARPET = registerWithItem("coronation_carpet", properties -> new CoronationCarpetBlock(DyeColor.RED, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.RED_CARPET).isValidSpawn(Blocks::always)); + + //ominous + public static final DeferredBlock OMINOUS_FIRE = register("ominous_fire", OminousFireBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_PURPLE).replaceable().noCollision().instabreak().lightLevel((state) -> 15).sound(SoundType.WOOL).pushReaction(PushReaction.DESTROY)); + public static final DeferredBlock OMINOUS_CANDLE = ominousCandle("ominous_candle", MapColor.SAND, Blocks.CANDLE); + public static final DeferredBlock OMINOUS_WHITE_CANDLE = ominousCandle("ominous_white_candle", MapColor.WOOL, Blocks.WHITE_CANDLE); + public static final DeferredBlock OMINOUS_ORANGE_CANDLE = ominousCandle("ominous_orange_candle", MapColor.COLOR_ORANGE, Blocks.ORANGE_CANDLE); + public static final DeferredBlock OMINOUS_MAGENTA_CANDLE = ominousCandle("ominous_magenta_candle", MapColor.COLOR_MAGENTA, Blocks.MAGENTA_CANDLE); + public static final DeferredBlock OMINOUS_LIGHT_BLUE_CANDLE = ominousCandle("ominous_light_blue_candle", MapColor.COLOR_LIGHT_BLUE, Blocks.LIGHT_BLUE_CANDLE); + public static final DeferredBlock OMINOUS_YELLOW_CANDLE = ominousCandle("ominous_yellow_candle", MapColor.COLOR_YELLOW, Blocks.YELLOW_CANDLE); + public static final DeferredBlock OMINOUS_LIME_CANDLE = ominousCandle("ominous_lime_candle", MapColor.COLOR_LIGHT_GREEN, Blocks.LIME_CANDLE); + public static final DeferredBlock OMINOUS_PINK_CANDLE = ominousCandle("ominous_pink_candle", MapColor.COLOR_PINK, Blocks.PINK_CANDLE); + public static final DeferredBlock OMINOUS_GRAY_CANDLE = ominousCandle("ominous_gray_candle", MapColor.COLOR_GRAY, Blocks.GRAY_CANDLE); + public static final DeferredBlock OMINOUS_LIGHT_GRAY_CANDLE = ominousCandle("ominous_light_gray_candle", MapColor.COLOR_LIGHT_GRAY, Blocks.LIGHT_GRAY_CANDLE); + public static final DeferredBlock OMINOUS_CYAN_CANDLE = ominousCandle("ominous_cyan_candle", MapColor.COLOR_CYAN, Blocks.CYAN_CANDLE); + public static final DeferredBlock OMINOUS_PURPLE_CANDLE = ominousCandle("ominous_purple_candle", MapColor.COLOR_PURPLE, Blocks.PURPLE_CANDLE); + public static final DeferredBlock OMINOUS_BLUE_CANDLE = ominousCandle("ominous_blue_candle", MapColor.COLOR_BLUE, Blocks.BLUE_CANDLE); + public static final DeferredBlock OMINOUS_BROWN_CANDLE = ominousCandle("ominous_brown_candle", MapColor.COLOR_BROWN, Blocks.BROWN_CANDLE); + public static final DeferredBlock OMINOUS_GREEN_CANDLE = ominousCandle("ominous_green_candle", MapColor.COLOR_GREEN, Blocks.GREEN_CANDLE); + public static final DeferredBlock OMINOUS_RED_CANDLE = ominousCandle("ominous_red_candle", MapColor.COLOR_RED, Blocks.RED_CANDLE); + public static final DeferredBlock OMINOUS_BLACK_CANDLE = ominousCandle("ominous_black_candle", MapColor.COLOR_BLACK, Blocks.BLACK_CANDLE); + + //labyrinth + public static final DeferredBlock MAZESTONE = registerWithItem("mazestone", Block::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(100.0F, 5.0F)); + public static final DeferredBlock MAZESTONE_BRICK = registerWithItem("mazestone_brick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(MAZESTONE.get())); + public static final DeferredBlock CUT_MAZESTONE = registerWithItem("cut_mazestone", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(MAZESTONE.get())); + public static final DeferredBlock DECORATIVE_MAZESTONE = registerWithItem("decorative_mazestone", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(MAZESTONE.get())); + public static final DeferredBlock CRACKED_MAZESTONE = registerWithItem("cracked_mazestone", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(MAZESTONE.get())); + public static final DeferredBlock MOSSY_MAZESTONE = registerWithItem("mossy_mazestone", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(MAZESTONE.get())); + public static final DeferredBlock MAZESTONE_MOSAIC = registerWithItem("mazestone_mosaic", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(MAZESTONE.get())); + public static final DeferredBlock MAZESTONE_BORDER = registerWithItem("mazestone_border", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(MAZESTONE.get())); + public static final DeferredBlock RED_THREAD = registerWithItem("red_thread", RedThreadBlock::new, () -> BlockBehaviour.Properties.of().instabreak().mapColor(MapColor.FIRE).isValidSpawn(TFBlocks::noSpawning).noCollision().noOcclusion().noTerrainParticles().pushReaction(PushReaction.DESTROY)); + public static final DeferredBlock MAZE_SLIME_BLOCK = registerWithItem("maze_slime_block", MazeSlimeBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.SLIME_BLOCK).mapColor(MapColor.STONE)); + + //stronghold + public static final DeferredBlock STRONGHOLD_SHIELD = registerWithItem("stronghold_shield", StrongholdShieldBlock::new, () -> BlockBehaviour.Properties.of().noLootTable().mapColor(MapColor.STONE).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.METAL).strength(-1.0F, 6000000.0F)); + public static final DeferredBlock TROPHY_PEDESTAL = registerWithItem("trophy_pedestal", TrophyPedestalBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(2.0F, 2000.0F)); + public static final DeferredBlock UNDERBRICK = registerWithItem("underbrick", Block::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).requiresCorrectToolForDrops().sound(SoundType.DEEPSLATE_BRICKS).strength(1.5F, 6.0F)); + public static final DeferredBlock MOSSY_UNDERBRICK = registerWithItem("mossy_underbrick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(UNDERBRICK.get())); + public static final DeferredBlock CRACKED_UNDERBRICK = registerWithItem("cracked_underbrick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(UNDERBRICK.get())); + public static final DeferredBlock UNDERBRICK_FLOOR = registerWithItem("underbrick_floor", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(UNDERBRICK.get())); + + //dark tower + public static final DeferredBlock TOWERWOOD = registerWithItem("towerwood", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.COLOR_ORANGE).strength(40.0F, 6.0F).sound(SoundType.WOOD)); + public static final DeferredBlock ENCASED_TOWERWOOD = registerWithItem("encased_towerwood", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(TOWERWOOD.get()).mapColor(MapColor.SAND)); + public static final DeferredBlock CRACKED_TOWERWOOD = registerWithItem("cracked_towerwood", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(TOWERWOOD.get())); + public static final DeferredBlock MOSSY_TOWERWOOD = registerWithItem("mossy_towerwood", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(TOWERWOOD.get())); + public static final DeferredBlock INFESTED_TOWERWOOD = registerWithItem("infested_towerwood", InfestedTowerwoodBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TOWERWOOD.get()).instrument(NoteBlockInstrument.FLUTE).noLootTable().strength(2.0F, 6.0F)); + public static final DeferredBlock REAPPEARING_BLOCK = registerWithItem("reappearing_block", ReappearingBlock::new, () -> BlockBehaviour.Properties.of().forceSolidOn().lightLevel((state) -> 4).mapColor(MapColor.SAND).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.WOOD).strength(10.0F, 35.0F)); + public static final DeferredBlock VANISHING_BLOCK = registerWithItem("vanishing_block", VanishingBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> state.getValue(VanishingBlock.ACTIVE) ? 4 : 0).mapColor(MapColor.SAND).pushReaction(PushReaction.BLOCK).sound(SoundType.WOOD).strength(10.0F, 35.0F)); + public static final DeferredBlock UNBREAKABLE_VANISHING_BLOCK = register("unbreakable_vanishing_block", VanishingBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(VANISHING_BLOCK.get()).noLootTable().strength(-1.0F, 6000000.0F)); + public static final DeferredBlock LOCKED_VANISHING_BLOCK = registerWithItem("locked_vanishing_block", LockedVanishingBlock::new, () -> BlockBehaviour.Properties.of().pushReaction(PushReaction.BLOCK).mapColor(MapColor.SAND).sound(SoundType.WOOD).strength(-1.0F, 2000.0F)); + public static final DeferredBlock CARMINITE_BUILDER = registerWithItem("carminite_builder", BuilderBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> state.getValue(BuilderBlock.STATE) == TowerDeviceVariant.BUILDER_ACTIVE ? 4 : 0).mapColor(MapColor.SAND).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.WOOD).strength(10.0F, 6.0F)); + public static final DeferredBlock BUILT_BLOCK = register("built_block", TranslucentBuiltBlock::new, () -> BlockBehaviour.Properties.of().noLootTable().noOcclusion().pushReaction(PushReaction.BLOCK).sound(SoundType.WOOD).strength(50.0F, 2000.0F)); + public static final DeferredBlock ANTIBUILDER = registerWithItem("antibuilder", AntibuilderBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> 10).noLootTable().pushReaction(PushReaction.BLOCK).mapColor(MapColor.SAND).requiresCorrectToolForDrops().sound(SoundType.WOOD).strength(10.0F, 6.0F)); + public static final DeferredBlock ANTIBUILT_BLOCK = register("antibuilt_block", Block::new, () -> BlockBehaviour.Properties.of().noLootTable().noOcclusion().pushReaction(PushReaction.BLOCK).sound(SoundType.WOOD).strength(0.3F, 2000.0F)); + public static final DeferredBlock GHAST_TRAP = registerWithItem("ghast_trap", GhastTrapBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> state.getValue(GhastTrapBlock.ACTIVE) ? 15 : 0).mapColor(MapColor.SAND).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.WOOD).strength(10.0F, 6.0F)); + public static final DeferredBlock CARMINITE_REACTOR = registerWithItem("carminite_reactor", CarminiteReactorBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> state.getValue(CarminiteReactorBlock.ACTIVE) ? 15 : 0).mapColor(MapColor.SAND).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.WOOD).strength(10.0F, 6.0F)); + public static final DeferredBlock REACTOR_DEBRIS = register("reactor_debris", ReactorDebrisBlock::new, () -> BlockBehaviour.Properties.of().noLootTable().noOcclusion().pushReaction(PushReaction.BLOCK).sound(SoundType.ANCIENT_DEBRIS).strength(0.3F, 2000.0F)); + public static final DeferredBlock FAKE_GOLD = register("fake_gold", Block::new, () -> BlockBehaviour.Properties.of().noLootTable().pushReaction(PushReaction.BLOCK).sound(SoundType.METAL).strength(50.0F, 2000.0F)); + public static final DeferredBlock FAKE_DIAMOND = register("fake_diamond", Block::new, () -> BlockBehaviour.Properties.of().noLootTable().pushReaction(PushReaction.BLOCK).sound(SoundType.METAL).strength(50.0F, 2000.0F)); + public static final DeferredBlock EXPERIMENT_115 = register("experiment_115", Experiment115Block::new, () -> BlockBehaviour.Properties.of().noLootTable().pushReaction(PushReaction.DESTROY).randomTicks().sound(SoundType.WOOL).strength(0.5F)); + + //aurora palace + public static final DeferredBlock AURORA_BLOCK = registerWithItem("aurora_block", AuroraBrickBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.CHIME).mapColor(MapColor.ICE).strength(10.0F, 6.0F)); + public static final DeferredBlock AURORA_PILLAR = registerWithItem("aurora_pillar", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.CHIME).mapColor(MapColor.ICE).requiresCorrectToolForDrops().strength(2.0F, 6.0F)); + public static final DeferredBlock AURORA_SLAB = registerWithItem("aurora_slab", SlabBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.CHIME).mapColor(MapColor.ICE).requiresCorrectToolForDrops().strength(2.0F, 6.0F)); + public static final DeferredBlock AURORALIZED_GLASS = registerWithItem("auroralized_glass", AuroralizedGlassBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.GLASS)); + + //highlands/thornlands + public static final DeferredBlock BROWN_THORNS = registerWithItem("brown_thorns", ThornsBlock::new, () -> BlockBehaviour.Properties.of().noLootTable().mapColor(MapColor.PODZOL).pushReaction(PushReaction.BLOCK).sound(SoundType.WOOD).strength(50.0F, 2000.0F)); + public static final DeferredBlock GREEN_THORNS = registerWithItem("green_thorns", ThornsBlock::new, () -> BlockBehaviour.Properties.of().noLootTable().mapColor(MapColor.PLANT).pushReaction(PushReaction.BLOCK).sound(SoundType.WOOD).strength(50.0F, 2000.0F)); + public static final DeferredBlock BURNT_THORNS = registerWithItem("burnt_thorns", BurntThornsBlock::new, () -> BlockBehaviour.Properties.of().instabreak().noLootTable().mapColor(MapColor.STONE).pushReaction(PushReaction.DESTROY).sound(SoundType.SAND)); + public static final DeferredBlock THORN_ROSE = registerWithItem("thorn_rose", ThornRoseBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).noCollision().pushReaction(PushReaction.DESTROY).sound(SoundType.GRASS).strength(10.0F, 0.0F)); + public static final DeferredBlock THORN_LEAVES = registerWithItem("thorn_leaves", properties -> new SpecialStemLeavesBlock(state -> state.is(TFBlocks.BROWN_THORNS) || state.is(TFBlocks.GREEN_THORNS), properties), () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.PLANT).noOcclusion().pushReaction(PushReaction.DESTROY).randomTicks().sound(SoundType.AZALEA_LEAVES).strength(0.2F).isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); + public static final DeferredBlock BEANSTALK_LEAVES = registerWithItem("beanstalk_leaves", properties -> new SpecialStemLeavesBlock(state -> state.is(TFBlocks.HUGE_STALK), properties), () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.PLANT).noOcclusion().pushReaction(PushReaction.DESTROY).randomTicks().sound(SoundType.AZALEA_LEAVES).strength(0.2F).isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); + public static final DeferredBlock DEADROCK = registerWithItem("deadrock", Block::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE).strength(100.0F, 6000000.0F)); + public static final DeferredBlock CRACKED_DEADROCK = registerWithItem("cracked_deadrock", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(DEADROCK.get())); + public static final DeferredBlock WEATHERED_DEADROCK = registerWithItem("weathered_deadrock", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(DEADROCK.get())); + public static final DeferredBlock TROLLSTEINN = registerWithItem("trollsteinn", TrollsteinnBlock::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.STONE).randomTicks().requiresCorrectToolForDrops().sound(SoundType.STONE).strength(2.0F, 6.0F)); + + public static final DeferredBlock WISPY_CLOUD = registerWithItem("wispy_cloud", properties -> new WispyCloudBlock(Biome.Precipitation.NONE, properties), () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.HAT).mapColor(MapColor.SNOW).noOcclusion().pushReaction(PushReaction.DESTROY).replaceable().sound(SoundType.WOOL).strength(0.3F, 0.0F).forceSolidOff()); + public static final DeferredBlock FLUFFY_CLOUD = registerWithItem("fluffy_cloud", properties -> new CloudBlock(null, properties), () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.HAT).mapColor(MapColor.ICE).pushReaction(PushReaction.DESTROY).sound(SoundType.WOOL).strength(0.8F, 0.0F).randomTicks()); + public static final DeferredBlock RAINY_CLOUD = registerWithItem("rainy_cloud", properties -> new CloudBlock(Biome.Precipitation.RAIN, properties), () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.HAT).mapColor(MapColor.ICE).pushReaction(PushReaction.DESTROY).sound(SoundType.WOOL).strength(0.8F, 0.0F).randomTicks()); + public static final DeferredBlock SNOWY_CLOUD = registerWithItem("snowy_cloud", properties -> new CloudBlock(Biome.Precipitation.SNOW, properties), () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.HAT).mapColor(MapColor.ICE).pushReaction(PushReaction.DESTROY).sound(SoundType.WOOL).strength(0.8F, 0.0F).randomTicks()); + + public static final DeferredBlock GIANT_COBBLESTONE = registerWithItem("giant_cobblestone", GiantBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.COBBLESTONE).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(128.0F, 50.0F)); + public static final DeferredBlock GIANT_LOG = registerWithItem("giant_log", GiantBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_PLANKS).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(128.0F, 30.0F)); + public static final DeferredBlock GIANT_LEAVES = registerWithItem("giant_leaves", GiantLeavesBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_LEAVES).noOcclusion().pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.AZALEA_LEAVES).strength(0.2F * 64.0F, 15.0F).isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isValidSpawn(TFBlocks::noSpawning).isRedstoneConductor((state, level, pos) -> false)); + public static final DeferredBlock GIANT_OBSIDIAN = registerWithItem("giant_obsidian", GiantBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.OBSIDIAN).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(50.0F * 64.0F * 64.0F, 2000.0F * 64.0F * 64.0F).isValidSpawn(TFBlocks::noSpawning)); + public static final DeferredBlock UBEROUS_SOIL = registerWithItem("uberous_soil", UberousSoilBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.DIRT).sound(SoundType.GRAVEL).strength(0.6F)); + public static final DeferredBlock HUGE_STALK = registerWithItem("huge_stalk", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.PLANT).sound(SoundType.STEM).strength(1.5F, 3.0F)); + public static final DeferredBlock BEANSTALK_GROWER = register("beanstalk_grower", GrowingBeanstalkBlock::new, () -> BlockBehaviour.Properties.of().noCollision().noLootTable().noOcclusion().noTerrainParticles().strength(-1.0F, 6000000.0F)); + public static final DeferredBlock HUGE_MUSHGLOOM = registerWithItem("huge_mushgloom", HugeMushroomBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().lightLevel((state) -> 5).mapColor(MapColor.COLOR_ORANGE).sound(SoundType.SHROOMLIGHT).strength(0.2F)); + public static final DeferredBlock HUGE_MUSHGLOOM_STEM = registerWithItem("huge_mushgloom_stem", HugeMushroomBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().lightLevel((state) -> 5).mapColor(MapColor.COLOR_ORANGE).sound(SoundType.NYLIUM).strength(0.2F)); + public static final DeferredBlock TROLLVIDR = registerWithItem("trollvidr", TrollRootBlock::new, () -> BlockBehaviour.Properties.of().instabreak().mapColor(MapColor.PLANT).noCollision().pushReaction(PushReaction.DESTROY).sound(SoundType.FLOWERING_AZALEA)); + public static final DeferredBlock UNRIPE_TROLLBER = registerWithItem("unripe_trollber", UnripeTorchClusterBlock::new, () -> BlockBehaviour.Properties.of().instabreak().mapColor(MapColor.PLANT).noCollision().pushReaction(PushReaction.DESTROY).randomTicks().sound(SoundType.FLOWERING_AZALEA)); + public static final DeferredBlock TROLLBER = registerWithItem("trollber", TrollRootBlock::new, () -> BlockBehaviour.Properties.of().instabreak().lightLevel((state) -> 15).mapColor(MapColor.PLANT).noCollision().pushReaction(PushReaction.DESTROY).sound(SoundType.FLOWERING_AZALEA)); + + //plateau castle + public static final DeferredBlock CASTLE_BRICK = registerWithItem("castle_brick", Block::new, () -> BlockBehaviour.Properties.of().instrument(NoteBlockInstrument.BASEDRUM).mapColor(MapColor.QUARTZ).requiresCorrectToolForDrops().sound(SoundType.DEEPSLATE_TILES).strength(100.0F, 50.0F)); + public static final DeferredBlock WORN_CASTLE_BRICK = registerWithItem("worn_castle_brick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get())); + public static final DeferredBlock CRACKED_CASTLE_BRICK = registerWithItem("cracked_castle_brick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get())); + public static final DeferredBlock CASTLE_ROOF_TILE = registerWithItem("castle_roof_tile", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get()).mapColor(MapColor.COLOR_GRAY)); + public static final DeferredBlock MOSSY_CASTLE_BRICK = registerWithItem("mossy_castle_brick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get())); + public static final DeferredBlock THICK_CASTLE_BRICK = registerWithItem("thick_castle_brick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get())); + public static final DeferredBlock ENCASED_CASTLE_BRICK_PILLAR = registerWithItem("encased_castle_brick_pillar", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get())); + public static final DeferredBlock ENCASED_CASTLE_BRICK_TILE = registerWithItem("encased_castle_brick_tile", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get())); + public static final DeferredBlock BOLD_CASTLE_BRICK_PILLAR = registerWithItem("bold_castle_brick_pillar", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get())); + public static final DeferredBlock BOLD_CASTLE_BRICK_TILE = registerWithItem("bold_castle_brick_tile", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get())); + public static final DeferredBlock CASTLE_BRICK_STAIRS = registerWithItem("castle_brick_stairs", properties -> new StairBlock(CASTLE_BRICK.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get())); + public static final DeferredBlock WORN_CASTLE_BRICK_STAIRS = registerWithItem("worn_castle_brick_stairs", properties -> new StairBlock(WORN_CASTLE_BRICK.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(WORN_CASTLE_BRICK.get())); + public static final DeferredBlock CRACKED_CASTLE_BRICK_STAIRS = registerWithItem("cracked_castle_brick_stairs", properties -> new StairBlock(CRACKED_CASTLE_BRICK.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(CRACKED_CASTLE_BRICK.get())); + public static final DeferredBlock MOSSY_CASTLE_BRICK_STAIRS = registerWithItem("mossy_castle_brick_stairs", properties -> new StairBlock(MOSSY_CASTLE_BRICK.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(MOSSY_CASTLE_BRICK.get())); + public static final DeferredBlock ENCASED_CASTLE_BRICK_STAIRS = registerWithItem("encased_castle_brick_stairs", properties -> new StairBlock(ENCASED_CASTLE_BRICK_PILLAR.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(ENCASED_CASTLE_BRICK_PILLAR.get())); + public static final DeferredBlock BOLD_CASTLE_BRICK_STAIRS = registerWithItem("bold_castle_brick_stairs", properties -> new StairBlock(BOLD_CASTLE_BRICK_PILLAR.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(BOLD_CASTLE_BRICK_PILLAR.get())); + public static final DeferredBlock PINK_CASTLE_RUNE_BRICK = registerWithItem("pink_castle_rune_brick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get()).mapColor(DyeColor.MAGENTA)); + public static final DeferredBlock BLUE_CASTLE_RUNE_BRICK = registerWithItem("blue_castle_rune_brick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get()).mapColor(DyeColor.LIGHT_BLUE)); + public static final DeferredBlock YELLOW_CASTLE_RUNE_BRICK = registerWithItem("yellow_castle_rune_brick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get()).mapColor(DyeColor.YELLOW)); + public static final DeferredBlock VIOLET_CASTLE_RUNE_BRICK = registerWithItem("violet_castle_rune_brick", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CASTLE_BRICK.get()).mapColor(DyeColor.PURPLE)); + public static final DeferredBlock VIOLET_FORCE_FIELD = registerWithItem("violet_force_field", ForceFieldBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> 2).mapColor(DyeColor.PURPLE).noLootTable().noOcclusion().pushReaction(PushReaction.BLOCK).strength(-1.0F, 3600000.8F)); + public static final DeferredBlock PINK_FORCE_FIELD = registerWithItem("pink_force_field", ForceFieldBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> 2).mapColor(DyeColor.MAGENTA).noLootTable().noOcclusion().pushReaction(PushReaction.BLOCK).strength(-1.0F, 3600000.8F)); + public static final DeferredBlock ORANGE_FORCE_FIELD = registerWithItem("orange_force_field", ForceFieldBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> 2).mapColor(DyeColor.ORANGE).noLootTable().noOcclusion().pushReaction(PushReaction.BLOCK).strength(-1.0F, 3600000.8F)); + public static final DeferredBlock GREEN_FORCE_FIELD = registerWithItem("green_force_field", ForceFieldBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> 2).mapColor(DyeColor.GREEN).noLootTable().noOcclusion().pushReaction(PushReaction.BLOCK).strength(-1.0F, 3600000.8F)); + public static final DeferredBlock BLUE_FORCE_FIELD = registerWithItem("blue_force_field", ForceFieldBlock::new, () -> BlockBehaviour.Properties.of().lightLevel((state) -> 2).mapColor(DyeColor.LIGHT_BLUE).noLootTable().noOcclusion().pushReaction(PushReaction.BLOCK).strength(-1.0F, 3600000.8F)); + public static final DeferredBlock CINDER_FURNACE = registerWithItem("cinder_furnace", CinderFurnaceBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).requiresCorrectToolForDrops().strength(7.0F).lightLevel((state) -> 15)); + public static final DeferredBlock CINDER_LOG = registerWithItem("cinder_log", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.COLOR_GRAY).strength(1.0F)); + public static final DeferredBlock CINDER_WOOD = registerWithItem("cinder_wood", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.COLOR_GRAY).strength(1.0F)); + public static final DeferredBlock YELLOW_CASTLE_DOOR = registerWithItem("yellow_castle_door", CastleDoorBlock::new, () -> BlockBehaviour.Properties.of().forceSolidOn().mapColor((state) -> state.getValue(CastleDoorBlock.VANISHED) ? MapColor.NONE : DyeColor.YELLOW.getMapColor()).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.DEEPSLATE_TILES).strength(100.0F, 100.0F)); + public static final DeferredBlock VIOLET_CASTLE_DOOR = registerWithItem("violet_castle_door", CastleDoorBlock::new, () -> BlockBehaviour.Properties.of().forceSolidOn().mapColor((state) -> state.getValue(CastleDoorBlock.VANISHED) ? MapColor.NONE : DyeColor.LIGHT_BLUE.getMapColor()).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.DEEPSLATE_TILES).strength(100.0F, 100.0F)); + public static final DeferredBlock PINK_CASTLE_DOOR = registerWithItem("pink_castle_door", CastleDoorBlock::new, () -> BlockBehaviour.Properties.of().forceSolidOn().mapColor((state) -> state.getValue(CastleDoorBlock.VANISHED) ? MapColor.NONE : DyeColor.MAGENTA.getMapColor()).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.DEEPSLATE_TILES).strength(100.0F, 100.0F)); + public static final DeferredBlock BLUE_CASTLE_DOOR = registerWithItem("blue_castle_door", CastleDoorBlock::new, () -> BlockBehaviour.Properties.of().forceSolidOn().mapColor((state) -> state.getValue(CastleDoorBlock.VANISHED) ? MapColor.NONE : DyeColor.PURPLE.getMapColor()).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().sound(SoundType.DEEPSLATE_TILES).strength(100.0F, 100.0F)); + + //mini structures + public static final DeferredBlock TWILIGHT_PORTAL_MINIATURE_STRUCTURE = registerWithItem("twilight_portal_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.of().noCollision().noOcclusion().requiresCorrectToolForDrops().strength(0.75F)); + // public static final DeferredBlock HEDGE_MAZE_MINIATURE_STRUCTURE = register("hedge_maze_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); +// public static final DeferredBlock HOLLOW_HILL_MINIATURE_STRUCTURE = register("hollow_hill_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); +// public static final DeferredBlock QUEST_GROVE_MINIATURE_STRUCTURE = register("quest_grove_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); +// public static final DeferredBlock MUSHROOM_TOWER_MINIATURE_STRUCTURE = register("mushroom_tower_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); + public static final DeferredBlock NAGA_COURTYARD_MINIATURE_STRUCTURE = registerWithItem("naga_courtyard_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); + public static final DeferredBlock LICH_TOWER_MINIATURE_STRUCTURE = registerWithItem("lich_tower_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); + public static final DeferredBlock MINOTAUR_LABYRINTH_MINIATURE_STRUCTURE = register("minotaur_labyrinth_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); +// public static final DeferredBlock HYDRA_LAIR_MINIATURE_STRUCTURE = register("hydra_lair_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); +// public static final DeferredBlock GOBLIN_STRONGHOLD_MINIATURE_STRUCTURE = register("goblin_stronghold_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); + public static final DeferredBlock DARK_TOWER_MINIATURE_STRUCTURE = register("dark_tower_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); +// public static final DeferredBlock YETI_CAVE_MINIATURE_STRUCTURE = register("yeti_cave_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); +// public static final DeferredBlock AURORA_PALACE_MINIATURE_STRUCTURE = register("aurora_palace_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); +// public static final DeferredBlock TROLL_CAVE_COTTAGE_MINIATURE_STRUCTURE = register("troll_cave_cottage_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); +// public static final DeferredBlock FINAL_CASTLE_MINIATURE_STRUCTURE = register("final_castle_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); + + //storage blocks + public static final DeferredBlock KNIGHTMETAL_BLOCK = registerWithItem("knightmetal_block", KnightmetalBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.METAL).requiresCorrectToolForDrops().sound(SoundType.NETHERITE_BLOCK).strength(5.0F, 40.0F)); + public static final DeferredBlock IRONWOOD_BLOCK = registerWithItem("ironwood_block", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.WOOD).sound(SoundType.WOOD).strength(5.0F, 6.0F)); + public static final DeferredBlock FIERY_BLOCK = registerWithItem("fiery_block", FieryBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).noOcclusion().requiresCorrectToolForDrops().sound(SoundType.METAL).strength(5.0F, 6.0F).emissiveRendering((state, world, pos) -> true), () -> new Item.Properties().fireResistant()); + public static final DeferredBlock STEELEAF_BLOCK = registerWithItem("steeleaf_block", Block::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).sound(SoundType.NETHERITE_BLOCK).strength(5.0F, 6.0F)); + public static final DeferredBlock ARCTIC_FUR_BLOCK = registerWithItem("arctic_fur_block", ArcticFurBlock::new, () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.WOOL).sound(SoundType.WOOL).strength(0.8F)); + public static final DeferredBlock CARMINITE_BLOCK = registerWithItem("carminite_block", Block::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_RED).strength(1.5F, 10.0F).requiresCorrectToolForDrops().sound(SoundType.METAL)); + + //boss trophies and spawners + public static final DeferredBlock NAGA_BOSS_SPAWNER = registerWithItem("naga_boss_spawner", properties -> new BossSpawnerBlock(BossVariant.NAGA, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).noLootTable().sound(SoundType.METAL).noOcclusion().strength(-1.0F, 3600000.8F)); + public static final DeferredBlock LICH_BOSS_SPAWNER = registerWithItem("lich_boss_spawner", properties -> new BossSpawnerBlock(BossVariant.LICH, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).noLootTable().sound(SoundType.METAL).noOcclusion().strength(-1.0F, 3600000.8F)); + public static final DeferredBlock HYDRA_BOSS_SPAWNER = registerWithItem("hydra_boss_spawner", properties -> new BossSpawnerBlock(BossVariant.HYDRA, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).noLootTable().sound(SoundType.METAL).noOcclusion().strength(-1.0F, 3600000.8F)); + public static final DeferredBlock UR_GHAST_BOSS_SPAWNER = registerWithItem("ur_ghast_boss_spawner", properties -> new BossSpawnerBlock(BossVariant.UR_GHAST, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).noLootTable().sound(SoundType.METAL).noOcclusion().strength(-1.0F, 3600000.8F)); + public static final DeferredBlock KNIGHT_PHANTOM_BOSS_SPAWNER = registerWithItem("knight_phantom_boss_spawner", properties -> new BossSpawnerBlock(BossVariant.KNIGHT_PHANTOM, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).noLootTable().sound(SoundType.METAL).noOcclusion().strength(-1.0F, 3600000.8F)); + public static final DeferredBlock SNOW_QUEEN_BOSS_SPAWNER = registerWithItem("snow_queen_boss_spawner", properties -> new BossSpawnerBlock(BossVariant.SNOW_QUEEN, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).noLootTable().sound(SoundType.METAL).noOcclusion().strength(-1.0F, 3600000.8F)); + public static final DeferredBlock MINOSHROOM_BOSS_SPAWNER = registerWithItem("minoshroom_boss_spawner", properties -> new BossSpawnerBlock(BossVariant.MINOSHROOM, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).noLootTable().sound(SoundType.METAL).noOcclusion().strength(-1.0F, 3600000.8F)); + public static final DeferredBlock ALPHA_YETI_BOSS_SPAWNER = registerWithItem("alpha_yeti_boss_spawner", properties -> new BossSpawnerBlock(BossVariant.ALPHA_YETI, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).noLootTable().sound(SoundType.METAL).noOcclusion().strength(-1.0F, 3600000.8F)); + public static final DeferredBlock FINAL_BOSS_BOSS_SPAWNER = registerWithItem("final_boss_boss_spawner", properties -> new BossSpawnerBlock(BossVariant.FINAL_BOSS, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).noLootTable().sound(SoundType.METAL).noOcclusion().strength(-1.0F, 3600000.8F)); + public static final DeferredBlock NAGA_TROPHY = register("naga_trophy", properties -> new TrophyBlock(BossVariant.NAGA, 5, properties), () -> BlockBehaviour.Properties.of().instabreak()); + public static final DeferredBlock LICH_TROPHY = register("lich_trophy", properties -> new TrophyBlock(BossVariant.LICH, 6, properties), () -> BlockBehaviour.Properties.of().instabreak()); + public static final DeferredBlock HYDRA_TROPHY = register("hydra_trophy", properties -> new TrophyBlock(BossVariant.HYDRA, 12, properties), () -> BlockBehaviour.Properties.of().instabreak()); + public static final DeferredBlock UR_GHAST_TROPHY = register("ur_ghast_trophy", properties -> new TrophyBlock(BossVariant.UR_GHAST, 13, properties), () -> BlockBehaviour.Properties.of().instabreak()); + public static final DeferredBlock KNIGHT_PHANTOM_TROPHY = register("knight_phantom_trophy", properties -> new TrophyBlock(BossVariant.KNIGHT_PHANTOM, 8, properties), () -> BlockBehaviour.Properties.of().instabreak()); + public static final DeferredBlock SNOW_QUEEN_TROPHY = register("snow_queen_trophy", properties -> new TrophyBlock(BossVariant.SNOW_QUEEN, 14, properties), () -> BlockBehaviour.Properties.of().instabreak()); + public static final DeferredBlock MINOSHROOM_TROPHY = register("minoshroom_trophy", properties -> new TrophyBlock(BossVariant.MINOSHROOM, 7, properties), () -> BlockBehaviour.Properties.of().instabreak()); + public static final DeferredBlock ALPHA_YETI_TROPHY = register("alpha_yeti_trophy", properties -> new TrophyBlock(BossVariant.ALPHA_YETI, 9, properties), () -> BlockBehaviour.Properties.of().instabreak()); + public static final DeferredBlock QUEST_RAM_TROPHY = register("quest_ram_trophy", properties -> new TrophyBlock(BossVariant.QUEST_RAM, 1, properties), () -> BlockBehaviour.Properties.of().instabreak()); + public static final DeferredBlock NAGA_WALL_TROPHY = register("naga_wall_trophy", properties -> new TrophyWallBlock(BossVariant.NAGA, properties), () -> BlockBehaviour.Properties.of().instabreak().pushReaction(PushReaction.DESTROY).overrideLootTable(NAGA_TROPHY.get().getLootTable()).overrideDescription(NAGA_TROPHY.get().getDescriptionId())); + public static final DeferredBlock LICH_WALL_TROPHY = register("lich_wall_trophy", properties -> new TrophyWallBlock(BossVariant.LICH, properties), () -> BlockBehaviour.Properties.of().instabreak().pushReaction(PushReaction.DESTROY).overrideLootTable(LICH_TROPHY.get().getLootTable()).overrideDescription(LICH_TROPHY.get().getDescriptionId())); + public static final DeferredBlock HYDRA_WALL_TROPHY = register("hydra_wall_trophy", properties -> new TrophyWallBlock(BossVariant.HYDRA, properties), () -> BlockBehaviour.Properties.of().instabreak().pushReaction(PushReaction.DESTROY).overrideLootTable(HYDRA_TROPHY.get().getLootTable()).overrideDescription(HYDRA_TROPHY.get().getDescriptionId())); + public static final DeferredBlock UR_GHAST_WALL_TROPHY = register("ur_ghast_wall_trophy", properties -> new TrophyWallBlock(BossVariant.UR_GHAST, properties), () -> BlockBehaviour.Properties.of().instabreak().pushReaction(PushReaction.DESTROY).overrideLootTable(UR_GHAST_TROPHY.get().getLootTable()).overrideDescription(UR_GHAST_TROPHY.get().getDescriptionId())); + public static final DeferredBlock KNIGHT_PHANTOM_WALL_TROPHY = register("knight_phantom_wall_trophy", properties -> new TrophyWallBlock(BossVariant.KNIGHT_PHANTOM, properties), () -> BlockBehaviour.Properties.of().instabreak().pushReaction(PushReaction.DESTROY).overrideLootTable(KNIGHT_PHANTOM_TROPHY.get().getLootTable()).overrideDescription(KNIGHT_PHANTOM_TROPHY.get().getDescriptionId())); + public static final DeferredBlock SNOW_QUEEN_WALL_TROPHY = register("snow_queen_wall_trophy", properties -> new TrophyWallBlock(BossVariant.SNOW_QUEEN, properties), () -> BlockBehaviour.Properties.of().instabreak().pushReaction(PushReaction.DESTROY).overrideLootTable(SNOW_QUEEN_TROPHY.get().getLootTable()).overrideDescription(SNOW_QUEEN_TROPHY.get().getDescriptionId())); + public static final DeferredBlock MINOSHROOM_WALL_TROPHY = register("minoshroom_wall_trophy", properties -> new TrophyWallBlock(BossVariant.MINOSHROOM, properties), () -> BlockBehaviour.Properties.of().instabreak().pushReaction(PushReaction.DESTROY).overrideLootTable(MINOSHROOM_TROPHY.get().getLootTable()).overrideDescription(MINOSHROOM_TROPHY.get().getDescriptionId())); + public static final DeferredBlock ALPHA_YETI_WALL_TROPHY = register("alpha_yeti_wall_trophy", properties -> new TrophyWallBlock(BossVariant.ALPHA_YETI, properties), () -> BlockBehaviour.Properties.of().instabreak().pushReaction(PushReaction.DESTROY).overrideLootTable(ALPHA_YETI_TROPHY.get().getLootTable()).overrideDescription(ALPHA_YETI_TROPHY.get().getDescriptionId())); + public static final DeferredBlock QUEST_RAM_WALL_TROPHY = register("quest_ram_wall_trophy", properties -> new TrophyWallBlock(BossVariant.QUEST_RAM, properties), () -> BlockBehaviour.Properties.of().instabreak().pushReaction(PushReaction.DESTROY).overrideLootTable(QUEST_RAM_TROPHY.get().getLootTable()).overrideDescription(QUEST_RAM_TROPHY.get().getDescriptionId())); + + // TODO Enumify all of the dang tree stuff + + //all tree related stuff + public static final DeferredBlock OAK_BANISTER = registerWithItem("oak_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_PLANKS)); + public static final DeferredBlock SPRUCE_BANISTER = registerWithItem("spruce_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.SPRUCE_PLANKS)); + public static final DeferredBlock BIRCH_BANISTER = registerWithItem("birch_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.BIRCH_PLANKS)); + public static final DeferredBlock JUNGLE_BANISTER = registerWithItem("jungle_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.JUNGLE_PLANKS)); + public static final DeferredBlock ACACIA_BANISTER = registerWithItem("acacia_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.ACACIA_PLANKS)); + public static final DeferredBlock DARK_OAK_BANISTER = registerWithItem("dark_oak_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.DARK_OAK_PLANKS)); + public static final DeferredBlock CRIMSON_BANISTER = registerWithItem("crimson_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.CRIMSON_PLANKS)); + public static final DeferredBlock WARPED_BANISTER = registerWithItem("warped_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.WARPED_PLANKS)); + public static final DeferredBlock VANGROVE_BANISTER = registerWithItem("vangrove_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.MANGROVE_PLANKS)); + public static final DeferredBlock BAMBOO_BANISTER = registerWithItem("bamboo_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.BAMBOO_PLANKS)); + public static final DeferredBlock CHERRY_BANISTER = registerWithItem("cherry_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.CHERRY_PLANKS)); + public static final DeferredBlock PALE_OAK_BANISTER = registerWithItem("pale_oak_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.PALE_OAK_PLANKS)); + + public static final DeferredBlock OAK_DRYING_RACK = register("oak_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.OAK_SLAB, 0.5F)); + public static final DeferredBlock SPRUCE_DRYING_RACK = register("spruce_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.SPRUCE_SLAB, 0.5F)); + public static final DeferredBlock BIRCH_DRYING_RACK = register("birch_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.BIRCH_SLAB, 0.5F)); + public static final DeferredBlock JUNGLE_DRYING_RACK = register("jungle_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.JUNGLE_SLAB, 0.5F)); + public static final DeferredBlock ACACIA_DRYING_RACK = register("acacia_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.ACACIA_SLAB, 0.5F)); + public static final DeferredBlock DARK_OAK_DRYING_RACK = register("dark_oak_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.DARK_OAK_SLAB, 0.5F)); + public static final DeferredBlock CRIMSON_DRYING_RACK = register("crimson_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.CRIMSON_SLAB, 0.5F)); + public static final DeferredBlock WARPED_DRYING_RACK = register("warped_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.WARPED_SLAB, 0.5F)); + public static final DeferredBlock VANGROVE_DRYING_RACK = register("vangrove_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.MANGROVE_SLAB, 0.5F)); + public static final DeferredBlock BAMBOO_DRYING_RACK = register("bamboo_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.BAMBOO_SLAB, 0.5F)); + public static final DeferredBlock CHERRY_DRYING_RACK = register("cherry_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.CHERRY_SLAB, 0.5F)); + public static final DeferredBlock PALE_OAK_DRYING_RACK = register("pale_oak_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(Blocks.CHERRY_SLAB, 0.5F)); + + public static final BlockBehaviour.Properties TWILIGHT_OAK_LOG_PROPS = logProperties(MapColor.WOOD, MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties CANOPY_LOG_PROPS = logProperties(MapColor.PODZOL, MapColor.COLOR_BROWN).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties MANGROVE_LOG_PROPS = logProperties(MapColor.DIRT, MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties DARK_LOG_PROPS = logProperties(MapColor.COLOR_BROWN, MapColor.STONE).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties TIME_LOG_PROPS = logProperties(MapColor.DIRT, MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties TRANSFORMATION_LOG_PROPS = logProperties(MapColor.WOOD, MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties MINING_LOG_PROPS = logProperties(MapColor.SAND, MapColor.QUARTZ).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties SORTING_LOG_PROPS = logProperties(MapColor.PODZOL, MapColor.COLOR_BROWN).strength(2.0F).sound(SoundType.WOOD); + + public static final BlockBehaviour.Properties TWILIGHT_OAK_BARK_PROPS = logProperties(MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties CANOPY_BARK_PROPS = logProperties(MapColor.COLOR_BROWN).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties MANGROVE_BARK_PROPS = logProperties(MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties DARK_BARK_PROPS = logProperties(MapColor.STONE).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties TIME_BARK_PROPS = logProperties(MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties TRANSFORMATION_BARK_PROPS = logProperties(MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties MINING_BARK_PROPS = logProperties(MapColor.QUARTZ).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties SORTING_BARK_PROPS = logProperties(MapColor.COLOR_BROWN).strength(2.0F).sound(SoundType.WOOD); + + public static final BlockBehaviour.Properties TWILIGHT_OAK_STRIPPED_PROPS = logProperties(MapColor.WOOD).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties CANOPY_STRIPPED_PROPS = logProperties(MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties MANGROVE_STRIPPED_PROPS = logProperties(MapColor.DIRT).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties DARK_STRIPPED_PROPS = logProperties(MapColor.COLOR_BROWN).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties TIME_STRIPPED_PROPS = logProperties(MapColor.DIRT).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties TRANSFORMATION_STRIPPED_PROPS = logProperties(MapColor.WOOD).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties MINING_STRIPPED_PROPS = logProperties(MapColor.SAND).strength(2.0F).sound(SoundType.WOOD); + public static final BlockBehaviour.Properties SORTING_STRIPPED_PROPS = logProperties(MapColor.PODZOL).strength(2.0F).sound(SoundType.WOOD); + + public static final DeferredBlock TWILIGHT_OAK_LOG = registerWithItem("twilight_oak_log", RotatedPillarBlock::new, () -> TWILIGHT_OAK_LOG_PROPS); + public static final DeferredBlock CANOPY_LOG = registerWithItem("canopy_log", RotatedPillarBlock::new, () -> CANOPY_LOG_PROPS); + public static final DeferredBlock MANGROVE_LOG = registerWithItem("mangrove_log", RotatedPillarBlock::new, () -> MANGROVE_LOG_PROPS); + public static final DeferredBlock DARK_LOG = registerWithItem("dark_log", RotatedPillarBlock::new, () -> DARK_LOG_PROPS); + public static final DeferredBlock TIME_LOG = registerWithItem("time_log", RotatedPillarBlock::new, () -> TIME_LOG_PROPS); + public static final DeferredBlock TRANSFORMATION_LOG = registerWithItem("transformation_log", RotatedPillarBlock::new, () -> TRANSFORMATION_LOG_PROPS); + public static final DeferredBlock MINING_LOG = registerWithItem("mining_log", RotatedPillarBlock::new, () -> MINING_LOG_PROPS); + public static final DeferredBlock SORTING_LOG = registerWithItem("sorting_log", RotatedPillarBlock::new, () -> SORTING_LOG_PROPS); + + public static final DeferredBlock HOLLOW_TWILIGHT_OAK_LOG_HORIZONTAL = registerCustomID("hollow_twilight_oak_log_horizontal", HorizontalHollowLogBlock::new, () -> TWILIGHT_OAK_BARK_PROPS, "hollow_twilight_oak_log"); + public static final DeferredBlock HOLLOW_CANOPY_LOG_HORIZONTAL = registerCustomID("hollow_canopy_log_horizontal", HorizontalHollowLogBlock::new, () -> CANOPY_BARK_PROPS, "hollow_canopy_log"); + public static final DeferredBlock HOLLOW_MANGROVE_LOG_HORIZONTAL = registerCustomID("hollow_mangrove_log_horizontal", HorizontalHollowLogBlock::new, () -> MANGROVE_BARK_PROPS, "hollow_mangrove_log"); + public static final DeferredBlock HOLLOW_DARK_LOG_HORIZONTAL = registerCustomID("hollow_dark_log_horizontal", HorizontalHollowLogBlock::new, () -> DARK_BARK_PROPS, "hollow_dark_log"); + public static final DeferredBlock HOLLOW_TIME_LOG_HORIZONTAL = registerCustomID("hollow_time_log_horizontal", HorizontalHollowLogBlock::new, () -> TIME_BARK_PROPS, "hollow_time_log"); + public static final DeferredBlock HOLLOW_TRANSFORMATION_LOG_HORIZONTAL = registerCustomID("hollow_transformation_log_horizontal", HorizontalHollowLogBlock::new, () -> TRANSFORMATION_BARK_PROPS, "hollow_transformation_log"); + public static final DeferredBlock HOLLOW_MINING_LOG_HORIZONTAL = registerCustomID("hollow_mining_log_horizontal", HorizontalHollowLogBlock::new, () -> MINING_BARK_PROPS, "hollow_mining_log"); + public static final DeferredBlock HOLLOW_SORTING_LOG_HORIZONTAL = registerCustomID("hollow_sorting_log_horizontal", HorizontalHollowLogBlock::new, () -> SORTING_BARK_PROPS, "hollow_sorting_log"); + + public static final DeferredBlock HOLLOW_TWILIGHT_OAK_LOG_VERTICAL = registerCustomID("hollow_twilight_oak_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_TWILIGHT_OAK_LOG_CLIMBABLE, properties), () -> TWILIGHT_OAK_STRIPPED_PROPS, "hollow_twilight_oak_log"); + public static final DeferredBlock HOLLOW_CANOPY_LOG_VERTICAL = registerCustomID("hollow_canopy_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_CANOPY_LOG_CLIMBABLE, properties), () -> CANOPY_STRIPPED_PROPS, "hollow_canopy_log"); + public static final DeferredBlock HOLLOW_MANGROVE_LOG_VERTICAL = registerCustomID("hollow_mangrove_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_MANGROVE_LOG_CLIMBABLE, properties), () -> MANGROVE_STRIPPED_PROPS, "hollow_mangrove_log"); + public static final DeferredBlock HOLLOW_DARK_LOG_VERTICAL = registerCustomID("hollow_dark_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_DARK_LOG_CLIMBABLE, properties), () -> DARK_STRIPPED_PROPS, "hollow_dark_log"); + public static final DeferredBlock HOLLOW_TIME_LOG_VERTICAL = registerCustomID("hollow_time_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_TIME_LOG_CLIMBABLE, properties), () -> TIME_STRIPPED_PROPS, "hollow_time_log"); + public static final DeferredBlock HOLLOW_TRANSFORMATION_LOG_VERTICAL = registerCustomID("hollow_transformation_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_TRANSFORMATION_LOG_CLIMBABLE, properties), () -> TRANSFORMATION_STRIPPED_PROPS, "hollow_transformation_log"); + public static final DeferredBlock HOLLOW_MINING_LOG_VERTICAL = registerCustomID("hollow_mining_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_MINING_LOG_CLIMBABLE, properties), () -> MINING_STRIPPED_PROPS, "hollow_mining_log"); + public static final DeferredBlock HOLLOW_SORTING_LOG_VERTICAL = registerCustomID("hollow_sorting_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_SORTING_LOG_CLIMBABLE, properties), () -> SORTING_STRIPPED_PROPS, "hollow_sorting_log"); + + public static final DeferredBlock HOLLOW_TWILIGHT_OAK_LOG_CLIMBABLE = registerCustomID("hollow_twilight_oak_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_TWILIGHT_OAK_LOG_VERTICAL, properties), () -> TWILIGHT_OAK_STRIPPED_PROPS, "hollow_twilight_oak_log"); + public static final DeferredBlock HOLLOW_CANOPY_LOG_CLIMBABLE = registerCustomID("hollow_canopy_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_CANOPY_LOG_VERTICAL, properties), () -> CANOPY_STRIPPED_PROPS, "hollow_canopy_log"); + public static final DeferredBlock HOLLOW_MANGROVE_LOG_CLIMBABLE = registerCustomID("hollow_mangrove_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_MANGROVE_LOG_VERTICAL, properties), () -> MANGROVE_STRIPPED_PROPS, "hollow_mangrove_log"); + public static final DeferredBlock HOLLOW_DARK_LOG_CLIMBABLE = registerCustomID("hollow_dark_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_DARK_LOG_VERTICAL, properties), () -> DARK_STRIPPED_PROPS, "hollow_dark_log"); + public static final DeferredBlock HOLLOW_TIME_LOG_CLIMBABLE = registerCustomID("hollow_time_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_TIME_LOG_VERTICAL, properties), () -> TIME_STRIPPED_PROPS, "hollow_time_log"); + public static final DeferredBlock HOLLOW_TRANSFORMATION_LOG_CLIMBABLE = registerCustomID("hollow_transformation_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_TRANSFORMATION_LOG_VERTICAL, properties), () -> TRANSFORMATION_STRIPPED_PROPS, "hollow_transformation_log"); + public static final DeferredBlock HOLLOW_MINING_LOG_CLIMBABLE = registerCustomID("hollow_mining_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_MINING_LOG_VERTICAL, properties), () -> MINING_STRIPPED_PROPS, "hollow_mining_log"); + public static final DeferredBlock HOLLOW_SORTING_LOG_CLIMBABLE = registerCustomID("hollow_sorting_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_SORTING_LOG_VERTICAL, properties), () -> SORTING_STRIPPED_PROPS, "hollow_sorting_log"); + + public static final DeferredBlock HOLLOW_OAK_LOG_HORIZONTAL = registerCustomID("hollow_oak_log_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_WOOD), "hollow_twilight_oak_log"); + public static final DeferredBlock HOLLOW_SPRUCE_LOG_HORIZONTAL = registerCustomID("hollow_spruce_log_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.SPRUCE_WOOD), "hollow_spruce_log"); + public static final DeferredBlock HOLLOW_BIRCH_LOG_HORIZONTAL = registerCustomID("hollow_birch_log_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.BIRCH_WOOD), "hollow_birch_log"); + public static final DeferredBlock HOLLOW_JUNGLE_LOG_HORIZONTAL = registerCustomID("hollow_jungle_log_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.JUNGLE_WOOD), "hollow_jungle_log"); + public static final DeferredBlock HOLLOW_ACACIA_LOG_HORIZONTAL = registerCustomID("hollow_acacia_log_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.ACACIA_WOOD), "hollow_acacia_log"); + public static final DeferredBlock HOLLOW_DARK_OAK_LOG_HORIZONTAL = registerCustomID("hollow_dark_oak_log_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.DARK_OAK_WOOD), "hollow_dark_oak_log"); + public static final DeferredBlock HOLLOW_CRIMSON_STEM_HORIZONTAL = registerCustomID("hollow_crimson_stem_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.CRIMSON_HYPHAE), "hollow_crimson_stem"); + public static final DeferredBlock HOLLOW_WARPED_STEM_HORIZONTAL = registerCustomID("hollow_warped_stem_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.WARPED_HYPHAE), "hollow_warped_stem"); + public static final DeferredBlock HOLLOW_VANGROVE_LOG_HORIZONTAL = registerCustomID("hollow_vangrove_log_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.MANGROVE_WOOD), "hollow_vangrove_log"); + public static final DeferredBlock HOLLOW_CHERRY_LOG_HORIZONTAL = registerCustomID("hollow_cherry_log_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.CHERRY_WOOD), "hollow_cherry_log"); + public static final DeferredBlock HOLLOW_PALE_OAK_LOG_HORIZONTAL = registerCustomID("hollow_pale_oak_log_horizontal", HorizontalHollowLogBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(Blocks.PALE_OAK_WOOD), "hollow_pale_oak_log"); + + public static final DeferredBlock HOLLOW_OAK_LOG_VERTICAL = registerCustomID("hollow_oak_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_OAK_LOG_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_OAK_WOOD), "hollow_twilight_oak_log"); + public static final DeferredBlock HOLLOW_SPRUCE_LOG_VERTICAL = registerCustomID("hollow_spruce_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_SPRUCE_LOG_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_SPRUCE_WOOD), "hollow_spruce_log"); + public static final DeferredBlock HOLLOW_BIRCH_LOG_VERTICAL = registerCustomID("hollow_birch_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_BIRCH_LOG_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_BIRCH_WOOD), "hollow_birch_log"); + public static final DeferredBlock HOLLOW_JUNGLE_LOG_VERTICAL = registerCustomID("hollow_jungle_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_JUNGLE_LOG_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_JUNGLE_WOOD), "hollow_jungle_log"); + public static final DeferredBlock HOLLOW_ACACIA_LOG_VERTICAL = registerCustomID("hollow_acacia_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_ACACIA_LOG_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_ACACIA_WOOD), "hollow_acacia_log"); + public static final DeferredBlock HOLLOW_DARK_OAK_LOG_VERTICAL = registerCustomID("hollow_dark_oak_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_DARK_OAK_LOG_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_DARK_OAK_WOOD), "hollow_dark_oak_log"); + public static final DeferredBlock HOLLOW_CRIMSON_STEM_VERTICAL = registerCustomID("hollow_crimson_stem_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_CRIMSON_STEM_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_CRIMSON_HYPHAE), "hollow_crimson_stem"); + public static final DeferredBlock HOLLOW_WARPED_STEM_VERTICAL = registerCustomID("hollow_warped_stem_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_WARPED_STEM_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_WARPED_HYPHAE), "hollow_warped_stem"); + // wanna see a funny crash? Use () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_MANGROVE_WOOD) instead of the BlockBehaviour.Properties.of(...) + // I still legit have no idea why it happens but it does + public static final DeferredBlock HOLLOW_VANGROVE_LOG_VERTICAL = registerCustomID("hollow_vangrove_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_VANGROVE_LOG_CLIMBABLE, properties), () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.COLOR_RED).strength(2.0F).sound(SoundType.WOOD), "hollow_vangrove_log"); + public static final DeferredBlock HOLLOW_CHERRY_LOG_VERTICAL = registerCustomID("hollow_cherry_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_CHERRY_LOG_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_CHERRY_WOOD), "hollow_cherry_log"); + public static final DeferredBlock HOLLOW_PALE_OAK_LOG_VERTICAL = registerCustomID("hollow_pale_oak_log_vertical", properties -> new VerticalHollowLogBlock(TFBlocks.HOLLOW_PALE_OAK_LOG_CLIMBABLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_PALE_OAK_WOOD), "hollow_pale_oak_log"); + + public static final DeferredBlock HOLLOW_OAK_LOG_CLIMBABLE = registerCustomID("hollow_oak_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_OAK_LOG_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_OAK_WOOD), "hollow_twilight_oak_log"); + public static final DeferredBlock HOLLOW_SPRUCE_LOG_CLIMBABLE = registerCustomID("hollow_spruce_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_SPRUCE_LOG_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_SPRUCE_WOOD), "hollow_spruce_log"); + public static final DeferredBlock HOLLOW_BIRCH_LOG_CLIMBABLE = registerCustomID("hollow_birch_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_BIRCH_LOG_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_BIRCH_WOOD), "hollow_birch_log"); + public static final DeferredBlock HOLLOW_JUNGLE_LOG_CLIMBABLE = registerCustomID("hollow_jungle_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_JUNGLE_LOG_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_JUNGLE_WOOD), "hollow_jungle_log"); + public static final DeferredBlock HOLLOW_ACACIA_LOG_CLIMBABLE = registerCustomID("hollow_acacia_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_ACACIA_LOG_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_ACACIA_WOOD), "hollow_acacia_log"); + public static final DeferredBlock HOLLOW_DARK_OAK_LOG_CLIMBABLE = registerCustomID("hollow_dark_oak_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_DARK_OAK_LOG_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_DARK_OAK_WOOD), "hollow_dark_oak_log"); + public static final DeferredBlock HOLLOW_CRIMSON_STEM_CLIMBABLE = registerCustomID("hollow_crimson_stem_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_CRIMSON_STEM_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_CRIMSON_HYPHAE), "hollow_crimson_stem"); + public static final DeferredBlock HOLLOW_WARPED_STEM_CLIMBABLE = registerCustomID("hollow_warped_stem_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_WARPED_STEM_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_WARPED_HYPHAE), "hollow_warped_stem"); + public static final DeferredBlock HOLLOW_VANGROVE_LOG_CLIMBABLE = registerCustomID("hollow_vangrove_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_VANGROVE_LOG_VERTICAL, properties), () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.COLOR_RED).strength(2.0F).sound(SoundType.WOOD), "hollow_vangrove_log"); + public static final DeferredBlock HOLLOW_CHERRY_LOG_CLIMBABLE = registerCustomID("hollow_cherry_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_CHERRY_LOG_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_CHERRY_WOOD), "hollow_cherry_log"); + public static final DeferredBlock HOLLOW_PALE_OAK_LOG_CLIMBABLE = registerCustomID("hollow_pale_oak_log_climbable", properties -> new ClimbableHollowLogBlock(TFBlocks.HOLLOW_PALE_OAK_LOG_VERTICAL, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.STRIPPED_PALE_OAK_WOOD), "hollow_pale_oak_log"); + + public static final DeferredBlock STRIPPED_TWILIGHT_OAK_LOG = registerWithItem("stripped_twilight_oak_log", RotatedPillarBlock::new, () -> TWILIGHT_OAK_STRIPPED_PROPS); + public static final DeferredBlock STRIPPED_CANOPY_LOG = registerWithItem("stripped_canopy_log", RotatedPillarBlock::new, () -> CANOPY_STRIPPED_PROPS); + public static final DeferredBlock STRIPPED_MANGROVE_LOG = registerWithItem("stripped_mangrove_log", RotatedPillarBlock::new, () -> MANGROVE_STRIPPED_PROPS); + public static final DeferredBlock STRIPPED_DARK_LOG = registerWithItem("stripped_dark_log", RotatedPillarBlock::new, () -> DARK_STRIPPED_PROPS); + public static final DeferredBlock STRIPPED_TIME_LOG = registerWithItem("stripped_time_log", RotatedPillarBlock::new, () -> TIME_STRIPPED_PROPS); + public static final DeferredBlock STRIPPED_TRANSFORMATION_LOG = registerWithItem("stripped_transformation_log", RotatedPillarBlock::new, () -> TRANSFORMATION_STRIPPED_PROPS); + public static final DeferredBlock STRIPPED_MINING_LOG = registerWithItem("stripped_mining_log", RotatedPillarBlock::new, () -> MINING_STRIPPED_PROPS); + public static final DeferredBlock STRIPPED_SORTING_LOG = registerWithItem("stripped_sorting_log", RotatedPillarBlock::new, () -> SORTING_STRIPPED_PROPS); + + public static final DeferredBlock TWILIGHT_OAK_WOOD = registerWithItem("twilight_oak_wood", RotatedPillarBlock::new, () -> TWILIGHT_OAK_BARK_PROPS); + public static final DeferredBlock CANOPY_WOOD = registerWithItem("canopy_wood", RotatedPillarBlock::new, () -> CANOPY_BARK_PROPS); + public static final DeferredBlock MANGROVE_WOOD = registerWithItem("mangrove_wood", RotatedPillarBlock::new, () -> MANGROVE_BARK_PROPS); + public static final DeferredBlock DARK_WOOD = registerWithItem("dark_wood", RotatedPillarBlock::new, () -> DARK_BARK_PROPS); + public static final DeferredBlock TIME_WOOD = registerWithItem("time_wood", RotatedPillarBlock::new, () -> TIME_BARK_PROPS); + public static final DeferredBlock TRANSFORMATION_WOOD = registerWithItem("transformation_wood", RotatedPillarBlock::new, () -> TRANSFORMATION_BARK_PROPS); + public static final DeferredBlock MINING_WOOD = registerWithItem("mining_wood", RotatedPillarBlock::new, () -> MINING_BARK_PROPS); + public static final DeferredBlock SORTING_WOOD = registerWithItem("sorting_wood", RotatedPillarBlock::new, () -> SORTING_BARK_PROPS); + + public static final DeferredBlock STRIPPED_TWILIGHT_OAK_WOOD = registerWithItem("stripped_twilight_oak_wood", RotatedPillarBlock::new, () -> TWILIGHT_OAK_STRIPPED_PROPS); + public static final DeferredBlock STRIPPED_CANOPY_WOOD = registerWithItem("stripped_canopy_wood", RotatedPillarBlock::new, () -> CANOPY_STRIPPED_PROPS); + public static final DeferredBlock STRIPPED_MANGROVE_WOOD = registerWithItem("stripped_mangrove_wood", RotatedPillarBlock::new, () -> MANGROVE_STRIPPED_PROPS); + public static final DeferredBlock STRIPPED_DARK_WOOD = registerWithItem("stripped_dark_wood", RotatedPillarBlock::new, () -> DARK_STRIPPED_PROPS); + public static final DeferredBlock STRIPPED_TIME_WOOD = registerWithItem("stripped_time_wood", RotatedPillarBlock::new, () -> TIME_STRIPPED_PROPS); + public static final DeferredBlock STRIPPED_TRANSFORMATION_WOOD = registerWithItem("stripped_transformation_wood", RotatedPillarBlock::new, () -> TRANSFORMATION_STRIPPED_PROPS); + public static final DeferredBlock STRIPPED_MINING_WOOD = registerWithItem("stripped_mining_wood", RotatedPillarBlock::new, () -> MINING_STRIPPED_PROPS); + public static final DeferredBlock STRIPPED_SORTING_WOOD = registerWithItem("stripped_sorting_wood", RotatedPillarBlock::new, () -> SORTING_STRIPPED_PROPS); + + public static final DeferredBlock TIME_LOG_CORE = registerWithItem("time_log_core", TimeLogCoreBlock::new, () -> TIME_LOG_PROPS); + public static final DeferredBlock TRANSFORMATION_LOG_CORE = registerWithItem("transformation_log_core", TransLogCoreBlock::new, () -> TRANSFORMATION_LOG_PROPS); + public static final DeferredBlock MINING_LOG_CORE = registerWithItem("mining_log_core", MineLogCoreBlock::new, () -> MINING_LOG_PROPS); + public static final DeferredBlock SORTING_LOG_CORE = registerWithItem("sorting_log_core", SortLogCoreBlock::new, () -> SORTING_LOG_PROPS); + + public static final DeferredBlock MANGROVE_ROOT = registerWithItem("mangrove_root", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.STONE).sound(SoundType.WOOD).strength(2.0F)); + + public static final DeferredBlock TWILIGHT_OAK_LEAVES = registerWithItem("twilight_oak_leaves", properties -> new TintedParticleLeavesBlock(0.01F, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(0.2F).randomTicks().noOcclusion().sound(SoundType.AZALEA_LEAVES).isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); + public static final DeferredBlock CANOPY_LEAVES = registerWithItem("canopy_leaves", properties -> new TintedParticleLeavesBlock(0.01F, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(0.2F).randomTicks().noOcclusion().sound(SoundType.AZALEA_LEAVES).isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); + public static final DeferredBlock MANGROVE_LEAVES = registerWithItem("mangrove_leaves", properties -> new TintedParticleLeavesBlock(0.01F, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(0.2F).randomTicks().noOcclusion().sound(SoundType.AZALEA_LEAVES).isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); + public static final DeferredBlock DARK_LEAVES = registerWithItem("dark_leaves", DarkLeavesBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(2.0F, 10.0F).sound(SoundType.AZALEA_LEAVES).isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); + public static final DeferredBlock HARDENED_DARK_LEAVES = register("hardened_dark_leaves", HardenedDarkLeavesBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(2.0F, 10.0F).sound(SoundType.AZALEA_LEAVES).isValidSpawn(TFBlocks::noSpawning).isRedstoneConductor((state, level, pos) -> false)); + public static final DeferredBlock RAINBOW_OAK_LEAVES = registerWithItem("rainbow_oak_leaves", properties -> new TintedParticleLeavesBlock(0.01F, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(0.2F).randomTicks().noOcclusion().sound(SoundType.AZALEA_LEAVES).isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); + public static final DeferredBlock TIME_LEAVES = registerWithItem("time_leaves", properties -> new TintedParticleLeavesBlock(0.01F, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(0.2F).sound(SoundType.AZALEA_LEAVES).randomTicks().noOcclusion().isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); + public static final DeferredBlock TRANSFORMATION_LEAVES = registerWithItem("transformation_leaves", TransformationLeavesBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(0.2F).sound(SoundType.AZALEA_LEAVES).randomTicks().noOcclusion().isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); + public static final DeferredBlock MINING_LEAVES = registerWithItem("mining_leaves", properties -> new TintedParticleLeavesBlock(0.01F, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(0.2F).sound(SoundType.AZALEA_LEAVES).randomTicks().noOcclusion().isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); + public static final DeferredBlock SORTING_LEAVES = registerWithItem("sorting_leaves", properties -> new TintedParticleLeavesBlock(0.01F, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).ignitedByLava().pushReaction(PushReaction.DESTROY).strength(0.2F).sound(SoundType.AZALEA_LEAVES).randomTicks().noOcclusion().isSuffocating((state, getter, pos) -> false).isViewBlocking((state, getter, pos) -> false).isRedstoneConductor((state, level, pos) -> false)); + + public static final DeferredBlock TWILIGHT_OAK_SAPLING = registerWithItem("twilight_oak_sapling", properties -> new SaplingBlock(TFTreeGrowers.TWILIGHT_OAK, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); + public static final DeferredBlock CANOPY_SAPLING = registerWithItem("canopy_sapling", properties -> new SaplingBlock(TFTreeGrowers.CANOPY, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); + public static final DeferredBlock MANGROVE_SAPLING = registerWithItem("mangrove_sapling", properties -> new MangroveSaplingBlock(TFTreeGrowers.MANGROVE, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); + public static final DeferredBlock DARKWOOD_SAPLING = registerWithItem("darkwood_sapling", properties -> new SaplingBlock(TFTreeGrowers.DARK, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); + public static final DeferredBlock HOLLOW_OAK_SAPLING = registerWithItem("hollow_oak_sapling", properties -> new SaplingBlock(TFTreeGrowers.HOLLOW_OAK, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); + public static final DeferredBlock TIME_SAPLING = registerWithItem("time_sapling", properties -> new SaplingBlock(TFTreeGrowers.TIME, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); + public static final DeferredBlock TRANSFORMATION_SAPLING = registerWithItem("transformation_sapling", properties -> new SaplingBlock(TFTreeGrowers.TRANSFORMATION, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); + public static final DeferredBlock MINING_SAPLING = registerWithItem("mining_sapling", properties -> new SaplingBlock(TFTreeGrowers.MINING, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); + public static final DeferredBlock SORTING_SAPLING = registerWithItem("sorting_sapling", properties -> new SaplingBlock(TFTreeGrowers.SORTING, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); + public static final DeferredBlock RAINBOW_OAK_SAPLING = registerWithItem("rainbow_oak_sapling", properties -> new SaplingBlock(TFTreeGrowers.RAINBOW_OAK, properties), () -> BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).pushReaction(PushReaction.DESTROY).instabreak().sound(SoundType.GRASS).noCollision().randomTicks()); + + public static final DeferredBlock TWILIGHT_OAK_PLANKS = registerWithItem("twilight_oak_planks", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.WOOD).strength(2.0F, 3.0F).sound(SoundType.WOOD)); + public static final DeferredBlock TWILIGHT_OAK_STAIRS = registerWithItem("twilight_oak_stairs", properties -> new StairBlock(TWILIGHT_OAK_PLANKS.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get())); + public static final DeferredBlock TWILIGHT_OAK_SLAB = registerWithItem("twilight_oak_slab", SlabBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get())); + public static final DeferredBlock TWILIGHT_OAK_BUTTON = registerWithItem("twilight_oak_button", properties -> new ButtonBlock(TFWoodTypes.TWILIGHT_OAK_SET, 30, properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).noCollision().strength(0.5F)); + public static final DeferredBlock TWILIGHT_OAK_FENCE = registerWithItem("twilight_oak_fence", FenceBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get())); + public static final DeferredBlock TWILIGHT_OAK_GATE = registerWithItem("twilight_oak_fence_gate", properties -> new FenceGateBlock(TFWoodTypes.TWILIGHT_OAK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).forceSolidOn()); + public static final DeferredBlock TWILIGHT_OAK_PLATE = registerWithItem("twilight_oak_pressure_plate", properties -> new PressurePlateBlock(TFWoodTypes.TWILIGHT_OAK_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).forceSolidOn().noCollision().strength(0.5F)); + public static final DeferredBlock TWILIGHT_OAK_DOOR = registerWithItem("twilight_oak_door", properties -> new DoorBlock(TFWoodTypes.TWILIGHT_OAK_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).strength(3.0F).sound(SoundType.WOOD).noOcclusion()); + public static final DeferredBlock TWILIGHT_OAK_TRAPDOOR = registerWithItem("twilight_oak_trapdoor", properties -> new TrapDoorBlock(TFWoodTypes.TWILIGHT_OAK_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).strength(3.0F).noOcclusion()); + public static final DeferredBlock TWILIGHT_OAK_SIGN = register("twilight_oak_sign", properties -> new StandingSignBlock(TFWoodTypes.TWILIGHT_OAK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).strength(3.0F).noOcclusion().noCollision()); + public static final DeferredBlock TWILIGHT_WALL_SIGN = register("twilight_wall_sign", properties -> new WallSignBlock(TFWoodTypes.TWILIGHT_OAK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).strength(3.0F).noOcclusion().noCollision().overrideLootTable(TWILIGHT_OAK_SIGN.get().getLootTable()).overrideDescription(TWILIGHT_OAK_SIGN.get().getDescriptionId())); + public static final DeferredBlock TWILIGHT_OAK_HANGING_SIGN = register("twilight_oak_hanging_sign", properties -> new CeilingHangingSignBlock(TFWoodTypes.TWILIGHT_OAK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).noCollision().strength(1.0F)); + public static final DeferredBlock TWILIGHT_OAK_WALL_HANGING_SIGN = register("twilight_oak_wall_hanging_sign", properties -> new WallHangingSignBlock(TFWoodTypes.TWILIGHT_OAK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).noCollision().strength(1.0F).overrideLootTable(TWILIGHT_OAK_HANGING_SIGN.get().getLootTable()).overrideDescription(TWILIGHT_OAK_HANGING_SIGN.get().getDescriptionId())); + public static final DeferredBlock TWILIGHT_OAK_BANISTER = registerWithItem("twilight_oak_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get())); + public static final DeferredBlock TWILIGHT_OAK_DRYING_RACK = register("twilight_oak_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(TWILIGHT_OAK_SLAB.get(), 0.5F)); + + public static final DeferredBlock CANOPY_PLANKS = registerWithItem("canopy_planks", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.PODZOL).strength(2.0F, 3.0F).sound(SoundType.WOOD)); + public static final DeferredBlock CANOPY_STAIRS = registerWithItem("canopy_stairs", properties -> new StairBlock(CANOPY_PLANKS.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get())); + public static final DeferredBlock CANOPY_SLAB = registerWithItem("canopy_slab", SlabBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get())); + public static final DeferredBlock CANOPY_BUTTON = registerWithItem("canopy_button", properties -> new ButtonBlock(TFWoodTypes.CANOPY_WOOD_SET, 30, properties), () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).noCollision().strength(0.5F)); + public static final DeferredBlock CANOPY_FENCE = registerWithItem("canopy_fence", FenceBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get())); + public static final DeferredBlock CANOPY_GATE = registerWithItem("canopy_fence_gate", properties -> new FenceGateBlock(TFWoodTypes.CANOPY_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).forceSolidOn()); + public static final DeferredBlock CANOPY_PLATE = registerWithItem("canopy_pressure_plate", properties -> new PressurePlateBlock(TFWoodTypes.CANOPY_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).forceSolidOn().noCollision().strength(0.5F)); + public static final DeferredBlock CANOPY_DOOR = registerWithItem("canopy_door", properties -> new DoorBlock(TFWoodTypes.CANOPY_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).strength(3.0F).noOcclusion()); + public static final DeferredBlock CANOPY_TRAPDOOR = registerWithItem("canopy_trapdoor", properties -> new TrapDoorBlock(TFWoodTypes.CANOPY_WOOD_SET, properties), () -> BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.SAND).strength(3.0F).sound(SoundType.WOOD).noOcclusion()); + public static final DeferredBlock CANOPY_SIGN = register("canopy_sign", properties -> new StandingSignBlock(TFWoodTypes.CANOPY_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).strength(1.0F).noOcclusion().noCollision()); + public static final DeferredBlock CANOPY_WALL_SIGN = register("canopy_wall_sign", properties -> new WallSignBlock(TFWoodTypes.CANOPY_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).strength(1.0F).noOcclusion().noCollision().overrideLootTable(CANOPY_SIGN.get().getLootTable()).overrideDescription(CANOPY_SIGN.get().getDescriptionId())); + public static final DeferredBlock CANOPY_BOOKSHELF = registerWithItem("canopy_bookshelf", Block::new, () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).strength(1.5F)); + public static final DeferredBlock CANOPY_HANGING_SIGN = register("canopy_hanging_sign", properties -> new CeilingHangingSignBlock(TFWoodTypes.CANOPY_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).noCollision().strength(1.0F)); + public static final DeferredBlock CANOPY_WALL_HANGING_SIGN = register("canopy_wall_hanging_sign", properties -> new WallHangingSignBlock(TFWoodTypes.CANOPY_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).noCollision().strength(1.0F).overrideLootTable(CANOPY_HANGING_SIGN.get().getLootTable()).overrideDescription(CANOPY_HANGING_SIGN.get().getDescriptionId())); + public static final DeferredBlock CANOPY_BANISTER = registerWithItem("canopy_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get())); + public static final DeferredBlock CANOPY_DRYING_RACK = register("canopy_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(CANOPY_SLAB.get(), 0.5F)); + + public static final DeferredBlock MANGROVE_PLANKS = registerWithItem("mangrove_planks", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.DIRT).strength(2.0F, 3.0F).sound(SoundType.WOOD)); + public static final DeferredBlock MANGROVE_STAIRS = registerWithItem("mangrove_stairs", properties -> new StairBlock(MANGROVE_PLANKS.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get())); + public static final DeferredBlock MANGROVE_SLAB = registerWithItem("mangrove_slab", SlabBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get())); + public static final DeferredBlock MANGROVE_BUTTON = registerWithItem("mangrove_button", properties -> new ButtonBlock(TFWoodTypes.MANGROVE_WOOD_SET, 30, properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).noCollision().strength(0.5F)); + public static final DeferredBlock MANGROVE_FENCE = registerWithItem("mangrove_fence", FenceBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get())); + public static final DeferredBlock MANGROVE_GATE = registerWithItem("mangrove_fence_gate", properties -> new FenceGateBlock(TFWoodTypes.MANGROVE_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).forceSolidOn()); + public static final DeferredBlock MANGROVE_PLATE = registerWithItem("mangrove_pressure_plate", properties -> new PressurePlateBlock(TFWoodTypes.MANGROVE_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).forceSolidOn().noCollision().strength(0.5F)); + public static final DeferredBlock MANGROVE_DOOR = registerWithItem("mangrove_door", properties -> new DoorBlock(TFWoodTypes.MANGROVE_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).strength(3.0F).noOcclusion()); + public static final DeferredBlock MANGROVE_TRAPDOOR = registerWithItem("mangrove_trapdoor", properties -> new TrapDoorBlock(TFWoodTypes.MANGROVE_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).strength(3.0F).noOcclusion()); + public static final DeferredBlock MANGROVE_SIGN = register("mangrove_sign", properties -> new StandingSignBlock(TFWoodTypes.MANGROVE_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).strength(1.0F).noOcclusion().noCollision()); + public static final DeferredBlock MANGROVE_WALL_SIGN = register("mangrove_wall_sign", properties -> new WallSignBlock(TFWoodTypes.MANGROVE_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).strength(1.0F).noOcclusion().noCollision().overrideLootTable(MANGROVE_SIGN.get().getLootTable()).overrideDescription(MANGROVE_SIGN.get().getDescriptionId())); + public static final DeferredBlock MANGROVE_HANGING_SIGN = register("mangrove_hanging_sign", properties -> new CeilingHangingSignBlock(TFWoodTypes.MANGROVE_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).noCollision().strength(1.0F)); + public static final DeferredBlock MANGROVE_WALL_HANGING_SIGN = register("mangrove_wall_hanging_sign", properties -> new WallHangingSignBlock(TFWoodTypes.MANGROVE_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).noCollision().strength(1.0F).overrideLootTable(MANGROVE_HANGING_SIGN.get().getLootTable()).overrideDescription(MANGROVE_HANGING_SIGN.get().getDescriptionId())); + public static final DeferredBlock MANGROVE_BANISTER = registerWithItem("mangrove_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get())); + public static final DeferredBlock MANGROVE_DRYING_RACK = register("mangrove_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(MANGROVE_SLAB.get(), 0.5F)); + + public static final DeferredBlock DARK_PLANKS = registerWithItem("dark_planks", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.COLOR_ORANGE).strength(2.0F, 3.0F).sound(SoundType.WOOD)); + public static final DeferredBlock DARK_STAIRS = registerWithItem("dark_stairs", properties -> new StairBlock(DARK_PLANKS.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get())); + public static final DeferredBlock DARK_SLAB = registerWithItem("dark_slab", SlabBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).sound(SoundType.WOOD)); + public static final DeferredBlock DARK_BUTTON = registerWithItem("dark_button", properties -> new ButtonBlock(TFWoodTypes.DARK_WOOD_SET, 30, properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).noCollision().strength(0.5F)); + public static final DeferredBlock DARK_FENCE = registerWithItem("dark_fence", FenceBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get())); + public static final DeferredBlock DARK_GATE = registerWithItem("dark_fence_gate", properties -> new FenceGateBlock(TFWoodTypes.DARK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).forceSolidOn()); + public static final DeferredBlock DARK_PLATE = registerWithItem("dark_pressure_plate", properties -> new PressurePlateBlock(TFWoodTypes.DARK_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).forceSolidOn().noCollision().strength(0.5F)); + public static final DeferredBlock DARK_DOOR = registerWithItem("dark_door", properties -> new DoorBlock(TFWoodTypes.DARK_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).strength(3.0F).sound(SoundType.WOOD).noOcclusion()); + public static final DeferredBlock DARK_TRAPDOOR = registerWithItem("dark_trapdoor", properties -> new TrapDoorBlock(TFWoodTypes.DARK_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).strength(3.0F).noOcclusion()); + public static final DeferredBlock DARK_SIGN = register("dark_sign", properties -> new StandingSignBlock(TFWoodTypes.DARK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).strength(1.0F).noOcclusion().noCollision()); + public static final DeferredBlock DARK_WALL_SIGN = register("dark_wall_sign", properties -> new WallSignBlock(TFWoodTypes.DARK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).strength(1.0F).noOcclusion().noCollision().overrideLootTable(DARK_SIGN.get().getLootTable()).overrideDescription(DARK_SIGN.get().getDescriptionId())); + public static final DeferredBlock DARK_HANGING_SIGN = register("dark_hanging_sign", properties -> new CeilingHangingSignBlock(TFWoodTypes.DARK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).noCollision().strength(1.0F)); + public static final DeferredBlock DARK_WALL_HANGING_SIGN = register("dark_wall_hanging_sign", properties -> new WallHangingSignBlock(TFWoodTypes.DARK_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).noCollision().strength(1.0F).overrideLootTable(DARK_HANGING_SIGN.get().getLootTable()).overrideDescription(DARK_HANGING_SIGN.get().getDescriptionId())); + public static final DeferredBlock DARK_BANISTER = registerWithItem("dark_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get())); + public static final DeferredBlock DARK_DRYING_RACK = register("dark_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(DARK_SLAB.get(), 0.5F)); + + public static final DeferredBlock TIME_PLANKS = registerWithItem("time_planks", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.DIRT).strength(2.0F, 3.0F).sound(SoundType.WOOD)); + public static final DeferredBlock TIME_STAIRS = registerWithItem("time_stairs", properties -> new StairBlock(TIME_PLANKS.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get())); + public static final DeferredBlock TIME_SLAB = registerWithItem("time_slab", SlabBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).sound(SoundType.WOOD)); + public static final DeferredBlock TIME_BUTTON = registerWithItem("time_button", properties -> new ButtonBlock(TFWoodTypes.TIME_WOOD_SET, 30, properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).noCollision().strength(0.5F)); + public static final DeferredBlock TIME_FENCE = registerWithItem("time_fence", FenceBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get())); + public static final DeferredBlock TIME_GATE = registerWithItem("time_fence_gate", properties -> new FenceGateBlock(TFWoodTypes.TIME_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).forceSolidOn()); + public static final DeferredBlock TIME_PLATE = registerWithItem("time_pressure_plate", properties -> new PressurePlateBlock(TFWoodTypes.TIME_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).forceSolidOn().noCollision().strength(0.5F)); + public static final DeferredBlock TIME_DOOR = registerWithItem("time_door", properties -> new DoorBlock(TFWoodTypes.TIME_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).strength(3.0F).sound(SoundType.WOOD).noOcclusion()); + public static final DeferredBlock TIME_TRAPDOOR = registerWithItem("time_trapdoor", properties -> new TrapDoorBlock(TFWoodTypes.TIME_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).strength(3.0F).noOcclusion()); + public static final DeferredBlock TIME_SIGN = register("time_sign", properties -> new StandingSignBlock(TFWoodTypes.TIME_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).strength(1.0F).noOcclusion().noCollision()); + public static final DeferredBlock TIME_WALL_SIGN = register("time_wall_sign", properties -> new WallSignBlock(TFWoodTypes.TIME_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).strength(1.0F).noOcclusion().noCollision().overrideLootTable(TIME_SIGN.get().getLootTable()).overrideDescription(TIME_SIGN.get().getDescriptionId())); + public static final DeferredBlock TIME_HANGING_SIGN = register("time_hanging_sign", properties -> new CeilingHangingSignBlock(TFWoodTypes.TIME_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).noCollision().strength(1.0F)); + public static final DeferredBlock TIME_WALL_HANGING_SIGN = register("time_wall_hanging_sign", properties -> new WallHangingSignBlock(TFWoodTypes.TIME_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).noCollision().strength(1.0F).overrideLootTable(TIME_HANGING_SIGN.get().getLootTable()).overrideDescription(TIME_HANGING_SIGN.get().getDescriptionId())); + public static final DeferredBlock TIME_BANISTER = registerWithItem("time_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get())); + public static final DeferredBlock TIME_DRYING_RACK = register("time_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(TIME_SLAB.get(), 0.5F)); + + public static final DeferredBlock TRANSFORMATION_PLANKS = registerWithItem("transformation_planks", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.WOOD).strength(2.0F, 3.0F).sound(SoundType.WOOD)); + public static final DeferredBlock TRANSFORMATION_STAIRS = registerWithItem("transformation_stairs", properties -> new StairBlock(TRANSFORMATION_PLANKS.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get())); + public static final DeferredBlock TRANSFORMATION_SLAB = registerWithItem("transformation_slab", SlabBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get())); + public static final DeferredBlock TRANSFORMATION_BUTTON = registerWithItem("transformation_button", properties -> new ButtonBlock(TFWoodTypes.TRANSFORMATION_WOOD_SET, 30, properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).noCollision().strength(0.5F)); + public static final DeferredBlock TRANSFORMATION_FENCE = registerWithItem("transformation_fence", FenceBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get())); + public static final DeferredBlock TRANSFORMATION_GATE = registerWithItem("transformation_fence_gate", properties -> new FenceGateBlock(TFWoodTypes.TRANSFORMATION_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).forceSolidOn()); + public static final DeferredBlock TRANSFORMATION_PLATE = registerWithItem("transformation_pressure_plate", properties -> new PressurePlateBlock(TFWoodTypes.TRANSFORMATION_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).forceSolidOn().noCollision().strength(0.5F)); + public static final DeferredBlock TRANSFORMATION_DOOR = registerWithItem("transformation_door", properties -> new DoorBlock(TFWoodTypes.TRANSFORMATION_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).strength(3.0F).noOcclusion()); + public static final DeferredBlock TRANSFORMATION_TRAPDOOR = registerWithItem("transformation_trapdoor", properties -> new TrapDoorBlock(TFWoodTypes.TRANSFORMATION_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).strength(3.0F).noOcclusion()); + public static final DeferredBlock TRANSFORMATION_SIGN = register("transformation_sign", properties -> new StandingSignBlock(TFWoodTypes.TRANSFORMATION_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).strength(1.0F).noOcclusion().noCollision()); + public static final DeferredBlock TRANSFORMATION_WALL_SIGN = register("transformation_wall_sign", properties -> new WallSignBlock(TFWoodTypes.TRANSFORMATION_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).strength(1.0F).noOcclusion().noCollision().overrideLootTable(TRANSFORMATION_SIGN.get().getLootTable()).overrideDescription(TRANSFORMATION_SIGN.get().getDescriptionId())); + public static final DeferredBlock TRANSFORMATION_HANGING_SIGN = register("transformation_hanging_sign", properties -> new CeilingHangingSignBlock(TFWoodTypes.TRANSFORMATION_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).noCollision().strength(1.0F)); + public static final DeferredBlock TRANSFORMATION_WALL_HANGING_SIGN = register("transformation_wall_hanging_sign", properties -> new WallHangingSignBlock(TFWoodTypes.TRANSFORMATION_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).noCollision().strength(1.0F).overrideLootTable(TRANSFORMATION_HANGING_SIGN.get().getLootTable()).overrideDescription(TRANSFORMATION_HANGING_SIGN.get().getDescriptionId())); + public static final DeferredBlock TRANSFORMATION_BANISTER = registerWithItem("transformation_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get())); + public static final DeferredBlock TRANSFORMATION_DRYING_RACK = register("transformation_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(TRANSFORMATION_SLAB.get(), 0.5F)); + + public static final DeferredBlock MINING_PLANKS = registerWithItem("mining_planks", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.SAND).strength(2.0F, 3.0F).sound(SoundType.WOOD)); + public static final DeferredBlock MINING_STAIRS = registerWithItem("mining_stairs", properties -> new StairBlock(MINING_PLANKS.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get())); + public static final DeferredBlock MINING_SLAB = registerWithItem("mining_slab", SlabBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get())); + public static final DeferredBlock MINING_BUTTON = registerWithItem("mining_button", properties -> new ButtonBlock(TFWoodTypes.MINING_WOOD_SET, 30, properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).noCollision().strength(0.5F)); + public static final DeferredBlock MINING_FENCE = registerWithItem("mining_fence", FenceBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get())); + public static final DeferredBlock MINING_GATE = registerWithItem("mining_fence_gate", properties -> new FenceGateBlock(TFWoodTypes.MINING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).forceSolidOn()); + public static final DeferredBlock MINING_PLATE = registerWithItem("mining_pressure_plate", properties -> new PressurePlateBlock(TFWoodTypes.MINING_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).forceSolidOn().noCollision().strength(0.5F)); + public static final DeferredBlock MINING_DOOR = registerWithItem("mining_door", properties -> new DoorBlock(TFWoodTypes.MINING_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).strength(3.0F).noOcclusion()); + public static final DeferredBlock MINING_TRAPDOOR = registerWithItem("mining_trapdoor", properties -> new TrapDoorBlock(TFWoodTypes.MINING_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).strength(3.0F).noOcclusion()); + public static final DeferredBlock MINING_SIGN = register("mining_sign", properties -> new StandingSignBlock(TFWoodTypes.MINING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).strength(1.0F).noOcclusion().noCollision()); + public static final DeferredBlock MINING_WALL_SIGN = register("mining_wall_sign", properties -> new WallSignBlock(TFWoodTypes.MINING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).strength(1.0F).noOcclusion().noCollision().overrideLootTable(MINING_SIGN.get().getLootTable()).overrideDescription(MINING_SIGN.get().getDescriptionId())); + public static final DeferredBlock MINING_HANGING_SIGN = register("mining_hanging_sign", properties -> new CeilingHangingSignBlock(TFWoodTypes.MINING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).noCollision().strength(1.0F)); + public static final DeferredBlock MINING_WALL_HANGING_SIGN = register("mining_wall_hanging_sign", properties -> new WallHangingSignBlock(TFWoodTypes.MINING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).noCollision().strength(1.0F).overrideLootTable(MINING_HANGING_SIGN.get().getLootTable()).overrideDescription(MINING_HANGING_SIGN.get().getDescriptionId())); + public static final DeferredBlock MINING_BANISTER = registerWithItem("mining_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get())); + public static final DeferredBlock MINING_DRYING_RACK = register("mining_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(MINING_SLAB.get(), 0.5F)); + + public static final DeferredBlock SORTING_PLANKS = registerWithItem("sorting_planks", Block::new, () -> BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(MapColor.PODZOL).strength(2.0F, 3.0F).sound(SoundType.WOOD)); + public static final DeferredBlock SORTING_STAIRS = registerWithItem("sorting_stairs", properties -> new StairBlock(SORTING_PLANKS.get().defaultBlockState(), properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get())); + public static final DeferredBlock SORTING_SLAB = registerWithItem("sorting_slab", SlabBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get())); + public static final DeferredBlock SORTING_BUTTON = registerWithItem("sorting_button", properties -> new ButtonBlock(TFWoodTypes.SORTING_WOOD_SET, 30, properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).noCollision().strength(0.5F)); + public static final DeferredBlock SORTING_FENCE = registerWithItem("sorting_fence", FenceBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get())); + public static final DeferredBlock SORTING_GATE = registerWithItem("sorting_fence_gate", properties -> new FenceGateBlock(TFWoodTypes.SORTING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).forceSolidOn()); + public static final DeferredBlock SORTING_PLATE = registerWithItem("sorting_pressure_plate", properties -> new PressurePlateBlock(TFWoodTypes.SORTING_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).forceSolidOn().noCollision().strength(0.5F)); + public static final DeferredBlock SORTING_DOOR = registerWithItem("sorting_door", properties -> new DoorBlock(TFWoodTypes.SORTING_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).strength(3.0F).noOcclusion()); + public static final DeferredBlock SORTING_TRAPDOOR = registerWithItem("sorting_trapdoor", properties -> new TrapDoorBlock(TFWoodTypes.SORTING_WOOD_SET, properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).strength(3.0F).noOcclusion()); + public static final DeferredBlock SORTING_SIGN = register("sorting_sign", properties -> new StandingSignBlock(TFWoodTypes.SORTING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).strength(1.0F).noOcclusion().noCollision()); + public static final DeferredBlock SORTING_WALL_SIGN = register("sorting_wall_sign", properties -> new WallSignBlock(TFWoodTypes.SORTING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).strength(1.0F).noOcclusion().noCollision().overrideLootTable(SORTING_SIGN.get().getLootTable()).overrideDescription(SORTING_SIGN.get().getDescriptionId())); + public static final DeferredBlock SORTING_HANGING_SIGN = register("sorting_hanging_sign", properties -> new CeilingHangingSignBlock(TFWoodTypes.SORTING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).noCollision().strength(1.0F)); + public static final DeferredBlock SORTING_WALL_HANGING_SIGN = register("sorting_wall_hanging_sign", properties -> new WallHangingSignBlock(TFWoodTypes.SORTING_WOOD_TYPE, properties), () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).noCollision().strength(1.0F).overrideLootTable(SORTING_HANGING_SIGN.get().getLootTable()).overrideDescription(SORTING_HANGING_SIGN.get().getDescriptionId())); + public static final DeferredBlock SORTING_BANISTER = registerWithItem("sorting_banister", BanisterBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get())); + public static final DeferredBlock SORTING_DRYING_RACK = register("sorting_drying_rack", DryingRackBlock::new, () -> copyAndScaleProperties(SORTING_SLAB.get(), 0.5F)); + + public static final DeferredBlock TWILIGHT_OAK_CHEST = registerWithItem("twilight_oak_chest", TFChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).strength(2.5F)); + public static final DeferredBlock CANOPY_CHEST = registerWithItem("canopy_chest", TFChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).strength(2.5F)); + public static final DeferredBlock MANGROVE_CHEST = registerWithItem("mangrove_chest", TFChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).strength(2.5F)); + public static final DeferredBlock DARK_CHEST = registerWithItem("dark_chest", TFChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).strength(2.5F)); + public static final DeferredBlock TIME_CHEST = registerWithItem("time_chest", TFChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).strength(2.5F)); + public static final DeferredBlock TRANSFORMATION_CHEST = registerWithItem("transformation_chest", TFChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).strength(2.5F)); + public static final DeferredBlock MINING_CHEST = registerWithItem("mining_chest", TFChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).strength(2.5F)); + public static final DeferredBlock SORTING_CHEST = registerWithItem("sorting_chest", TFChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).strength(2.5F)); + + public static final DeferredBlock TWILIGHT_OAK_TRAPPED_CHEST = registerWithItem("twilight_oak_trapped_chest", TFTrappedChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_OAK_PLANKS.get()).strength(2.5F)); + public static final DeferredBlock CANOPY_TRAPPED_CHEST = registerWithItem("canopy_trapped_chest", TFTrappedChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(CANOPY_PLANKS.get()).strength(2.5F)); + public static final DeferredBlock MANGROVE_TRAPPED_CHEST = registerWithItem("mangrove_trapped_chest", TFTrappedChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MANGROVE_PLANKS.get()).strength(2.5F)); + public static final DeferredBlock DARK_TRAPPED_CHEST = registerWithItem("dark_trapped_chest", TFTrappedChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(DARK_PLANKS.get()).strength(2.5F)); + public static final DeferredBlock TIME_TRAPPED_CHEST = registerWithItem("time_trapped_chest", TFTrappedChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TIME_PLANKS.get()).strength(2.5F)); + public static final DeferredBlock TRANSFORMATION_TRAPPED_CHEST = registerWithItem("transformation_trapped_chest", TFTrappedChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TRANSFORMATION_PLANKS.get()).strength(2.5F)); + public static final DeferredBlock MINING_TRAPPED_CHEST = registerWithItem("mining_trapped_chest", TFTrappedChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(MINING_PLANKS.get()).strength(2.5F)); + public static final DeferredBlock SORTING_TRAPPED_CHEST = registerWithItem("sorting_trapped_chest", TFTrappedChestBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(SORTING_PLANKS.get()).strength(2.5F)); + + //Flower Pots + public static final DeferredBlock POTTED_TWILIGHT_OAK_SAPLING = register("potted_twilight_oak_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, TWILIGHT_OAK_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); + public static final DeferredBlock POTTED_CANOPY_SAPLING = register("potted_canopy_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, CANOPY_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); + public static final DeferredBlock POTTED_MANGROVE_SAPLING = register("potted_mangrove_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, MANGROVE_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); + public static final DeferredBlock POTTED_DARKWOOD_SAPLING = register("potted_darkwood_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, DARKWOOD_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); + public static final DeferredBlock POTTED_HOLLOW_OAK_SAPLING = register("potted_hollow_oak_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, HOLLOW_OAK_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); + public static final DeferredBlock POTTED_RAINBOW_OAK_SAPLING = register("potted_rainbow_oak_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, RAINBOW_OAK_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); + public static final DeferredBlock POTTED_TIME_SAPLING = register("potted_time_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, TIME_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); + public static final DeferredBlock POTTED_TRANSFORMATION_SAPLING = register("potted_transformation_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, TRANSFORMATION_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); + public static final DeferredBlock POTTED_MINING_SAPLING = register("potted_mining_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, MINING_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); + public static final DeferredBlock POTTED_SORTING_SAPLING = register("potted_sorting_sapling", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, SORTING_SAPLING, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); + public static final DeferredBlock POTTED_MAYAPPLE = register("potted_mayapple", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, MAYAPPLE, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); + public static final DeferredBlock POTTED_FIDDLEHEAD = register("potted_fiddlehead", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, FIDDLEHEAD, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); + public static final DeferredBlock POTTED_MUSHGLOOM = register("potted_mushgloom", properties -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, MUSHGLOOM, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); + public static final DeferredBlock POTTED_THORN = register("potted_thorn", properties -> new SpecialFlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, BROWN_THORNS, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); + public static final DeferredBlock POTTED_GREEN_THORN = register("potted_green_thorn", properties -> new SpecialFlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, GREEN_THORNS, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); + public static final DeferredBlock POTTED_DEAD_THORN = register("potted_dead_thorn", properties -> new SpecialFlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, BURNT_THORNS, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.FLOWER_POT)); + + public static DeferredBlock register(String name, Function block, Supplier properties) { + return BLOCKS.register(name, () -> block.apply(properties.get().setId(ResourceKey.create(Registries.BLOCK, TwilightForestMod.prefix(name))))); + } + + public static DeferredBlock registerCustomID(String name, Function block, Supplier properties, String id) { + return BLOCKS.register(name, () -> block.apply(properties.get().setId(ResourceKey.create(Registries.BLOCK, TwilightForestMod.prefix(name))).overrideDescription("block.twilightforest." + id))); + } + + public static DeferredBlock registerWithItem(String name, Function block, Supplier properties) { + return registerWithItem(name, block, properties, Item.Properties::new); + } + + public static DeferredBlock registerWithItem(String name, Function block, Supplier properties, Supplier itemProperties) { + DeferredBlock ret = register(name, block, properties); + TFItems.register(name, itemProps -> new BlockItem(ret.get(), itemProps.useBlockDescriptionPrefix()), itemProperties); + return ret; + } + + public static DeferredBlock ominousCandle(String name, MapColor mapColor, Block candle) { + return BLOCKS.register(name, () -> new OminousCandleBlock(candle, + BlockBehaviour.Properties.of() + .mapColor(mapColor) + .noOcclusion() + .strength(0.1F) + .sound(SoundType.CANDLE) + .lightLevel(state -> 2 * state.getValue(OminousCandleBlock.CANDLES)) + .pushReaction(PushReaction.DESTROY) + )); + } + + private static BlockBehaviour.Properties logProperties(MapColor color) { + return BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor(color); + } + + private static BlockBehaviour.Properties logProperties(MapColor top, MapColor side) { + return BlockBehaviour.Properties.of().ignitedByLava().instrument(NoteBlockInstrument.BASS).mapColor((state) -> state.getValue(RotatedPillarBlock.AXIS) == Direction.Axis.Y ? top : side); + } + + public static BlockBehaviour.Properties copyAndScaleProperties(BlockBehaviour blockBehaviour, float scale) { + BlockBehaviour.Properties properties = BlockBehaviour.Properties.ofFullCopy(blockBehaviour); + return properties.destroyTime(blockBehaviour.defaultDestroyTime() * scale).explosionResistance(properties.explosionResistance * scale); + } + + private static boolean noSpawning(BlockState pState, BlockGetter pLevel, BlockPos pPos, EntityType pValue) { + return false; + } +} diff --git a/src/main/java/twilightforest/util/UnbakedGeometryUtil.java b/src/main/java/twilightforest/util/UnbakedGeometryUtil.java new file mode 100644 index 0000000000..9e09db00e9 --- /dev/null +++ b/src/main/java/twilightforest/util/UnbakedGeometryUtil.java @@ -0,0 +1,41 @@ +package twilightforest.util; + +import net.minecraft.client.renderer.block.dispatch.ModelState; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.ModelBaker; +import net.minecraft.client.resources.model.cuboid.CuboidFace; +import net.minecraft.client.resources.model.cuboid.CuboidModelElement; +import net.minecraft.client.resources.model.cuboid.FaceBakery; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.sprite.Material; +import net.minecraft.core.Direction; +import twilightforest.client.model.block.connected.ConnectionLogic; + +// this class returns back removed methods from the sources +public class UnbakedGeometryUtil { + public static CuboidFace.UVs uvsByFace(Direction face, CuboidModelElement element) { + return switch (face) { + case DOWN -> new CuboidFace.UVs(element.from().x(), 16.0F - element.to().z(), element.to().x(), 16.0F - element.from().z()); + case UP -> new CuboidFace.UVs(element.from().x(), element.from().z(), element.to().x(), element.to().z()); + case SOUTH -> new CuboidFace.UVs(element.from().x(), 16.0F - element.to().y(), element.to().x(), 16.0F - element.from().y()); + case WEST -> new CuboidFace.UVs(element.from().z(), 16.0F - element.to().y(), element.to().z(), 16.0F - element.from().y()); + case EAST -> new CuboidFace.UVs(16.0F - element.to().z(), 16.0F - element.to().y(), 16.0F - element.from().z(), 16.0F - element.from().y()); + default -> new CuboidFace.UVs(16.0F - element.to().x(), 16.0F - element.to().y(), 16.0F - element.from().x(), 16.0F - element.from().y()); + }; + } + + public static BakedQuad bakeElementFace(ModelBaker baker, CuboidModelElement element, CuboidFace face, Material.Baked sprite, Direction direction, ModelState state) { + return FaceBakery.bakeQuad(baker, element.from(), element.to(), face, sprite, direction, state, null, element.shade(), 0); + } + + public static Material.Baked chooseAndBake(ConnectionLogic target, TextureAtlasSprite[] spriteOptions, Material[] materials) { + TextureAtlasSprite unbakedChoice = target.chooseTexture(spriteOptions); + // spriteOptions.length should be equal to materials.length + for (int i = 0; i < spriteOptions.length; i++) { + if (unbakedChoice == spriteOptions[i]) { + return new Material.Baked(spriteOptions[i], materials[i].forceTranslucent()); + } + } + return new Material.Baked(spriteOptions[0], false); + } +} From 06d4e51cdebf42db4afdd65c78c315aaa8c1e051 Mon Sep 17 00:00:00 2001 From: Albazavr Date: Mon, 20 Jul 2026 02:46:08 +0300 Subject: [PATCH 14/18] Removed wrong fixes --- .../block/CoronationCarpetBlock.java | 76 -------- .../entity/CoronationCarpetBlockEntity.java | 73 ------- .../model/block/carpet/RoyalRagsBuilder.java | 17 ++ .../model/block/carpet/RoyalRagsModel.java | 184 ++++++++++++++++++ .../block/carpet/RoyalRagsModelLoader.java | 4 +- .../block/carpet/UnbakedRoyalRagsModel.java | 101 ++++------ .../connected/ConnectedTextureModel.java | 130 ++++++++++--- .../ConnectedTextureModelLoader.java | 2 +- .../block/connected/ConnectionLogic.java | 6 +- .../UnbakedConnectedTextureModel.java | 184 +++++++----------- .../block/forcefield/ForceFieldModel.java | 177 +++++++++-------- .../forcefield/ForceFieldModelBuilder.java | 101 ++++++---- .../forcefield/ForceFieldModelLoader.java | 10 +- .../forcefield/UnbakedForceFieldModel.java | 23 +-- .../block/giantblock/GiantBlockBuilder.java | 1 - .../client/model/block/patch/PatchModel.java | 134 +++++++------ .../model/block/patch/UnbakedPatchModel.java | 9 +- .../twilightforest/init/TFBlockEntities.java | 2 - .../java/twilightforest/init/TFBlocks.java | 4 +- .../util/UnbakedGeometryUtil.java | 40 ++-- 20 files changed, 688 insertions(+), 590 deletions(-) delete mode 100644 src/main/java/twilightforest/block/CoronationCarpetBlock.java delete mode 100644 src/main/java/twilightforest/block/entity/CoronationCarpetBlockEntity.java create mode 100644 src/main/java/twilightforest/client/model/block/carpet/RoyalRagsBuilder.java create mode 100644 src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModel.java diff --git a/src/main/java/twilightforest/block/CoronationCarpetBlock.java b/src/main/java/twilightforest/block/CoronationCarpetBlock.java deleted file mode 100644 index 90a3501765..0000000000 --- a/src/main/java/twilightforest/block/CoronationCarpetBlock.java +++ /dev/null @@ -1,76 +0,0 @@ -package twilightforest.block; - -import com.mojang.serialization.MapCodec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.util.RandomSource; -import net.minecraft.world.item.DyeColor; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.ScheduledTickAccess; -import net.minecraft.world.level.block.BaseEntityBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.WoolCarpetBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; -import org.jspecify.annotations.Nullable; -import twilightforest.block.entity.CoronationCarpetBlockEntity; -import twilightforest.init.TFBlockEntities; - -// [VanillaCopy] extended WoolCarpetBlock with BlockEntity -public class CoronationCarpetBlock extends BaseEntityBlock { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec((i) -> i.group(DyeColor.CODEC.fieldOf("color").forGetter(CoronationCarpetBlock::getColor), propertiesCodec()).apply(i, CoronationCarpetBlock::new)); - private static final VoxelShape SHAPE = Block.column(16.0D, 0.0D, 1.0D); - - private final DyeColor color; - - public CoronationCarpetBlock(DyeColor color, Properties properties) { - super(properties); - this.color = color; - } - - @Override - protected MapCodec codec() { - return CODEC; - } - - @Override - public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) { - return new CoronationCarpetBlockEntity(blockPos, blockState); - } - - @Override - protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { - return SHAPE; - } - - @Override - protected BlockState updateShape(BlockState state, LevelReader level, ScheduledTickAccess ticks, BlockPos pos, Direction directionToNeighbour, BlockPos neighbourPos, BlockState neighbourState, RandomSource random) { - if (!state.canSurvive(level, pos)) { - return Blocks.AIR.defaultBlockState(); - } - - if (level instanceof Level world && world.isClientSide()) { - BlockEntity blockEntity = world.getBlockEntity(pos); - if (blockEntity instanceof CoronationCarpetBlockEntity) { - world.getModelDataManager().requestRefresh(blockEntity); - } - } - - return super.updateShape(state, level, ticks, pos, directionToNeighbour, neighbourPos, neighbourState, random); - } - - @Override - protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) { - return !level.isEmptyBlock(pos.below()); - } - - public DyeColor getColor() { - return color; - } -} diff --git a/src/main/java/twilightforest/block/entity/CoronationCarpetBlockEntity.java b/src/main/java/twilightforest/block/entity/CoronationCarpetBlockEntity.java deleted file mode 100644 index 6cbe86227f..0000000000 --- a/src/main/java/twilightforest/block/entity/CoronationCarpetBlockEntity.java +++ /dev/null @@ -1,73 +0,0 @@ -package twilightforest.block.entity; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.neoforged.neoforge.model.data.ModelData; -import net.neoforged.neoforge.model.data.ModelProperty; -import twilightforest.client.model.block.connected.ConnectionLogic; -import twilightforest.init.TFBlockEntities; -import twilightforest.init.TFBlocks; - -import java.util.Arrays; - -public class CoronationCarpetBlockEntity extends BlockEntity { - private final Block[] validConnectors = {TFBlocks.CORONATION_CARPET.value()}; - private static final ModelProperty DATA = new ModelProperty<>(); - - public CoronationCarpetBlockEntity(BlockPos worldPosition, BlockState blockState) { - super(TFBlockEntities.CORONATION_CARPET.get(), worldPosition, blockState); - } - - @Override - public ModelData getModelData() { - if (this.level == null) { - return ModelData.EMPTY; - } - - LoftyCarpetData data = new LoftyCarpetData(); - - for (Direction face : Direction.values()) { - Direction[] directions = ConnectionLogic.AXIS_PLANE_DIRECTIONS[face.getAxis().ordinal()]; - boolean[] sideStates = new boolean[4]; - - int faceIndex; - for (faceIndex = 0; faceIndex < directions.length; faceIndex++) { - sideStates[faceIndex] = this.shouldConnectSide(this.level, this.worldPosition, face, directions[faceIndex]); - } - - faceIndex = face.get3DDataValue(); - - for (int dir = 0; dir < directions.length; dir++) { - int cornerOffset = (dir + 1) % directions.length; - boolean side1 = sideStates[dir]; - boolean side2 = sideStates[cornerOffset]; - boolean corner = side1 && side2 && this.isCornerBlockPresent(this.level, this.worldPosition, face, directions[dir], directions[cornerOffset]); - data.logic[faceIndex][dir] = dir % 2 == 0 ? ConnectionLogic.of(side1, side2, corner) : ConnectionLogic.of(side2, side1, corner); - } - } - - return ModelData.EMPTY.derive().with(DATA, data).build(); - } - - private boolean shouldConnectSide(BlockGetter getter, BlockPos pos, Direction face, Direction side) { - BlockState neighborState = getter.getBlockState(pos.relative(side)); - return Arrays.stream(this.validConnectors).anyMatch(neighborState::is) && Block.shouldRenderFace(getter, pos, getter.getBlockState(pos), neighborState, face); - } - - private boolean isCornerBlockPresent(BlockGetter getter, BlockPos pos, Direction face, Direction side1, Direction side2) { - BlockState neighborState = getter.getBlockState(pos.relative(side1).relative(side2)); - return Arrays.stream(this.validConnectors).anyMatch(neighborState::is) && Block.shouldRenderFace(getter, pos, getter.getBlockState(pos), neighborState, face); - } - - //we need a class to make model data. Fine, here you go - private static final class LoftyCarpetData { - private final ConnectionLogic[][] logic = new ConnectionLogic[6][4]; - - private LoftyCarpetData() { - } - } -} diff --git a/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsBuilder.java b/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsBuilder.java new file mode 100644 index 0000000000..b6548da59f --- /dev/null +++ b/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsBuilder.java @@ -0,0 +1,17 @@ +package twilightforest.client.model.block.carpet; + +import net.neoforged.neoforge.client.model.generators.CustomLoaderBuilder; +import net.neoforged.neoforge.client.model.generators.ModelBuilder; +import net.neoforged.neoforge.common.data.ExistingFileHelper; +import twilightforest.TwilightForestMod; + +public class RoyalRagsBuilder> extends CustomLoaderBuilder { + + protected RoyalRagsBuilder(T parent, ExistingFileHelper existingFileHelper) { + super(TwilightForestMod.prefix("royal_rags"), parent, existingFileHelper, false); + } + + public static > RoyalRagsBuilder begin(T parent, ExistingFileHelper helper) { + return new RoyalRagsBuilder<>(parent, helper); + } +} \ No newline at end of file diff --git a/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModel.java b/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModel.java new file mode 100644 index 0000000000..e80e8fce5b --- /dev/null +++ b/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModel.java @@ -0,0 +1,184 @@ +package twilightforest.client.model.block.carpet; + +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.ItemOverrides; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.neoforged.neoforge.client.ChunkRenderTypeSet; +import net.neoforged.neoforge.client.RenderTypeGroup; +import net.neoforged.neoforge.client.model.IDynamicBakedModel; +import net.neoforged.neoforge.client.model.data.ModelData; +import net.neoforged.neoforge.client.model.data.ModelProperty; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import twilightforest.client.model.block.connected.ConnectionLogic; +import twilightforest.init.TFBlocks; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@SuppressWarnings("deprecation") +public class RoyalRagsModel implements IDynamicBakedModel { + @Nullable + private final List[] baseQuads; + private final BakedQuad[][][] quads; + private final TextureAtlasSprite particle; + private final ItemOverrides overrides; + private final ItemTransforms transforms; + private final ChunkRenderTypeSet blockRenderTypes; + private final List itemRenderTypes; + private final List fabulousItemRenderTypes; + // FIXME Generalize + private final Block[] validConnectors = {TFBlocks.CORONATION_CARPET.value()}; + private static final ModelProperty DATA = new ModelProperty<>(); + + public RoyalRagsModel(@Nullable List[] baseQuads, BakedQuad[][][] quads, TextureAtlasSprite particle, ItemOverrides overrides, ItemTransforms transforms, RenderTypeGroup group) { + this.baseQuads = baseQuads; + this.quads = quads; + this.particle = particle; + this.overrides = overrides; + this.transforms = transforms; + this.blockRenderTypes = !group.isEmpty() ? ChunkRenderTypeSet.of(group.block()) : null; + this.itemRenderTypes = !group.isEmpty() ? List.of(group.entity()) : null; + this.fabulousItemRenderTypes = !group.isEmpty() ? List.of(group.entityFabulous()) : null; + } + + @NotNull + @Override + public List getQuads(@Nullable BlockState state, @Nullable Direction side, @NotNull RandomSource random, @NotNull ModelData extraData, @Nullable RenderType type) { + if (side != null) { + ArrayList quads = new ArrayList<>(4 + (this.baseQuads != null ? 4 : 0)); + if (side.getAxis().isHorizontal()) { + if (this.baseQuads != null) { + quads.addAll(this.baseQuads[side.get2DDataValue()]); + } + } else { + int faceIndex = side.get3DDataValue(); + LoftyCarpetData data = extraData.get(DATA); + for (int quad = 0; quad < 4; ++quad) { + //if our model data is null (I really hope it isn't) we can skip connected textures since we dont have the info we need + //i'd rather do this than crash the game or skip rendering the block entirely + ConnectionLogic connectionType = data != null ? data.logic[faceIndex][quad] : ConnectionLogic.NONE; + quads.add(this.quads[faceIndex][quad][connectionType.ordinal()]); + } + } + + return quads; + } else { + return List.of(); + } + } + + @NotNull + @Override + public ModelData getModelData(@NotNull BlockAndTintGetter getter, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull ModelData modelData) { + LoftyCarpetData data = new LoftyCarpetData(); + + for (Direction face : Direction.values()) { + Direction[] directions = ConnectionLogic.AXIS_PLANE_DIRECTIONS[face.getAxis().ordinal()]; + boolean[] sideStates = new boolean[4]; + + int faceIndex; + for (faceIndex = 0; faceIndex < directions.length; faceIndex++) { + sideStates[faceIndex] = this.shouldConnectSide(getter, pos, face, directions[faceIndex]); + } + + faceIndex = face.get3DDataValue(); + + for (int dir = 0; dir < directions.length; dir++) { + int cornerOffset = (dir + 1) % directions.length; + boolean side1 = sideStates[dir]; + boolean side2 = sideStates[cornerOffset]; + boolean corner = side1 && side2 && this.isCornerBlockPresent(getter, pos, face, directions[dir], directions[cornerOffset]); + data.logic[faceIndex][dir] = dir % 2 == 0 ? ConnectionLogic.of(side1, side2, corner) : ConnectionLogic.of(side2, side1, corner); + } + } + + return modelData.derive().with(DATA, data).build(); + } + + private boolean shouldConnectSide(BlockAndTintGetter getter, BlockPos pos, Direction face, Direction side) { + BlockState neighborState = getter.getBlockState(pos.relative(side)); + return Arrays.stream(this.validConnectors).anyMatch(neighborState::is) && Block.shouldRenderFace(neighborState, getter, pos, face, pos.relative(face)); + } + + private boolean isCornerBlockPresent(BlockAndTintGetter getter, BlockPos pos, Direction face, Direction side1, Direction side2) { + BlockState neighborState = getter.getBlockState(pos.relative(side1).relative(side2)); + return Arrays.stream(this.validConnectors).anyMatch(neighborState::is) && Block.shouldRenderFace(neighborState, getter, pos, face, pos.relative(face)); + } + + @Override + public boolean useAmbientOcclusion() { + return true; + } + + @Override + public boolean isGui3d() { + return true; + } + + @Override + public boolean usesBlockLight() { + return true; + } + + @Override + public boolean isCustomRenderer() { + return false; + } + + @NotNull + @Override + public TextureAtlasSprite getParticleIcon() { + return this.particle; + } + + @NotNull + @Override + public ItemOverrides getOverrides() { + return this.overrides; + } + + @NotNull + @Override + public ItemTransforms getTransforms() { + return this.transforms; + } + + @NotNull + @Override + public ChunkRenderTypeSet getRenderTypes(@NotNull BlockState state, @NotNull RandomSource rand, @NotNull ModelData data) { + return this.blockRenderTypes != null ? this.blockRenderTypes : IDynamicBakedModel.super.getRenderTypes(state, rand, data); + } + + @NotNull + @Override + public List getRenderTypes(@NotNull ItemStack stack, boolean fabulous) { + if (!fabulous) { + if (this.itemRenderTypes != null) { + return this.itemRenderTypes; + } + } else if (this.fabulousItemRenderTypes != null) { + return this.fabulousItemRenderTypes; + } + + return IDynamicBakedModel.super.getRenderTypes(stack, fabulous); + } + + //we need a class to make model data. Fine, here you go + private static final class LoftyCarpetData { + private final ConnectionLogic[][] logic = new ConnectionLogic[6][4]; + + private LoftyCarpetData() { + } + } +} \ No newline at end of file diff --git a/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java b/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java index 7fca73cb5a..f73af20a25 100644 --- a/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java +++ b/src/main/java/twilightforest/client/model/block/carpet/RoyalRagsModelLoader.java @@ -3,9 +3,9 @@ import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import net.neoforged.neoforge.client.model.UnbakedModelLoader; +import net.neoforged.neoforge.client.model.geometry.IGeometryLoader; -public class RoyalRagsModelLoader implements UnbakedModelLoader { +public class RoyalRagsModelLoader implements IGeometryLoader { @Deprecated // FIXME: Generalize alongside with CastleDoor models public static final RoyalRagsModelLoader INSTANCE = new RoyalRagsModelLoader(); diff --git a/src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java b/src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java index 3ac7de26a5..9e3452b574 100644 --- a/src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java +++ b/src/main/java/twilightforest/client/model/block/carpet/UnbakedRoyalRagsModel.java @@ -1,134 +1,105 @@ package twilightforest.client.model.block.carpet; -import com.mojang.math.Quadrant; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.block.dispatch.ModelState; +import com.mojang.math.Transformation; +import net.minecraft.client.renderer.block.model.*; import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.Material; import net.minecraft.client.resources.model.ModelBaker; -import net.minecraft.client.resources.model.ModelDebugName; -import net.minecraft.client.resources.model.cuboid.CuboidFace; -import net.minecraft.client.resources.model.cuboid.CuboidModelElement; -import net.minecraft.client.resources.model.geometry.BakedQuad; -import net.minecraft.client.resources.model.geometry.QuadCollection; -import net.minecraft.client.resources.model.geometry.UnbakedGeometry; -import net.minecraft.client.resources.model.sprite.Material; -import net.minecraft.client.resources.model.sprite.TextureSlots; +import net.minecraft.client.resources.model.ModelState; import net.minecraft.core.Direction; import net.minecraft.core.Vec3i; -import net.minecraft.data.AtlasIds; -import org.jetbrains.annotations.Nullable; +import net.minecraft.resources.Identifier; +import net.neoforged.neoforge.client.RenderTypeGroup; +import net.neoforged.neoforge.client.model.SimpleModelState; +import net.neoforged.neoforge.client.model.geometry.IGeometryBakingContext; +import net.neoforged.neoforge.client.model.geometry.IUnbakedGeometry; +import net.neoforged.neoforge.client.model.geometry.UnbakedGeometryHelper; +import org.apache.commons.lang3.mutable.MutableObject; import org.joml.Vector3f; import twilightforest.client.model.block.connected.ConnectionLogic; -import twilightforest.util.UnbakedGeometryUtil; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.function.Function; //for now, im keeping this hardcoded to a 2 layer block, with the overlay layer being fullbright and tinted. //It might be worth expanding this in the future to be more flexible for other kinds of blocks (1 layer blocks, determining emissivity and tinting per layer, maybe >2 layer blocks?) but for now, I see no point. //I only wanted this system for castle doors after all! -public class UnbakedRoyalRagsModel implements UnbakedGeometry { +public class UnbakedRoyalRagsModel implements IUnbakedGeometry { - private final CuboidModelElement[][] baseElements; - private final CuboidModelElement[][][] faceElements; + private final BlockElement[][] baseElements; + private final BlockElement[][][] faceElements; public UnbakedRoyalRagsModel() { //base elements - the side faces without ctm. No Connected Textures on this bit. //the array is made of horizontal directions (Direction.get2DDataValue) and quads - this.baseElements = new CuboidModelElement[4][4]; + this.baseElements = new BlockElement[4][4]; //face elements - the connected bit of the model. //the array is made of the directions, quads, and each logic value in the ConnectionLogic class //Topmost array indexes to up/dpwn directions (Direction.get3DDataValue, down = 0, up = 1) then inside are quads - this.faceElements = new CuboidModelElement[2][4][5]; + this.faceElements = new BlockElement[2][4][5]; Vec3i center = new Vec3i(8, 8, 8); for (Direction face : Direction.values()) { Direction[] planeDirections = ConnectionLogic.AXIS_PLANE_DIRECTIONS[face.getAxis().ordinal()]; for (int quad = 0; quad < 4; quad++) { - Vec3i corner = face.getUnitVec3i().offset(planeDirections[quad].getUnitVec3i()).offset(planeDirections[(quad + 1) % 4].getUnitVec3i()).offset(1, 1, 1).multiply(8); - CuboidModelElement element = new CuboidModelElement(new Vector3f((float) Math.min(center.getX(), corner.getX()), (float) Math.min(center.getY(), corner.getY()) / 16f, (float) Math.min(center.getZ(), corner.getZ())), new Vector3f((float) Math.max(center.getX(), corner.getX()), (float) Math.max(center.getY(), corner.getY()) / 16f, (float) Math.max(center.getZ(), corner.getZ())), Map.of()); + Vec3i corner = face.getNormal().offset(planeDirections[quad].getNormal()).offset(planeDirections[(quad + 1) % 4].getNormal()).offset(1, 1, 1).multiply(8); + BlockElement element = new BlockElement(new Vector3f((float) Math.min(center.getX(), corner.getX()), (float) Math.min(center.getY(), corner.getY()) / 16f, (float) Math.min(center.getZ(), corner.getZ())), new Vector3f((float) Math.max(center.getX(), corner.getX()), (float) Math.max(center.getY(), corner.getY()) / 16f, (float) Math.max(center.getZ(), corner.getZ())), Map.of(), null, true); if (face.getAxis().isHorizontal()) { - this.baseElements[face.get2DDataValue()][quad] = new CuboidModelElement(element.from(), element.to(), Map.of(face, new CuboidFace(face, -1, "", ConnectionLogic.NONE.remapUVs(UnbakedGeometryUtil.uvsByFace(face, element)), Quadrant.R0))); + this.baseElements[face.get2DDataValue()][quad] = new BlockElement(element.from, element.to, Map.of(face, new BlockElementFace(face, -1, "", new BlockFaceUV(ConnectionLogic.NONE.remapUVs(element.uvsByFace(face)), 0))), null, true); } else { for (ConnectionLogic connectionType : ConnectionLogic.values()) { - this.faceElements[face.get3DDataValue()][quad][connectionType.ordinal()] = new CuboidModelElement(element.from(), element.to(), Map.of(face, new CuboidFace(face, 0, "", connectionType.remapUVs(UnbakedGeometryUtil.uvsByFace(face, element)), Quadrant.R0))); + this.faceElements[face.get3DDataValue()][quad][connectionType.ordinal()] = new BlockElement(element.from, element.to, Map.of(face, new BlockElementFace(face, 0, "", new BlockFaceUV(connectionType.remapUVs(element.uvsByFace(face)), 0), null, new MutableObject<>())), null, true); } } } } } - public QuadCollection getQuads(@Nullable Direction side, List[] baseQuads, BakedQuad[][][] quads) { - if (side != null) { - QuadCollection.Builder builder = new QuadCollection.Builder(); - if (side.getAxis().isHorizontal()) { - if (baseQuads != null) { - for (BakedQuad bakedQuad : baseQuads[side.get2DDataValue()]) { - builder.addCulledFace(side, bakedQuad); - } - } - } else { - int faceIndex = side.get3DDataValue(); - for (int quad = 0; quad < 4; ++quad) { - ConnectionLogic connectionType = ConnectionLogic.NONE; - builder.addCulledFace(side, quads[faceIndex][quad][connectionType.ordinal()]); - } - } + @Override + public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, Function spriteGetter, ModelState modelState, ItemOverrides overrides) { + Transformation transformation = context.getRootTransform(); - return builder.build(); - } else { - return QuadCollection.EMPTY; + if (!transformation.isIdentity()) { + modelState = new SimpleModelState(modelState.getRotation().compose(transformation), modelState.isUvLocked()); } - } - @Override - public QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName modelDebugName) { //making an array list like this is cursed, would not recommend @SuppressWarnings("unchecked") //this is fine, I hope List[] baseQuads = (List[]) Array.newInstance(List.class, 4); - Material baseMaterial = textureSlots.getMaterial("wool"); - TextureAtlasSprite baseTexture = Minecraft.getInstance().getAtlasManager().getAtlasOrThrow(AtlasIds.BLOCKS).getSprite(baseMaterial.sprite()); - Material.Baked baseBakedMaterial = new Material.Baked(baseTexture, baseMaterial.forceTranslucent()); - - Material ctmMaterial = textureSlots.getMaterial("wool_ctm"); - TextureAtlasSprite ctmTexture = Minecraft.getInstance().getAtlasManager().getAtlasOrThrow(AtlasIds.BLOCKS).getSprite(ctmMaterial.sprite()); + TextureAtlasSprite baseTexture = spriteGetter.apply(context.getMaterial("wool")); for (Direction direction : Direction.Plane.HORIZONTAL) { baseQuads[direction.get2DDataValue()] = new ArrayList<>(); - for (CuboidModelElement element : this.baseElements[direction.get2DDataValue()]) { - baseQuads[direction.get2DDataValue()].add(UnbakedGeometryUtil.bakeElementFace(modelBaker, element, element.faces().values().iterator().next(), baseBakedMaterial, direction, modelState)); + for (BlockElement element : this.baseElements[direction.get2DDataValue()]) { + baseQuads[direction.get2DDataValue()].add(UnbakedGeometryHelper.bakeElementFace(element, element.faces.values().iterator().next(), baseTexture, direction, modelState)); } } //we'll use this to figure out which texture to use with the Connected Texture logic //NONE uses the first one, everything else uses the 2nd one - TextureAtlasSprite[] sprites = new TextureAtlasSprite[]{baseTexture, ctmTexture}; - Material[] materials = new Material[]{baseMaterial, ctmMaterial}; + TextureAtlasSprite[] sprites = new TextureAtlasSprite[]{spriteGetter.apply(context.getMaterial("wool")), spriteGetter.apply(context.getMaterial("wool_ctm"))}; BakedQuad[][][] quads = new BakedQuad[2][4][5]; for (int dir = 0; dir < 2; dir++) { for (int quad = 0; quad < 4; quad++) { for (int type = 0; type < 5; type++) { - CuboidModelElement element = this.faceElements[dir][quad][type]; - Material.Baked bakedChoice = UnbakedGeometryUtil.chooseAndBake(ConnectionLogic.values()[type], sprites, materials); - quads[dir][quad][type] = UnbakedGeometryUtil.bakeElementFace(modelBaker, element, element.faces().values().iterator().next(), bakedChoice, Direction.values()[dir], modelState); + BlockElement element = this.faceElements[dir][quad][type]; + quads[dir][quad][type] = UnbakedGeometryHelper.bakeElementFace(element, element.faces.values().iterator().next(), ConnectionLogic.values()[type].chooseTexture(sprites), Direction.values()[dir], modelState); } } } - QuadCollection.Builder builder = new QuadCollection.Builder(); - - for (Direction value : Direction.values()) { - builder.addAll(getQuads(value, baseQuads, quads)); - } - - return builder.build(); + Identifier renderTypeHint = context.getRenderTypeHint(); + RenderTypeGroup renderTypes = renderTypeHint != null ? context.getRenderType(renderTypeHint) : RenderTypeGroup.EMPTY; + return new RoyalRagsModel(baseQuads, quads, spriteGetter.apply(context.getMaterial("wool")), overrides, context.getTransforms(), renderTypes); } } \ No newline at end of file diff --git a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java index d72ca1e978..b853ee29c5 100644 --- a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java +++ b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModel.java @@ -1,61 +1,65 @@ package twilightforest.client.model.block.connected; -import net.minecraft.client.renderer.block.BlockAndTintGetter; -import net.minecraft.client.renderer.block.dispatch.ModelState; -import net.minecraft.client.resources.model.ModelBaker; -import net.minecraft.client.resources.model.ModelDebugName; -import net.minecraft.client.resources.model.geometry.BakedQuad; -import net.minecraft.client.resources.model.geometry.QuadCollection; -import net.minecraft.client.resources.model.geometry.UnbakedGeometry; -import net.minecraft.client.resources.model.sprite.TextureSlots; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; -import net.neoforged.neoforge.model.data.ModelData; -import net.neoforged.neoforge.model.data.ModelProperty; -import org.jetbrains.annotations.NotNull; +import net.neoforged.neoforge.client.ChunkRenderTypeSet; +import net.neoforged.neoforge.client.RenderTypeGroup; +import net.neoforged.neoforge.client.model.IDynamicBakedModel; +import net.neoforged.neoforge.client.model.data.ModelData; +import net.neoforged.neoforge.client.model.data.ModelProperty; +import org.jetbrains.annotations.Nullable; import java.util.*; -public class ConnectedTextureModel implements UnbakedGeometry { +public class ConnectedTextureModel implements IDynamicBakedModel { private final Set connectedFaces; private final Set unculledFaces; private final boolean renderOverlayOnAllFaces; private final Map baseQuads; private final Map connectedQuads; + private final TextureAtlasSprite particle; + private final boolean usesAO; + private final boolean usesBlockLight; + private final ItemTransforms transforms; + @Nullable + private final ChunkRenderTypeSet blockRenderTypes; + @Nullable + private final RenderType itemRenderType; private final List validConnectors; - private static final ModelProperty<@NotNull ConnectedTextureData> DATA = new ModelProperty<>(); + private static final ModelProperty DATA = new ModelProperty<>(); - public ConnectedTextureModel(Set connectedFaces, Set unculledFaces, boolean renderOverlayOnAllFaces, List connectableBlocks, Map baseQuads, Map connectedQuads) { + public ConnectedTextureModel(Set connectedFaces, Set unculledFaces, boolean renderOverlayOnAllFaces, List connectableBlocks, Map baseQuads, Map connectedQuads, TextureAtlasSprite particle, boolean usesAO, boolean usesBlockLight, ItemTransforms transforms, RenderTypeGroup group) { this.connectedFaces = connectedFaces; this.unculledFaces = unculledFaces; this.renderOverlayOnAllFaces = renderOverlayOnAllFaces; this.validConnectors = connectableBlocks; this.baseQuads = baseQuads; this.connectedQuads = connectedQuads; + this.particle = particle; + this.usesAO = usesAO; + this.usesBlockLight = usesBlockLight; + this.transforms = transforms; + this.blockRenderTypes = !group.isEmpty() ? ChunkRenderTypeSet.of(group.block()) : null; + this.itemRenderType = !group.isEmpty() ? group.entity() : null; } @Override - public QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName modelDebugName) { - QuadCollection.Builder builder = new QuadCollection.Builder(); - - for (Direction direction : this.unculledFaces) { - List unculledQuads = this.getQuadsForFace(direction, ModelData.EMPTY); - for (BakedQuad quad : unculledQuads) { - builder.addUnculledFace(quad); - } - } - - for (Direction direction : Direction.values()) { - List culledQuads = this.getQuadsForFace(direction, ModelData.EMPTY); - for (BakedQuad quad : culledQuads) { - builder.addCulledFace(direction, quad); - } - } - - return builder.build(); + public List getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource random, ModelData extraData, @Nullable RenderType type) { + if (side == null) { + List quadList = new ArrayList<>(); + for (Direction direction : this.unculledFaces) quadList.addAll(this.getQuadsForFace(direction, extraData)); + return quadList; + } else return this.getQuadsForFace(side, extraData); } public List getQuadsForFace(Direction side, ModelData extraData) { @@ -75,6 +79,33 @@ public List getQuadsForFace(Direction side, ModelData extraData) { return quads; } + @Override + public ModelData getModelData(BlockAndTintGetter getter, BlockPos pos, BlockState state, ModelData modelData) { + ConnectedTextureData data = new ConnectedTextureData(); + + for (Direction face : Direction.values()) { + Direction[] directions = ConnectionLogic.AXIS_PLANE_DIRECTIONS[face.getAxis().ordinal()]; + boolean[] sideStates = new boolean[4]; + + int faceIndex; + for (faceIndex = 0; faceIndex < directions.length; faceIndex++) { + sideStates[faceIndex] = this.shouldConnectSide(getter, pos, face, directions[faceIndex]); + } + + faceIndex = face.get3DDataValue(); + + for (int dir = 0; dir < directions.length; dir++) { + int cornerOffset = (dir + 1) % directions.length; + boolean side1 = sideStates[dir]; + boolean side2 = sideStates[cornerOffset]; + boolean corner = side1 && side2 && this.isCornerBlockPresent(getter, pos, face, directions[dir], directions[cornerOffset]); + data.logic[faceIndex][dir] = dir % 2 == 0 ? ConnectionLogic.of(side1, side2, corner) : ConnectionLogic.of(side2, side1, corner); + } + } + + return modelData.derive().with(DATA, data).build(); + } + private boolean shouldConnectSide(BlockAndTintGetter getter, BlockPos pos, Direction face, Direction side) { BlockState neighborState = getter.getBlockState(pos.relative(side)); if (this.unculledFaces.contains(face)) return this.validConnectors.stream().anyMatch(neighborState::is); @@ -87,6 +118,41 @@ private boolean isCornerBlockPresent(BlockAndTintGetter getter, BlockPos pos, Di return this.validConnectors.stream().anyMatch(neighborState::is) && Block.shouldRenderFace(getter, pos.relative(face), neighborState, getter.getBlockState(pos.relative(face)), face); } + @Override + public boolean useAmbientOcclusion() { + return this.usesAO; + } + + @Override + public boolean isGui3d() { + return true; + } + + @Override + public boolean usesBlockLight() { + return this.usesBlockLight; + } + + @Override + public TextureAtlasSprite getParticleIcon() { + return this.particle; + } + + @Override + public ItemTransforms getTransforms() { + return this.transforms; + } + + @Override + public ChunkRenderTypeSet getRenderTypes(BlockState state, RandomSource rand, ModelData data) { + return this.blockRenderTypes != null ? this.blockRenderTypes : IDynamicBakedModel.super.getRenderTypes(state, rand, data); + } + + @Override + public RenderType getRenderType(ItemStack stack) { + return this.itemRenderType != null ? this.itemRenderType : IDynamicBakedModel.super.getRenderType(stack); + } + private static final class ConnectedTextureData { private final ConnectionLogic[][] logic = new ConnectionLogic[6][4]; diff --git a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java index 2b4c86be61..44b5c47c7d 100644 --- a/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java +++ b/src/main/java/twilightforest/client/model/block/connected/ConnectedTextureModelLoader.java @@ -45,7 +45,7 @@ public UnbakedConnectedTextureModel read(JsonObject jsonObject, JsonDeserializat EnumSet faces = this.parseEnabledFaces(overlayInfo, "faces"); List connectables = this.parseConnnectableBlocks(jsonObject); - return new UnbakedConnectedTextureModel(element, faces, renderDisabled, connectables, baseEmissivity, emissivity, StandardModelParameters.parse(jsonObject, deserializationContext)); + return new UnbakedConnectedTextureModel(element, faces, renderDisabled, connectables, baseTintIndex, baseEmissivity, tintIndex, emissivity, StandardModelParameters.parse(jsonObject, deserializationContext)); } private EnumSet parseEnabledFaces(JsonObject object, String key) { diff --git a/src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java b/src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java index 54a7f70901..39b2cf1d6b 100644 --- a/src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java +++ b/src/main/java/twilightforest/client/model/block/connected/ConnectionLogic.java @@ -1,7 +1,6 @@ package twilightforest.client.model.block.connected; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.cuboid.CuboidFace; import net.minecraft.core.Direction; //let the magic begin. @@ -59,9 +58,8 @@ public TextureAtlasSprite chooseTexture(TextureAtlasSprite[] sprites) { return sprites[this.texture]; } - public CuboidFace.UVs remapUVs(CuboidFace.UVs uvs) { - if (uvs == null) return new CuboidFace.UVs(0, 0, 0, 0); - return new CuboidFace.UVs(this.getU(uvs.maxU()), this.getV(uvs.minV()), this.getU(uvs.maxU()), this.getV(uvs.maxV())); + public float[] remapUVs(float[] uvs) { + return new float[]{this.getU(uvs[0]), this.getV(uvs[1]), this.getU(uvs[2]), this.getV(uvs[3])}; } public float getU(float delta) { diff --git a/src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java b/src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java index cc2e015ab2..7eaf0d2497 100644 --- a/src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java +++ b/src/main/java/twilightforest/client/model/block/connected/UnbakedConnectedTextureModel.java @@ -1,18 +1,20 @@ package twilightforest.client.model.block.connected; import com.mojang.datafixers.util.Pair; -import net.minecraft.client.renderer.texture.TextureAtlas; +import com.mojang.math.Transformation; +import net.minecraft.client.renderer.block.model.*; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.geometry.BakedQuad; -import net.minecraft.client.resources.model.geometry.UnbakedGeometry; -import net.minecraft.client.resources.model.sprite.Material; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelBaker; +import net.minecraft.client.resources.model.ModelState; import net.minecraft.core.Direction; -import net.minecraft.resources.Identifier; -import net.minecraft.util.Mth; +import net.minecraft.core.Vec3i; +import net.minecraft.util.context.ContextMap; import net.minecraft.world.level.block.Block; import net.neoforged.neoforge.client.model.AbstractUnbakedModel; +import net.neoforged.neoforge.client.model.NeoForgeModelProperties; import net.neoforged.neoforge.client.model.StandardModelParameters; -import net.neoforged.neoforge.client.model.quad.MutableQuad; +import net.neoforged.neoforge.client.model.UnbakedElementsHelper; import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; @@ -23,19 +25,23 @@ public class UnbakedConnectedTextureModel extends AbstractUnbakedModel { protected final boolean renderOverlayOnAllFaces; protected final Set connectedFaces; protected final List connectableBlocks; + protected BlockElement[][] baseElements; + protected BlockElement[][][] connectedElements; - protected MutableQuad[][] baseElements; - protected MutableQuad[][][] connectedElements; - - - public UnbakedConnectedTextureModel(Pair element, Set connectedFaces, boolean renderOnDisabledFaces, List connectableBlocks, int baseEmissivity, int emissivity, StandardModelParameters parameters) { + public UnbakedConnectedTextureModel(Pair element, Set connectedFaces, boolean renderOnDisabledFaces, List connectableBlocks, int baseTintIndex, int baseEmissivity, int tintIndex, int emissivity, StandardModelParameters parameters) { super(parameters); + //a list of block faces that should have connected textures. this.connectedFaces = connectedFaces; + //whether the overlay texture should render on all faces or not. Defaults to true this.renderOverlayOnAllFaces = renderOnDisabledFaces; + //a list of blocks this block can connect its texture to this.connectableBlocks = connectableBlocks; - - this.baseElements = new MutableQuad[6][4]; - this.connectedElements = new MutableQuad[6][4][5]; + //base elements - the base block. No Connected Textures on this bit. + //the array is made of the directions and "sections". Each section is a corner quadrant of the block + this.baseElements = new BlockElement[6][4]; + //face elements - the connected bit of the model. + //the array is made of the directions, "sections", and each logic value in the ConnectionLogic class + this.connectedElements = new BlockElement[6][4][5]; int center = 8; @@ -44,65 +50,26 @@ public UnbakedConnectedTextureModel(Pair element, Set finalBaseQuads = new HashMap<>(); - Map finalConnectedQuads = new HashMap<>(); + Map baseQuads = new HashMap<>(); Set unculledFaces = new HashSet<>(); - for (Direction dir : Direction.values()) { - int dirIdx = dir.get3DDataValue(); + if (textureSlots.getMaterial("base_texture") != null) { + TextureAtlasSprite baseTexture = baker.findSprite(textureSlots, "base_texture"); + + for (Direction dir : Direction.values()) { + List quadList = new ArrayList<>(); - List baseQuadList = new ArrayList<>(); - for (int i = 0; i < 4; i++) { - MutableQuad quad = this.baseElements[dirIdx][i]; - for (int v = 0; v < 4; v++) { - quad.setUv(v, baseTexture.getU(quad.u(v) * 16f), baseTexture.getV(quad.v(v) * 16f)); + for (BlockElement element : this.baseElements[dir.get3DDataValue()]) { + quadList.add(FaceBakery.bakeQuad(element.from, element.to, element.faces.get(dir), baseTexture, dir, state, element.rotation, element.shade, element.lightEmission)); } - baseQuadList.add(quad.toBakedQuad()); + baseQuads.put(dir, quadList.toArray(new BakedQuad[0])); } - finalBaseQuads.put(dir, baseQuadList.toArray(new BakedQuad[0])); + } - BakedQuad[][] dirQuads = new BakedQuad[4][5]; - for (int quadIdx = 0; quadIdx < 4; quadIdx++) { - for (int typeIdx = 0; typeIdx < 5; typeIdx++) { - MutableQuad quad = this.connectedElements[dirIdx][quadIdx][typeIdx]; + //we'll use this to figure out which texture to use with the Connected Texture logic + //NONE uses the first one, everything else uses the 2nd one + TextureAtlasSprite[] sprites = new TextureAtlasSprite[]{baker.findSprite(textureSlots, "overlay_texture"), baker.findSprite(textureSlots, "overlay_connected"), baker.findSprite(textureSlots, "particle")}; + if (textureSlots.getMaterial("particle") == null) { + sprites[2] = sprites[0]; + } - TextureAtlasSprite chosenSprite = ConnectionLogic.values()[typeIdx].chooseTexture(sprites); + Map connectedQuads = new HashMap<>(); - for (int v = 0; v < 4; v++) { - quad.setUv(v, chosenSprite.getU(quad.u(v) * 16f), chosenSprite.getV(quad.v(v) * 16f)); - } - dirQuads[quadIdx][typeIdx] = quad.toBakedQuad(); + for (Direction dir : Direction.values()) { + BakedQuad[][] dirQuads = new BakedQuad[4][5]; + for (int quad = 0; quad < 4; quad++) { + for (int type = 0; type < 5; type++) { + BlockElement element = this.connectedElements[dir.get3DDataValue()][quad][type]; + BlockElementFace face = element.faces.get(dir); + if (face.cullForDirection() == null) unculledFaces.add(dir); + dirQuads[quad][type] = FaceBakery.bakeQuad(element.from, element.to, face, ConnectionLogic.values()[type].chooseTexture(sprites), dir, state, element.rotation, element.shade, element.lightEmission); } } - finalConnectedQuads.put(dir, dirQuads); + connectedQuads.put(dir, dirQuads); } - return new ConnectedTextureModel( - this.connectedFaces, - unculledFaces, - this.renderOverlayOnAllFaces, - this.connectableBlocks, - finalBaseQuads, - finalConnectedQuads - ); + return new ConnectedTextureModel(this.connectedFaces, unculledFaces, this.renderOverlayOnAllFaces, this.connectableBlocks, baseQuads, connectedQuads, sprites[2], useAmbientOcclusion, usesBlockLight, itemTransforms, this.parameters.renderTypeGroup()); } } \ No newline at end of file diff --git a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java index 64d94092f7..e4a1968854 100644 --- a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java +++ b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModel.java @@ -1,118 +1,88 @@ package twilightforest.client.model.block.forcefield; -import net.minecraft.client.renderer.block.BlockAndTintGetter; -import net.minecraft.client.renderer.block.dispatch.ModelState; -import net.minecraft.client.renderer.rendertype.RenderType; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.*; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.ModelBaker; -import net.minecraft.client.resources.model.ModelDebugName; -import net.minecraft.client.resources.model.cuboid.ItemTransforms; -import net.minecraft.client.resources.model.geometry.BakedQuad; -import net.minecraft.client.resources.model.geometry.QuadCollection; -import net.minecraft.client.resources.model.geometry.UnbakedGeometry; -import net.minecraft.client.resources.model.sprite.Material; -import net.minecraft.client.resources.model.sprite.TextureSlots; +import net.minecraft.client.resources.model.BlockModelRotation; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.resources.Identifier; +import net.minecraft.util.RandomSource; import net.minecraft.util.StringRepresentable; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.block.state.BlockState; -import net.neoforged.neoforge.client.model.quad.MutableQuad; -import net.neoforged.neoforge.model.data.ModelData; -import net.neoforged.neoforge.model.data.ModelProperty; +import net.neoforged.neoforge.client.ChunkRenderTypeSet; +import net.neoforged.neoforge.client.RenderTypeGroup; +import net.neoforged.neoforge.client.model.IDynamicBakedModel; +import net.neoforged.neoforge.client.model.data.ModelData; +import net.neoforged.neoforge.client.model.data.ModelProperty; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import twilightforest.block.ForceFieldBlock; import java.util.*; import java.util.function.Function; -public class ForceFieldModel implements UnbakedGeometry { +public class ForceFieldModel implements IDynamicBakedModel { private static final ModelProperty DATA = new ModelProperty<>(); - private final Map parts; - private final Function spriteFunction; + private final Map parts; + private final Function spriteFunction; + private final TextureAtlasSprite particle; private final boolean usesAO; private final boolean usesBlockLight; private final ItemTransforms transforms; @Nullable - private final Set renderTypes; + private final ChunkRenderTypeSet blockRenderTypes; + @Nullable + private final RenderType itemRenderType; - public ForceFieldModel(Map parts, Function spriteFunction, boolean useAmbientOcclusion, boolean usesBlockLight, ItemTransforms itemTransforms, @Nullable Set renderTypes) { + public ForceFieldModel(Map parts, Function spriteFunction, boolean useAmbientOcclusion, boolean usesBlockLight, ItemTransforms itemTransforms, RenderTypeGroup group) { this.parts = parts; this.spriteFunction = spriteFunction; + this.particle = spriteFunction.apply("particle"); this.usesAO = useAmbientOcclusion; this.usesBlockLight = usesBlockLight; this.transforms = itemTransforms; - this.renderTypes = renderTypes; + this.blockRenderTypes = !group.isEmpty() ? ChunkRenderTypeSet.of(group.block()) : null; + this.itemRenderType = !group.isEmpty() ? group.entity() : null; } @Override - public QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName modelDebugName) { - QuadCollection.Builder builder = new QuadCollection.Builder(); - - ForceFieldData defaultData = new ForceFieldData(java.util.Collections.emptyMap()); - - List unculledQuads = new java.util.ArrayList<>(); - for (Direction direction : Direction.values()) { - unculledQuads = this.getQuads(unculledQuads, direction, defaultData); - } - for (BakedQuad quad : unculledQuads) { - builder.addUnculledFace(quad); - } - - for (Direction direction : Direction.values()) { - List culledQuads = new java.util.ArrayList<>(); - culledQuads = this.getQuads(culledQuads, direction, defaultData); - for (BakedQuad quad : culledQuads) { - builder.addCulledFace(direction, quad); - } + public @NotNull List getQuads(@Nullable BlockState state, @Nullable Direction cullFace, @NotNull RandomSource rand, @NotNull ModelData extraData, @Nullable RenderType renderType) { + List quads = new ArrayList<>(); + ForceFieldData data = extraData.get(DATA); + + if (data != null) { + if (cullFace == null) { + for (Direction direction : Direction.values()) { + quads = this.getQuads(quads, direction, data, false); + } + } else return this.getQuads(quads, cullFace, data, true); } - return builder.build(); + return quads; } - public List getQuads(List quads, Direction side, ForceFieldData data) { - for (Map.Entry entry : this.parts.entrySet()) { - - if (ForceFieldModel.skipRender(data.directions(), entry.getValue().direction(), entry.getValue().b(), entry.getValue().parents(), side)) { - continue; - } - - String texturePath = this.spriteFunction.apply(entry.getKey() + "_" + side.getName()); - - if (texturePath != null) { - Identifier identifier = Identifier.parse(texturePath); - Material material = new Material(identifier); - - material = material.withForceTranslucent(true); - - TextureAtlasSprite sprite = net.minecraft.client.Minecraft.getInstance() - .getAtlasManager().getAtlasOrThrow(net.minecraft.client.renderer.texture.TextureAtlas.LOCATION_BLOCKS) - .getSprite(material.sprite()); - - MutableQuad mutableQuad = new MutableQuad(); - - for (int vertexIndex = 0; vertexIndex < 4; vertexIndex++) { - float x = (vertexIndex == 1 || vertexIndex == 2) ? 1.0f : 0.0f; - float y = (vertexIndex == 2 || vertexIndex == 3) ? 1.0f : 0.0f; - float z = 0.5f; - - mutableQuad.setPosition(vertexIndex, new org.joml.Vector3f(x, y, z)); - - float u = sprite.getU(x * 16.0f); - float v = sprite.getV(y * 16.0f); - mutableQuad.setUv(vertexIndex, u, v); - } - - mutableQuad.setDirection(side); - mutableQuad.setShade(this.usesAO); - - if (this.usesBlockLight) { - mutableQuad.setLightEmission(15); - } - - quads.add(mutableQuad.toBakedQuad()); + public @NotNull List getQuads(List quads, Direction side, ForceFieldData data, boolean cull) { + for (Map.Entry entry : this.parts.entrySet()) { + BlockElementFace blockelementface = entry.getKey().faces.get(side); + if (blockelementface != null && blockelementface.cullForDirection() != null == cull) { + if (ForceFieldModel.skipRender(data.directions(), entry.getValue().direction(), entry.getValue().b(), entry.getValue().parents(), side)) continue; + + TextureAtlasSprite sprite = this.spriteFunction.apply(blockelementface.texture()); + quads.add(FaceBakery.bakeQuad( + entry.getKey().from, + entry.getKey().to, + blockelementface, + sprite, + side, + BlockModelRotation.X0_Y0, + entry.getKey().rotation, + entry.getKey().shade, + entry.getKey().lightEmission) + ); } } return quads; @@ -127,7 +97,8 @@ protected static boolean skipRender(Map> directi return false; } - public ModelData getModelData(BlockAndTintGetter level, BlockPos pos, BlockState state, ModelData modelData) { + @Override + public @NotNull ModelData getModelData(@NotNull BlockAndTintGetter level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull ModelData modelData) { if (modelData == ModelData.EMPTY) { Map> map = new HashMap<>(); for (ExtraDirection extraDirection : getExtraDirections(state, level, pos)) { @@ -189,6 +160,43 @@ public static List getExtraDirections(BlockState state, BlockGet return directions; } + @Override + public boolean useAmbientOcclusion() { + return this.usesAO; + } + + @Override + public boolean isGui3d() { + return false; + } + + @Override + public boolean usesBlockLight() { + return this.usesBlockLight; + } + + @Override + public TextureAtlasSprite getParticleIcon() { + return this.particle; + } + + @NotNull + @Override + public ItemTransforms getTransforms() { + return this.transforms; + } + + @NotNull + @Override + public ChunkRenderTypeSet getRenderTypes(@NotNull BlockState state, @NotNull RandomSource rand, @NotNull ModelData data) { + return this.blockRenderTypes != null ? this.blockRenderTypes : IDynamicBakedModel.super.getRenderTypes(state, rand, data); + } + + @Override + public RenderType getRenderType(ItemStack stack) { + return this.itemRenderType != null ? this.itemRenderType : IDynamicBakedModel.super.getRenderType(stack); + } + public enum ExtraDirection implements StringRepresentable { DOWN("down", 0, 1, 0), UP("up", 1, 0, 1), @@ -212,6 +220,7 @@ public enum ExtraDirection implements StringRepresentable { SOUTH_WEST("south_west", 17, 16, 14), SOUTH_EAST("south_east", 16, 17, 15); + @SuppressWarnings("deprecation") public static final EnumCodec CODEC = StringRepresentable.fromEnum(ExtraDirection::values); private final String name; private final int xAxisMirror; @@ -239,7 +248,7 @@ public ExtraDirection mirrored(Direction.Axis axis) { } @Nullable - public static ExtraDirection byName(String name) { + public static ExtraDirection byName(@Nullable String name) { return CODEC.byName(name); } } diff --git a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java index 02b1d5a494..536bd46915 100644 --- a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java +++ b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelBuilder.java @@ -5,18 +5,27 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.mojang.datafixers.util.Pair; +import com.mojang.math.Quadrant; import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; +import net.minecraft.client.resources.model.cuboid.CuboidFace; +import net.minecraft.client.resources.model.cuboid.CuboidModelElement; +import net.minecraft.client.resources.model.cuboid.CuboidRotation; import net.minecraft.core.Direction; import net.minecraft.resources.Identifier; import net.minecraft.util.Mth; +import net.neoforged.neoforge.client.model.ExtraFaceData; import net.neoforged.neoforge.client.model.generators.template.CustomLoaderBuilder; +import org.apache.commons.lang3.mutable.MutableObject; import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; +import org.joml.Vector3fc; import twilightforest.TwilightForestMod; import twilightforest.client.model.block.forcefield.ForceFieldModel.ExtraDirection; +import twilightforest.util.UnbakedGeometryUtil; import java.util.*; import java.util.function.BiConsumer; +import java.util.stream.Collectors; public class ForceFieldModelBuilder extends CustomLoaderBuilder { @@ -72,8 +81,9 @@ protected CustomLoaderBuilder copyInternal() { public JsonObject toJson(JsonObject json) { json = super.toJson(json); if (!this.elements.isEmpty()) { - JsonArray elementsArray = new JsonArray(); + JsonArray elements = new JsonArray(); this.elements.forEach(forceFieldElementBuilder -> { + CuboidModelElement part = forceFieldElementBuilder.build(); JsonObject partObj = new JsonObject(); if (forceFieldElementBuilder.condition != null) { @@ -90,63 +100,55 @@ public JsonObject toJson(JsonObject json) { partObj.add("condition", condition); } - partObj.add("from", serializeVector3f(forceFieldElementBuilder.from)); - partObj.add("to", serializeVector3f(forceFieldElementBuilder.to)); + partObj.add("from", serializeVector3fc(part.from())); + partObj.add("to", serializeVector3fc(part.to())); - if (forceFieldElementBuilder.rotation != null) { + if (part.rotation() != null) { JsonObject rotation = new JsonObject(); - rotation.add("origin", serializeVector3f(forceFieldElementBuilder.rotation.origin)); - rotation.addProperty("axis", forceFieldElementBuilder.rotation.axis.getSerializedName()); - rotation.addProperty("angle", forceFieldElementBuilder.rotation.angle); - if (forceFieldElementBuilder.rotation.rescale) { + rotation.add("origin", serializeVector3fc(part.rotation().origin())); + rotation.addProperty("axis", part.rotation.axis().getSerializedName()); + rotation.addProperty("angle", part.rotation.angle()); + if (part.rotation().rescale()) { rotation.addProperty("rescale", true); } partObj.add("rotation", rotation); } - if (!forceFieldElementBuilder.shade) { - partObj.addProperty("shade", forceFieldElementBuilder.shade); + if (!part.shade()) { + partObj.addProperty("shade", part.shade()); } - if (forceFieldElementBuilder.light != 0) { - partObj.addProperty("light", forceFieldElementBuilder.light); + if (part.lightEmission() != 0) { + partObj.addProperty("light_emission", part.lightEmission()); } - JsonObject facesObj = new JsonObject(); - - for (net.minecraft.core.Direction dir : net.minecraft.core.Direction.values()) { - var faceBuilder = forceFieldElementBuilder.faces.get(dir); - if (faceBuilder == null) continue; + JsonObject faces = new JsonObject(); + for (Direction dir : Direction.values()) { + CuboidFace face = part.faces().get(dir); + if (face == null) continue; JsonObject faceObj = new JsonObject(); - - faceObj.addProperty("texture", serializeLocOrKey(faceBuilder.texture)); - - if (faceBuilder.uvs != null) { - faceObj.add("uvs", new Gson().toJsonTree(faceBuilder.uvs)); + faceObj.addProperty("texture", serializeLocOrKey(face.texture())); + if (!UnbakedGeometryUtil.areUVsEqual(face.uvs(), UnbakedGeometryUtil.uvsByFace(dir, part))) { + faceObj.add("uv", new Gson().toJsonTree(face.uvs())); } - - if (faceBuilder.cullface != null) { - faceObj.addProperty("cullface", faceBuilder.cullface.getSerializedName()); + if (face.cullForDirection() != null) { + faceObj.addProperty("cullface", face.cullForDirection().getSerializedName()); } - - if (faceBuilder.rotation.rotation != 0) { - faceObj.addProperty("rotation", faceBuilder.rotation.rotation); + if (face.rotation() != Quadrant.R0) { + faceObj.addProperty("rotation", UnbakedGeometryUtil.angleFromQuadrant(face.rotation())); } - - if (faceBuilder.tintindex != -1) { - faceObj.addProperty("tintindex", faceBuilder.tintindex); + if (face.tintIndex() != -1) { + faceObj.addProperty("tintindex", face.tintIndex()); } - - facesObj.add(dir.getSerializedName(), faceObj); + faces.add(dir.getSerializedName(), faceObj); } - - if (!forceFieldElementBuilder.faces.isEmpty()) { - partObj.add("faces", facesObj); + if (!part.faces().isEmpty()) { + partObj.add("faces", faces); } - elementsArray.add(partObj); + elements.add(partObj); }); - json.add("elements", elementsArray); + json.add("elements", elements); } return json; } @@ -158,7 +160,7 @@ private static String serializeLocOrKey(String tex) { return Identifier.parse(tex).toString(); } - private static JsonArray serializeVector3f(Vector3f vec) { + private static JsonArray serializeVector3fc(Vector3fc vec) { JsonArray ret = new JsonArray(); ret.add(serializeFloat(vec.x())); ret.add(serializeFloat(vec.y())); @@ -288,6 +290,14 @@ private BiConsumer addTexture(S return (direction, builder) -> builder.texture(texture); } + CuboidModelElement build() { + Map faces = this.faces.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().build(), (direction, face) -> { + throw new IllegalArgumentException(); + }, LinkedHashMap::new)); + return new CuboidModelElement(this.from, this.to, faces, this.rotation == null ? null : this.rotation.build(), this.shade, this.light, ExtraFaceData.DEFAULT); + } + public ForceFieldModelBuilder end() { return self(); } @@ -332,6 +342,13 @@ public ForceFieldElementBuilder.FaceBuilder rotation(FaceRotation rot) { return this; } + CuboidFace build() { + if (this.texture == null) { + throw new IllegalStateException("A model face must have a texture"); + } + return new CuboidFace(this.cullface, this.tintindex, this.texture, this.uvs == null ? new CuboidFace.UVs(0, 0, 16, 16) : UnbakedGeometryUtil.uvsFromArray(this.uvs), UnbakedGeometryUtil.quadrantFromAngle(this.rotation.rotation), ExtraFaceData.DEFAULT, new MutableObject<>()); + } + public ForceFieldElementBuilder end() { return ForceFieldElementBuilder.this; } @@ -369,6 +386,12 @@ public ForceFieldElementBuilder.RotationBuilder rescale(boolean rescale) { return this; } + CuboidRotation build() { + Preconditions.checkNotNull(this.origin, "No origin specified"); + Preconditions.checkNotNull(this.axis, "No axis specified"); + return new CuboidRotation(this.origin, new CuboidRotation.SingleAxisRotation(this.axis, this.angle), this.rescale); + } + public ForceFieldElementBuilder end() { return ForceFieldElementBuilder.this; } diff --git a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java index ee251fb99f..cdf18cd0d2 100644 --- a/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java +++ b/src/main/java/twilightforest/client/model/block/forcefield/ForceFieldModelLoader.java @@ -4,6 +4,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; +import net.minecraft.client.resources.model.cuboid.CuboidModelElement; import net.minecraft.util.GsonHelper; import net.neoforged.neoforge.client.model.StandardModelParameters; import net.neoforged.neoforge.client.model.UnbakedModelLoader; @@ -22,10 +23,9 @@ public class ForceFieldModelLoader implements UnbakedModelLoader elementsAndConditions = new HashMap<>(); + Map elementsAndConditions = new HashMap<>(); if (json.has("elements")) { - int elementIndex = 0; for (JsonElement jsonElement : GsonHelper.getAsJsonArray(json, "elements")) { ExtraDirection direction = null; boolean b = false; @@ -39,12 +39,8 @@ public UnbakedForceFieldModel read(JsonObject json, JsonDeserializationContext c parents.add(ForceFieldModel.ExtraDirection.byName(parentElement.getAsString())); } } - - String elementName = element.has("name") ? GsonHelper.getAsString(element, "name") : "element_" + elementIndex; - - elementsAndConditions.put(elementName, new Condition(direction, b, parents)); - elementIndex++; } + elementsAndConditions.put(context.deserialize(jsonElement, CuboidModelElement.class), new Condition(direction, b, parents)); } } diff --git a/src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java b/src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java index 2bbf4cb784..b382165d1b 100644 --- a/src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java +++ b/src/main/java/twilightforest/client/model/block/forcefield/UnbakedForceFieldModel.java @@ -1,8 +1,10 @@ package twilightforest.client.model.block.forcefield; -import net.minecraft.client.renderer.rendertype.RenderTypes; -import net.minecraft.client.resources.model.cuboid.ItemTransforms; -import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.block.model.TextureSlots; +import net.minecraft.client.resources.model.*; +import net.minecraft.client.resources.model.cuboid.CuboidModelElement; +import net.minecraft.util.context.ContextMap; import net.neoforged.neoforge.client.model.AbstractUnbakedModel; import net.neoforged.neoforge.client.model.StandardModelParameters; @@ -10,22 +12,15 @@ public class UnbakedForceFieldModel extends AbstractUnbakedModel { - private final Map elementsAndConditions; + private final Map elementsAndConditions; - public UnbakedForceFieldModel(Map elementsAndConditions, StandardModelParameters parameters) { + public UnbakedForceFieldModel(Map elementsAndConditions, StandardModelParameters parameters) { super(parameters); this.elementsAndConditions = elementsAndConditions; } @Override - public UnbakedGeometry geometry() { - return new ForceFieldModel( - this.elementsAndConditions, - (String textureKey) -> textureKey, - Boolean.TRUE.equals(this.parameters.ambientOcclusion()), - this.parameters.guiLight().lightLikeBlock(), - ItemTransforms.NO_TRANSFORMS, - java.util.Set.of(RenderTypes.translucentMovingBlock()) - ); + public BakedModel bake(TextureSlots textures, ModelBaker baker, ModelState modelState, boolean useAmbientOcclusion, boolean usesBlockLight, ItemTransforms itemTransforms, ContextMap additionalProperties) { + return new ForceFieldModel(this.elementsAndConditions, s -> baker.findSprite(textures, s), useAmbientOcclusion, usesBlockLight, itemTransforms, this.parameters.renderTypeGroup()); } } diff --git a/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockBuilder.java b/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockBuilder.java index 1ebca90c16..a8ecaa1d0a 100644 --- a/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockBuilder.java +++ b/src/main/java/twilightforest/client/model/block/giantblock/GiantBlockBuilder.java @@ -1,6 +1,5 @@ package twilightforest.client.model.block.giantblock; -import com.google.gson.JsonObject; import net.neoforged.neoforge.client.model.generators.template.CustomLoaderBuilder; import twilightforest.TwilightForestMod; diff --git a/src/main/java/twilightforest/client/model/block/patch/PatchModel.java b/src/main/java/twilightforest/client/model/block/patch/PatchModel.java index 4681e968ba..76cc54a379 100644 --- a/src/main/java/twilightforest/client/model/block/patch/PatchModel.java +++ b/src/main/java/twilightforest/client/model/block/patch/PatchModel.java @@ -1,40 +1,64 @@ package twilightforest.client.model.block.patch; import com.google.common.collect.ImmutableList; -import net.minecraft.client.renderer.block.dispatch.ModelState; +import com.mojang.math.Transformation; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.*; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.ModelBaker; -import net.minecraft.client.resources.model.ModelDebugName; -import net.minecraft.client.resources.model.geometry.BakedQuad; -import net.minecraft.client.resources.model.geometry.QuadCollection; -import net.minecraft.client.resources.model.geometry.UnbakedGeometry; -import net.minecraft.client.resources.model.sprite.TextureSlots; +import net.minecraft.client.resources.model.BakedModel; import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; import net.minecraft.util.RandomSource; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.structure.BoundingBox; -import net.neoforged.neoforge.client.model.quad.MutableQuad; +import net.neoforged.neoforge.client.ChunkRenderTypeSet; +import net.neoforged.neoforge.client.RenderTypeGroup; +import net.neoforged.neoforge.client.model.IDynamicBakedModel; +import net.neoforged.neoforge.client.model.SimpleModelState; +import net.neoforged.neoforge.client.model.StandardModelParameters; +import net.neoforged.neoforge.client.model.data.ModelData; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; import twilightforest.block.PatchBlock; +import twilightforest.client.model.block.connected.UnbakedConnectedTextureModel; +import twilightforest.init.TFBlocks; import java.util.ArrayList; import java.util.List; -public class PatchModel implements UnbakedGeometry { +public class PatchModel implements BakedModel { + private final TextureAtlasSprite texture; private final boolean shaggify; - - private TextureAtlasSprite texture; - private boolean usesAO; - private boolean usesBlockLight; - - public PatchModel(boolean shaggify) { - this.shaggify = shaggify; - } - - public PatchModel(TextureAtlasSprite texture, boolean shaggify, boolean usesAO, boolean usesBlockLight) { + private final TextureAtlasSprite particle; + private final boolean usesAO; + private final boolean usesBlockLight; + private final ItemTransforms transforms; + @Nullable + private final ChunkRenderTypeSet blockRenderTypes; + @Nullable + private final RenderType itemRenderType; + + public PatchModel(TextureAtlasSprite texture, boolean shaggify, TextureAtlasSprite particle, boolean usesAO, boolean usesBlockLight, ItemTransforms transforms, RenderTypeGroup group) { this.texture = texture; this.shaggify = shaggify; + this.particle = particle; this.usesAO = usesAO; this.usesBlockLight = usesBlockLight; + this.transforms = transforms; + this.blockRenderTypes = !group.isEmpty() ? ChunkRenderTypeSet.of(group.block()) : null; + this.itemRenderType = !group.isEmpty() ? group.entity() : null; + } + + @Override + public List getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource random) { + if (state == null) + return this.getQuads(false, false, false, false, random); + else + return this.getQuads(state.getValue(PatchBlock.NORTH), state.getValue(PatchBlock.EAST), state.getValue(PatchBlock.SOUTH), state.getValue(PatchBlock.WEST), random); } private List getQuads(boolean north, boolean east, boolean south, boolean west, RandomSource posRandom) { @@ -149,50 +173,50 @@ private void quadsFromAABB(List quads, float minX, float minY, float } private BakedQuad quadFromVectors(Direction direction, float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { - MutableQuad mutableQuad = new MutableQuad(); - - mutableQuad.setDirection(direction); - mutableQuad.setShade(this.usesAO); - - if (this.usesBlockLight) { - mutableQuad.setLightEmission(15); - } - - for (int v = 0; v < 4; v++) { - float x = (v == 1 || v == 2) ? maxX / 16.0f : minX / 16.0f; - float y = (v == 2 || v == 3) ? maxY / 16.0f : minY / 16.0f; - float z = (direction.getAxis() == net.minecraft.core.Direction.Axis.Z) ? maxZ / 16.0f : minZ / 16.0f; - - mutableQuad.setPosition(v, new org.joml.Vector3f(x, y, z)); + BlockElementFace face = new BlockElementFace(null, 0, this.texture.atlasLocation().toString(), switch (direction) { + case NORTH -> new BlockFaceUV(new float[]{maxX, minZ + 1f, minX, minZ}, 0); + case EAST -> new BlockFaceUV(new float[]{maxX, minZ, maxX - 1f, maxZ}, 90); + case SOUTH -> new BlockFaceUV(new float[]{minX, maxZ, maxX, maxZ - 1f}, 0); + case WEST -> new BlockFaceUV(new float[]{minX, maxZ, minX + 1f, minZ}, 90); + default -> new BlockFaceUV(new float[]{minX, minZ, maxX, maxZ}, 0); + }); + + return FaceBakery.bakeQuad(new Vector3f(minX, minY, minZ), new Vector3f(maxX, maxY, maxZ), face, this.texture, direction, new SimpleModelState(Transformation.identity()), null, true, 0); + } - float u = this.texture.getU(x * 16.0f); - float vCoord = this.texture.getV(y * 16.0f); + @Override + public boolean useAmbientOcclusion() { + return this.usesAO; + } - if (direction == net.minecraft.core.Direction.EAST || direction == net.minecraft.core.Direction.WEST) { - mutableQuad.setUv(v, vCoord, u); - } else { - mutableQuad.setUv(v, u, vCoord); - } - } + @Override + public boolean isGui3d() { + return false; + } - return mutableQuad.toBakedQuad(); + @Override + public boolean usesBlockLight() { + return this.usesBlockLight; } @Override - public QuadCollection bake(TextureSlots textureSlots, ModelBaker modelBaker, ModelState modelState, ModelDebugName modelDebugName) { - QuadCollection.Builder builder = new QuadCollection.Builder(); + public ItemTransforms getTransforms() { + return this.transforms; + } - RandomSource staticRandom = RandomSource.create(42L); - List myPatchQuads = this.getQuads(false, false, false, false, staticRandom); + @Override + public TextureAtlasSprite getParticleIcon() { + return this.particle; + } - for (BakedQuad quad : myPatchQuads) { - if (quad.direction() != null) { - builder.addCulledFace(quad.direction(), quad); - } else { - builder.addUnculledFace(quad); - } - } + @NotNull + @Override + public ChunkRenderTypeSet getRenderTypes(@NotNull BlockState state, @NotNull RandomSource rand, @NotNull ModelData data) { + return this.blockRenderTypes != null ? this.blockRenderTypes : BakedModel.super.getRenderTypes(state, rand, data); + } - return builder.build(); + @Override + public RenderType getRenderType(ItemStack stack) { + return this.itemRenderType != null ? this.itemRenderType : BakedModel.super.getRenderType(stack); } } diff --git a/src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java b/src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java index ff875d6fb8..0ca1c5a901 100644 --- a/src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java +++ b/src/main/java/twilightforest/client/model/block/patch/UnbakedPatchModel.java @@ -1,6 +1,9 @@ package twilightforest.client.model.block.patch; -import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.block.model.TextureSlots; +import net.minecraft.client.resources.model.*; +import net.minecraft.util.context.ContextMap; import net.neoforged.neoforge.client.model.AbstractUnbakedModel; import net.neoforged.neoforge.client.model.StandardModelParameters; @@ -14,7 +17,7 @@ public UnbakedPatchModel(boolean shaggify, StandardModelParameters parameters) { } @Override - public UnbakedGeometry geometry() { - return new PatchModel(this.shaggify); + public BakedModel bake(TextureSlots textureSlots, ModelBaker baker, ModelState modelState, boolean hasAmbientOcclusion, boolean useBlockLight, ItemTransforms transforms, ContextMap additionalProperties) { + return new PatchModel(baker.findSprite(textureSlots, "texture"), this.shaggify, baker.findSprite(textureSlots, "particle"), hasAmbientOcclusion, useBlockLight, transforms, this.parameters.renderTypeGroup()); } } diff --git a/src/main/java/twilightforest/init/TFBlockEntities.java b/src/main/java/twilightforest/init/TFBlockEntities.java index be58af63ee..8ebf010cbf 100644 --- a/src/main/java/twilightforest/init/TFBlockEntities.java +++ b/src/main/java/twilightforest/init/TFBlockEntities.java @@ -68,8 +68,6 @@ public class TFBlockEntities { new BlockEntityType<>(KeepsakeCasketBlockEntity::new, TFBlocks.KEEPSAKE_CASKET.get())); public static final DeferredHolder, BlockEntityType> BRAZIER = BLOCK_ENTITIES.register("brazier", () -> new BlockEntityType<>(BrazierBlockEntity::new, TFBlocks.BRAZIER.get())); - public static final DeferredHolder, BlockEntityType> CORONATION_CARPET = BLOCK_ENTITIES.register("coronation_carpet", () -> - new BlockEntityType<>(CoronationCarpetBlockEntity::new, TFBlocks.CORONATION_CARPET.get())); public static final DeferredHolder, BlockEntityType> TF_CHEST = BLOCK_ENTITIES.register("chest", () -> new BlockEntityType<>(TFChestBlockEntity::new, diff --git a/src/main/java/twilightforest/init/TFBlocks.java b/src/main/java/twilightforest/init/TFBlocks.java index e053ba27d6..a72e48317d 100644 --- a/src/main/java/twilightforest/init/TFBlocks.java +++ b/src/main/java/twilightforest/init/TFBlocks.java @@ -126,7 +126,7 @@ public class TFBlocks { public static final DeferredBlock TERRORCOTTA_ARCS = registerWithItem("terrorcotta_arcs", RotatedPillarBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(1.5F, 6.0F)); public static final DeferredBlock TERRORCOTTA_CURVES = registerWithItem("terrorcotta_curves", GlazedTerracottaBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(1.5F, 6.0F)); public static final DeferredBlock TERRORCOTTA_LINES = registerWithItem("terrorcotta_lines", BinaryRotatedBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.STONE).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(1.5F, 6.0F)); - public static final DeferredBlock CORONATION_CARPET = registerWithItem("coronation_carpet", properties -> new CoronationCarpetBlock(DyeColor.RED, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.RED_CARPET).isValidSpawn(Blocks::always)); + public static final DeferredBlock CORONATION_CARPET = registerWithItem("coronation_carpet", properties -> new WoolCarpetBlock(DyeColor.RED, properties), () -> BlockBehaviour.Properties.ofFullCopy(Blocks.RED_CARPET).isValidSpawn(Blocks::always)); //ominous public static final DeferredBlock OMINOUS_FIRE = register("ominous_fire", OminousFireBlock::new, () -> BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_PURPLE).replaceable().noCollision().instabreak().lightLevel((state) -> 15).sound(SoundType.WOOL).pushReaction(PushReaction.DESTROY)); @@ -268,7 +268,7 @@ public class TFBlocks { public static final DeferredBlock NAGA_COURTYARD_MINIATURE_STRUCTURE = registerWithItem("naga_courtyard_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); public static final DeferredBlock LICH_TOWER_MINIATURE_STRUCTURE = registerWithItem("lich_tower_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); public static final DeferredBlock MINOTAUR_LABYRINTH_MINIATURE_STRUCTURE = register("minotaur_labyrinth_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); -// public static final DeferredBlock HYDRA_LAIR_MINIATURE_STRUCTURE = register("hydra_lair_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); + // public static final DeferredBlock HYDRA_LAIR_MINIATURE_STRUCTURE = register("hydra_lair_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); // public static final DeferredBlock GOBLIN_STRONGHOLD_MINIATURE_STRUCTURE = register("goblin_stronghold_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); public static final DeferredBlock DARK_TOWER_MINIATURE_STRUCTURE = register("dark_tower_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); // public static final DeferredBlock YETI_CAVE_MINIATURE_STRUCTURE = register("yeti_cave_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); diff --git a/src/main/java/twilightforest/util/UnbakedGeometryUtil.java b/src/main/java/twilightforest/util/UnbakedGeometryUtil.java index 9e09db00e9..890c8075b2 100644 --- a/src/main/java/twilightforest/util/UnbakedGeometryUtil.java +++ b/src/main/java/twilightforest/util/UnbakedGeometryUtil.java @@ -1,7 +1,7 @@ package twilightforest.util; +import com.mojang.math.Quadrant; import net.minecraft.client.renderer.block.dispatch.ModelState; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.ModelBaker; import net.minecraft.client.resources.model.cuboid.CuboidFace; import net.minecraft.client.resources.model.cuboid.CuboidModelElement; @@ -9,10 +9,9 @@ import net.minecraft.client.resources.model.geometry.BakedQuad; import net.minecraft.client.resources.model.sprite.Material; import net.minecraft.core.Direction; -import twilightforest.client.model.block.connected.ConnectionLogic; -// this class returns back removed methods from the sources public class UnbakedGeometryUtil { + // [VanillaCopy] returned back this method from 1.21.1 Vanilla Sources public static CuboidFace.UVs uvsByFace(Direction face, CuboidModelElement element) { return switch (face) { case DOWN -> new CuboidFace.UVs(element.from().x(), 16.0F - element.to().z(), element.to().x(), 16.0F - element.from().z()); @@ -24,18 +23,37 @@ public static CuboidFace.UVs uvsByFace(Direction face, CuboidModelElement elemen }; } + // [VanillaCopy] returned back this method from 1.21.1 Vanilla Sources public static BakedQuad bakeElementFace(ModelBaker baker, CuboidModelElement element, CuboidFace face, Material.Baked sprite, Direction direction, ModelState state) { return FaceBakery.bakeQuad(baker, element.from(), element.to(), face, sprite, direction, state, null, element.shade(), 0); } - public static Material.Baked chooseAndBake(ConnectionLogic target, TextureAtlasSprite[] spriteOptions, Material[] materials) { - TextureAtlasSprite unbakedChoice = target.chooseTexture(spriteOptions); - // spriteOptions.length should be equal to materials.length - for (int i = 0; i < spriteOptions.length; i++) { - if (unbakedChoice == spriteOptions[i]) { - return new Material.Baked(spriteOptions[i], materials[i].forceTranslucent()); - } + public static boolean areUVsEqual(CuboidFace.UVs first, CuboidFace.UVs second) { + return first.minU() == second.minU() && first.minV() == second.minV() && first.maxU() == second.maxU() && first.maxV() == second.maxV(); + } + + public static int angleFromQuadrant(Quadrant quadrant) { + return switch (quadrant) { + case R90 -> 90; + case R180 -> 180; + case R270 -> 270; + default -> 0; + }; + } + + public static Quadrant quadrantFromAngle(int angle) { + if (angle >= 0 && angle < 90) { + return Quadrant.R90; + } else if (angle >= 90 && angle < 180) { + return Quadrant.R180; + } else if (angle >= 180 && angle < 270) { + return Quadrant.R270; + } else { + return Quadrant.R0; } - return new Material.Baked(spriteOptions[0], false); + } + + public static CuboidFace.UVs uvsFromArray(float[] array) { + return new CuboidFace.UVs(array[0], array[1], array[2], array[3]); } } From 144ffac17415682076d52e196bc6d54a843ca4cb Mon Sep 17 00:00:00 2001 From: Albazavr Date: Mon, 20 Jul 2026 02:49:29 +0300 Subject: [PATCH 15/18] Removed unnecessary changes from TFBlocks --- src/main/java/twilightforest/init/TFBlocks.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/twilightforest/init/TFBlocks.java b/src/main/java/twilightforest/init/TFBlocks.java index a72e48317d..525d52304e 100644 --- a/src/main/java/twilightforest/init/TFBlocks.java +++ b/src/main/java/twilightforest/init/TFBlocks.java @@ -268,7 +268,7 @@ public class TFBlocks { public static final DeferredBlock NAGA_COURTYARD_MINIATURE_STRUCTURE = registerWithItem("naga_courtyard_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); public static final DeferredBlock LICH_TOWER_MINIATURE_STRUCTURE = registerWithItem("lich_tower_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); public static final DeferredBlock MINOTAUR_LABYRINTH_MINIATURE_STRUCTURE = register("minotaur_labyrinth_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); - // public static final DeferredBlock HYDRA_LAIR_MINIATURE_STRUCTURE = register("hydra_lair_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); +// public static final DeferredBlock HYDRA_LAIR_MINIATURE_STRUCTURE = register("hydra_lair_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); // public static final DeferredBlock GOBLIN_STRONGHOLD_MINIATURE_STRUCTURE = register("goblin_stronghold_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); public static final DeferredBlock DARK_TOWER_MINIATURE_STRUCTURE = register("dark_tower_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); // public static final DeferredBlock YETI_CAVE_MINIATURE_STRUCTURE = register("yeti_cave_miniature_structure", MiniatureStructureBlock::new, () -> BlockBehaviour.Properties.ofFullCopy(TWILIGHT_PORTAL_MINIATURE_STRUCTURE.get())); From bbbdaa3d5882b054b8fde1b57f2266218025822b Mon Sep 17 00:00:00 2001 From: Albazavr Date: Mon, 20 Jul 2026 02:57:13 +0300 Subject: [PATCH 16/18] Reverted back LichMinionModel --- .../client/model/entity/LichMinionModel.java | 31 +++++++++++++++++++ .../state/entity/LichMinionRenderState.java | 7 +++++ 2 files changed, 38 insertions(+) create mode 100644 src/main/java/twilightforest/client/model/entity/LichMinionModel.java create mode 100644 src/main/java/twilightforest/client/state/entity/LichMinionRenderState.java diff --git a/src/main/java/twilightforest/client/model/entity/LichMinionModel.java b/src/main/java/twilightforest/client/model/entity/LichMinionModel.java new file mode 100644 index 0000000000..e4b514c615 --- /dev/null +++ b/src/main/java/twilightforest/client/model/entity/LichMinionModel.java @@ -0,0 +1,31 @@ +package twilightforest.client.model.entity; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.model.monster.zombie.ZombieModel; +import net.minecraft.util.ARGB; +import twilightforest.client.state.entity.LichMinionRenderState; + +public class LichMinionModel extends ZombieModel { + + private boolean hasStrength; + + public LichMinionModel(ModelPart root) { + super(root); + } + + @Override + public void setupAnim(LichMinionRenderState state) { + this.hasStrength = state.hasStrength; + } + + @Override + public void renderToBuffer(PoseStack stack, VertexConsumer builder, int light, int overlay, int color) { + if (this.hasStrength) { + super.renderToBuffer(stack, builder, light, overlay, ARGB.color(ARGB.alpha(color), (int) (ARGB.red(color) * 0.25F), ARGB.green(color), (int) (ARGB.blue(color) * 0.25F))); + } else { + super.renderToBuffer(stack, builder, light, overlay, ARGB.color(ARGB.alpha(color), (int) (ARGB.red(color) * 0.5F), ARGB.green(color), (int) (ARGB.blue(color) * 0.5F))); + } + } +} \ No newline at end of file diff --git a/src/main/java/twilightforest/client/state/entity/LichMinionRenderState.java b/src/main/java/twilightforest/client/state/entity/LichMinionRenderState.java new file mode 100644 index 0000000000..8426cd207c --- /dev/null +++ b/src/main/java/twilightforest/client/state/entity/LichMinionRenderState.java @@ -0,0 +1,7 @@ +package twilightforest.client.state.entity; + +import net.minecraft.client.renderer.entity.state.ZombieRenderState; + +public class LichMinionRenderState extends ZombieRenderState { + public boolean hasStrength; +} \ No newline at end of file From 4c1891d48cb8150d995941250a5aecb3336bf7d3 Mon Sep 17 00:00:00 2001 From: Albazavr Date: Mon, 20 Jul 2026 03:00:35 +0300 Subject: [PATCH 17/18] Extracted LoyalZombieRenderState to its own file --- .../client/model/entity/LoyalZombieModel.java | 8 ++------ .../client/state/entity/LoyalZombieRenderState.java | 7 +++++++ 2 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 src/main/java/twilightforest/client/state/entity/LoyalZombieRenderState.java diff --git a/src/main/java/twilightforest/client/model/entity/LoyalZombieModel.java b/src/main/java/twilightforest/client/model/entity/LoyalZombieModel.java index d32f6b6c08..2e9ce59bfb 100644 --- a/src/main/java/twilightforest/client/model/entity/LoyalZombieModel.java +++ b/src/main/java/twilightforest/client/model/entity/LoyalZombieModel.java @@ -7,12 +7,12 @@ import net.minecraft.client.model.geom.ModelPart; import net.minecraft.util.ARGB; import net.minecraft.util.Mth; -import net.minecraft.client.renderer.entity.state.HumanoidRenderState; +import twilightforest.client.state.entity.LoyalZombieRenderState; /** * [VanillaCopy] {@link net.minecraft.client.model.monster.zombie.AbstractZombieModel} due to generic restrictions */ -public class LoyalZombieModel extends HumanoidModel { +public class LoyalZombieModel extends HumanoidModel { public LoyalZombieModel(ModelPart part) { super(part); @@ -41,8 +41,4 @@ public void renderToBuffer(PoseStack stack, VertexConsumer builder, int light, i int greenColor = ARGB.color(ARGB.alpha(color), (int) (ARGB.red(color) * 0.25F), ARGB.green(color), (int) (ARGB.blue(color) * 0.25F)); super.renderToBuffer(stack, builder, light, overlay, greenColor); } - - public static class LoyalZombieRenderState extends HumanoidRenderState { - public boolean isAggressive; - } } diff --git a/src/main/java/twilightforest/client/state/entity/LoyalZombieRenderState.java b/src/main/java/twilightforest/client/state/entity/LoyalZombieRenderState.java new file mode 100644 index 0000000000..e1a23174d1 --- /dev/null +++ b/src/main/java/twilightforest/client/state/entity/LoyalZombieRenderState.java @@ -0,0 +1,7 @@ +package twilightforest.client.state.entity; + +import net.minecraft.client.renderer.entity.state.HumanoidRenderState; + +public class LoyalZombieRenderState extends HumanoidRenderState { + public boolean isAggressive; +} \ No newline at end of file From 7dcc892ac69b7a2a0afe2914c74a1585aac81c95 Mon Sep 17 00:00:00 2001 From: Albazavr Date: Mon, 20 Jul 2026 03:02:31 +0300 Subject: [PATCH 18/18] Fixed UpperGoblinKnightModel --- .../client/model/entity/LichMinionModel.java | 31 ------------- .../client/model/entity/LoyalZombieModel.java | 44 ------------------- .../model/entity/UpperGoblinKnightModel.java | 4 +- 3 files changed, 1 insertion(+), 78 deletions(-) delete mode 100644 src/main/java/twilightforest/client/model/entity/LichMinionModel.java delete mode 100644 src/main/java/twilightforest/client/model/entity/LoyalZombieModel.java diff --git a/src/main/java/twilightforest/client/model/entity/LichMinionModel.java b/src/main/java/twilightforest/client/model/entity/LichMinionModel.java deleted file mode 100644 index e4b514c615..0000000000 --- a/src/main/java/twilightforest/client/model/entity/LichMinionModel.java +++ /dev/null @@ -1,31 +0,0 @@ -package twilightforest.client.model.entity; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import net.minecraft.client.model.geom.ModelPart; -import net.minecraft.client.model.monster.zombie.ZombieModel; -import net.minecraft.util.ARGB; -import twilightforest.client.state.entity.LichMinionRenderState; - -public class LichMinionModel extends ZombieModel { - - private boolean hasStrength; - - public LichMinionModel(ModelPart root) { - super(root); - } - - @Override - public void setupAnim(LichMinionRenderState state) { - this.hasStrength = state.hasStrength; - } - - @Override - public void renderToBuffer(PoseStack stack, VertexConsumer builder, int light, int overlay, int color) { - if (this.hasStrength) { - super.renderToBuffer(stack, builder, light, overlay, ARGB.color(ARGB.alpha(color), (int) (ARGB.red(color) * 0.25F), ARGB.green(color), (int) (ARGB.blue(color) * 0.25F))); - } else { - super.renderToBuffer(stack, builder, light, overlay, ARGB.color(ARGB.alpha(color), (int) (ARGB.red(color) * 0.5F), ARGB.green(color), (int) (ARGB.blue(color) * 0.5F))); - } - } -} \ No newline at end of file diff --git a/src/main/java/twilightforest/client/model/entity/LoyalZombieModel.java b/src/main/java/twilightforest/client/model/entity/LoyalZombieModel.java deleted file mode 100644 index 2e9ce59bfb..0000000000 --- a/src/main/java/twilightforest/client/model/entity/LoyalZombieModel.java +++ /dev/null @@ -1,44 +0,0 @@ -package twilightforest.client.model.entity; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import net.minecraft.client.model.AnimationUtils; -import net.minecraft.client.model.HumanoidModel; -import net.minecraft.client.model.geom.ModelPart; -import net.minecraft.util.ARGB; -import net.minecraft.util.Mth; -import twilightforest.client.state.entity.LoyalZombieRenderState; - -/** - * [VanillaCopy] {@link net.minecraft.client.model.monster.zombie.AbstractZombieModel} due to generic restrictions - */ -public class LoyalZombieModel extends HumanoidModel { - - public LoyalZombieModel(ModelPart part) { - super(part); - } - - @Override - public void setupAnim(LoyalZombieRenderState state) { - super.setupAnim(state); - boolean flag = state.isAggressive; - float f = Mth.sin(state.attackTime * Mth.PI); - float f1 = Mth.sin((1.0F - (1.0F - state.attackTime) * (1.0F - state.attackTime)) * Mth.PI); - this.rightArm.zRot = 0.0F; - this.leftArm.zRot = 0.0F; - this.rightArm.yRot = -(0.1F - f * 0.6F); - this.leftArm.yRot = 0.1F - f * 0.6F; - float f2 = -Mth.PI / (flag ? 1.5F : 2.25F); - this.rightArm.xRot = f2; - this.leftArm.xRot = f2; - this.rightArm.xRot += f * 1.2F - f1 * 0.4F; - this.leftArm.xRot += f * 1.2F - f1 * 0.4F; - AnimationUtils.bobArms(this.rightArm, this.leftArm, state.ageScale); - } - - @Override - public void renderToBuffer(PoseStack stack, VertexConsumer builder, int light, int overlay, int color) { - int greenColor = ARGB.color(ARGB.alpha(color), (int) (ARGB.red(color) * 0.25F), ARGB.green(color), (int) (ARGB.blue(color) * 0.25F)); - super.renderToBuffer(stack, builder, light, overlay, greenColor); - } -} diff --git a/src/main/java/twilightforest/client/model/entity/UpperGoblinKnightModel.java b/src/main/java/twilightforest/client/model/entity/UpperGoblinKnightModel.java index 315d2d96c3..30634c0a45 100644 --- a/src/main/java/twilightforest/client/model/entity/UpperGoblinKnightModel.java +++ b/src/main/java/twilightforest/client/model/entity/UpperGoblinKnightModel.java @@ -26,11 +26,9 @@ public static LayerDefinition create() { MeshDefinition meshdefinition = new MeshDefinition(); PartDefinition partdefinition = meshdefinition.getRoot(); - var head = partdefinition.addOrReplaceChild("head", CubeListBuilder.create(), + partdefinition.addOrReplaceChild("head", CubeListBuilder.create(), PartPose.offset(0.0F, 12.0F, 0.0F)); - head.addOrReplaceChild("hat", CubeListBuilder.create(), PartPose.ZERO); - var hat = partdefinition.addOrReplaceChild("hat", CubeListBuilder.create(), PartPose.offset(0.0F, 12.0F, 0.0F));