10 Commits

Author SHA1 Message Date
ae5783aa1d gitea workflow I hope
Some checks failed
Build Minecraft Mod / build (push) Failing after 1m24s
Build Minecraft Mod / release (push) Has been skipped
2026-03-31 14:05:03 +02:00
99a04d5b43 get update from school pc since github banned us :( 2026-03-31 14:00:23 +02:00
6fc34318bf end update in the end wohoo idfk 2026-03-29 19:13:20 +02:00
0a120a8ee6 end update fahhhh 2026-03-29 13:58:42 +02:00
0501d8ee09 end update vol 1 2026-03-28 18:05:20 +01:00
7c779124dc plane fix kinda 2026-03-27 13:34:11 +01:00
9c48313990 update readme and make blueprints survival friendly 2026-03-26 18:03:52 +01:00
8869dc4087 fix blueprint lighting 2026-03-25 18:33:10 +01:00
7e5700d723 fah 2026-03-25 16:30:37 +01:00
d44fb3ca9a blueprint small fix 2026-03-25 15:34:18 +01:00
110 changed files with 1968 additions and 177 deletions

128
.gitea/workflows/build.yml Normal file
View File

@@ -0,0 +1,128 @@
name: Build Minecraft Mod
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 21
- name: Make gradlew executable
run: chmod +x ./gradlew
- name: Build mod
run: ./gradlew build
- name: Read mod info
id: mod_info
run: |
NAME=$(grep "^archives_base_name" gradle.properties | cut -d'=' -f2)
VERSION=$(grep "^mod_version" gradle.properties | cut -d'=' -f2)
if [ -z "$NAME" ] || [ -z "$VERSION" ]; then
echo "Failed to read mod info"
exit 1
fi
JAR="build/libs/${NAME}-${VERSION}.jar"
if [ ! -f "$JAR" ]; then
echo "Jar not found: $JAR"
exit 1
fi
echo "NAME=$NAME" >> $GITEA_ENV
echo "VERSION=$VERSION" >> $GITEA_ENV
echo "JAR=$JAR" >> $GITEA_ENV
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: minecraft-mod
path: ${{ env.JAR }}
release:
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download artifact
uses: actions/download-artifact@v3
with:
name: minecraft-mod
path: ./release-artifacts/
- name: Install jq
run: sudo apt-get update && sudo apt-get install -y jq
- name: Read mod info again
run: |
NAME=$(grep "^archives_base_name" gradle.properties | cut -d'=' -f2)
VERSION=$(grep "^mod_version" gradle.properties | cut -d'=' -f2)
echo "NAME=$NAME" >> $GITEA_ENV
echo "VERSION=$VERSION" >> $GITEA_ENV
- name: Determine tag
run: |
BASE="${NAME}-${VERSION}"
TAG="$BASE"
i=1
while true; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: token ${{ secrets.GITEATOKEN }}" \
"${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}/releases/tags/$TAG")
if [ "$STATUS" = "404" ]; then
break
fi
TAG="${BASE}($i)"
i=$((i+1))
done
echo "TAG=$TAG" >> $GITEA_ENV
- name: Create release
run: |
curl -X POST "${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}/releases" \
-H "Authorization: token ${{ secrets.GITEATOKEN }}" \
-H "Content-Type: application/json" \
-d "{
\"tag_name\": \"${TAG}\",
\"name\": \"${TAG}\"
}"
- name: Get release ID
run: |
RELEASE_ID=$(curl -s \
-H "Authorization: token ${{ secrets.GITEATOKEN }}" \
"${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}/releases/tags/${TAG}" \
| jq -r '.id')
echo "RELEASE_ID=$RELEASE_ID" >> $GITEA_ENV
- name: Upload jar to release
run: |
FILE=$(ls ./release-artifacts/*.jar | head -n 1)
curl -X POST \
-H "Authorization: token ${{ secrets.GITEATOKEN }}" \
-H "Content-Type: application/java-archive" \
--data-binary @"$FILE" \
"${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}/releases/${RELEASE_ID}/assets?name=$(basename $FILE)"

View File

@@ -1,34 +1,49 @@
![Showcase](https://tggamesyt.dev/assets/szar.gif) ![Showcase](https://tggamesyt.dev/assets/szar.gif)
# Szar # Szar
*Szar means <u>Shit</u> in Hungarian*
Ez egy privát, kísérleti fabric Minecraft 1.20.1 mod. Szar is a private, experimental Fabric Minecraft 1.20.1 mod created as a school programming project and as a joke between classmates and friends.
## FIGYELMEZTETÉS The mod features a wide variety of over-the-top, humorous, and intentionally absurd ideas. Its content is entirely fictional and parody-style, designed for fun and creativity, and **not meant to be taken seriously**.
Ez a mod 18+ tartalmat tartalmaz, beleértve:
- sértő, rasszista vagy provokatív elemeket
- felnőtteknek szóló témákat
- illegális vagy valós életben elfogadhatatlan dolgok fiktív megjelenítését
A mod **nem oktatási célú**, **nem támogatja**, és **nem népszerűsíti** ezeket a témákat. ## Features
Kizárólag saját használatra készült.
Ha ezek a tartalmak zavaróak számodra, **NE használd**. This mod includes (but is not limited to):
A mod használata **kizárólag saját felelősségre történik**.
- Crazy functional blocks
- Custom music discs
- Weapons such as guns
- Casinos with multiple gambling machines
- Police systems
- Drugs, memes, and historical figures
- Nukes and backrooms
- Board games
- And basically anything that would be “crazy in Minecraft”
If you can imagine it being absurd or over-the-top in Minecraft, chances are this mod has it, if not, please contact me and it will!
# Hungarian / Magyar
# Szar
*buzi ai forditas mer lusta vagyok*
# Shit A Szar egy privát, kísérleti Fabric Minecraft 1.20.1 mod, amelyet iskolai programozási projektként és viccnek készítettek osztálytársak és barátok között.
This is a private, experimental 1.20.1 fabric Minecraft mod. A mod számos túlzó, humoros és szándékosan abszurd ötletet tartalmaz. A tartalom teljesen fiktív és paródiaszerű, szórakoztatásra és kreativitásra készült, **nem szabad komolyan venni**.
## WARNING (EN) ### Funkciók
This mod contains **18+ content**, including the following: A mod tartalmaz (de nem kizárólagosan):
- offensive, provocative, or otherwise inappropriate themes
- adult themed content
- fictional representations of content that would be unacceptable or illegal in real life
This mod is **not intended for public use**, does **not endorse** any of the themes depicted, and was created **for personal use only**. - Őrült, funkcionális blokkok
- Egyedi zenélőlemezek
- Fegyverek, például pisztolyok
- Kaszinók többféle szerencsejáték géppel
- Rendőrségi rendszerek
- Drogok, mémek és történelmi személyek
- Nukleáris fegyverek és backroomból inspirált helyszínek
- Társasjátékok
- És gyakorlatilag bármi, ami “őrült” lenne a Minecraftban
If you find such content disturbing or offensive, **do not use this mod**. Ha el tudod képzelni, hogy valami túlzó vagy őrült lehet a Minecraftban, nagy valószínűséggel ez a mod tartalmazza, ha meg nem, akkor írj rám, és fogja!
Use at your **own responsibility**.

View File

@@ -6,7 +6,7 @@ minecraft_version=1.20.1
yarn_mappings=1.20.1+build.10 yarn_mappings=1.20.1+build.10
loader_version=0.18.3 loader_version=0.18.3
# Mod Properties # Mod Properties
mod_version=26.3.25 mod_version=26.3.30
maven_group=dev.tggamesyt maven_group=dev.tggamesyt
archives_base_name=szar archives_base_name=szar
# Dependencies # Dependencies

View File

@@ -4,13 +4,17 @@ import dev.tggamesyt.szar.BlueprintBlockEntity;
import net.minecraft.block.BlockRenderType; import net.minecraft.block.BlockRenderType;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.LightmapTextureManager;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.WorldRenderer;
import net.minecraft.client.render.block.BlockRenderManager; import net.minecraft.client.render.block.BlockRenderManager;
import net.minecraft.client.render.block.entity.BlockEntityRenderer; import net.minecraft.client.render.block.entity.BlockEntityRenderer;
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory; import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.registry.Registries; import net.minecraft.registry.Registries;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.random.Random; import net.minecraft.util.math.random.Random;
public class BlueprintBlockEntityRenderer implements BlockEntityRenderer<BlueprintBlockEntity> { public class BlueprintBlockEntityRenderer implements BlockEntityRenderer<BlueprintBlockEntity> {
@@ -20,6 +24,7 @@ public class BlueprintBlockEntityRenderer implements BlockEntityRenderer<Bluepri
@Override @Override
public void render(BlueprintBlockEntity entity, float tickDelta, MatrixStack matrices, public void render(BlueprintBlockEntity entity, float tickDelta, MatrixStack matrices,
VertexConsumerProvider vertexConsumers, int light, int overlay) { VertexConsumerProvider vertexConsumers, int light, int overlay) {
if (!entity.hasStoredBlock()) return; if (!entity.hasStoredBlock()) return;
String storedId = entity.getStoredBlockId(); String storedId = entity.getStoredBlockId();
@@ -31,72 +36,38 @@ public class BlueprintBlockEntityRenderer implements BlockEntityRenderer<Bluepri
BlockState storedState = block.getDefaultState(); BlockState storedState = block.getDefaultState();
if (storedState.getRenderType() == BlockRenderType.INVISIBLE) return; if (storedState.getRenderType() == BlockRenderType.INVISIBLE) return;
// Get the shape/state of the blueprint block itself
BlockState blueprintState = entity.getCachedState(); BlockState blueprintState = entity.getCachedState();
// We want to render the stored block's TEXTURE but on the blueprint block's SHAPE. var renderer = MinecraftClient.getInstance().getBlockRenderManager();
// The way to do this: find the model for the blueprint block shape,
// but swap in the stored block's sprite via a custom render layer.
// Simplest approach: render the blueprint block's model with the stored block's
// textures by remapping the sprite.
BlockRenderManager renderer = MinecraftClient.getInstance().getBlockRenderManager();
matrices.push();
// Render the blueprint shape using the stored block's texture
// by temporarily using the stored block's model sprites on our shape
renderWithStoredTexture(entity, blueprintState, storedState, matrices, vertexConsumers, light, overlay, renderer);
matrices.pop();
}
private void renderWithStoredTexture(BlueprintBlockEntity entity, BlockState blueprintState,
BlockState storedState, MatrixStack matrices,
VertexConsumerProvider vertexConsumers, int light, int overlay,
BlockRenderManager renderer) {
// Get the first (main) sprite from the stored block's model
var storedModel = renderer.getModel(storedState); var storedModel = renderer.getModel(storedState);
var blueprintModel = renderer.getModel(blueprintState); var blueprintModel = renderer.getModel(blueprintState);
var sprites = storedModel.getParticleSprite(); // main texture of stored block var wrappedModel = new BlueprintWrappedModel(
blueprintModel,
storedModel,
blueprintState,
storedState, entity
);
// Render blueprint model quads, replacing its texture with stored block's sprite var layer = net.minecraft.client.render.RenderLayers.getBlockLayer(storedState);
var random = Random.create(); var consumer = vertexConsumers.getBuffer(layer);
random.setSeed(42L);
var bufferSource = vertexConsumers; matrices.push();
var layer = net.minecraft.client.render.RenderLayers.getBlockLayer(blueprintState);
var consumer = bufferSource.getBuffer(layer);
for (var direction : new net.minecraft.util.math.Direction[]{ renderer.getModelRenderer().render(
null, entity.getWorld(),
net.minecraft.util.math.Direction.UP, wrappedModel,
net.minecraft.util.math.Direction.DOWN, storedState,
net.minecraft.util.math.Direction.NORTH, entity.getPos(),
net.minecraft.util.math.Direction.SOUTH, matrices,
net.minecraft.util.math.Direction.EAST, consumer,
net.minecraft.util.math.Direction.WEST false,
}) { net.minecraft.util.math.random.Random.create(),
random.setSeed(42L); 42L,
var quads = blueprintModel.getQuads(blueprintState, direction, random); overlay
for (var quad : quads) { );
// Emit the quad but with the stored block's sprite UV remapped
emitQuadWithSprite(consumer, matrices, quad, sprites, light, overlay);
}
}
}
private void emitQuadWithSprite(net.minecraft.client.render.VertexConsumer consumer, matrices.pop();
MatrixStack matrices,
net.minecraft.client.render.model.BakedQuad quad,
net.minecraft.client.texture.Sprite sprite,
int light, int overlay) {
// Re-emit the quad geometry but remap UVs to the new sprite
consumer.quad(matrices.peek(), quad, 1f, 1f, 1f, light, overlay);
// Note: this uses the quad's original UVs which point to the blueprint texture.
// For full texture remapping you'd need to manually rewrite vertex data.
// This gives correct shape with blueprint texture as fallback —
// see note below for full UV remapping.
} }
} }

View File

@@ -0,0 +1,165 @@
package dev.tggamesyt.szar.client;
import dev.tggamesyt.szar.BlueprintBlockEntity;
import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.render.model.json.ModelOverrideList;
import net.minecraft.client.render.model.json.ModelTransformation;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.random.Random;
import java.util.ArrayList;
import java.util.List;
public class BlueprintWrappedModel implements BakedModel {
private final BakedModel blueprint;
private final BakedModel stored;
private final BlockState blueprintState;
private final BlockState storedState;
private final BlueprintBlockEntity entity;
public BlueprintWrappedModel(BakedModel blueprint, BakedModel stored,
BlockState blueprintState, BlockState storedState, BlueprintBlockEntity entity) {
this.blueprint = blueprint;
this.stored = stored;
this.blueprintState = blueprintState;
this.storedState = storedState;
this.entity = entity;
}
@Override
public List<BakedQuad> getQuads(BlockState state, Direction face, Random random) {
List<BakedQuad> original = blueprint.getQuads(blueprintState, face, random);
List<BakedQuad> result = new ArrayList<>(original.size());
for (BakedQuad quad : original) {
int[] data = quad.getVertexData().clone();
Direction quadFace = quad.getFace();
Sprite target = getSpriteForFace(stored, storedState, quadFace);
remapUVs(data, quad.getSprite(), target);
BlockPos pos = entity.getPos();
Camera camera = MinecraftClient.getInstance().gameRenderer.getCamera();
Vec3d camPos = camera.getPos();
double dx = pos.getX() + 0.5 - camPos.x;
double dy = pos.getY() + 0.5 - camPos.y;
double dz = pos.getZ() + 0.5 - camPos.z;
double distance = Math.sqrt(dx*dx + dy*dy + dz*dz);
float offsetAmount = 0.0001f + (float)distance * 1e-5f;
offsetAmount = Math.min(offsetAmount, 0.001f); // clamp max
offsetVertsAlongNormal(data, quad.getFace(), offsetAmount);
result.add(new BakedQuad(
data,
quad.getColorIndex(),
quadFace,
target,
quad.hasShade()
));
}
return result;
}
// --- IMPORTANT: delegate everything else properly ---
@Override
public boolean useAmbientOcclusion() {
return stored.useAmbientOcclusion(); // important for lighting
}
@Override
public boolean hasDepth() {
return stored.hasDepth();
}
@Override
public boolean isSideLit() {
return stored.isSideLit();
}
@Override
public boolean isBuiltin() {
return false;
}
@Override
public Sprite getParticleSprite() {
return stored.getParticleSprite();
}
@Override
public ModelTransformation getTransformation() {
return stored.getTransformation();
}
@Override
public ModelOverrideList getOverrides() {
return stored.getOverrides();
}
// --- helpers ---
private Sprite getSpriteForFace(BakedModel model, BlockState state, Direction face) {
Random rand = Random.create(42L);
List<BakedQuad> quads = model.getQuads(state, face, rand);
if (!quads.isEmpty()) return quads.get(0).getSprite();
quads = model.getQuads(state, null, rand);
for (BakedQuad q : quads) {
if (q.getFace() == face) return q.getSprite();
}
return model.getParticleSprite();
}
private void remapUVs(int[] vertexData, Sprite from, Sprite to) {
int stride = 8;
for (int i = 0; i < 4; i++) {
int uvIndex = i * stride + 4;
float u = Float.intBitsToFloat(vertexData[uvIndex]);
float v = Float.intBitsToFloat(vertexData[uvIndex + 1]);
float nu = (u - from.getMinU()) / (from.getMaxU() - from.getMinU());
float nv = (v - from.getMinV()) / (from.getMaxV() - from.getMinV());
float newU = to.getMinU() + nu * (to.getMaxU() - to.getMinU());
float newV = to.getMinV() + nv * (to.getMaxV() - to.getMinV());
vertexData[uvIndex] = Float.floatToRawIntBits(newU);
vertexData[uvIndex + 1] = Float.floatToRawIntBits(newV);
}
}
private void offsetVertsAlongNormal(int[] vertexData, Direction face, float amount) {
if (face == null) return; // skip general quads
float dx = face.getOffsetX() * amount;
float dy = face.getOffsetY() * amount;
float dz = face.getOffsetZ() * amount;
int vertexSize = 8; // X,Y,Z,COLOR,U,V,UV2,NORMAL
for (int i = 0; i < 4; i++) {
int base = i * vertexSize;
float x = Float.intBitsToFloat(vertexData[base]);
float y = Float.intBitsToFloat(vertexData[base + 1]);
float z = Float.intBitsToFloat(vertexData[base + 2]);
vertexData[base] = Float.floatToRawIntBits(x + dx);
vertexData[base + 1] = Float.floatToRawIntBits(y + dy);
vertexData[base + 2] = Float.floatToRawIntBits(z + dz);
}
}
}

View File

@@ -38,31 +38,35 @@ public class PlaneEntityRenderer extends EntityRenderer<PlaneEntity> {
) { ) {
matrices.push(); matrices.push();
// Smooth interpolation of rotation float interpolatedYaw = entity.prevYaw + (entity.getYaw() - entity.prevYaw) * tickDelta;
float interpolatedYaw = entity.prevYaw + (entity.getYaw() - entity.prevYaw) * tickDelta;
float interpolatedPitch = entity.prevPitch + (entity.getPitch() - entity.prevPitch) * tickDelta; float interpolatedPitch = entity.prevPitch + (entity.getPitch() - entity.prevPitch) * tickDelta;
// Scale float pitchRad = (float) Math.toRadians(interpolatedPitch);
matrices.scale(4.0F, 4.0F, 4.0F); float yawRad = (float) Math.toRadians(interpolatedYaw);
// Move model to correct pivot point final float PIVOT_OFFSET = 4F;
final float ARC_RADIUS = 8F;
float dy = PIVOT_OFFSET * (1.0F - (float) Math.cos(pitchRad))
- (ARC_RADIUS * (1.0F - (float) Math.cos(pitchRad)) - ARC_RADIUS * (1.0F - (float) Math.cos(pitchRad)));
float dz = ARC_RADIUS * (float) Math.sin(pitchRad);
float worldX = -dz * (float) Math.sin(yawRad);
float worldZ = dz * (float) Math.cos(yawRad);
float worldY = PIVOT_OFFSET * (1.0F - (float) Math.cos(pitchRad));
matrices.translate(worldX, worldY, worldZ);
matrices.scale(4.0F, 4.0F, 4.0F);
matrices.translate(0.0, 1.5, 0.0); matrices.translate(0.0, 1.5, 0.0);
// Rotate to match hitbox exactly
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-interpolatedYaw)); matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-interpolatedYaw));
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(interpolatedPitch)); matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(interpolatedPitch));
// Rotate 180° to fix backwards-facing
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180.0F)); matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180.0F));
// Flip model upright (Minecraft model fix)
matrices.scale(-1.0F, -1.0F, 1.0F); matrices.scale(-1.0F, -1.0F, 1.0F);
// Set model angles
model.setAngles( model.setAngles(
entity, entity, 0, 0,
0,
0,
entity.age + tickDelta, entity.age + tickDelta,
interpolatedYaw, interpolatedYaw,
interpolatedPitch interpolatedPitch
@@ -72,10 +76,8 @@ public class PlaneEntityRenderer extends EntityRenderer<PlaneEntity> {
vertices.getBuffer(RenderLayer.getEntityCutout(getTexture(entity))); vertices.getBuffer(RenderLayer.getEntityCutout(getTexture(entity)));
model.render( model.render(
matrices, matrices, consumer,
consumer, light, OverlayTexture.DEFAULT_UV,
light,
OverlayTexture.DEFAULT_UV,
1.0F, 1.0F, 1.0F, 1.0F 1.0F, 1.0F, 1.0F, 1.0F
); );

View File

@@ -565,6 +565,18 @@ public class SzarClient implements ClientModInitializer {
Szar.CANNABIS_BLOCK, Szar.CANNABIS_BLOCK,
RenderLayer.getCutout() RenderLayer.getCutout()
); );
BlockRenderLayerMap.INSTANCE.putBlock(
CONNECT_FOUR_BLOCK,
RenderLayer.getCutout()
);
BlockRenderLayerMap.INSTANCE.putBlock(
SMALL_CHORUS,
RenderLayer.getCutout()
);
BlockRenderLayerMap.INSTANCE.putBlock(
SMALL_CHORUS_FLOWER,
RenderLayer.getCutout()
);
BlockRenderLayerMap.INSTANCE.putBlock( BlockRenderLayerMap.INSTANCE.putBlock(
ROULETTE_BLOCK, ROULETTE_BLOCK,
RenderLayer.getCutout() RenderLayer.getCutout()

View File

@@ -0,0 +1,130 @@
package dev.tggamesyt.szar.client.mixin;
import dev.tggamesyt.szar.*;
import net.minecraft.block.BlockState;
import net.minecraft.client.particle.BlockDustParticle;
import net.minecraft.client.particle.ParticleManager;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.registry.Registries;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ParticleManager.class)
public class ParticleManagerMixin {
@Shadow
public ClientWorld world;
@Inject(method = "addBlockBreakParticles", at = @At("HEAD"), cancellable = true)
private void redirectBreakParticles(BlockPos pos, BlockState state, CallbackInfo ci) {
if (world == null) return;
if (!(state.getBlock() instanceof BlueprintStairsBlock ||
state.getBlock() instanceof BlueprintSlabBlock ||
state.getBlock() instanceof BlueprintDoorBlock ||
state.getBlock() instanceof BlueprintTrapDoorBlock ||
state.getBlock() instanceof BlueprintWallBlock ||
state.getBlock() instanceof BlueprintFenceBlock)) {
return;
}
var be = world.getBlockEntity(pos);
if (!(be instanceof BlueprintBlockEntity blueprint) || !blueprint.hasStoredBlock()) return;
BlockState storedState = Registries.BLOCK
.get(new Identifier(blueprint.getStoredBlockId()))
.getDefaultState();
ci.cancel();
// ✅ USE BLUEPRINT SHAPE, NOT STORED
var shape = state.getOutlineShape(world, pos);
shape.forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> {
double dx = Math.min(1.0, maxX - minX);
double dy = Math.min(1.0, maxY - minY);
double dz = Math.min(1.0, maxZ - minZ);
int ix = Math.max(2, net.minecraft.util.math.MathHelper.ceil(dx / 0.25));
int iy = Math.max(2, net.minecraft.util.math.MathHelper.ceil(dy / 0.25));
int iz = Math.max(2, net.minecraft.util.math.MathHelper.ceil(dz / 0.25));
for (int x = 0; x < ix; x++) {
for (int y = 0; y < iy; y++) {
for (int z = 0; z < iz; z++) {
double fx = (x + 0.5) / ix;
double fy = (y + 0.5) / iy;
double fz = (z + 0.5) / iz;
double px = fx * dx + minX;
double py = fy * dy + minY;
double pz = fz * dz + minZ;
((ParticleManager)(Object)this).addParticle(
new BlockDustParticle(
world,
pos.getX() + px,
pos.getY() + py,
pos.getZ() + pz,
fx - 0.5,
fy - 0.5,
fz - 0.5,
storedState, // ✅ texture comes from stored
pos
)
);
}
}
}
});
}
@Inject(method = "addBlockBreakingParticles", at = @At("HEAD"), cancellable = true)
private void redirectBreakingParticles(BlockPos pos, Direction direction, CallbackInfo ci) {
if (world == null) return;
BlockState state = world.getBlockState(pos);
if (!(state.getBlock() instanceof BlueprintStairsBlock ||
state.getBlock() instanceof BlueprintSlabBlock ||
state.getBlock() instanceof BlueprintDoorBlock ||
state.getBlock() instanceof BlueprintTrapDoorBlock ||
state.getBlock() instanceof BlueprintWallBlock ||
state.getBlock() instanceof BlueprintFenceBlock)) {return;}
var be = world.getBlockEntity(pos);
if (!(be instanceof BlueprintBlockEntity blueprint) || !blueprint.hasStoredBlock()) return;
BlockState storedState = Registries.BLOCK
.get(new Identifier(blueprint.getStoredBlockId()))
.getDefaultState();
ci.cancel();
Box box = storedState.getOutlineShape(world, pos).getBoundingBox();
int i = pos.getX(), j = pos.getY(), k = pos.getZ();
Random random = Random.create();
double d = i + random.nextDouble() * (box.maxX - box.minX - 0.2) + 0.1 + box.minX;
double e = j + random.nextDouble() * (box.maxY - box.minY - 0.2) + 0.1 + box.minY;
double g = k + random.nextDouble() * (box.maxZ - box.minZ - 0.2) + 0.1 + box.minZ;
if (direction == Direction.DOWN) e = j + box.minY - 0.1;
if (direction == Direction.UP) e = j + box.maxY + 0.1;
if (direction == Direction.NORTH) g = k + box.minZ - 0.1;
if (direction == Direction.SOUTH) g = k + box.maxZ + 0.1;
if (direction == Direction.WEST) d = i + box.minX - 0.1;
if (direction == Direction.EAST) d = i + box.maxX + 0.1;
((ParticleManager)(Object)this).addParticle(
new BlockDustParticle(world, d, e, g, 0, 0, 0, storedState, pos).move(0.2f).scale(0.6f)
);
}
}

View File

@@ -16,6 +16,7 @@
"MouseMixin", "MouseMixin",
"PackMixin", "PackMixin",
"PackScreenCloseMixin", "PackScreenCloseMixin",
"ParticleManagerMixin",
"PlayerEntityRendererMixin", "PlayerEntityRendererMixin",
"PlayerHeldItemFeatureRendererMixin", "PlayerHeldItemFeatureRendererMixin",
"PlayerModelMixin", "PlayerModelMixin",

View File

@@ -1,13 +1,17 @@
package dev.tggamesyt.szar; package dev.tggamesyt.szar;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.DoorBlock;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.enums.DoubleBlockHalf;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.registry.Registries; import net.minecraft.registry.Registries;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockView; import net.minecraft.world.BlockView;
@@ -29,13 +33,20 @@ public class BlueprintBehavior {
ItemStack held = player.getStackInHand(hand); ItemStack held = player.getStackInHand(hand);
if (held.isEmpty()) { if (held.isEmpty() && player.isSneaking()) {
// Clear stored block
blueprint.clearStoredBlock(); blueprint.clearStoredBlock();
return ActionResult.SUCCESS; return ActionResult.SUCCESS;
} }
if (held.getItem() instanceof BlockItem blockItem) { if (!held.isEmpty() && held.getItem() instanceof BlockItem blockItem && !blueprint.hasStoredBlock()) {
if (blockItem.getBlock() instanceof BlueprintStairsBlock ||
blockItem.getBlock() instanceof BlueprintSlabBlock ||
blockItem.getBlock() instanceof BlueprintDoorBlock ||
blockItem.getBlock() instanceof BlueprintTrapDoorBlock ||
blockItem.getBlock() instanceof BlueprintWallBlock ||
blockItem.getBlock() instanceof BlueprintFenceBlock) {
return ActionResult.PASS;
}
String id = Registries.BLOCK.getId(blockItem.getBlock()).toString(); String id = Registries.BLOCK.getId(blockItem.getBlock()).toString();
blueprint.setStoredBlock(id); blueprint.setStoredBlock(id);
if (!player.isCreative()) held.decrement(1); if (!player.isCreative()) held.decrement(1);
@@ -51,12 +62,17 @@ public class BlueprintBehavior {
public static float calcBreakingDelta(BlockState state, PlayerEntity player, public static float calcBreakingDelta(BlockState state, PlayerEntity player,
BlockView world, BlockPos pos, float baseHardness) { BlockView world, BlockPos pos, float baseHardness) {
BlockEntity be = world.getBlockEntity(pos); BlockEntity be = world.getBlockEntity(pos);
if (!(be instanceof BlueprintBlockEntity blueprint) || !blueprint.hasStoredBlock()) { if (!(be instanceof BlueprintBlockEntity blueprint) || !blueprint.hasStoredBlock()) {
return baseHardness; return baseHardness;
} }
float hardness = blueprint.getStoredHardness();
if (hardness < 0) return 0f; // unbreakable BlockState storedState = Registries.BLOCK
return player.getBlockBreakingSpeed(state) / hardness / 30f; .get(new Identifier(blueprint.getStoredBlockId()))
.getDefaultState();
// Fully delegate to vanilla logic
return storedState.calcBlockBreakingDelta(player, world, pos);
} }
/** /**
@@ -64,11 +80,28 @@ public class BlueprintBehavior {
*/ */
public static void onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) { public static void onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) {
BlockEntity be = world.getBlockEntity(pos); BlockEntity be = world.getBlockEntity(pos);
if (!(be instanceof BlueprintBlockEntity blueprint) || !blueprint.hasStoredBlock()) return;
if (!player.isCreative()) { if (!(be instanceof BlueprintBlockEntity blueprint) || !blueprint.hasStoredBlock()) {
ItemStack drop = blueprint.getStoredDrop(); return;
if (!drop.isEmpty()) { }
dropStack(world, pos, drop);
// Drop stored block
if (!world.isClient) {
Block.dropStack(world, pos, blueprint.getStoredDrop());
}
// Handle doors (break other half properly)
if (state.getBlock() instanceof DoorBlock) {
DoubleBlockHalf half = state.get(DoorBlock.HALF);
BlockPos otherPos = (half == DoubleBlockHalf.LOWER) ? pos.up() : pos.down();
BlockState otherState = world.getBlockState(otherPos);
BlockEntity otherBe = world.getBlockEntity(otherPos);
if (otherBe instanceof BlueprintBlockEntity otherBlueprint && otherBlueprint.hasStoredBlock()) {
if (!world.isClient) {
Block.dropStack(world, otherPos, otherBlueprint.getStoredDrop());
}
} }
} }
} }

View File

@@ -1,5 +1,6 @@
package dev.tggamesyt.szar; package dev.tggamesyt.szar;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType; import net.minecraft.block.entity.BlockEntityType;
@@ -16,8 +17,19 @@ public class BlueprintBlockEntity extends BlockEntity {
@Nullable @Nullable
private String storedBlockId = null; private String storedBlockId = null;
public BlueprintBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) { public BlueprintBlockEntity(BlockPos pos, BlockState state) {
super(type, pos, state); super(getBEType(state), pos, state);
}
private static BlockEntityType<BlueprintBlockEntity> getBEType(BlockState state) {
Block block = state.getBlock();
if (block instanceof BlueprintStairsBlock) return BlueprintBlocks.BLUEPRINT_STAIRS_BE_TYPE;
if (block instanceof BlueprintSlabBlock) return BlueprintBlocks.BLUEPRINT_SLAB_BE_TYPE;
if (block instanceof BlueprintDoorBlock) return BlueprintBlocks.BLUEPRINT_DOOR_BE_TYPE;
if (block instanceof BlueprintTrapDoorBlock) return BlueprintBlocks.BLUEPRINT_TRAPDOOR_BE_TYPE;
if (block instanceof BlueprintWallBlock) return BlueprintBlocks.BLUEPRINT_WALL_BE_TYPE;
if (block instanceof BlueprintFenceBlock) return BlueprintBlocks.BLUEPRINT_FENCE_BE_TYPE;
throw new IllegalStateException("Unknown blueprint block: " + block);
} }
public boolean hasStoredBlock() { public boolean hasStoredBlock() {
@@ -40,6 +52,9 @@ public class BlueprintBlockEntity extends BlockEntity {
public void clearStoredBlock() { public void clearStoredBlock() {
this.storedBlockId = null; this.storedBlockId = null;
markDirty(); markDirty();
if (world != null && !world.isClient) {
world.updateListeners(pos, getCachedState(), getCachedState(), 3);
}
} }
/** Gets the hardness of the stored block, or default if none. */ /** Gets the hardness of the stored block, or default if none. */

View File

@@ -4,6 +4,7 @@ import dev.tggamesyt.szar.Szar;
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
import net.minecraft.block.AbstractBlock; import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.block.MapColor; import net.minecraft.block.MapColor;
import net.minecraft.block.entity.BlockEntityType; import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItem;
@@ -12,6 +13,8 @@ import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry; import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import static dev.tggamesyt.szar.Szar.MOD_ID;
public class BlueprintBlocks { public class BlueprintBlocks {
private static AbstractBlock.Settings settings() { private static AbstractBlock.Settings settings() {
@@ -19,88 +22,89 @@ public class BlueprintBlocks {
.mapColor(MapColor.TERRACOTTA_LIGHT_BLUE) .mapColor(MapColor.TERRACOTTA_LIGHT_BLUE)
.strength(1.0f); .strength(1.0f);
} }
public static final Item BLUEPRINT = Registry.register(
Registries.ITEM,
new Identifier(MOD_ID, "blueprint"),
new Item(new Item.Settings())
);
public static final BlueprintStairsBlock BLUEPRINT_STAIRS = public static final BlueprintStairsBlock BLUEPRINT_STAIRS =
Registry.register(Registries.BLOCK, new Identifier(Szar.MOD_ID, "blueprint_stairs"), Registry.register(Registries.BLOCK, new Identifier(MOD_ID, "blueprint_stairs"),
new BlueprintStairsBlock(settings())); new BlueprintStairsBlock(settings()));
public static final BlueprintSlabBlock BLUEPRINT_SLAB = public static final BlueprintSlabBlock BLUEPRINT_SLAB =
Registry.register(Registries.BLOCK, new Identifier(Szar.MOD_ID, "blueprint_slab"), Registry.register(Registries.BLOCK, new Identifier(MOD_ID, "blueprint_slab"),
new BlueprintSlabBlock(settings())); new BlueprintSlabBlock(settings()));
public static final BlueprintDoorBlock BLUEPRINT_DOOR = public static final BlueprintDoorBlock BLUEPRINT_DOOR =
Registry.register(Registries.BLOCK, new Identifier(Szar.MOD_ID, "blueprint_door"), Registry.register(Registries.BLOCK, new Identifier(MOD_ID, "blueprint_door"),
new BlueprintDoorBlock(settings())); new BlueprintDoorBlock(settings()));
public static final BlueprintTrapDoorBlock BLUEPRINT_TRAPDOOR = public static final BlueprintTrapDoorBlock BLUEPRINT_TRAPDOOR =
Registry.register(Registries.BLOCK, new Identifier(Szar.MOD_ID, "blueprint_trapdoor"), Registry.register(Registries.BLOCK, new Identifier(MOD_ID, "blueprint_trapdoor"),
new BlueprintTrapDoorBlock(settings())); new BlueprintTrapDoorBlock(settings()));
public static final BlueprintWallBlock BLUEPRINT_WALL = public static final BlueprintWallBlock BLUEPRINT_WALL =
Registry.register(Registries.BLOCK, new Identifier(Szar.MOD_ID, "blueprint_wall"), Registry.register(Registries.BLOCK, new Identifier(MOD_ID, "blueprint_wall"),
new BlueprintWallBlock(settings())); new BlueprintWallBlock(AbstractBlock.Settings.copy(Blocks.STONE_BRICK_WALL)));
public static final BlueprintFenceBlock BLUEPRINT_FENCE = public static final BlueprintFenceBlock BLUEPRINT_FENCE =
Registry.register(Registries.BLOCK, new Identifier(Szar.MOD_ID, "blueprint_fence"), Registry.register(Registries.BLOCK, new Identifier(MOD_ID, "blueprint_fence"),
new BlueprintFenceBlock(settings())); new BlueprintFenceBlock(AbstractBlock.Settings.copy(Blocks.OAK_FENCE)));
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_STAIRS_BE_TYPE = public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_STAIRS_BE_TYPE;
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Szar.MOD_ID, "blueprint_stairs_be"), public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_SLAB_BE_TYPE;
FabricBlockEntityTypeBuilder.create( public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_DOOR_BE_TYPE;
(pos, state) -> new BlueprintBlockEntity(null, pos, state), public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_TRAPDOOR_BE_TYPE;
BLUEPRINT_STAIRS).build()); public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_WALL_BE_TYPE;
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_FENCE_BE_TYPE;
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_SLAB_BE_TYPE = static {
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Szar.MOD_ID, "blueprint_slab_be"), BLUEPRINT_STAIRS_BE_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE,
FabricBlockEntityTypeBuilder.create( new Identifier(MOD_ID, "blueprint_stairs_be"),
(pos, state) -> new BlueprintBlockEntity(null, pos, state), FabricBlockEntityTypeBuilder.create(BlueprintBlockEntity::new, BLUEPRINT_STAIRS).build());
BLUEPRINT_SLAB).build());
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_DOOR_BE_TYPE = BLUEPRINT_SLAB_BE_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE,
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Szar.MOD_ID, "blueprint_door_be"), new Identifier(MOD_ID, "blueprint_slab_be"),
FabricBlockEntityTypeBuilder.create( FabricBlockEntityTypeBuilder.create(BlueprintBlockEntity::new, BLUEPRINT_SLAB).build());
(pos, state) -> new BlueprintBlockEntity(null, pos, state),
BLUEPRINT_DOOR).build());
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_TRAPDOOR_BE_TYPE = BLUEPRINT_DOOR_BE_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE,
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Szar.MOD_ID, "blueprint_trapdoor_be"), new Identifier(MOD_ID, "blueprint_door_be"),
FabricBlockEntityTypeBuilder.create( FabricBlockEntityTypeBuilder.create(BlueprintBlockEntity::new, BLUEPRINT_DOOR).build());
(pos, state) -> new BlueprintBlockEntity(null, pos, state),
BLUEPRINT_TRAPDOOR).build());
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_WALL_BE_TYPE = BLUEPRINT_TRAPDOOR_BE_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE,
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Szar.MOD_ID, "blueprint_wall_be"), new Identifier(MOD_ID, "blueprint_trapdoor_be"),
FabricBlockEntityTypeBuilder.create( FabricBlockEntityTypeBuilder.create(BlueprintBlockEntity::new, BLUEPRINT_TRAPDOOR).build());
(pos, state) -> new BlueprintBlockEntity(null, pos, state),
BLUEPRINT_WALL).build());
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_FENCE_BE_TYPE = BLUEPRINT_WALL_BE_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE,
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Szar.MOD_ID, "blueprint_fence_be"), new Identifier(MOD_ID, "blueprint_wall_be"),
FabricBlockEntityTypeBuilder.create( FabricBlockEntityTypeBuilder.create(BlueprintBlockEntity::new, BLUEPRINT_WALL).build());
(pos, state) -> new BlueprintBlockEntity(null, pos, state),
BLUEPRINT_FENCE).build()); BLUEPRINT_FENCE_BE_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE,
new Identifier(MOD_ID, "blueprint_fence_be"),
FabricBlockEntityTypeBuilder.create(BlueprintBlockEntity::new, BLUEPRINT_FENCE).build());
}
public static final BlockItem BLUEPRINT_STAIRS_ITEM = Registry.register(Registries.ITEM, public static final BlockItem BLUEPRINT_STAIRS_ITEM = Registry.register(Registries.ITEM,
new Identifier(Szar.MOD_ID, "blueprint_stairs"), new Identifier(MOD_ID, "blueprint_stairs"),
new BlockItem(BLUEPRINT_STAIRS, new Item.Settings())); new BlockItem(BLUEPRINT_STAIRS, new Item.Settings()));
public static final BlockItem BLUEPRINT_SLAB_ITEM = Registry.register(Registries.ITEM, public static final BlockItem BLUEPRINT_SLAB_ITEM = Registry.register(Registries.ITEM,
new Identifier(Szar.MOD_ID, "blueprint_slab"), new Identifier(MOD_ID, "blueprint_slab"),
new BlockItem(BLUEPRINT_SLAB, new Item.Settings())); new BlockItem(BLUEPRINT_SLAB, new Item.Settings()));
public static final BlockItem BLUEPRINT_DOOR_ITEM = Registry.register(Registries.ITEM, public static final BlockItem BLUEPRINT_DOOR_ITEM = Registry.register(Registries.ITEM,
new Identifier(Szar.MOD_ID, "blueprint_door"), new Identifier(MOD_ID, "blueprint_door"),
new BlockItem(BLUEPRINT_DOOR, new Item.Settings())); new BlockItem(BLUEPRINT_DOOR, new Item.Settings()));
public static final BlockItem BLUEPRINT_TRAPDOOR_ITEM = Registry.register(Registries.ITEM, public static final BlockItem BLUEPRINT_TRAPDOOR_ITEM = Registry.register(Registries.ITEM,
new Identifier(Szar.MOD_ID, "blueprint_trapdoor"), new Identifier(MOD_ID, "blueprint_trapdoor"),
new BlockItem(BLUEPRINT_TRAPDOOR, new Item.Settings())); new BlockItem(BLUEPRINT_TRAPDOOR, new Item.Settings()));
public static final BlockItem BLUEPRINT_WALL_ITEM = Registry.register(Registries.ITEM, public static final BlockItem BLUEPRINT_WALL_ITEM = Registry.register(Registries.ITEM,
new Identifier(Szar.MOD_ID, "blueprint_wall"), new Identifier(MOD_ID, "blueprint_wall"),
new BlockItem(BLUEPRINT_WALL, new Item.Settings())); new BlockItem(BLUEPRINT_WALL, new Item.Settings()));
public static final BlockItem BLUEPRINT_FENCE_ITEM = Registry.register(Registries.ITEM, public static final BlockItem BLUEPRINT_FENCE_ITEM = Registry.register(Registries.ITEM,
new Identifier(Szar.MOD_ID, "blueprint_fence"), new Identifier(MOD_ID, "blueprint_fence"),
new BlockItem(BLUEPRINT_FENCE, new Item.Settings())); new BlockItem(BLUEPRINT_FENCE, new Item.Settings()));
public static void init() {} // just call this to trigger class loading public static void init() {} // just call this to trigger class loading
} }

View File

@@ -19,7 +19,7 @@ public class BlueprintDoorBlock extends DoorBlock implements BlockEntityProvider
@Override @Override
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
return new BlueprintBlockEntity(BlueprintBlocks.BLUEPRINT_DOOR_BE_TYPE, pos, state); return new BlueprintBlockEntity(pos, state);
} }
@Override @Override

View File

@@ -18,7 +18,7 @@ public class BlueprintFenceBlock extends FenceBlock implements BlockEntityProvid
@Override @Override
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
return new BlueprintBlockEntity(BlueprintBlocks.BLUEPRINT_FENCE_BE_TYPE, pos, state); return new BlueprintBlockEntity(pos, state);
} }
@Override @Override

View File

@@ -18,7 +18,7 @@ public class BlueprintSlabBlock extends SlabBlock implements BlockEntityProvider
@Override @Override
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
return new BlueprintBlockEntity(BlueprintBlocks.BLUEPRINT_SLAB_BE_TYPE, pos, state); return new BlueprintBlockEntity(pos, state);
} }
@Override @Override

View File

@@ -18,7 +18,7 @@ public class BlueprintStairsBlock extends StairsBlock implements BlockEntityProv
@Override @Override
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
return new BlueprintBlockEntity(BlueprintBlocks.BLUEPRINT_STAIRS_BE_TYPE, pos, state); return new BlueprintBlockEntity(pos, state);
} }
@Override @Override

View File

@@ -18,7 +18,7 @@ public class BlueprintTrapDoorBlock extends TrapdoorBlock implements BlockEntity
@Override @Override
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
return new BlueprintBlockEntity(BlueprintBlocks.BLUEPRINT_TRAPDOOR_BE_TYPE, pos, state); return new BlueprintBlockEntity(pos, state);
} }
@Override @Override

View File

@@ -9,6 +9,7 @@ import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockView; import net.minecraft.world.BlockView;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.block.WallBlock;
public class BlueprintWallBlock extends WallBlock implements BlockEntityProvider { public class BlueprintWallBlock extends WallBlock implements BlockEntityProvider {
@@ -18,7 +19,7 @@ public class BlueprintWallBlock extends WallBlock implements BlockEntityProvider
@Override @Override
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
return new BlueprintBlockEntity(BlueprintBlocks.BLUEPRINT_WALL_BE_TYPE, pos, state); return new BlueprintBlockEntity(pos, state);
} }
@Override @Override

View File

@@ -0,0 +1,62 @@
package dev.tggamesyt.szar;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.Fertilizable;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.World;
import net.minecraft.world.WorldView;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.feature.*;
import java.util.List;
import java.util.Optional;
public class ChorusEndStone extends EndSpreadableBlock implements Fertilizable {
public ChorusEndStone(Settings settings) {
super(settings);
}
@Override
public boolean isFertilizable(WorldView world, BlockPos pos, BlockState state, boolean isClient) {
return true;
}
@Override
public boolean canGrow(World world, Random random, BlockPos pos, BlockState state) {
return true;
}
@Override
public void grow(ServerWorld world, Random random, BlockPos pos, BlockState state) {
BlockPos target = pos.up();
var registry = world.getRegistryManager().get(RegistryKeys.PLACED_FEATURE);
var featureEntry = registry.getEntry(Szar.SMALL_CHORUS_PLACED);
// ❌ if blocked, do nothing
if (!world.getBlockState(target).isAir()) return;
// 🌸 VERY RARE chorus flower (~5%)
if (random.nextInt(20) == 0) {
world.setBlockState(target, Blocks.CHORUS_FLOWER.getDefaultState());
return;
}
// 🌿 otherwise place ONE patch
if (featureEntry.isPresent()) {
featureEntry.get().value().generateUnregistered(
world,
world.getChunkManager().getChunkGenerator(),
random,
target
);
}
}
}

View File

@@ -0,0 +1,77 @@
package dev.tggamesyt.szar;
import net.minecraft.block.*;
import net.minecraft.registry.tag.FluidTags;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.WorldView;
import net.minecraft.world.chunk.light.ChunkLightProvider;
public abstract class EndSpreadableBlock extends SnowyBlock {
protected EndSpreadableBlock(Settings settings) {
super(settings);
}
private static boolean canSurvive(BlockState state, WorldView world, BlockPos pos) {
BlockPos up = pos.up();
BlockState upState = world.getBlockState(up);
if (upState.isOf(Blocks.SNOW) && upState.get(SnowBlock.LAYERS) == 1) {
return true;
}
if (upState.getFluidState().getLevel() == 8) {
return false;
}
int opacity = ChunkLightProvider.getRealisticOpacity(
world, state, pos, upState, up, Direction.UP,
upState.getOpacity(world, up)
);
return opacity < world.getMaxLightLevel();
}
private static boolean canSpread(BlockState state, WorldView world, BlockPos pos) {
BlockPos up = pos.up();
return canSurvive(state, world, pos)
&& !world.getFluidState(up).isIn(FluidTags.WATER);
}
@Override
public void randomTick(BlockState state, ServerWorld world, BlockPos pos, Random random) {
// ❌ Decay (like grass → dirt)
if (!canSurvive(state, world, pos)) {
world.setBlockState(pos, Blocks.END_STONE.getDefaultState());
return;
}
// 🌱 Spread
if (world.getLightLevel(pos.up()) >= 9) {
BlockState spreadState = this.getDefaultState();
for (int i = 0; i < 4; i++) {
BlockPos target = pos.add(
random.nextInt(3) - 1,
random.nextInt(5) - 3,
random.nextInt(3) - 1
);
if (world.getBlockState(target).isOf(Blocks.END_STONE)
&& canSpread(spreadState, world, target)) {
world.setBlockState(
target,
spreadState.with(SNOWY,
world.getBlockState(target.up()).isOf(Blocks.SNOW)
)
);
}
}
}
}
}

View File

@@ -0,0 +1,25 @@
package dev.tggamesyt.szar;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class EnderObsidian extends Block {
public EnderObsidian(AbstractBlock.Settings settings) {
super(settings);
}
@Override
public void afterBreak(World world, PlayerEntity player, BlockPos pos, BlockState state, net.minecraft.block.entity.BlockEntity blockEntity, net.minecraft.item.ItemStack stack) {
super.afterBreak(world, player, pos, state, blockEntity, stack);
if (!world.isClient) {
world.setBlockState(pos, Szar.ENDER_ORE.getDefaultState());
}
}
}

View File

@@ -0,0 +1,25 @@
package dev.tggamesyt.szar;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.PlantBlock;
import net.minecraft.block.ShapeContext;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.world.BlockView;
public class SmallChorusBlock extends PlantBlock {
protected static final VoxelShape SHAPE = Block.createCuboidShape((double)2.0F, (double)0.0F, (double)2.0F, (double)14.0F, (double)13.0F, (double)14.0F);
public SmallChorusBlock(Settings settings) {
super(settings);
}
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
return SHAPE;
}
@Override
protected boolean canPlantOnTop(BlockState floor, BlockView world, BlockPos pos) {
return floor.isOf(Szar.CHORUS_ENDSTONE);
}
}

View File

@@ -0,0 +1,52 @@
package dev.tggamesyt.szar;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.PlantBlock;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.random.Random;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
public class SmallChorusFlowerBlock extends PlantBlock {
protected static final VoxelShape SHAPE = Block.createCuboidShape(
2.0, 0.0, 2.0,
14.0, 13.0, 14.0
);
public SmallChorusFlowerBlock(Settings settings) {
super(settings);
}
@Override
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, net.minecraft.block.ShapeContext context) {
return SHAPE;
}
@Override
protected boolean canPlantOnTop(BlockState floor, BlockView world, BlockPos pos) {
return floor.isOf(Szar.CHORUS_ENDSTONE);
}
@Override
public void randomTick(BlockState state, ServerWorld world, BlockPos pos, Random random) {
// small chance per random tick → averages ~510 minutes
if (random.nextInt(6) == 0) { // tweak this number
// only grow if space above
if (world.getBlockState(pos.up()).isAir()) {
world.setBlockState(pos, Blocks.CHORUS_FLOWER.getDefaultState());
}
}
}
@Override
public boolean hasRandomTicks(BlockState state) {
return true;
}
}

View File

@@ -0,0 +1,48 @@
package dev.tggamesyt.szar;
import com.mojang.serialization.Codec;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.StructureWorldAccess;
import net.minecraft.world.gen.feature.DefaultFeatureConfig;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.util.FeatureContext;
public class SurfaceReplaceFeature extends Feature<DefaultFeatureConfig> {
public SurfaceReplaceFeature(Codec<DefaultFeatureConfig> codec) {
super(codec);
}
@Override
public boolean generate(FeatureContext<DefaultFeatureConfig> context) {
StructureWorldAccess world = context.getWorld();
BlockPos origin = context.getOrigin();
// snap to chunk corner
int startX = (origin.getX() >> 4) << 4;
int startZ = (origin.getZ() >> 4) << 4;
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
BlockPos column = new BlockPos(startX + x, origin.getY(), startZ + z);
for (int i = 10; i > -10; i--) {
BlockPos pos = column.up(i);
BlockState state = world.getBlockState(pos);
if (state.isOf(Blocks.END_STONE)) {
world.setBlockState(pos, Szar.CHORUS_ENDSTONE.getDefaultState(), Block.NOTIFY_LISTENERS);
break;
} else if (!state.isAir()) {
break;
}
}
}
}
return true;
}
}

View File

@@ -1,7 +1,6 @@
package dev.tggamesyt.szar; package dev.tggamesyt.szar;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.mojang.authlib.minecraft.client.MinecraftClient;
import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import net.fabricmc.api.ModInitializer; import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.biome.v1.BiomeModifications; import net.fabricmc.fabric.api.biome.v1.BiomeModifications;
@@ -28,6 +27,7 @@ import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityTypeBuilder;
import net.fabricmc.fabric.api.object.builder.v1.trade.TradeOfferHelper; import net.fabricmc.fabric.api.object.builder.v1.trade.TradeOfferHelper;
import net.fabricmc.fabric.api.object.builder.v1.world.poi.PointOfInterestHelper; import net.fabricmc.fabric.api.object.builder.v1.world.poi.PointOfInterestHelper;
import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry; import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry;
import net.fabricmc.fabric.impl.biome.TheEndBiomeData;
import net.minecraft.advancement.Advancement; import net.minecraft.advancement.Advancement;
import net.minecraft.block.*; import net.minecraft.block.*;
import net.minecraft.block.dispenser.FallibleItemDispenserBehavior; import net.minecraft.block.dispenser.FallibleItemDispenserBehavior;
@@ -75,6 +75,7 @@ import net.minecraft.village.TradeOffer;
import net.minecraft.village.VillagerProfession; import net.minecraft.village.VillagerProfession;
import net.minecraft.world.Heightmap; import net.minecraft.world.Heightmap;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeKeys; import net.minecraft.world.biome.BiomeKeys;
import net.minecraft.world.dimension.DimensionOptions; import net.minecraft.world.dimension.DimensionOptions;
import net.minecraft.world.dimension.DimensionType; import net.minecraft.world.dimension.DimensionType;
@@ -90,14 +91,12 @@ import net.minecraft.world.poi.PointOfInterestType;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.awt.*;
import java.util.*; import java.util.*;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static dev.tggamesyt.szar.ServerCosmetics.USERS; import static dev.tggamesyt.szar.ServerCosmetics.USERS;
import static dev.tggamesyt.szar.ServerCosmetics.sync;
public class Szar implements ModInitializer { public class Szar implements ModInitializer {
public static final String MOD_ID = "szar"; public static final String MOD_ID = "szar";
@@ -164,6 +163,7 @@ public class Szar implements ModInitializer {
new Identifier(Szar.MOD_ID, "won"), new Identifier(Szar.MOD_ID, "won"),
SoundEvent.of(new Identifier(Szar.MOD_ID, "won")) SoundEvent.of(new Identifier(Szar.MOD_ID, "won"))
); );
private static final Set<Integer> chorusRolledEntities = new HashSet<>();
public static final SoundEvent MERL_SOUND = public static final SoundEvent MERL_SOUND =
SoundEvent.of(new Identifier(MOD_ID, "merl")); SoundEvent.of(new Identifier(MOD_ID, "merl"));
public static final Map<UUID, Long> recentPlaneCrashDeaths = new java.util.HashMap<>(); public static final Map<UUID, Long> recentPlaneCrashDeaths = new java.util.HashMap<>();
@@ -366,7 +366,7 @@ public class Szar implements ModInitializer {
boolean showRacist = !ServerConfig.get("racist"); boolean showRacist = !ServerConfig.get("racist");
boolean showGambling = !ServerConfig.get("gambling"); boolean showGambling = !ServerConfig.get("gambling");
boolean showNsfw = !ServerConfig.get("nsfw"); boolean showNsfw = !ServerConfig.get("nsfw");
// random ahh silly stuff // memes
entries.add(Szar.POPTART); entries.add(Szar.POPTART);
entries.add(Szar.NYAN_SPAWNEGG); entries.add(Szar.NYAN_SPAWNEGG);
entries.add(Szar.BAITER_DISC); entries.add(Szar.BAITER_DISC);
@@ -374,6 +374,8 @@ public class Szar implements ModInitializer {
entries.add(Szar.EFN_DISK); entries.add(Szar.EFN_DISK);
entries.add(Szar.FIRTANA); entries.add(Szar.FIRTANA);
entries.add(Szar.HELLO_DISC); entries.add(Szar.HELLO_DISC);
entries.add(Szar.KEBAB);
// backrooms
entries.add(Szar.TRACKER_BLOCK_ITEM); entries.add(Szar.TRACKER_BLOCK_ITEM);
entries.add(Szar.PORTAL_BLOCK_ITEM); entries.add(Szar.PORTAL_BLOCK_ITEM);
entries.add(Szar.WALL_ITEM); entries.add(Szar.WALL_ITEM);
@@ -384,15 +386,23 @@ public class Szar implements ModInitializer {
entries.add(Szar.BEAN); entries.add(Szar.BEAN);
entries.add(Szar.CAN_OF_BEANS); entries.add(Szar.CAN_OF_BEANS);
entries.add(Szar.ALMOND_WATER); entries.add(Szar.ALMOND_WATER);
entries.add(Szar.KEBAB); // end update
entries.add(Szar.CHORUS_ENDSTONE_ITEM);
entries.add(Szar.SMALL_CHORUS_ITEM);
entries.add(Szar.SMALL_CHORUS_FLOWER_ITEM);
entries.add(Szar.ENDER_OBSIDIAN_ITEM);
entries.add(Szar.ENDER_ORE_ITEM);
entries.add(Szar.RAW_ENDER);
entries.add(Szar.ENDER_INGOT);
// blueprint stuff
entries.add(BlueprintBlocks.BLUEPRINT);
entries.add(BlueprintBlocks.BLUEPRINT_DOOR_ITEM); entries.add(BlueprintBlocks.BLUEPRINT_DOOR_ITEM);
entries.add(BlueprintBlocks.BLUEPRINT_TRAPDOOR_ITEM); entries.add(BlueprintBlocks.BLUEPRINT_TRAPDOOR_ITEM);
entries.add(BlueprintBlocks.BLUEPRINT_FENCE_ITEM); entries.add(BlueprintBlocks.BLUEPRINT_FENCE_ITEM);
entries.add(BlueprintBlocks.BLUEPRINT_SLAB_ITEM); entries.add(BlueprintBlocks.BLUEPRINT_SLAB_ITEM);
entries.add(BlueprintBlocks.BLUEPRINT_WALL_ITEM); entries.add(BlueprintBlocks.BLUEPRINT_WALL_ITEM);
entries.add(BlueprintBlocks.BLUEPRINT_STAIRS_ITEM); entries.add(BlueprintBlocks.BLUEPRINT_STAIRS_ITEM);
// board games
entries.add(Szar.TIC_TAC_TOE_ITEM); entries.add(Szar.TIC_TAC_TOE_ITEM);
entries.add(Szar.CONNECT_FOUR_ITEM); entries.add(Szar.CONNECT_FOUR_ITEM);
entries.add(Szar.CHESS_ITEM); entries.add(Szar.CHESS_ITEM);
@@ -1024,7 +1034,7 @@ public class Szar implements ModInitializer {
}); });
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
dispatcher.register( dispatcher.register(
LiteralArgumentBuilder.<ServerCommandSource>literal("szar") LiteralArgumentBuilder.<ServerCommandSource>literal(MOD_ID)
.requires(context -> context.hasPermissionLevel(2)) .requires(context -> context.hasPermissionLevel(2))
// /szar ny // /szar ny
@@ -1378,6 +1388,35 @@ public class Szar implements ModInitializer {
ServerLifecycleEvents.SERVER_STARTED.register(SzarGameRules::pushToGameRules); ServerLifecycleEvents.SERVER_STARTED.register(SzarGameRules::pushToGameRules);
BlueprintBlocks.init(); BlueprintBlocks.init();
ServerTickEvents.END_SERVER_TICK.register(server -> {
for (ServerWorld world : server.getWorlds()) {
// Handle item transformation
for (ItemEntity item : world.getEntitiesByType(EntityType.ITEM, e -> true)) {
if (!item.getStack().isOf(Items.CHORUS_FRUIT)) continue;
BlockPos pos = item.getBlockPos();
BlockPos down = pos.down();
if (!chorusRolledEntities.contains(item.getId()) && world.getBlockState(down).isOf(Szar.CHORUS_ENDSTONE)) {
chorusRolledEntities.add(item.getId());
int roll = world.getRandom().nextInt(100); // 0-99
if (roll < 5) { // 5% -> 1 in 20 chance
world.setBlockState(pos, Szar.SMALL_CHORUS.getDefaultState());
item.remove(Entity.RemovalReason.DISCARDED);
} else if (roll == 5) { // 2% -> 1 in 50 chance
world.setBlockState(pos, Szar.SMALL_CHORUS_FLOWER.getDefaultState());
item.remove(Entity.RemovalReason.DISCARDED);
}
// otherwise do nothing, just mark it as rolled
}
}
}
});
TheEndBiomeData.addEndBiomeReplacement(BiomeKeys.END_HIGHLANDS, Szar.CHORUS_FOREST, 0.7);
} }
public static final Block TIC_TAC_TOE_BLOCK = Registry.register( public static final Block TIC_TAC_TOE_BLOCK = Registry.register(
@@ -1442,7 +1481,74 @@ public class Szar implements ModInitializer {
public static final Identifier CHESS_CLOSE_SCREEN = new Identifier(MOD_ID, "chess_close"); public static final Identifier CHESS_CLOSE_SCREEN = new Identifier(MOD_ID, "chess_close");
public static final Map<UUID, BlockPos> chessActivePlayers = new java.util.HashMap<>(); public static final Map<UUID, BlockPos> chessActivePlayers = new java.util.HashMap<>();
public static final RegistryKey<ConfiguredFeature<?, ?>> SMALL_CHORUS_CONFIGURED =
RegistryKey.of(RegistryKeys.CONFIGURED_FEATURE, new Identifier(MOD_ID, "small_chorus"));
public static final RegistryKey<PlacedFeature> SMALL_CHORUS_PLACED =
RegistryKey.of(RegistryKeys.PLACED_FEATURE, new Identifier(MOD_ID, "small_chorus_patch"));
public static final Block CHORUS_ENDSTONE = Registry.register(
Registries.BLOCK,
new Identifier(MOD_ID, "chorus_endstone"),
new ChorusEndStone(FabricBlockSettings.copyOf(Blocks.END_STONE).ticksRandomly())
);
public static final Item CHORUS_ENDSTONE_ITEM = Registry.register(
Registries.ITEM,
new Identifier(MOD_ID, "chorus_endstone"),
new BlockItem(CHORUS_ENDSTONE, new FabricItemSettings())
);
public static final Block SMALL_CHORUS = Registry.register(
Registries.BLOCK,
new Identifier(MOD_ID, "small_chorus"),
new SmallChorusBlock(FabricBlockSettings.copyOf(Blocks.GRASS))
);
public static final Item SMALL_CHORUS_ITEM = Registry.register(
Registries.ITEM,
new Identifier(MOD_ID, "small_chorus"),
new BlockItem(SMALL_CHORUS, new FabricItemSettings())
);
public static final Block SMALL_CHORUS_FLOWER = Registry.register(
Registries.BLOCK,
new Identifier(MOD_ID, "small_chorus_flower"),
new SmallChorusFlowerBlock(FabricBlockSettings.copyOf(Blocks.POPPY).ticksRandomly())
);
public static final Item SMALL_CHORUS_FLOWER_ITEM = Registry.register(
Registries.ITEM,
new Identifier(MOD_ID, "small_chorus_flower"),
new BlockItem(SMALL_CHORUS_FLOWER, new FabricItemSettings())
);
public static final RegistryKey<Biome> CHORUS_FOREST = RegistryKey.of(
RegistryKeys.BIOME,
new Identifier(MOD_ID, "chorus_forest")
);
public static final Block ENDER_OBSIDIAN = Registry.register(
Registries.BLOCK,
new Identifier(MOD_ID, "ender_obsidian"),
new EnderObsidian(FabricBlockSettings.copyOf(Blocks.OBSIDIAN))
);
public static final Item ENDER_OBSIDIAN_ITEM = Registry.register(
Registries.ITEM,
new Identifier(MOD_ID, "ender_obsidian"),
new BlockItem(ENDER_OBSIDIAN, new FabricItemSettings())
);
public static final Block ENDER_ORE = Registry.register(
Registries.BLOCK,
new Identifier(MOD_ID, "ender_ore"),
new Block(FabricBlockSettings.copyOf(Blocks.OBSIDIAN))
);
public static final Item ENDER_ORE_ITEM = Registry.register(
Registries.ITEM,
new Identifier(MOD_ID, "ender_ore"),
new BlockItem(ENDER_ORE, new FabricItemSettings())
);
public static final Item RAW_ENDER = Registry.register(
Registries.ITEM,
new Identifier(MOD_ID, "raw_ender"),
new Item(new FabricItemSettings())
);
public static final Item ENDER_INGOT = Registry.register(
Registries.ITEM,
new Identifier(MOD_ID, "ender_ingot"),
new Item(new FabricItemSettings())
);
// Blocks // Blocks
public static final TrackerBlock TRACKER_BLOCK = Registry.register( public static final TrackerBlock TRACKER_BLOCK = Registry.register(
Registries.BLOCK, new Identifier(MOD_ID, "tracker"), Registries.BLOCK, new Identifier(MOD_ID, "tracker"),
@@ -2530,7 +2636,7 @@ public class Szar implements ModInitializer {
MinecraftServer server = serverPlayer.getServer(); MinecraftServer server = serverPlayer.getServer();
if (server == null) return; if (server == null) return;
if (!advancement.equals("szar")) { if (!advancement.equals(MOD_ID)) {
grantAdvancement(player, "szar"); grantAdvancement(player, "szar");
} }

View File

@@ -0,0 +1,54 @@
package dev.tggamesyt.szar.mixin;
import dev.tggamesyt.szar.Szar;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.ChorusFlowerBlock;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.WorldView;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ChorusFlowerBlock.class)
public abstract class ChorusFlowerBlockMixin {
@Unique
private static final TagKey<Block> ENDSTONES =
TagKey.of(RegistryKeys.BLOCK, new Identifier(Szar.MOD_ID, "endstones"));
/**
* 🔥 Redirect EVERY BlockState.isOf call inside ChorusFlowerBlock
* and replace END_STONE checks with tag checks
*/
@Redirect(
method = {
"canPlaceAt",
"randomTick",
"generate*",
"scheduledTick"
},
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/block/BlockState;isOf(Lnet/minecraft/block/Block;)Z"
)
)
private boolean replaceEndStoneChecks(BlockState state, Block block) {
// Replace ONLY END_STONE checks
if (block == Blocks.END_STONE) {
return state.isIn(ENDSTONES);
}
// Everything else stays vanilla
return state.isOf(block);
}
}

View File

@@ -0,0 +1,46 @@
package dev.tggamesyt.szar.mixin;
import dev.tggamesyt.szar.Szar;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.ChorusPlantBlock;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(ChorusPlantBlock.class)
public abstract class ChorusPlantBlockMixin {
@Unique
private static final TagKey<Block> ENDSTONES =
TagKey.of(RegistryKeys.BLOCK, new Identifier(Szar.MOD_ID, "endstones"));
/**
* 🔥 Replace ALL END_STONE checks in ChorusPlantBlock
*/
@Redirect(
method = {
"withConnectionProperties",
"getStateForNeighborUpdate",
"canPlaceAt"
},
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/block/BlockState;isOf(Lnet/minecraft/block/Block;)Z"
)
)
private boolean replaceEndStoneChecks(BlockState state, Block block) {
// Replace END_STONE with your tag
if (block == Blocks.END_STONE) {
return state.isIn(ENDSTONES);
}
return state.isOf(block);
}
}

View File

@@ -0,0 +1,36 @@
package dev.tggamesyt.szar.mixin;
import dev.tggamesyt.szar.Szar;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier;
import net.minecraft.world.gen.feature.ChorusPlantFeature;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(ChorusPlantFeature.class)
public class ChorusPlantFeatureMixin {
@Unique
private static final TagKey<Block> ENDSTONES =
TagKey.of(RegistryKeys.BLOCK, new Identifier(Szar.MOD_ID, "endstones"));
@Redirect(
method = "generate",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/block/BlockState;isOf(Lnet/minecraft/block/Block;)Z"
)
)
private boolean replaceEndStoneCheck(BlockState state, Block block) {
if (block == Blocks.END_STONE) {
return state.isIn(ENDSTONES);
}
return state.isOf(block);
}
}

View File

@@ -0,0 +1,46 @@
package dev.tggamesyt.szar.mixin;
import dev.tggamesyt.szar.Szar;
import net.minecraft.block.Blocks;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.gen.chunk.Blender;
import net.minecraft.world.gen.chunk.NoiseChunkGenerator;
import net.minecraft.world.ChunkRegion;
import net.minecraft.world.gen.StructureAccessor;
import net.minecraft.world.gen.noise.NoiseConfig;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(NoiseChunkGenerator.class)
public class NoiseChunkGeneratorMixin {
@Inject(method = "buildSurface*", at = @At("TAIL"))
private void replaceSurface(ChunkRegion region, StructureAccessor structures, NoiseConfig noiseConfig, Chunk chunk, CallbackInfo ci) {
BlockPos.Mutable mutable = new BlockPos.Mutable();
int startX = chunk.getPos().getStartX();
int startZ = chunk.getPos().getStartZ();
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
int worldX = startX + x;
int worldZ = startZ + z;
int topY = chunk.getHeightmap(net.minecraft.world.Heightmap.Type.WORLD_SURFACE_WG).get(x, z);
mutable.set(worldX, topY, worldZ);
RegistryEntry<Biome> biome = region.getBiome(mutable);
if (biome.matchesKey(Szar.CHORUS_FOREST)) {
mutable.set(worldX, topY - 1, worldZ);
if (chunk.getBlockState(mutable).isOf(Blocks.END_STONE)) {
chunk.setBlockState(mutable, Szar.CHORUS_ENDSTONE.getDefaultState(), false);
}
}
}
}
}
}

View File

@@ -0,0 +1,50 @@
package dev.tggamesyt.szar.mixin;
import dev.tggamesyt.szar.Szar;
import net.minecraft.registry.RegistryEntryLookup;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.util.math.ChunkSectionPos;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeKeys;
import net.minecraft.world.biome.source.BiomeCoords;
import net.minecraft.world.biome.source.TheEndBiomeSource;
import net.minecraft.world.biome.source.util.MultiNoiseUtil;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(TheEndBiomeSource.class)
public class TheEndBiomeSourceMixin {
@Unique
private RegistryEntry<Biome> szar$chorusEntry;
@Inject(method = "<init>", at = @At("TAIL"))
private void onInit(RegistryEntry<Biome> centerBiome, RegistryEntry<Biome> highlandsBiome, RegistryEntry<Biome> midlandsBiome, RegistryEntry<Biome> smallIslandsBiome, RegistryEntry<Biome> barrensBiome, CallbackInfo ci) {
RegistryEntryLookup<Biome> lookup = net.fabricmc.fabric.impl.biome.TheEndBiomeData.biomeRegistry.get();
if (lookup != null) {
this.szar$chorusEntry = lookup.getOrThrow(Szar.CHORUS_FOREST);
}
}
@Inject(method = "getBiome", at = @At("RETURN"), cancellable = true)
private void overrideBiome(int x, int y, int z, MultiNoiseUtil.MultiNoiseSampler noise, CallbackInfoReturnable<RegistryEntry<Biome>> cir) {
if (szar$chorusEntry == null) return;
RegistryEntry<Biome> result = cir.getReturnValue();
if (!result.matchesKey(BiomeKeys.END_HIGHLANDS)
&& !result.matchesKey(BiomeKeys.END_MIDLANDS)
&& !result.matchesKey(BiomeKeys.END_BARRENS)) return;
int islandX = ChunkSectionPos.getSectionCoord(BiomeCoords.toBlock(x)) >> 3;
int islandZ = ChunkSectionPos.getSectionCoord(BiomeCoords.toBlock(z)) >> 3;
long islandSeed = (long) islandX * 341873128712L + (long) islandZ * 132897987541L;
if (new java.util.Random(islandSeed).nextFloat() < 0.4f) {
cir.setReturnValue(szar$chorusEntry);
}
}
}

View File

@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "szar:block/chorus_endstone"
}
}
}

View File

@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "szar:block/ender_obsidian"
}
}
}

View File

@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "szar:block/ender_ore"
}
}
}

View File

@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "szar:block/small_chorus"
}
}
}

View File

@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "szar:block/small_chorus_flower"
}
}
}

View File

@@ -197,5 +197,14 @@
"block.szar.blueprint_door": "Blueprint Door", "block.szar.blueprint_door": "Blueprint Door",
"block.szar.blueprint_trapdoor": "Blueprint Trapdoor", "block.szar.blueprint_trapdoor": "Blueprint Trapdoor",
"block.szar.blueprint_wall": "Blueprint Wall", "block.szar.blueprint_wall": "Blueprint Wall",
"block.szar.blueprint_fence": "Blueprint Fence" "block.szar.blueprint_fence": "Blueprint Fence",
"item.szar.blueprint": "Blueprint",
"block.szar.chorus_endstone": "Chorus EndStone",
"block.szar.small_chorus": "Small Chorus",
"block.szar.small_chorus_flower": "Small Chorus Flower",
"block.szar.ender_obsidian": "Ender Obsidian",
"block.szar.ender_ore": "Ender Ore",
"item.szar.raw_ender": "Raw Ender",
"item.szar.ender_ingot": "Ender Ingot"
} }

View File

@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/fence_inventory",
"textures": {
"texture": "szar:block/blueprint"
}
}

View File

@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/wall_inventory",
"textures": {
"wall": "szar:block/blueprint"
}
}

View File

@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/cube_bottom_top",
"textures": {
"side": "szar:block/end_stone_grass",
"bottom": "szar:block/end_stone",
"top": "szar:block/chorus_top"
}
}

View File

@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "szar:block/ender_obsidian"
}
}

View File

@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "szar:block/ender_ore"
}
}

View File

@@ -0,0 +1,6 @@
{
"parent": "block/cross",
"textures": {
"cross": "szar:block/small_chorus"
}
}

View File

@@ -0,0 +1,6 @@
{
"parent": "block/cross",
"textures": {
"cross": "szar:block/small_chorus_flower"
}
}

View File

@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "szar:item/blueprint"
}
}

View File

@@ -1 +1 @@
{ "parent": "minecraft:item/generated", "textures": { "layer0": "szar:block/blueprint" } } { "parent": "minecraft:item/generated", "textures": { "layer0": "szar:block/blueprint_door" } }

View File

@@ -1 +1 @@
{ "parent": "szar:block/blueprint_fence_post" } { "parent": "szar:block/blueprint_fence_inventory" }

View File

@@ -1 +1 @@
{ "parent": "szar:block/blueprint_wall_post" } { "parent": "szar:block/blueprint_wall_inventory" }

View File

@@ -0,0 +1,3 @@
{
"parent": "szar:block/chorus_endstone"
}

View File

@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "szar:item/ender_ingot"
}
}

View File

@@ -0,0 +1,3 @@
{
"parent": "szar:block/ender_obsidian"
}

View File

@@ -0,0 +1,3 @@
{
"parent": "szar:block/ender_ore"
}

View File

@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "szar:item/raw_ender"
}
}

View File

@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "szar:block/small_chorus"
}
}

View File

@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "szar:block/small_chorus_flower"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 880 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 984 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 823 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 904 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 795 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 854 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 B

View File

@@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"szar:blueprint_fence"
]
}

View File

@@ -1,5 +1,6 @@
{ {
"values": [ "values": [
"szar:chemical_workbench",
"szar:roulette", "szar:roulette",
"szar:slot_machine", "szar:slot_machine",
"szar:tictactoe", "szar:tictactoe",

View File

@@ -2,6 +2,9 @@
"replace": false, "replace": false,
"values": [ "values": [
"szar:uranium_ore", "szar:uranium_ore",
"szar:niggerite_block" "szar:niggerite_block",
"szar:chorus_endstone",
"szar:ender_ore",
"szar:ender_obsidian"
] ]
} }

View File

@@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"szar:blueprint_wall"
]
}

View File

@@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"szar:blueprint_fence"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "szar:blueprint_door"
}
]
}
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "szar:blueprint_fence"
}
]
}
]
}

View File

@@ -0,0 +1,35 @@
{
"type": "minecraft:block",
"pools": [
{
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"functions": [
{
"add": false,
"conditions": [
{
"block": "szar:blueprint_slab",
"condition": "minecraft:block_state_property",
"properties": {
"type": "double"
}
}
],
"count": 2.0,
"function": "minecraft:set_count"
},
{
"function": "minecraft:explosion_decay"
}
],
"name": "szar:blueprint_slab"
}
],
"rolls": 1.0
}
],
"random_sequence": "minecraft:blocks/stone_slab"
}

View File

@@ -0,0 +1,14 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "szar:blueprint_stairs"
}
]
}
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "szar:blueprint_trapdoor"
}
]
}
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "szar:blueprint_wall"
}
]
}
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "szar:chemical_workbench"
}
]
}
]
}

View File

@@ -0,0 +1,45 @@
{
"type": "minecraft:block",
"pools": [
{
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:alternatives",
"children": [
{
"type": "minecraft:item",
"conditions": [
{
"condition": "minecraft:match_tool",
"predicate": {
"enchantments": [
{
"enchantment": "minecraft:silk_touch",
"levels": {
"min": 1
}
}
]
}
}
],
"name": "szar:chorus_endstone"
},
{
"type": "minecraft:item",
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
],
"name": "minecraft:end_stone"
}
]
}
],
"rolls": 1.0
}
],
"random_sequence": "minecraft:blocks/grass_block"
}

View File

@@ -0,0 +1,52 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:alternatives",
"children": [
{
"type": "minecraft:item",
"name": "szar:ender_ore",
"conditions": [
{
"condition": "minecraft:match_tool",
"predicate": {
"enchantments": [
{
"enchantment": "minecraft:silk_touch",
"levels": {
"min": 1
}
}
],
"items": [
"minecraft:diamond_pickaxe",
"minecraft:netherite_pickaxe"
]
}
}
]
},
{
"type": "minecraft:item",
"name": "szar:raw_ender",
"conditions": [
{
"condition": "minecraft:match_tool",
"predicate": {
"items": [
"minecraft:netherite_pickaxe"
]
}
}
]
}
]
}
]
}
]
}

View File

@@ -0,0 +1,54 @@
{
"type": "minecraft:block",
"pools": [
{
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:alternatives",
"children": [
{
"type": "minecraft:item",
"conditions": [
{
"condition": "minecraft:match_tool",
"predicate": {
"items": [
"minecraft:shears"
]
}
}
],
"name": "szar:small_chorus"
},
{
"type": "minecraft:item",
"conditions": [
{
"chance": 0.125,
"condition": "minecraft:random_chance"
}
],
"functions": [
{
"enchantment": "minecraft:fortune",
"formula": "minecraft:uniform_bonus_count",
"function": "minecraft:apply_bonus",
"parameters": {
"bonusMultiplier": 2
}
},
{
"function": "minecraft:explosion_decay"
}
],
"name": "minecraft:chorus_fruit"
}
]
}
],
"rolls": 1.0
}
],
"random_sequence": "minecraft:blocks/grass"
}

View File

@@ -0,0 +1,21 @@
{
"type": "minecraft:block",
"pools": [
{
"bonus_rolls": 0.0,
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
],
"entries": [
{
"type": "minecraft:item",
"name": "szar:small_chorus_flower"
}
],
"rolls": 1.0
}
],
"random_sequence": "minecraft:blocks/poppy"
}

View File

@@ -0,0 +1,20 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
" B ",
"BPB",
" B "
],
"key": {
"B": {
"tag": "szar:blue"
},
"P": {
"item": "minecraft:paper"
}
},
"result": {
"item": "szar:blueprint",
"count": 1
}
}

View File

@@ -0,0 +1,17 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
"BB",
"BB",
"BB"
],
"key": {
"B": {
"item": "szar:blueprint"
}
},
"result": {
"item": "szar:blueprint_door",
"count": 1
}
}

View File

@@ -0,0 +1,19 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
"BDB",
"BDB"
],
"key": {
"B": {
"item": "szar:blueprint"
},
"D": {
"tag": "szar:blue"
}
},
"result": {
"item": "szar:blueprint_fence",
"count": 1
}
}

View File

@@ -0,0 +1,15 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
"BBB"
],
"key": {
"B": {
"item": "szar:blueprint"
}
},
"result": {
"item": "szar:blueprint_slab",
"count": 1
}
}

View File

@@ -0,0 +1,17 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
"B ",
"BB ",
"BBB"
],
"key": {
"B": {
"item": "szar:blueprint"
}
},
"result": {
"item": "szar:blueprint_stairs",
"count": 1
}
}

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