connect four, and some minor fixes
This commit is contained in:
153
src/client/java/dev/tggamesyt/szar/client/ConnectFourScreen.java
Normal file
153
src/client/java/dev/tggamesyt/szar/client/ConnectFourScreen.java
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
package dev.tggamesyt.szar.client;
|
||||||
|
|
||||||
|
import dev.tggamesyt.szar.ConnectFourBlockEntity;
|
||||||
|
import dev.tggamesyt.szar.Szar;
|
||||||
|
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
|
import net.minecraft.network.PacketByteBuf;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class ConnectFourScreen extends Screen {
|
||||||
|
|
||||||
|
private static final Identifier BG =
|
||||||
|
new Identifier("szar", "textures/gui/connectfour.png");
|
||||||
|
private static final Identifier RED_TEX =
|
||||||
|
new Identifier("szar", "textures/gui/c4_red.png");
|
||||||
|
private static final Identifier YELLOW_TEX =
|
||||||
|
new Identifier("szar", "textures/gui/c4_yellow.png");
|
||||||
|
private static final Identifier HOVER_TEX =
|
||||||
|
new Identifier("szar", "textures/gui/c4_hover.png");
|
||||||
|
|
||||||
|
// GUI dimensions — adjust to match your texture
|
||||||
|
private static final int GUI_WIDTH = 204; // 7 cells * ~28px + padding
|
||||||
|
private static final int GUI_HEIGHT = 196; // 6 cells * ~28px + padding + status
|
||||||
|
private static final int BOARD_X = 18;
|
||||||
|
private static final int BOARD_Y = 18;
|
||||||
|
private static final int CELL_SIZE = 24;
|
||||||
|
|
||||||
|
private ConnectFourBlockEntity.State state;
|
||||||
|
private final BlockPos blockPos;
|
||||||
|
private final UUID localPlayer;
|
||||||
|
private boolean isSpectator;
|
||||||
|
private int hoveredCol = -1;
|
||||||
|
|
||||||
|
public ConnectFourScreen(BlockPos pos, ConnectFourBlockEntity.State state) {
|
||||||
|
super(Text.literal("Connect Four"));
|
||||||
|
this.blockPos = pos;
|
||||||
|
this.state = state;
|
||||||
|
this.localPlayer = MinecraftClient.getInstance().player.getUuid();
|
||||||
|
this.isSpectator = state.isSpectator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateState(ConnectFourBlockEntity.State newState) {
|
||||||
|
this.state = newState;
|
||||||
|
this.isSpectator = newState.isSpectator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||||
|
renderBackground(context);
|
||||||
|
|
||||||
|
int x = (this.width - GUI_WIDTH) / 2;
|
||||||
|
int y = (this.height - GUI_HEIGHT) / 2;
|
||||||
|
|
||||||
|
// Draw background
|
||||||
|
context.drawTexture(BG, x, y, 0, 0, GUI_WIDTH, GUI_HEIGHT, GUI_WIDTH, GUI_HEIGHT);
|
||||||
|
|
||||||
|
// Update hovered column
|
||||||
|
hoveredCol = -1;
|
||||||
|
for (int col = 0; col < ConnectFourBlockEntity.COLS; col++) {
|
||||||
|
int cx = x + BOARD_X + col * CELL_SIZE;
|
||||||
|
if (mouseX >= cx && mouseX < cx + CELL_SIZE) {
|
||||||
|
hoveredCol = col;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw hover indicator on top row if it's our turn
|
||||||
|
boolean myTurn = !isSpectator && state.winner == 0
|
||||||
|
&& ((state.currentTurn == 1 && localPlayer.equals(state.player1))
|
||||||
|
|| (state.currentTurn == 2 && localPlayer.equals(state.player2)));
|
||||||
|
|
||||||
|
if (myTurn && hoveredCol >= 0) {
|
||||||
|
int cx = x + BOARD_X + hoveredCol * CELL_SIZE;
|
||||||
|
context.drawTexture(HOVER_TEX, cx + 2, y + BOARD_Y - CELL_SIZE + 2, 0, 0,
|
||||||
|
CELL_SIZE - 4, CELL_SIZE - 4, CELL_SIZE - 4, CELL_SIZE - 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw board — row 0 is bottom, so render rows in reverse
|
||||||
|
for (int row = 0; row < ConnectFourBlockEntity.ROWS; row++) {
|
||||||
|
for (int col = 0; col < ConnectFourBlockEntity.COLS; col++) {
|
||||||
|
int cx = x + BOARD_X + col * CELL_SIZE;
|
||||||
|
// Flip row so row 0 (bottom) renders at the bottom of the GUI
|
||||||
|
int displayRow = ConnectFourBlockEntity.ROWS - 1 - row;
|
||||||
|
int cy = y + BOARD_Y + displayRow * CELL_SIZE;
|
||||||
|
|
||||||
|
int val = state.board[row][col];
|
||||||
|
if (val == 1) {
|
||||||
|
context.drawTexture(RED_TEX, cx + 2, cy + 2, 0, 0,
|
||||||
|
CELL_SIZE - 4, CELL_SIZE - 4,
|
||||||
|
CELL_SIZE - 4, CELL_SIZE - 4);
|
||||||
|
} else if (val == 2) {
|
||||||
|
context.drawTexture(YELLOW_TEX, cx + 2, cy + 2, 0, 0,
|
||||||
|
CELL_SIZE - 4, CELL_SIZE - 4,
|
||||||
|
CELL_SIZE - 4, CELL_SIZE - 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status text
|
||||||
|
String status;
|
||||||
|
if (state.winner == 1) status = "§cRed wins!";
|
||||||
|
else if (state.winner == 2) status = "§eYellow wins!";
|
||||||
|
else if (state.winner == 3) status = "§7Draw!";
|
||||||
|
else if (isSpectator) status = "§7Spectating...";
|
||||||
|
else status = myTurn ? "§aYour turn!" : "§7Opponent's turn...";
|
||||||
|
|
||||||
|
context.drawTextWithShadow(this.textRenderer, Text.literal(status),
|
||||||
|
x + GUI_WIDTH / 2 - this.textRenderer.getWidth(status) / 2,
|
||||||
|
y + BOARD_Y + ConnectFourBlockEntity.ROWS * CELL_SIZE + 6,
|
||||||
|
0xFFFFFF);
|
||||||
|
|
||||||
|
super.render(context, mouseX, mouseY, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||||
|
if (isSpectator) return super.mouseClicked(mouseX, mouseY, button);
|
||||||
|
if (button != 0) return super.mouseClicked(mouseX, mouseY, button);
|
||||||
|
if (state.winner != 0) return super.mouseClicked(mouseX, mouseY, button);
|
||||||
|
|
||||||
|
boolean myTurn = (state.currentTurn == 1 && localPlayer.equals(state.player1))
|
||||||
|
|| (state.currentTurn == 2 && localPlayer.equals(state.player2));
|
||||||
|
if (!myTurn) return super.mouseClicked(mouseX, mouseY, button);
|
||||||
|
|
||||||
|
int x = (this.width - GUI_WIDTH) / 2;
|
||||||
|
|
||||||
|
for (int col = 0; col < ConnectFourBlockEntity.COLS; col++) {
|
||||||
|
int cx = x + BOARD_X + col * CELL_SIZE;
|
||||||
|
if (mouseX >= cx && mouseX < cx + CELL_SIZE) {
|
||||||
|
sendMove(col);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.mouseClicked(mouseX, mouseY, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendMove(int col) {
|
||||||
|
PacketByteBuf buf = PacketByteBufs.create();
|
||||||
|
buf.writeBlockPos(blockPos);
|
||||||
|
buf.writeInt(col);
|
||||||
|
ClientPlayNetworking.send(Szar.C4_MAKE_MOVE, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldPause() { return false; }
|
||||||
|
}
|
||||||
@@ -90,11 +90,17 @@ public class SzarClient implements ClientModInitializer {
|
|||||||
);
|
);
|
||||||
@Override
|
@Override
|
||||||
public void onInitializeClient() {
|
public void onInitializeClient() {
|
||||||
// Open screen
|
// TTT
|
||||||
ClientPlayNetworking.registerGlobalReceiver(Szar.TTT_OPEN_SCREEN, (client, handler, buf, sender) -> {
|
ClientPlayNetworking.registerGlobalReceiver(Szar.TTT_OPEN_SCREEN, (client, handler, buf, sender) -> {
|
||||||
BlockPos pos = buf.readBlockPos();
|
BlockPos pos = buf.readBlockPos();
|
||||||
TicTacToeBlockEntity.State state = TicTacToeBlockEntity.readStateFromBuf(buf);
|
TicTacToeBlockEntity.State state = TicTacToeBlockEntity.readStateFromBuf(buf);
|
||||||
client.execute(() -> client.setScreen(new TicTacToeScreen(pos, state)));
|
client.execute(() -> {
|
||||||
|
if (client.currentScreen instanceof TicTacToeScreen existing) {
|
||||||
|
existing.updateState(state); // just update, don't replace
|
||||||
|
} else {
|
||||||
|
client.setScreen(new TicTacToeScreen(pos, state));
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
ClientPlayNetworking.registerGlobalReceiver(Szar.TTT_CLOSE_SCREEN, (client, handler, buf, sender) -> {
|
ClientPlayNetworking.registerGlobalReceiver(Szar.TTT_CLOSE_SCREEN, (client, handler, buf, sender) -> {
|
||||||
client.execute(() -> {
|
client.execute(() -> {
|
||||||
@@ -112,6 +118,37 @@ public class SzarClient implements ClientModInitializer {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// C4
|
||||||
|
ClientPlayNetworking.registerGlobalReceiver(Szar.C4_OPEN_SCREEN, (client, handler, buf, sender) -> {
|
||||||
|
BlockPos pos = buf.readBlockPos();
|
||||||
|
ConnectFourBlockEntity.State state = ConnectFourBlockEntity.readStateFromBuf(buf);
|
||||||
|
client.execute(() -> {
|
||||||
|
if (client.currentScreen instanceof ConnectFourScreen existing) {
|
||||||
|
existing.updateState(state);
|
||||||
|
} else {
|
||||||
|
client.setScreen(new ConnectFourScreen(pos, state));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ClientPlayNetworking.registerGlobalReceiver(Szar.C4_STATE_SYNC, (client, handler, buf, sender) -> {
|
||||||
|
BlockPos pos = buf.readBlockPos();
|
||||||
|
ConnectFourBlockEntity.State state = ConnectFourBlockEntity.readStateFromBuf(buf);
|
||||||
|
client.execute(() -> {
|
||||||
|
if (client.currentScreen instanceof ConnectFourScreen screen) {
|
||||||
|
screen.updateState(state);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ClientPlayNetworking.registerGlobalReceiver(Szar.C4_CLOSE_SCREEN, (client, handler, buf, sender) -> {
|
||||||
|
client.execute(() -> {
|
||||||
|
if (client.currentScreen instanceof ConnectFourScreen) {
|
||||||
|
client.setScreen(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
ClientPlayNetworking.registerGlobalReceiver(Szar.DRUNK_TYPE_PACKET, (client, handler, buf, responseSender) -> {
|
ClientPlayNetworking.registerGlobalReceiver(Szar.DRUNK_TYPE_PACKET, (client, handler, buf, responseSender) -> {
|
||||||
String typeName = buf.readString();
|
String typeName = buf.readString();
|
||||||
client.execute(() -> DrunkEffect.setDisplayType(typeName));
|
client.execute(() -> DrunkEffect.setDisplayType(typeName));
|
||||||
|
|||||||
81
src/main/java/dev/tggamesyt/szar/ConnectFourBlock.java
Normal file
81
src/main/java/dev/tggamesyt/szar/ConnectFourBlock.java
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
package dev.tggamesyt.szar;
|
||||||
|
|
||||||
|
import net.minecraft.block.*;
|
||||||
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.block.entity.BlockEntityTicker;
|
||||||
|
import net.minecraft.block.entity.BlockEntityType;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class ConnectFourBlock extends BlockWithEntity {
|
||||||
|
|
||||||
|
private static final VoxelShape SHAPE = VoxelShapes.union(
|
||||||
|
VoxelShapes.cuboid(0f, 0f, 0f, 1f, 0.75f, 1f)
|
||||||
|
);
|
||||||
|
|
||||||
|
public ConnectFourBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockRenderType getRenderType(BlockState state) {
|
||||||
|
return BlockRenderType.MODEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world,
|
||||||
|
BlockPos pos, ShapeContext ctx) {
|
||||||
|
return SHAPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCollisionShape(BlockState state, BlockView world,
|
||||||
|
BlockPos pos, ShapeContext ctx) {
|
||||||
|
return SHAPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||||
|
return new ConnectFourBlockEntity(pos, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionResult onUse(BlockState state, World world, BlockPos pos,
|
||||||
|
PlayerEntity player, Hand hand, BlockHitResult hit) {
|
||||||
|
if (world.isClient) return ActionResult.SUCCESS;
|
||||||
|
if (!(player instanceof ServerPlayerEntity sp)) return ActionResult.PASS;
|
||||||
|
if (!(world.getBlockEntity(pos) instanceof ConnectFourBlockEntity be)) return ActionResult.PASS;
|
||||||
|
be.handlePlayerJoin(sp, pos);
|
||||||
|
return ActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(
|
||||||
|
World world, BlockState state, BlockEntityType<T> type) {
|
||||||
|
if (world.isClient) return null;
|
||||||
|
return type == Szar.CONNECT_FOUR_ENTITY
|
||||||
|
? (w, pos, s, be) -> ConnectFourBlockEntity.tick(w, pos, s,
|
||||||
|
(ConnectFourBlockEntity) be)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) {
|
||||||
|
if (!world.isClient && world.getBlockEntity(pos) instanceof ConnectFourBlockEntity be) {
|
||||||
|
be.closeScreenForAll(world.getServer());
|
||||||
|
if (be.player1 != null) Szar.c4ActivePlayers.remove(be.player1);
|
||||||
|
if (be.player2 != null) Szar.c4ActivePlayers.remove(be.player2);
|
||||||
|
}
|
||||||
|
super.onBreak(world, pos, state, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
308
src/main/java/dev/tggamesyt/szar/ConnectFourBlockEntity.java
Normal file
308
src/main/java/dev/tggamesyt/szar/ConnectFourBlockEntity.java
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
package dev.tggamesyt.szar;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.nbt.NbtCompound;
|
||||||
|
import net.minecraft.network.PacketByteBuf;
|
||||||
|
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class ConnectFourBlockEntity extends BlockEntity {
|
||||||
|
|
||||||
|
public static final int COLS = 7;
|
||||||
|
public static final int ROWS = 6;
|
||||||
|
|
||||||
|
// board[row][col], 0=empty, 1=player1(red), 2=player2(yellow)
|
||||||
|
// row 0 = bottom
|
||||||
|
public int[][] board = new int[ROWS][COLS];
|
||||||
|
public UUID player1 = null; // red
|
||||||
|
public UUID player2 = null; // yellow
|
||||||
|
public int currentTurn = 1;
|
||||||
|
public int winner = 0; // 0=ongoing, 1=p1, 2=p2, 3=draw
|
||||||
|
public Set<UUID> spectators = new HashSet<>();
|
||||||
|
public int resetTimer = -1;
|
||||||
|
|
||||||
|
public ConnectFourBlockEntity(BlockPos pos, BlockState state) {
|
||||||
|
super(Szar.CONNECT_FOUR_ENTITY, pos, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void tick(World world, BlockPos pos, BlockState state,
|
||||||
|
ConnectFourBlockEntity entity) {
|
||||||
|
if (!world.isClient && entity.resetTimer > 0) {
|
||||||
|
entity.resetTimer--;
|
||||||
|
if (entity.resetTimer == 0) {
|
||||||
|
entity.resetTimer = -1;
|
||||||
|
var server = ((net.minecraft.server.world.ServerWorld) world).getServer();
|
||||||
|
entity.resetGame(server);
|
||||||
|
entity.syncToPlayers(server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handlePlayerJoin(ServerPlayerEntity player, BlockPos pos) {
|
||||||
|
UUID uuid = player.getUuid();
|
||||||
|
|
||||||
|
BlockPos activePos = Szar.c4ActivePlayers.get(uuid);
|
||||||
|
if (activePos != null && !activePos.equals(pos)) {
|
||||||
|
player.sendMessage(Text.literal("§cYou are already in a game at another board!"), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rejoin existing game
|
||||||
|
if (uuid.equals(player1) || uuid.equals(player2)) {
|
||||||
|
if (player1 != null && player2 != null) {
|
||||||
|
// Game in progress — reopen screen
|
||||||
|
openScreen(player);
|
||||||
|
} else {
|
||||||
|
// Still waiting for second player — leave
|
||||||
|
if (uuid.equals(player1)) {
|
||||||
|
Szar.c4ActivePlayers.remove(player1);
|
||||||
|
player1 = null;
|
||||||
|
} else {
|
||||||
|
Szar.c4ActivePlayers.remove(player2);
|
||||||
|
player2 = null;
|
||||||
|
}
|
||||||
|
player.sendMessage(Text.literal("§7Left the game."), true);
|
||||||
|
markDirty();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player1 == null) {
|
||||||
|
player1 = uuid;
|
||||||
|
Szar.c4ActivePlayers.put(uuid, pos);
|
||||||
|
player.sendMessage(Text.literal("§aYou are §cRed§a! Waiting for second player..."), true);
|
||||||
|
markDirty();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player2 == null && !uuid.equals(player1)) {
|
||||||
|
player2 = uuid;
|
||||||
|
Szar.c4ActivePlayers.put(uuid, pos);
|
||||||
|
player.sendMessage(Text.literal("§aYou are §eYellow§a! Game starting!"), true);
|
||||||
|
ServerPlayerEntity p1 = player.getServer().getPlayerManager().getPlayer(player1);
|
||||||
|
if (p1 != null) p1.sendMessage(Text.literal("§aSecond player joined! Your turn!"), true);
|
||||||
|
openScreenForBoth(player);
|
||||||
|
markDirty();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player1 != null && player2 != null) {
|
||||||
|
spectators.add(uuid);
|
||||||
|
player.sendMessage(Text.literal("§7Spectating the match..."), true);
|
||||||
|
openScreen(player);
|
||||||
|
markDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleMove(ServerPlayerEntity player, int col) {
|
||||||
|
if (winner != 0) return;
|
||||||
|
if (col < 0 || col >= COLS) return;
|
||||||
|
|
||||||
|
UUID uuid = player.getUuid();
|
||||||
|
int playerNum = uuid.equals(player1) ? 1 : uuid.equals(player2) ? 2 : 0;
|
||||||
|
if (playerNum == 0) return;
|
||||||
|
if (playerNum != currentTurn) {
|
||||||
|
player.sendMessage(Text.literal("§cNot your turn!"), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find lowest empty row in this column (gravity)
|
||||||
|
int targetRow = -1;
|
||||||
|
for (int row = 0; row < ROWS; row++) {
|
||||||
|
if (board[row][col] == 0) {
|
||||||
|
targetRow = row;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (targetRow == -1) {
|
||||||
|
player.sendMessage(Text.literal("§cColumn is full!"), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
board[targetRow][col] = playerNum;
|
||||||
|
currentTurn = (currentTurn == 1) ? 2 : 1;
|
||||||
|
checkWinner();
|
||||||
|
markDirty();
|
||||||
|
syncToPlayers(player.getServer());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkWinner() {
|
||||||
|
// Check all 4-in-a-row directions
|
||||||
|
int[][] directions = {{0,1},{1,0},{1,1},{1,-1}};
|
||||||
|
for (int row = 0; row < ROWS; row++) {
|
||||||
|
for (int col = 0; col < COLS; col++) {
|
||||||
|
int val = board[row][col];
|
||||||
|
if (val == 0) continue;
|
||||||
|
for (int[] dir : directions) {
|
||||||
|
int count = 1;
|
||||||
|
for (int i = 1; i < 4; i++) {
|
||||||
|
int r = row + dir[0] * i;
|
||||||
|
int c = col + dir[1] * i;
|
||||||
|
if (r < 0 || r >= ROWS || c < 0 || c >= COLS) break;
|
||||||
|
if (board[r][c] != val) break;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
if (count == 4) {
|
||||||
|
winner = val;
|
||||||
|
resetTimer = 100; // 5 seconds
|
||||||
|
markDirty();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check draw — top row full
|
||||||
|
boolean full = true;
|
||||||
|
for (int col = 0; col < COLS; col++) {
|
||||||
|
if (board[ROWS - 1][col] == 0) { full = false; break; }
|
||||||
|
}
|
||||||
|
if (full) {
|
||||||
|
winner = 3;
|
||||||
|
resetTimer = 100;
|
||||||
|
markDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void openScreenForBoth(ServerPlayerEntity joiner) {
|
||||||
|
openScreen(joiner);
|
||||||
|
ServerPlayerEntity p1 = joiner.getServer().getPlayerManager().getPlayer(player1);
|
||||||
|
if (p1 != null) openScreen(p1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void openScreen(ServerPlayerEntity player) {
|
||||||
|
PacketByteBuf buf = PacketByteBufs.create();
|
||||||
|
buf.writeBlockPos(this.pos);
|
||||||
|
writeStateToBuf(buf, player.getUuid());
|
||||||
|
ServerPlayNetworking.send(player, Szar.C4_OPEN_SCREEN, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void syncToPlayers(net.minecraft.server.MinecraftServer server) {
|
||||||
|
sendToPlayer(server, player1);
|
||||||
|
sendToPlayer(server, player2);
|
||||||
|
for (UUID uuid : spectators) sendToPlayer(server, uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendToPlayer(net.minecraft.server.MinecraftServer server, UUID uuid) {
|
||||||
|
if (uuid == null) return;
|
||||||
|
ServerPlayerEntity p = server.getPlayerManager().getPlayer(uuid);
|
||||||
|
if (p == null) return;
|
||||||
|
PacketByteBuf buf = PacketByteBufs.create();
|
||||||
|
buf.writeBlockPos(this.pos);
|
||||||
|
writeStateToBuf(buf, uuid);
|
||||||
|
ServerPlayNetworking.send(p, Szar.C4_STATE_SYNC, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeStateToBuf(PacketByteBuf buf, UUID viewerUuid) {
|
||||||
|
for (int row = 0; row < ROWS; row++)
|
||||||
|
for (int col = 0; col < COLS; col++)
|
||||||
|
buf.writeInt(board[row][col]);
|
||||||
|
buf.writeBoolean(player1 != null);
|
||||||
|
if (player1 != null) buf.writeUuid(player1);
|
||||||
|
buf.writeBoolean(player2 != null);
|
||||||
|
if (player2 != null) buf.writeUuid(player2);
|
||||||
|
buf.writeInt(currentTurn);
|
||||||
|
buf.writeInt(winner);
|
||||||
|
boolean isSpectator = viewerUuid != null
|
||||||
|
&& !viewerUuid.equals(player1)
|
||||||
|
&& !viewerUuid.equals(player2);
|
||||||
|
buf.writeBoolean(isSpectator);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static State readStateFromBuf(PacketByteBuf buf) {
|
||||||
|
State s = new State();
|
||||||
|
s.board = new int[ROWS][COLS];
|
||||||
|
for (int row = 0; row < ROWS; row++)
|
||||||
|
for (int col = 0; col < COLS; col++)
|
||||||
|
s.board[row][col] = buf.readInt();
|
||||||
|
if (buf.readBoolean()) s.player1 = buf.readUuid();
|
||||||
|
if (buf.readBoolean()) s.player2 = buf.readUuid();
|
||||||
|
s.currentTurn = buf.readInt();
|
||||||
|
s.winner = buf.readInt();
|
||||||
|
s.isSpectator = buf.readBoolean();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class State {
|
||||||
|
public int[][] board;
|
||||||
|
public UUID player1, player2;
|
||||||
|
public int currentTurn, winner;
|
||||||
|
public boolean isSpectator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetGame(net.minecraft.server.MinecraftServer server) {
|
||||||
|
closeScreenForAll(server);
|
||||||
|
if (player1 != null) Szar.c4ActivePlayers.remove(player1);
|
||||||
|
if (player2 != null) Szar.c4ActivePlayers.remove(player2);
|
||||||
|
spectators.clear();
|
||||||
|
board = new int[ROWS][COLS];
|
||||||
|
player1 = null;
|
||||||
|
player2 = null;
|
||||||
|
currentTurn = 1;
|
||||||
|
winner = 0;
|
||||||
|
resetTimer = -1;
|
||||||
|
markDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeScreenForAll(net.minecraft.server.MinecraftServer server) {
|
||||||
|
closeScreenForPlayer(server, player1);
|
||||||
|
closeScreenForPlayer(server, player2);
|
||||||
|
for (UUID uuid : spectators) closeScreenForPlayer(server, uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeScreenForPlayer(net.minecraft.server.MinecraftServer server, UUID uuid) {
|
||||||
|
if (uuid == null) return;
|
||||||
|
ServerPlayerEntity p = server.getPlayerManager().getPlayer(uuid);
|
||||||
|
if (p == null) return;
|
||||||
|
ServerPlayNetworking.send(p, Szar.C4_CLOSE_SCREEN, PacketByteBufs.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeNbt(NbtCompound nbt) {
|
||||||
|
super.writeNbt(nbt);
|
||||||
|
int[] flat = new int[ROWS * COLS];
|
||||||
|
for (int r = 0; r < ROWS; r++)
|
||||||
|
for (int c = 0; c < COLS; c++)
|
||||||
|
flat[r * COLS + c] = board[r][c];
|
||||||
|
nbt.putIntArray("Board", flat);
|
||||||
|
if (player1 != null) nbt.putUuid("Player1", player1);
|
||||||
|
if (player2 != null) nbt.putUuid("Player2", player2);
|
||||||
|
nbt.putInt("Turn", currentTurn);
|
||||||
|
nbt.putInt("Winner", winner);
|
||||||
|
nbt.putInt("ResetTimer", resetTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readNbt(NbtCompound nbt) {
|
||||||
|
super.readNbt(nbt);
|
||||||
|
int[] flat = nbt.getIntArray("Board");
|
||||||
|
if (flat.length == ROWS * COLS) {
|
||||||
|
for (int r = 0; r < ROWS; r++)
|
||||||
|
for (int c = 0; c < COLS; c++)
|
||||||
|
board[r][c] = flat[r * COLS + c];
|
||||||
|
}
|
||||||
|
if (nbt.containsUuid("Player1")) player1 = nbt.getUuid("Player1");
|
||||||
|
if (nbt.containsUuid("Player2")) player2 = nbt.getUuid("Player2");
|
||||||
|
currentTurn = nbt.getInt("Turn");
|
||||||
|
winner = nbt.getInt("Winner");
|
||||||
|
resetTimer = nbt.getInt("ResetTimer");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NbtCompound toInitialChunkDataNbt() { return createNbt(); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockEntityUpdateS2CPacket toUpdatePacket() {
|
||||||
|
return BlockEntityUpdateS2CPacket.create(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -385,6 +385,7 @@ public class Szar implements ModInitializer {
|
|||||||
entries.add(Szar.ALMOND_WATER);
|
entries.add(Szar.ALMOND_WATER);
|
||||||
entries.add(Szar.KEBAB);
|
entries.add(Szar.KEBAB);
|
||||||
entries.add(Szar.TIC_TAC_TOE_ITEM);
|
entries.add(Szar.TIC_TAC_TOE_ITEM);
|
||||||
|
entries.add(Szar.CONNECT_FOUR_ITEM);
|
||||||
// crazy weponary
|
// crazy weponary
|
||||||
entries.add(Szar.BULLET_ITEM);
|
entries.add(Szar.BULLET_ITEM);
|
||||||
entries.add(Szar.AK47);
|
entries.add(Szar.AK47);
|
||||||
@@ -398,11 +399,11 @@ public class Szar implements ModInitializer {
|
|||||||
entries.add(Szar.WHEEL);
|
entries.add(Szar.WHEEL);
|
||||||
entries.add(Szar.PLANE);
|
entries.add(Szar.PLANE);
|
||||||
// drugs
|
// drugs
|
||||||
|
entries.add(Szar.BEER);
|
||||||
|
entries.add(Szar.CHEMICAL_WORKBENCH_ITEM);
|
||||||
entries.add(Szar.CANNABIS_ITEM);
|
entries.add(Szar.CANNABIS_ITEM);
|
||||||
entries.add(Szar.WEED_ITEM);
|
entries.add(Szar.WEED_ITEM);
|
||||||
entries.add(Szar.WEED_JOINT_ITEM);
|
entries.add(Szar.WEED_JOINT_ITEM);
|
||||||
entries.add(Szar.CHEMICAL_WORKBENCH_ITEM);
|
|
||||||
entries.add(Szar.BEER);
|
|
||||||
// war guys
|
// war guys
|
||||||
entries.add(Szar.HITTER_SPAWNEGG);
|
entries.add(Szar.HITTER_SPAWNEGG);
|
||||||
entries.add(Szar.NAZI_SPAWNEGG);
|
entries.add(Szar.NAZI_SPAWNEGG);
|
||||||
@@ -1337,6 +1338,15 @@ public class Szar implements ModInitializer {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
ServerPlayNetworking.registerGlobalReceiver(C4_MAKE_MOVE, (server, player, handler, buf, sender) -> {
|
||||||
|
BlockPos pos = buf.readBlockPos();
|
||||||
|
int col = buf.readInt();
|
||||||
|
server.execute(() -> {
|
||||||
|
if (player.getWorld().getBlockEntity(pos) instanceof ConnectFourBlockEntity be) {
|
||||||
|
be.handleMove(player, col);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Block TIC_TAC_TOE_BLOCK = Registry.register(
|
public static final Block TIC_TAC_TOE_BLOCK = Registry.register(
|
||||||
@@ -1359,7 +1369,27 @@ public class Szar implements ModInitializer {
|
|||||||
public static final Identifier TTT_MAKE_MOVE = new Identifier(MOD_ID, "ttt_move");
|
public static final Identifier TTT_MAKE_MOVE = new Identifier(MOD_ID, "ttt_move");
|
||||||
public static final Identifier TTT_STATE_SYNC = new Identifier(MOD_ID, "ttt_sync");
|
public static final Identifier TTT_STATE_SYNC = new Identifier(MOD_ID, "ttt_sync");
|
||||||
public static final Identifier TTT_CLOSE_SCREEN = new Identifier(MOD_ID, "ttt_close");
|
public static final Identifier TTT_CLOSE_SCREEN = new Identifier(MOD_ID, "ttt_close");
|
||||||
|
public static final Block CONNECT_FOUR_BLOCK = Registry.register(
|
||||||
|
Registries.BLOCK, new Identifier(MOD_ID, "connectfour"),
|
||||||
|
new ConnectFourBlock(AbstractBlock.Settings.create().strength(2f))
|
||||||
|
);
|
||||||
|
public static final BlockItem CONNECT_FOUR_ITEM = Registry.register(
|
||||||
|
Registries.ITEM, new Identifier(MOD_ID, "connectfour"),
|
||||||
|
new BlockItem(CONNECT_FOUR_BLOCK, new Item.Settings())
|
||||||
|
);
|
||||||
|
public static final BlockEntityType<ConnectFourBlockEntity> CONNECT_FOUR_ENTITY =
|
||||||
|
Registry.register(
|
||||||
|
Registries.BLOCK_ENTITY_TYPE, new Identifier(MOD_ID, "connectfour"),
|
||||||
|
FabricBlockEntityTypeBuilder.create(ConnectFourBlockEntity::new,
|
||||||
|
CONNECT_FOUR_BLOCK).build()
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Identifier C4_OPEN_SCREEN = new Identifier(MOD_ID, "c4_open");
|
||||||
|
public static final Identifier C4_MAKE_MOVE = new Identifier(MOD_ID, "c4_move");
|
||||||
|
public static final Identifier C4_STATE_SYNC = new Identifier(MOD_ID, "c4_sync");
|
||||||
|
public static final Identifier C4_CLOSE_SCREEN = new Identifier(MOD_ID, "c4_close");
|
||||||
|
|
||||||
|
public static final Map<UUID, BlockPos> c4ActivePlayers = new java.util.HashMap<>();
|
||||||
// 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"),
|
||||||
|
|||||||
@@ -52,7 +52,21 @@ public class TicTacToeBlockEntity extends BlockEntity {
|
|||||||
|
|
||||||
// Rejoin existing game
|
// Rejoin existing game
|
||||||
if (uuid.equals(player1) || uuid.equals(player2)) {
|
if (uuid.equals(player1) || uuid.equals(player2)) {
|
||||||
openScreen(player);
|
if (player1 != null && player2 != null) {
|
||||||
|
// Game in progress — reopen screen
|
||||||
|
openScreen(player);
|
||||||
|
} else {
|
||||||
|
// Still waiting for second player — leave
|
||||||
|
if (uuid.equals(player1)) {
|
||||||
|
Szar.tttActivePlayers.remove(player1); // use c4ActivePlayers for ConnectFour
|
||||||
|
player1 = null;
|
||||||
|
} else {
|
||||||
|
Szar.tttActivePlayers.remove(player2);
|
||||||
|
player2 = null;
|
||||||
|
}
|
||||||
|
player.sendMessage(Text.literal("§7Left the game."), true);
|
||||||
|
markDirty();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": { "model": "szar:block/connectfour" }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -187,5 +187,6 @@
|
|||||||
"advancement.szar.backrooms.title": "Where did the world go?",
|
"advancement.szar.backrooms.title": "Where did the world go?",
|
||||||
"advancement.szar.backrooms.description": "Step into the Backrooms",
|
"advancement.szar.backrooms.description": "Step into the Backrooms",
|
||||||
|
|
||||||
"block.szar.tictactoe": "Tic Tac Toe"
|
"block.szar.tictactoe": "Tic Tac Toe",
|
||||||
|
"block.szar.connectfour": "Connect Four"
|
||||||
}
|
}
|
||||||
|
|||||||
64
src/main/resources/assets/szar/models/block/connectfour.json
Normal file
64
src/main/resources/assets/szar/models/block/connectfour.json
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.9.0",
|
||||||
|
"credit": "Made with Blockbench",
|
||||||
|
"parent": "block/block",
|
||||||
|
"texture_size": [32, 32],
|
||||||
|
"textures": {
|
||||||
|
"0": "szar:block/plank",
|
||||||
|
"1": "szar:block/connect4",
|
||||||
|
"particle": "szar:block/plank"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"from": [0, 0, 0],
|
||||||
|
"to": [16, 12, 16],
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [0, 0, 16, 12], "texture": "#0"},
|
||||||
|
"east": {"uv": [0, 0, 16, 12], "texture": "#0"},
|
||||||
|
"south": {"uv": [0, 0, 16, 12], "texture": "#0"},
|
||||||
|
"west": {"uv": [0, 0, 16, 12], "texture": "#0"},
|
||||||
|
"up": {"uv": [0, 0, 16, 16], "texture": "#0"},
|
||||||
|
"down": {"uv": [0, 0, 16, 16], "texture": "#0"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 14, 0],
|
||||||
|
"to": [9, 24, 16],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [1, 12, 0]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [9, 0, 10, 5], "texture": "#1"},
|
||||||
|
"east": {"uv": [0, 0, 8, 5], "texture": "#1"},
|
||||||
|
"south": {"uv": [9, 5, 10, 10], "texture": "#1"},
|
||||||
|
"west": {"uv": [0, 5, 8, 10], "texture": "#1"},
|
||||||
|
"up": {"uv": [9, 8, 8, 0], "texture": "#1"},
|
||||||
|
"down": {"uv": [9, 8, 8, 16], "texture": "#1"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 12, 0],
|
||||||
|
"to": [9, 14, 1],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [1, 10, 0]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [0, 10, 1, 11], "texture": "#1"},
|
||||||
|
"east": {"uv": [2, 10, 2.5, 11], "texture": "#1"},
|
||||||
|
"south": {"uv": [10, 0, 11, 1], "texture": "#1"},
|
||||||
|
"west": {"uv": [10, 2, 10.5, 3], "texture": "#1"},
|
||||||
|
"up": {"uv": [3.5, 10.5, 2.5, 10], "texture": "#1"},
|
||||||
|
"down": {"uv": [11, 3, 10, 3.5], "texture": "#1"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 12, 15],
|
||||||
|
"to": [9, 14, 16],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [1, 10, 15]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [1, 10, 2, 11], "texture": "#1"},
|
||||||
|
"east": {"uv": [3.5, 10, 4, 11], "texture": "#1"},
|
||||||
|
"south": {"uv": [10, 1, 11, 2], "texture": "#1"},
|
||||||
|
"west": {"uv": [10, 3.5, 10.5, 4.5], "texture": "#1"},
|
||||||
|
"up": {"uv": [5, 10.5, 4, 10], "texture": "#1"},
|
||||||
|
"down": {"uv": [11, 4.5, 10, 5], "texture": "#1"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"parent": "szar:block/connectfour"
|
||||||
|
}
|
||||||
BIN
src/main/resources/assets/szar/textures/block/connect4.png
Normal file
BIN
src/main/resources/assets/szar/textures/block/connect4.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 257 B |
BIN
src/main/resources/assets/szar/textures/gui/c4_hover.png
Normal file
BIN
src/main/resources/assets/szar/textures/gui/c4_hover.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 761 B |
BIN
src/main/resources/assets/szar/textures/gui/c4_red.png
Normal file
BIN
src/main/resources/assets/szar/textures/gui/c4_red.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 694 B |
BIN
src/main/resources/assets/szar/textures/gui/c4_yellow.png
Normal file
BIN
src/main/resources/assets/szar/textures/gui/c4_yellow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 688 B |
BIN
src/main/resources/assets/szar/textures/gui/connectfour.png
Normal file
BIN
src/main/resources/assets/szar/textures/gui/connectfour.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
@@ -2,6 +2,7 @@
|
|||||||
"values": [
|
"values": [
|
||||||
"szar:roulette",
|
"szar:roulette",
|
||||||
"szar:slot_machine",
|
"szar:slot_machine",
|
||||||
"szar:tictactoe"
|
"szar:tictactoe",
|
||||||
|
"szar:connectfour"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"type": "minecraft:block",
|
||||||
|
"pools": [
|
||||||
|
{
|
||||||
|
"rolls": 1,
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"type": "minecraft:item",
|
||||||
|
"name": "szar:connectfour"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
23
src/main/resources/data/szar/recipes/connectfour.json
Normal file
23
src/main/resources/data/szar/recipes/connectfour.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"type": "minecraft:crafting_shaped",
|
||||||
|
"pattern": [
|
||||||
|
"RBR",
|
||||||
|
"BPB",
|
||||||
|
"RBR"
|
||||||
|
],
|
||||||
|
"key": {
|
||||||
|
"R": {
|
||||||
|
"item": "minecraft:red_dye"
|
||||||
|
},
|
||||||
|
"B": {
|
||||||
|
"item": "minecraft:yellow_dye"
|
||||||
|
},
|
||||||
|
"P": {
|
||||||
|
"tag": "minecraft:planks"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"item": "szar:connectfour",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user