roulette update
270
src/client/java/dev/tggamesyt/szar/client/RouletteScreen.java
Normal file
@@ -0,0 +1,270 @@
|
||||
package dev.tggamesyt.szar.client;
|
||||
|
||||
import dev.tggamesyt.szar.*;
|
||||
import net.minecraft.client.gui.DrawContext;
|
||||
import net.minecraft.client.gui.screen.ingame.HandledScreen;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.RotationAxis;
|
||||
|
||||
public class RouletteScreen extends HandledScreen<RouletteScreenHandler> {
|
||||
|
||||
private static final Identifier BG_TEXTURE =
|
||||
new Identifier(Szar.MOD_ID, "textures/gui/roulette.png");
|
||||
|
||||
// Add these fields to the class
|
||||
private int dotAnimFrame = 0;
|
||||
private int dotAnimTick = 0;
|
||||
private static final int DOT_FRAME_DURATION = 20;
|
||||
private static final String[] DOT_FRAMES = {
|
||||
"...", "⋅..", "⋅⋅.", ".⋅⋅", "..⋅", "...", "...", "...", "..."
|
||||
};
|
||||
private boolean showingWinner = false;
|
||||
private int stoppedTick = 0; // elapsed ticks since spin stopped
|
||||
|
||||
private final PlayerInventory inventory;
|
||||
private final RouletteBlockEntity blockEntity;
|
||||
private final RouletteScreenHandler handler;
|
||||
|
||||
public String spinString = "Next spin in: 0s";
|
||||
public int nextspinTime = 0;
|
||||
public boolean isIntermission = true;
|
||||
private int winnernum = 0;
|
||||
|
||||
private float wheelDeg = 0f;
|
||||
private float ballDeg = 0f;
|
||||
|
||||
// Spin start positions (captured when spin begins)
|
||||
private float wheelStartDeg = 0f;
|
||||
private float ballStartDeg = 0f;
|
||||
|
||||
// Total distance each will travel over the entire spin duration
|
||||
private float wheelTotalDist = 0f;
|
||||
private float ballTotalDist = 0f;
|
||||
|
||||
// Total ticks for the active spin (rollingTicks + halfWaitTicks)
|
||||
private int spinTotalTicks = 0;
|
||||
|
||||
// How many ticks of the spin are "locked still" at the end (second half of wait)
|
||||
private int spinStopTicks = 0;
|
||||
|
||||
private boolean spinInitialized = false;
|
||||
private int lastElapsed = -1;
|
||||
|
||||
// Full speed in degrees/tick — used to compute how far wheel/ball travel
|
||||
// during the constant-speed portion so total distance lands on target
|
||||
private static final float WHEEL_FULL_SPEED = 8.0f;
|
||||
private static final float BALL_FULL_SPEED = 14.0f;
|
||||
|
||||
public RouletteScreen(RouletteScreenHandler handler,
|
||||
PlayerInventory inventory,
|
||||
Text title) {
|
||||
super(handler, inventory, title);
|
||||
this.handler = handler;
|
||||
this.blockEntity = handler.blockEntity;
|
||||
this.backgroundWidth = 326;
|
||||
this.backgroundHeight = 194;
|
||||
this.inventory = inventory;
|
||||
}
|
||||
|
||||
// Ease curve: constant speed phase (0→splitT) then ease-out (splitT→1)
|
||||
// At t=splitT the curve transitions smoothly — the ease-out's initial
|
||||
// derivative is set to match FULL_SPEED so there is no speed discontinuity.
|
||||
//
|
||||
// For t in [0, splitT]: pos(t) = fullSpeed * t * totalTicks
|
||||
// For t in [splitT, 1]: pos(t) = pos(splitT) + decelDist * easeOut((t-splitT)/(1-splitT))
|
||||
//
|
||||
// easeOut(u) = 2u - u² → derivative at u=0 is 2/totalDecelTicks * decelDist
|
||||
// We need that to equal fullSpeed * totalTicks (per-tick speed at split point).
|
||||
// This is satisfied automatically because we set decelDist so the curve lands on target,
|
||||
// and the split is at the rollingTicks boundary.
|
||||
|
||||
private void onSpinStart(int rollingTicks, int halfWaitTicks) {
|
||||
spinTotalTicks = rollingTicks + halfWaitTicks;
|
||||
spinStopTicks = blockEntity.wheelWaitSeconds * 20 - halfWaitTicks; // second half of wait
|
||||
|
||||
wheelStartDeg = wheelDeg;
|
||||
ballStartDeg = ballDeg;
|
||||
|
||||
float targetWheelDeg = RouletteBlockEntity.getWheelDegrees(winnernum);
|
||||
float targetBallDeg = 0f;
|
||||
|
||||
// Distance covered during constant phase (phase1)
|
||||
float wheelPhase1Dist = WHEEL_FULL_SPEED * rollingTicks;
|
||||
float ballPhase1Dist = BALL_FULL_SPEED * rollingTicks;
|
||||
|
||||
// Where each ends up after phase1
|
||||
float wheelAfterPhase1 = (wheelStartDeg + wheelPhase1Dist) % 360f;
|
||||
float ballAfterPhase1 = (ballStartDeg + ballPhase1Dist) % 360f;
|
||||
|
||||
// Phase2 must cover exactly the right distance to land on target.
|
||||
// Pick the smallest distance >= a minimum so the wheel visibly decelerates.
|
||||
float minDecelRotations = 1.0f; // at least 1 full extra rotation during decel
|
||||
float wheelPhase2Dist = positiveMod(targetWheelDeg - wheelAfterPhase1, 360f);
|
||||
if (wheelPhase2Dist < 360f * minDecelRotations) wheelPhase2Dist += 360f;
|
||||
|
||||
float ballPhase2Dist = positiveMod(targetBallDeg - ballAfterPhase1, 360f);
|
||||
if (ballPhase2Dist < 360f * minDecelRotations) ballPhase2Dist += 360f;
|
||||
|
||||
wheelTotalDist = wheelPhase1Dist + wheelPhase2Dist;
|
||||
ballTotalDist = ballPhase1Dist + ballPhase2Dist;
|
||||
|
||||
spinInitialized = true;
|
||||
}
|
||||
|
||||
// Returns position fraction [0,1] along the total distance given elapsed ticks.
|
||||
// Uses a piecewise curve: linear up to splitTick, then ease-out after.
|
||||
// The ease-out's initial slope matches the linear slope → no speed jump.
|
||||
private float curvePosition(int elapsed, int splitTick, int totalTicks,
|
||||
float phase1Dist, float totalDist) {
|
||||
if (elapsed <= 0) return 0f;
|
||||
if (elapsed >= totalTicks) return 1f;
|
||||
|
||||
float phase2Dist = totalDist - phase1Dist;
|
||||
|
||||
if (elapsed <= splitTick) {
|
||||
// Linear phase
|
||||
return (phase1Dist * ((float) elapsed / splitTick)) / totalDist;
|
||||
} else {
|
||||
// Ease-out phase: u goes 0→1 over (totalTicks - splitTick) ticks
|
||||
float u = (float)(elapsed - splitTick) / (totalTicks - splitTick);
|
||||
// easeOut(u) = 2u - u² (starts at slope 2, ends at slope 0)
|
||||
float eased = 2f * u - u * u;
|
||||
return (phase1Dist + eased * phase2Dist) / totalDist;
|
||||
}
|
||||
}
|
||||
|
||||
public void tickScreen() {
|
||||
nextspinTime = handler.getPropertyDelegate().get(1);
|
||||
isIntermission = handler.getPropertyDelegate().get(0) == 1;
|
||||
winnernum = handler.getPropertyDelegate().get(2);
|
||||
|
||||
if (isIntermission) {
|
||||
spinString = "Next spin in: " + (nextspinTime + 19) / 20 + "s";
|
||||
spinInitialized = false;
|
||||
lastElapsed = -1;
|
||||
showingWinner = false;
|
||||
stoppedTick = 0;
|
||||
wheelDeg = RouletteBlockEntity.getWheelDegrees(winnernum);
|
||||
ballDeg = 0f;
|
||||
return;
|
||||
}
|
||||
|
||||
int rollingTicks = blockEntity.wheelRollingSeconds * 20;
|
||||
int waitTicks = blockEntity.wheelWaitSeconds * 20;
|
||||
int halfWaitTicks = waitTicks / 2;
|
||||
int elapsed = -nextspinTime;
|
||||
|
||||
if (!spinInitialized || lastElapsed < 0) {
|
||||
dotAnimFrame = 0;
|
||||
dotAnimTick = 0;
|
||||
showingWinner = false;
|
||||
stoppedTick = 0;
|
||||
onSpinStart(rollingTicks, halfWaitTicks);
|
||||
}
|
||||
lastElapsed = elapsed;
|
||||
|
||||
if (elapsed >= spinTotalTicks) {
|
||||
// Wheel has stopped — count ticks and show winner at halfWaitTicks
|
||||
stoppedTick++;
|
||||
wheelDeg = RouletteBlockEntity.getWheelDegrees(winnernum);
|
||||
ballDeg = 0f;
|
||||
if (stoppedTick >= halfWaitTicks) {
|
||||
showingWinner = true;
|
||||
}
|
||||
spinString = showingWinner ? "Winner: " + winnernum + " (" + RouletteBlockEntity.NUMBER_COLORS[winnernum].toUpperCase() + ")" : "Spinning" + DOT_FRAMES[dotAnimFrame];
|
||||
return;
|
||||
}
|
||||
|
||||
// Animate dots while spinning
|
||||
dotAnimTick++;
|
||||
if (dotAnimTick >= DOT_FRAME_DURATION) {
|
||||
dotAnimTick = 0;
|
||||
dotAnimFrame = (dotAnimFrame + 1) % DOT_FRAMES.length;
|
||||
}
|
||||
spinString = "Spinning" + DOT_FRAMES[dotAnimFrame];
|
||||
|
||||
float wheelFrac = curvePosition(elapsed, rollingTicks, spinTotalTicks,
|
||||
WHEEL_FULL_SPEED * rollingTicks, wheelTotalDist);
|
||||
float ballFrac = curvePosition(elapsed, rollingTicks, spinTotalTicks,
|
||||
BALL_FULL_SPEED * rollingTicks, ballTotalDist);
|
||||
|
||||
wheelDeg = (wheelStartDeg + wheelFrac * wheelTotalDist) % 360f;
|
||||
ballDeg = (ballStartDeg + ballFrac * ballTotalDist) % 360f;
|
||||
}
|
||||
|
||||
private static float positiveMod(float value, float mod) {
|
||||
return ((value % mod) + mod) % mod;
|
||||
}
|
||||
|
||||
// ----------------------------
|
||||
// BACKGROUND
|
||||
// ----------------------------
|
||||
|
||||
@Override
|
||||
protected void drawBackground(DrawContext context, float delta, int mouseX, int mouseY) {
|
||||
int guiLeft = (width - backgroundWidth) / 2;
|
||||
int guiTop = (height - backgroundHeight) / 2;
|
||||
context.getMatrices().push();
|
||||
context.getMatrices().translate(guiLeft, guiTop, 0);
|
||||
context.getMatrices().scale(2.0f, 2.0f, 1.0f);
|
||||
context.drawTexture(BG_TEXTURE, 0, 0, 0, 0, backgroundWidth, backgroundHeight);
|
||||
context.getMatrices().pop();
|
||||
}
|
||||
|
||||
protected void drawText(DrawContext context) {
|
||||
int guiLeft = (width - backgroundWidth) / 2;
|
||||
int guiTop = (height - backgroundHeight) / 2;
|
||||
context.drawText(textRenderer, Text.literal(spinString),
|
||||
guiLeft + 190, guiTop + 115, 0x373737, false);
|
||||
}
|
||||
|
||||
protected void drawWheel(DrawContext context) {
|
||||
int cx = ((width - backgroundWidth) / 2) + 255;
|
||||
int cy = ((height - backgroundHeight) / 2) + 155;
|
||||
|
||||
Identifier wheelTex = new Identifier(Szar.MOD_ID, "textures/gui/roulette_wheel.png");
|
||||
Identifier ballTex = new Identifier(Szar.MOD_ID, "textures/gui/roulette_ball.png");
|
||||
int imgWidth = 64;
|
||||
int imgHeight = 64;
|
||||
|
||||
context.getMatrices().push();
|
||||
context.getMatrices().translate(cx, cy, 0);
|
||||
context.getMatrices().multiply(RotationAxis.POSITIVE_Z.rotationDegrees(wheelDeg));
|
||||
context.drawTexture(wheelTex, -imgWidth / 2, -imgHeight / 2, 0, 0,
|
||||
imgWidth, imgHeight, imgWidth, imgHeight);
|
||||
context.getMatrices().pop();
|
||||
|
||||
context.getMatrices().push();
|
||||
context.getMatrices().translate(cx, cy, 0);
|
||||
context.getMatrices().multiply(RotationAxis.POSITIVE_Z.rotationDegrees(ballDeg));
|
||||
context.drawTexture(ballTex, -imgWidth / 2, -imgHeight / 2, 0, 0,
|
||||
imgWidth, imgHeight, imgWidth, imgHeight);
|
||||
context.getMatrices().pop();
|
||||
}
|
||||
|
||||
// ----------------------------
|
||||
// RENDER
|
||||
// ----------------------------
|
||||
|
||||
@Override
|
||||
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||
renderBackground(context);
|
||||
super.render(context, mouseX, mouseY, delta);
|
||||
drawWheel(context);
|
||||
drawText(context);
|
||||
drawMouseoverTooltip(context, mouseX, mouseY);
|
||||
tickScreen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||
return super.mouseClicked(mouseX, mouseY, button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed() {
|
||||
super.removed();
|
||||
}
|
||||
}
|
||||
@@ -250,6 +250,7 @@ public class SzarClient implements ClientModInitializer {
|
||||
SlotMachineRenderer::new
|
||||
);*/
|
||||
HandledScreens.register(Szar.SLOT_MACHINE_SCREEN_HANDLER_TYPE, SlotMachineScreen::new);
|
||||
HandledScreens.register(Szar.ROULETTE_SCREEN_HANDLER_TYPE, RouletteScreen::new);
|
||||
|
||||
EntityRendererRegistry.register(
|
||||
Szar.NiggerEntityType,
|
||||
|
||||
204
src/main/java/dev/tggamesyt/szar/RouletteBlock.java
Normal file
@@ -0,0 +1,204 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockEntityProvider;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.ShapeContext;
|
||||
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.entity.player.PlayerInventory;
|
||||
import net.minecraft.item.ItemPlacementContext;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.screen.NamedScreenHandlerFactory;
|
||||
import net.minecraft.screen.ScreenHandler;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.state.StateManager;
|
||||
import net.minecraft.state.property.DirectionProperty;
|
||||
import net.minecraft.state.property.Properties;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.BlockMirror;
|
||||
import net.minecraft.util.BlockRotation;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.shape.VoxelShape;
|
||||
import net.minecraft.util.shape.VoxelShapes;
|
||||
import net.minecraft.world.BlockView;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class RouletteBlock extends Block implements BlockEntityProvider {
|
||||
|
||||
public static final DirectionProperty FACING = Properties.HORIZONTAL_FACING;
|
||||
|
||||
public RouletteBlock(Settings settings) {
|
||||
super(settings);
|
||||
setDefaultState(getStateManager().getDefaultState().with(FACING, Direction.NORTH));
|
||||
}
|
||||
|
||||
VoxelShape shape23 = VoxelShapes.cuboid(0.25f, 0f, 0f, 0.75f, 0.25f, 0.125f);
|
||||
VoxelShape shape24 = VoxelShapes.cuboid(0.125f, 0f, 0.125f, 0.875f, 0.125f, 0.25f);
|
||||
VoxelShape shape25 = VoxelShapes.cuboid(0f, 0f, 0.25f, 1f, 0.125f, 0.75f);
|
||||
VoxelShape shape26 = VoxelShapes.cuboid(0.125f, 0f, 0.75f, 0.875f, 0.125f, 0.875f);
|
||||
VoxelShape shape27 = VoxelShapes.cuboid(0.25f, 0f, 0.875f, 0.75f, 0.25f, 1f);
|
||||
VoxelShape shape28 = VoxelShapes.cuboid(0f, 0.125f, 0.25f, 0.125f, 0.25f, 0.75f);
|
||||
VoxelShape shape29 = VoxelShapes.cuboid(0.875f, 0.125f, 0.25f, 1f, 0.25f, 0.75f);
|
||||
VoxelShape shape30 = VoxelShapes.cuboid(0.75f, 0.125f, 0.125f, 0.875f, 0.25f, 0.25f);
|
||||
VoxelShape shape31 = VoxelShapes.cuboid(0.75f, 0.125f, 0.75f, 0.875f, 0.25f, 0.875f);
|
||||
VoxelShape shape32 = VoxelShapes.cuboid(0.125f, 0.125f, 0.125f, 0.25f, 0.25f, 0.25f);
|
||||
VoxelShape shape33 = VoxelShapes.cuboid(0.125f, 0.125f, 0.75f, 0.25f, 0.25f, 0.875f);
|
||||
VoxelShape shape34 = VoxelShapes.cuboid(0.3125f, 0.313125f, 0.3125f, 0.6875f, 0.313125f, 0.6875f);
|
||||
VoxelShape shape35 = VoxelShapes.cuboid(0.4375f, 0.125f, 0.4375f, 0.5625f, 0.3125f, 0.5625f);
|
||||
VoxelShape BASE_SHAPE = VoxelShapes.union(shape23, shape24, shape25, shape26, shape27, shape28, shape29, shape30, shape31, shape32, shape33, shape34, shape35);
|
||||
|
||||
private static VoxelShape rotateShape(Direction from, Direction to, VoxelShape shape) {
|
||||
VoxelShape[] buffer = new VoxelShape[]{shape, VoxelShapes.empty()};
|
||||
|
||||
int times = (to.getHorizontal() - from.getHorizontal() + 4) % 4;
|
||||
|
||||
for (int i = 0; i < times; i++) {
|
||||
buffer[0].forEachBox((minX, minY, minZ, maxX, maxY, maxZ) ->
|
||||
buffer[1] = VoxelShapes.union(buffer[1],
|
||||
VoxelShapes.cuboid(1 - maxZ, minY, minX, 1 - minZ, maxY, maxX))
|
||||
);
|
||||
buffer[0] = buffer[1];
|
||||
buffer[1] = VoxelShapes.empty();
|
||||
}
|
||||
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getCollisionShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||
return rotateShape(Direction.NORTH, state.get(FACING), BASE_SHAPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||
return getCollisionShape(state, world, pos, context);
|
||||
}
|
||||
|
||||
// ===== ROTATION =====
|
||||
|
||||
@Override
|
||||
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||
return getDefaultState().with(FACING, ctx.getHorizontalPlayerFacing().getOpposite());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||
builder.add(FACING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new RouletteBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult onUse(BlockState state, World world, BlockPos pos,
|
||||
PlayerEntity player, Hand hand, BlockHitResult hit) {
|
||||
|
||||
if (hand != Hand.MAIN_HAND) return ActionResult.PASS;
|
||||
|
||||
BlockEntity blockEntity = world.getBlockEntity(pos);
|
||||
if (!(blockEntity instanceof RouletteBlockEntity be)) {
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
|
||||
Vec3d hitVec = hit.getPos().subtract(pos.getX(), pos.getY(), pos.getZ());
|
||||
Direction facing = state.get(FACING);
|
||||
|
||||
double x = hitVec.x;
|
||||
double y = hitVec.y;
|
||||
double z = hitVec.z;
|
||||
|
||||
// Rotate based on facing (proper Minecraft rotation logic)
|
||||
switch (facing) {
|
||||
case NORTH -> {
|
||||
// no change
|
||||
}
|
||||
case SOUTH -> {
|
||||
x = 1 - x;
|
||||
z = 1 - z;
|
||||
}
|
||||
case WEST -> {
|
||||
double temp = x;
|
||||
x = z;
|
||||
z = 1 - temp;
|
||||
}
|
||||
case EAST -> {
|
||||
double temp = x;
|
||||
x = 1 - z;
|
||||
z = temp;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isHandle =
|
||||
x >= 0.0625 && x <= 0.25 &&
|
||||
y >= 0.5 && y <= 0.6875 &&
|
||||
z >= 0.4375 && z <= 1.1875;
|
||||
if (!world.isClient) {
|
||||
// Open the GUI (client will receive block position)
|
||||
player.openHandledScreen(state.createScreenHandlerFactory(world, pos));
|
||||
}
|
||||
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
@Override
|
||||
public NamedScreenHandlerFactory createScreenHandlerFactory(BlockState state, World world, BlockPos pos) {
|
||||
BlockEntity be = world.getBlockEntity(pos);
|
||||
if (!(be instanceof RouletteBlockEntity slotBe)) return null;
|
||||
|
||||
// Return an ExtendedScreenHandlerFactory that sends the BlockPos to the client
|
||||
return new ExtendedScreenHandlerFactory() {
|
||||
@Override
|
||||
public void writeScreenOpeningData(ServerPlayerEntity player, PacketByteBuf buf) {
|
||||
buf.writeBlockPos(pos); // send the block pos to client for the constructor
|
||||
}
|
||||
|
||||
@Override
|
||||
public Text getDisplayName() {
|
||||
return Text.literal("Roulette");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScreenHandler createMenu(int syncId, PlayerInventory inv, PlayerEntity player) {
|
||||
return new RouletteScreenHandler(syncId, inv, slotBe);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||
if (state.contains(FACING)) {
|
||||
return state.with(FACING, rotation.rotate(state.get(FACING)));
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||
if (state.contains(FACING)) {
|
||||
return state.rotate(mirror.getRotation(state.get(FACING)));
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(
|
||||
World world,
|
||||
BlockState state,
|
||||
BlockEntityType<T> type) {
|
||||
|
||||
return type == Szar.ROULETTE_BLOCKENTITY
|
||||
? (world1, pos, state1, blockEntity) ->
|
||||
RouletteBlockEntity.tick(world1, pos, state1, (RouletteBlockEntity) blockEntity)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
318
src/main/java/dev/tggamesyt/szar/RouletteBlockEntity.java
Normal file
@@ -0,0 +1,318 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.inventory.SimpleInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.nbt.NbtList;
|
||||
import net.minecraft.network.listener.ClientPlayPacketListener;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket;
|
||||
import net.minecraft.screen.ArrayPropertyDelegate;
|
||||
import net.minecraft.screen.PropertyDelegate;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
public class RouletteBlockEntity extends BlockEntity {
|
||||
public int wheelWaitSeconds = 10;
|
||||
public int wheelRollingSeconds = 5;
|
||||
public int intermissionSeconds = 20;
|
||||
|
||||
private static final int[] WHEEL_ORDER = {
|
||||
0, 26, 3, 35, 12, 28, 7, 29, 18, 22, 9,
|
||||
31, 14, 20, 1, 33, 16, 24, 5, 10, 23, 8,
|
||||
30, 11, 36, 13, 27, 6, 34, 17, 25, 2, 21,
|
||||
4, 19, 15, 32
|
||||
};
|
||||
|
||||
// 0=green, then alternating red/black in standard European roulette order
|
||||
// Index = the number itself (0-36)
|
||||
public static final String[] NUMBER_COLORS = {
|
||||
"green", // 0
|
||||
"red", "black", "red", "black", "red", // 1-5
|
||||
"black", "red", "black", "red", "black",// 6-10
|
||||
"black", "red", "black", "red", "black",// 11-15
|
||||
"red", "black", "red", "black", "black",// 16-20
|
||||
"red", "black", "red", "black", "red", // 21-25
|
||||
"black", "red", "red", "black", "red", // 26-30
|
||||
"black", "red", "black", "red", "black",// 31-35
|
||||
"red" // 36
|
||||
};
|
||||
|
||||
public static float getWheelDegrees(int winnerNum) {
|
||||
for (int i = 0; i < WHEEL_ORDER.length; i++) {
|
||||
if (WHEEL_ORDER[i] == winnerNum) return i * 9.73f;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
private int winnernum = 0;
|
||||
public boolean isIntermission = true;
|
||||
public int nextspinTime = intermissionSeconds * 20;
|
||||
final PropertyDelegate propertyDelegate;
|
||||
|
||||
private final Map<UUID, PlayerBetInventories> playerInventories = new HashMap<>();
|
||||
|
||||
public RouletteBlockEntity(BlockPos pos, BlockState state) {
|
||||
super(Szar.ROULETTE_BLOCKENTITY, pos, state);
|
||||
this.propertyDelegate = new ArrayPropertyDelegate(3);
|
||||
}
|
||||
|
||||
public static class PlayerBetInventories {
|
||||
public final SimpleInventory fullbet = new SimpleInventory(37);
|
||||
public final SimpleInventory twelves = new SimpleInventory(3);
|
||||
public final SimpleInventory halves = new SimpleInventory(2);
|
||||
public final SimpleInventory evenodd = new SimpleInventory(2);
|
||||
public final SimpleInventory blackred = new SimpleInventory(2);
|
||||
public final SimpleInventory thirds = new SimpleInventory(3);
|
||||
|
||||
public void clear() {
|
||||
fullbet.clear();
|
||||
twelves.clear();
|
||||
halves.clear();
|
||||
evenodd.clear();
|
||||
blackred.clear();
|
||||
thirds.clear();
|
||||
}
|
||||
|
||||
public void writeNbt(NbtCompound nbt) {
|
||||
nbt.put("fullbet", inventoryToNbt(fullbet));
|
||||
nbt.put("twelves", inventoryToNbt(twelves));
|
||||
nbt.put("halves", inventoryToNbt(halves));
|
||||
nbt.put("evenodd", inventoryToNbt(evenodd));
|
||||
nbt.put("blackred", inventoryToNbt(blackred));
|
||||
nbt.put("thirds", inventoryToNbt(thirds));
|
||||
}
|
||||
|
||||
public void readNbt(NbtCompound nbt) {
|
||||
nbtToInventory(nbt.getList("fullbet", 10), fullbet);
|
||||
nbtToInventory(nbt.getList("twelves", 10), twelves);
|
||||
nbtToInventory(nbt.getList("halves", 10), halves);
|
||||
nbtToInventory(nbt.getList("evenodd", 10), evenodd);
|
||||
nbtToInventory(nbt.getList("blackred", 10), blackred);
|
||||
nbtToInventory(nbt.getList("thirds", 10), thirds);
|
||||
}
|
||||
|
||||
private static NbtList inventoryToNbt(SimpleInventory inv) {
|
||||
NbtList list = new NbtList();
|
||||
for (int i = 0; i < inv.size(); i++) {
|
||||
NbtCompound slot = new NbtCompound();
|
||||
slot.putByte("Slot", (byte) i);
|
||||
inv.getStack(i).writeNbt(slot);
|
||||
list.add(slot);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static void nbtToInventory(NbtList list, SimpleInventory inv) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
NbtCompound slot = list.getCompound(i);
|
||||
int index = slot.getByte("Slot") & 0xFF;
|
||||
if (index < inv.size()) {
|
||||
inv.setStack(index, ItemStack.fromNbt(slot));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PlayerBetInventories getInventoriesFor(UUID uuid) {
|
||||
return playerInventories.computeIfAbsent(uuid, id -> new PlayerBetInventories());
|
||||
}
|
||||
|
||||
public PlayerBetInventories getInventoriesFor(net.minecraft.entity.player.PlayerEntity player) {
|
||||
return getInventoriesFor(player.getUuid());
|
||||
}
|
||||
|
||||
// ─── Payout logic ────────────────────────────────────────────────────────
|
||||
|
||||
private static void giveItems(ServerPlayerEntity player, ItemStack stack, int multiplier) {
|
||||
if (stack.isEmpty()) return;
|
||||
int total = stack.getCount() * multiplier;
|
||||
while (total > 0) {
|
||||
int batchSize = Math.min(total, stack.getMaxCount());
|
||||
ItemStack give = new ItemStack(stack.getItem(), batchSize);
|
||||
player.getInventory().offerOrDrop(give);
|
||||
total -= batchSize;
|
||||
}
|
||||
}
|
||||
|
||||
private void resolvePayouts(World world, int winner) {
|
||||
String winnerColor = NUMBER_COLORS[winner];
|
||||
|
||||
for (Map.Entry<UUID, PlayerBetInventories> entry : playerInventories.entrySet()) {
|
||||
ServerPlayerEntity player = (ServerPlayerEntity) world.getPlayerByUuid(entry.getKey());
|
||||
if (player == null) {
|
||||
continue;
|
||||
}
|
||||
PlayerBetInventories inv = entry.getValue();
|
||||
|
||||
// fullbet
|
||||
ItemStack fullbetBet = inv.fullbet.getStack(winner).copy();
|
||||
inv.fullbet.setStack(winner, ItemStack.EMPTY);
|
||||
if (!fullbetBet.isEmpty()) {
|
||||
giveItems(player, fullbetBet, 36);
|
||||
}
|
||||
|
||||
// twelves
|
||||
if (winner >= 1 && winner <= 12) {
|
||||
ItemStack bet = inv.twelves.getStack(0).copy();
|
||||
inv.twelves.setStack(0, ItemStack.EMPTY);
|
||||
if (!bet.isEmpty()) { giveItems(player, bet, 3); }
|
||||
} else if (winner >= 13 && winner <= 24) {
|
||||
ItemStack bet = inv.twelves.getStack(1).copy();
|
||||
inv.twelves.setStack(1, ItemStack.EMPTY);
|
||||
if (!bet.isEmpty()) { giveItems(player, bet, 3); }
|
||||
} else if (winner >= 25 && winner <= 36) {
|
||||
ItemStack bet = inv.twelves.getStack(2).copy();
|
||||
inv.twelves.setStack(2, ItemStack.EMPTY);
|
||||
if (!bet.isEmpty()) { giveItems(player, bet, 3); }
|
||||
}
|
||||
|
||||
// halves
|
||||
if (winner >= 1 && winner <= 18) {
|
||||
ItemStack bet = inv.halves.getStack(0).copy();
|
||||
inv.halves.setStack(0, ItemStack.EMPTY);
|
||||
if (!bet.isEmpty()) { giveItems(player, bet, 2); }
|
||||
} else if (winner >= 19 && winner <= 36) {
|
||||
ItemStack bet = inv.halves.getStack(1).copy();
|
||||
inv.halves.setStack(1, ItemStack.EMPTY);
|
||||
if (!bet.isEmpty()) { giveItems(player, bet, 2); }
|
||||
}
|
||||
|
||||
// evenodd
|
||||
if (winner != 0) {
|
||||
if (winner % 2 == 0) {
|
||||
ItemStack bet = inv.evenodd.getStack(0).copy();
|
||||
inv.evenodd.setStack(0, ItemStack.EMPTY);
|
||||
if (!bet.isEmpty()) { giveItems(player, bet, 2); }
|
||||
} else {
|
||||
ItemStack bet = inv.evenodd.getStack(1).copy();
|
||||
inv.evenodd.setStack(1, ItemStack.EMPTY);
|
||||
if (!bet.isEmpty()) { giveItems(player, bet, 2); }
|
||||
}
|
||||
}
|
||||
|
||||
// blackred
|
||||
if (winnerColor.equals("red")) {
|
||||
ItemStack bet = inv.blackred.getStack(0).copy();
|
||||
inv.blackred.setStack(0, ItemStack.EMPTY);
|
||||
if (!bet.isEmpty()) { giveItems(player, bet, 2); }
|
||||
} else if (winnerColor.equals("black")) {
|
||||
ItemStack bet = inv.blackred.getStack(1).copy();
|
||||
inv.blackred.setStack(1, ItemStack.EMPTY);
|
||||
if (!bet.isEmpty()) { giveItems(player, bet, 2); }
|
||||
}
|
||||
|
||||
// thirds
|
||||
if (winner != 0) {
|
||||
if (winner % 3 == 0) {
|
||||
ItemStack bet = inv.thirds.getStack(0).copy();
|
||||
inv.thirds.setStack(0, ItemStack.EMPTY);
|
||||
if (!bet.isEmpty()) { giveItems(player, bet, 2); }
|
||||
} else if ((winner + 1) % 3 == 0) {
|
||||
ItemStack bet = inv.thirds.getStack(1).copy();
|
||||
inv.thirds.setStack(1, ItemStack.EMPTY);
|
||||
if (!bet.isEmpty()) { giveItems(player, bet, 2); }
|
||||
} else if ((winner + 2) % 3 == 0) {
|
||||
ItemStack bet = inv.thirds.getStack(2).copy();
|
||||
inv.thirds.setStack(2, ItemStack.EMPTY);
|
||||
if (!bet.isEmpty()) { giveItems(player, bet, 2); }
|
||||
}
|
||||
}
|
||||
inv.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Tick ─────────────────────────────────────────────────────────────────
|
||||
|
||||
public static void tick(World world, BlockPos pos, BlockState state, RouletteBlockEntity be) {
|
||||
if (world.isClient) return;
|
||||
|
||||
be.nextspinTime--;
|
||||
|
||||
if (be.isIntermission) {
|
||||
if (be.nextspinTime > 0) {
|
||||
// still counting down to spin
|
||||
} else if (be.nextspinTime == 0) {
|
||||
// Spin is starting — pick winner and clear all bets
|
||||
be.winnernum = new Random().nextInt(37);
|
||||
be.isIntermission = false;
|
||||
}
|
||||
} else {
|
||||
// Spinning phase — nextspinTime is negative here
|
||||
int spinTicks = (be.wheelWaitSeconds + be.wheelRollingSeconds) * 20;
|
||||
if (be.nextspinTime <= -spinTicks) {
|
||||
// Spin ended — resolve payouts then go back to intermission
|
||||
be.resolvePayouts(world, be.winnernum);
|
||||
be.isIntermission = true;
|
||||
be.nextspinTime = be.intermissionSeconds * 20;
|
||||
}
|
||||
}
|
||||
|
||||
be.propertyDelegate.set(0, be.isIntermission ? 1 : 0);
|
||||
be.propertyDelegate.set(1, be.nextspinTime);
|
||||
be.propertyDelegate.set(2, be.winnernum);
|
||||
be.markDirty();
|
||||
}
|
||||
|
||||
private void clearAllBets() {
|
||||
for (PlayerBetInventories inv : playerInventories.values()) {
|
||||
inv.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// ─── NBT ──────────────────────────────────────────────────────────────────
|
||||
|
||||
@Override
|
||||
public void writeNbt(NbtCompound nbt) {
|
||||
super.writeNbt(nbt);
|
||||
nbt.putBoolean("isIntermission", isIntermission);
|
||||
nbt.putInt("nextspinTime", nextspinTime);
|
||||
nbt.putInt("winnernum", winnernum);
|
||||
|
||||
NbtCompound playersNbt = new NbtCompound();
|
||||
for (Map.Entry<UUID, PlayerBetInventories> entry : playerInventories.entrySet()) {
|
||||
NbtCompound playerNbt = new NbtCompound();
|
||||
entry.getValue().writeNbt(playerNbt);
|
||||
playersNbt.put(entry.getKey().toString(), playerNbt);
|
||||
}
|
||||
nbt.put("playerInventories", playersNbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readNbt(NbtCompound nbt) {
|
||||
super.readNbt(nbt);
|
||||
isIntermission = nbt.getBoolean("isIntermission");
|
||||
nextspinTime = nbt.getInt("nextspinTime");
|
||||
winnernum = nbt.getInt("winnernum");
|
||||
|
||||
playerInventories.clear();
|
||||
NbtCompound playersNbt = nbt.getCompound("playerInventories");
|
||||
for (String key : playersNbt.getKeys()) {
|
||||
UUID uuid = UUID.fromString(key);
|
||||
PlayerBetInventories invs = new PlayerBetInventories();
|
||||
invs.readNbt(playersNbt.getCompound(key));
|
||||
playerInventories.put(uuid, invs);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Packet<ClientPlayPacketListener> toUpdatePacket() {
|
||||
return BlockEntityUpdateS2CPacket.create(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NbtCompound toInitialChunkDataNbt() {
|
||||
NbtCompound nbt = new NbtCompound();
|
||||
writeNbt(nbt);
|
||||
return nbt;
|
||||
}
|
||||
}
|
||||
143
src/main/java/dev/tggamesyt/szar/RouletteScreenHandler.java
Normal file
@@ -0,0 +1,143 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.screen.PropertyDelegate;
|
||||
import net.minecraft.screen.ScreenHandler;
|
||||
import net.minecraft.screen.slot.Slot;
|
||||
|
||||
public class RouletteScreenHandler extends ScreenHandler {
|
||||
|
||||
public final RouletteBlockEntity blockEntity;
|
||||
|
||||
public static final int SLOT_SIZE = 18;
|
||||
public static final int GRID_START_X = 60;
|
||||
public static final int GRID_START_Y = 8;
|
||||
|
||||
private static int gx(int col) { return GRID_START_X + (col - 1) * SLOT_SIZE; }
|
||||
private static int gy(int row) { return GRID_START_Y + (row - 1) * SLOT_SIZE; }
|
||||
|
||||
// Slot that locks itself when the block entity is spinning
|
||||
private class BetSlot extends Slot {
|
||||
public BetSlot(Inventory inventory, int index, int x, int y) {
|
||||
super(inventory, index, x, y);
|
||||
}
|
||||
|
||||
private boolean isSpinning() {
|
||||
return !blockEntity.isIntermission;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInsert(ItemStack stack) {
|
||||
return !isSpinning();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTakeItems(PlayerEntity playerEntity) {
|
||||
return !isSpinning();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack takeStack(int amount) {
|
||||
if (isSpinning()) return ItemStack.EMPTY;
|
||||
return super.takeStack(amount);
|
||||
}
|
||||
}
|
||||
|
||||
public RouletteScreenHandler(int syncId, PlayerInventory playerInv, RouletteBlockEntity blockEntity) {
|
||||
super(Szar.ROULETTE_SCREEN_HANDLER_TYPE, syncId);
|
||||
this.blockEntity = blockEntity;
|
||||
|
||||
this.addProperties(blockEntity.propertyDelegate);
|
||||
|
||||
RouletteBlockEntity.PlayerBetInventories inv =
|
||||
blockEntity.getInventoriesFor(playerInv.player);
|
||||
|
||||
// === fullbetInventory ===
|
||||
this.addSlot(new BetSlot(inv.fullbet, 0, gx(1), gy(2)));
|
||||
int fbIdx = 1;
|
||||
for (int col = 2; col <= 13; col++) {
|
||||
this.addSlot(new BetSlot(inv.fullbet, fbIdx++, gx(col), gy(3)));
|
||||
this.addSlot(new BetSlot(inv.fullbet, fbIdx++, gx(col), gy(2)));
|
||||
this.addSlot(new BetSlot(inv.fullbet, fbIdx++, gx(col), gy(1)));
|
||||
}
|
||||
|
||||
// === twelvesInventory ===
|
||||
this.addSlot(new BetSlot(inv.twelves, 0, gx(3), gy(4)));
|
||||
this.addSlot(new BetSlot(inv.twelves, 1, gx(7), gy(4)));
|
||||
this.addSlot(new BetSlot(inv.twelves, 2, gx(11), gy(4)));
|
||||
|
||||
// === halvesInventory ===
|
||||
this.addSlot(new BetSlot(inv.halves, 0, gx(2), gy(5)));
|
||||
this.addSlot(new BetSlot(inv.halves, 1, gx(12), gy(5)));
|
||||
|
||||
// === evenoddInventory ===
|
||||
this.addSlot(new BetSlot(inv.evenodd, 0, gx(4), gy(5)));
|
||||
this.addSlot(new BetSlot(inv.evenodd, 1, gx(10), gy(5)));
|
||||
|
||||
// === blackredInventory ===
|
||||
this.addSlot(new BetSlot(inv.blackred, 0, gx(6), gy(5)));
|
||||
this.addSlot(new BetSlot(inv.blackred, 1, gx(8), gy(5)));
|
||||
|
||||
// === thirdsInventory ===
|
||||
this.addSlot(new BetSlot(inv.thirds, 0, gx(14), gy(1)));
|
||||
this.addSlot(new BetSlot(inv.thirds, 1, gx(14), gy(2)));
|
||||
this.addSlot(new BetSlot(inv.thirds, 2, gx(14), gy(3)));
|
||||
|
||||
// === Player inventory ===
|
||||
int playerInvY = GRID_START_Y + 5 * SLOT_SIZE + 14;
|
||||
for (int y = 0; y < 3; y++)
|
||||
for (int x = 0; x < 9; x++)
|
||||
this.addSlot(new Slot(playerInv, x + y * 9 + 9, 8 + x * 18, playerInvY + y * 18));
|
||||
for (int x = 0; x < 9; x++)
|
||||
this.addSlot(new Slot(playerInv, x, 8 + x * 18, playerInvY + 58));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onButtonClick(PlayerEntity player, int id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUse(PlayerEntity player) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack quickMove(PlayerEntity player, int index) {
|
||||
ItemStack newStack = ItemStack.EMPTY;
|
||||
Slot slot = this.slots.get(index);
|
||||
|
||||
if (slot.hasStack()) {
|
||||
ItemStack originalStack = slot.getStack();
|
||||
newStack = originalStack.copy();
|
||||
|
||||
int playerStart = 49;
|
||||
int totalSlots = this.slots.size();
|
||||
|
||||
if (index >= playerStart) {
|
||||
if (!this.insertItem(originalStack, 0, 1, false)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
} else if (index == 0) {
|
||||
if (!this.insertItem(originalStack, playerStart, totalSlots, true)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
if (originalStack.isEmpty()) {
|
||||
slot.setStack(ItemStack.EMPTY);
|
||||
} else {
|
||||
slot.markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
return newStack;
|
||||
}
|
||||
|
||||
public PropertyDelegate getPropertyDelegate() {
|
||||
return blockEntity.propertyDelegate;
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import net.minecraft.entity.damage.DamageType;
|
||||
import net.minecraft.entity.data.DataTracker;
|
||||
import net.minecraft.entity.data.TrackedData;
|
||||
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
|
||||
import net.minecraft.entity.decoration.painting.PaintingVariant;
|
||||
import net.minecraft.entity.effect.StatusEffect;
|
||||
import net.minecraft.entity.effect.StatusEffectInstance;
|
||||
import net.minecraft.entity.passive.VillagerEntity;
|
||||
@@ -718,8 +719,50 @@ public class Szar implements ModInitializer {
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
Registry.register(
|
||||
Registries.PAINTING_VARIANT,
|
||||
new Identifier(MOD_ID, "axolotl"),
|
||||
new PaintingVariant(32, 32)
|
||||
);
|
||||
Registry.register(
|
||||
Registries.PAINTING_VARIANT,
|
||||
new Identifier(MOD_ID, "bloc"),
|
||||
new PaintingVariant(32, 32)
|
||||
);
|
||||
Registry.register(
|
||||
Registries.PAINTING_VARIANT,
|
||||
new Identifier(MOD_ID, "block_wave"),
|
||||
new PaintingVariant(32, 32)
|
||||
);
|
||||
Registry.register(
|
||||
Registries.PAINTING_VARIANT,
|
||||
new Identifier(MOD_ID, "bounce"),
|
||||
new PaintingVariant(32, 32)
|
||||
);
|
||||
Registry.register(
|
||||
Registries.PAINTING_VARIANT,
|
||||
new Identifier(MOD_ID, "chicken_jokey"),
|
||||
new PaintingVariant(16, 16)
|
||||
);
|
||||
Registry.register(
|
||||
Registries.PAINTING_VARIANT,
|
||||
new Identifier(MOD_ID, "frogs"),
|
||||
new PaintingVariant(32, 32)
|
||||
);
|
||||
Registry.register(
|
||||
Registries.PAINTING_VARIANT,
|
||||
new Identifier(MOD_ID, "matrix"),
|
||||
new PaintingVariant(32, 32)
|
||||
);
|
||||
Registry.register(
|
||||
Registries.PAINTING_VARIANT,
|
||||
new Identifier(MOD_ID, "nyansniffer"),
|
||||
new PaintingVariant(32, 32)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static ObeliskCoreBlockEntity findNearestObelisk(ServerWorld world, BlockPos center, int radius) {
|
||||
ObeliskCoreBlockEntity closest = null;
|
||||
double closestDistance = Double.MAX_VALUE;
|
||||
@@ -817,29 +860,34 @@ public class Szar implements ModInitializer {
|
||||
new Identifier(MOD_ID, "firtana"),
|
||||
new FirtanaItem(new Item.Settings())
|
||||
);
|
||||
static VoxelShape shape23 = VoxelShapes.cuboid(0.25f, 0f, 0f, 0.75f, 0.25f, 0.125f);
|
||||
static VoxelShape shape24 = VoxelShapes.cuboid(0.125f, 0f, 0.125f, 0.875f, 0.125f, 0.25f);
|
||||
static VoxelShape shape25 = VoxelShapes.cuboid(0f, 0f, 0.25f, 1f, 0.125f, 0.75f);
|
||||
static VoxelShape shape26 = VoxelShapes.cuboid(0.125f, 0f, 0.75f, 0.875f, 0.125f, 0.875f);
|
||||
static VoxelShape shape27 = VoxelShapes.cuboid(0.25f, 0f, 0.875f, 0.75f, 0.25f, 1f);
|
||||
static VoxelShape shape28 = VoxelShapes.cuboid(0f, 0.125f, 0.25f, 0.125f, 0.25f, 0.75f);
|
||||
static VoxelShape shape29 = VoxelShapes.cuboid(0.875f, 0.125f, 0.25f, 1f, 0.25f, 0.75f);
|
||||
static VoxelShape shape30 = VoxelShapes.cuboid(0.75f, 0.125f, 0.125f, 0.875f, 0.25f, 0.25f);
|
||||
static VoxelShape shape31 = VoxelShapes.cuboid(0.75f, 0.125f, 0.75f, 0.875f, 0.25f, 0.875f);
|
||||
static VoxelShape shape32 = VoxelShapes.cuboid(0.125f, 0.125f, 0.125f, 0.25f, 0.25f, 0.25f);
|
||||
static VoxelShape shape33 = VoxelShapes.cuboid(0.125f, 0.125f, 0.75f, 0.25f, 0.25f, 0.875f);
|
||||
static VoxelShape shape34 = VoxelShapes.cuboid(0.3125f, 0.313125f, 0.3125f, 0.6875f, 0.313125f, 0.6875f);
|
||||
static VoxelShape shape35 = VoxelShapes.cuboid(0.4375f, 0.125f, 0.4375f, 0.5625f, 0.3125f, 0.5625f);
|
||||
static VoxelShape ROULETTE_SHAPE = VoxelShapes.union(shape23, shape24, shape25, shape26, shape27, shape28, shape29, shape30, shape31, shape32, shape33, shape34, shape35);
|
||||
public static final ScreenHandlerType<RouletteScreenHandler> ROULETTE_SCREEN_HANDLER_TYPE =
|
||||
ScreenHandlerRegistry.registerExtended(
|
||||
new Identifier(Szar.MOD_ID, "roulette"),
|
||||
(syncId, inv, buf) -> {
|
||||
BlockPos pos = buf.readBlockPos();
|
||||
BlockEntity be = inv.player.getWorld().getBlockEntity(pos);
|
||||
if (!(be instanceof RouletteBlockEntity blockEntity)) {
|
||||
throw new IllegalStateException("BlockEntity is not a RouletteBlockEntity");
|
||||
}
|
||||
return new RouletteScreenHandler(syncId, inv, blockEntity);
|
||||
}
|
||||
);
|
||||
public static final Block ROULETTE_BLOCK = Registry.register(
|
||||
Registries.BLOCK,
|
||||
new Identifier(MOD_ID, "roulette"),
|
||||
new BasicRotatableModelBlock(
|
||||
new RouletteBlock(
|
||||
AbstractBlock.Settings
|
||||
.copy(Blocks.OAK_WOOD),
|
||||
ROULETTE_SHAPE
|
||||
.copy(Blocks.IRON_BLOCK)
|
||||
)
|
||||
);
|
||||
public static final BlockEntityType<RouletteBlockEntity> ROULETTE_BLOCKENTITY = Registry.register(
|
||||
Registries.BLOCK_ENTITY_TYPE,
|
||||
new Identifier(MOD_ID, "roulette"),
|
||||
FabricBlockEntityTypeBuilder.create(
|
||||
RouletteBlockEntity::new,
|
||||
ROULETTE_BLOCK
|
||||
).build(null)
|
||||
);
|
||||
public static final Item ROULETTE = Registry.register(
|
||||
Registries.ITEM,
|
||||
new Identifier(MOD_ID, "roulette"),
|
||||
|
||||
BIN
src/main/resources/assets/szar/textures/gui/roulette.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
src/main/resources/assets/szar/textures/gui/roulette_ball.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
BIN
src/main/resources/assets/szar/textures/gui/roulette_wheel.png
Normal file
|
After Width: | Height: | Size: 416 KiB |
|
After Width: | Height: | Size: 400 KiB |
BIN
src/main/resources/assets/szar/textures/painting/axolotl.png
Normal file
|
After Width: | Height: | Size: 140 KiB |
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"animation": {
|
||||
"frametime": 1
|
||||
}
|
||||
}
|
||||
BIN
src/main/resources/assets/szar/textures/painting/bloc.png
Normal file
|
After Width: | Height: | Size: 95 KiB |
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"animation": {
|
||||
"frametime": 2
|
||||
}
|
||||
}
|
||||
BIN
src/main/resources/assets/szar/textures/painting/block_wave.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"animation": {
|
||||
"frametime": 2
|
||||
}
|
||||
}
|
||||
BIN
src/main/resources/assets/szar/textures/painting/bounce.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"animation": {
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"animation": {
|
||||
"frametime": 1
|
||||
}
|
||||
}
|
||||
BIN
src/main/resources/assets/szar/textures/painting/frogs.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"animation": {
|
||||
"frametime": 1
|
||||
}
|
||||
}
|
||||
BIN
src/main/resources/assets/szar/textures/painting/matrix.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"animation": {
|
||||
"frametime": 2
|
||||
}
|
||||
}
|
||||
BIN
src/main/resources/assets/szar/textures/painting/nyansniffer.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"animation": {
|
||||
"frametime": 2
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"szar:axolotl",
|
||||
"szar:bloc",
|
||||
"szar:block_wave",
|
||||
"szar:bounce",
|
||||
"szar:chicken_jokey",
|
||||
"szar:frogs",
|
||||
"szar:matrix",
|
||||
"szar:nyansniffer"
|
||||
]
|
||||
}
|
||||