backrooms
@@ -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.17
|
mod_version=26.3.17.1
|
||||||
maven_group=dev.tggamesyt
|
maven_group=dev.tggamesyt
|
||||||
archives_base_name=szar
|
archives_base_name=szar
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import net.fabricmc.loader.api.FabricLoader;
|
|||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.gui.screen.ingame.HandledScreens;
|
import net.minecraft.client.gui.screen.ingame.HandledScreens;
|
||||||
import net.minecraft.client.option.KeyBinding;
|
import net.minecraft.client.option.KeyBinding;
|
||||||
|
import net.minecraft.client.render.block.entity.BlockEntityRendererFactories;
|
||||||
import net.minecraft.client.render.entity.EmptyEntityRenderer;
|
import net.minecraft.client.render.entity.EmptyEntityRenderer;
|
||||||
import net.minecraft.client.render.entity.EntityRenderer;
|
import net.minecraft.client.render.entity.EntityRenderer;
|
||||||
import net.minecraft.client.render.entity.FlyingItemEntityRenderer;
|
import net.minecraft.client.render.entity.FlyingItemEntityRenderer;
|
||||||
@@ -361,10 +362,10 @@ public class SzarClient implements ClientModInitializer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
/*BlockEntityRendererRegistry.register(
|
BlockEntityRendererFactories.register(
|
||||||
SLOT_MACHINE_BLOCKENTITY,
|
Szar.TRACKER_BLOCK_ENTITY,
|
||||||
SlotMachineRenderer::new
|
TGTrackerBlockRenderer::new
|
||||||
);*/
|
);
|
||||||
HandledScreens.register(Szar.SLOT_MACHINE_SCREEN_HANDLER_TYPE, SlotMachineScreen::new);
|
HandledScreens.register(Szar.SLOT_MACHINE_SCREEN_HANDLER_TYPE, SlotMachineScreen::new);
|
||||||
HandledScreens.register(Szar.ROULETTE_SCREEN_HANDLER_TYPE, RouletteScreen::new);
|
HandledScreens.register(Szar.ROULETTE_SCREEN_HANDLER_TYPE, RouletteScreen::new);
|
||||||
EntityRendererRegistry.register(Szar.BULLET, BulletRenderer::new);
|
EntityRendererRegistry.register(Szar.BULLET, BulletRenderer::new);
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package dev.tggamesyt.szar.client;
|
||||||
|
|
||||||
|
import dev.tggamesyt.szar.Szar;
|
||||||
|
import dev.tggamesyt.szar.TrackerBlockEntity;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.render.VertexConsumerProvider;
|
||||||
|
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
|
||||||
|
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
|
||||||
|
import net.minecraft.client.render.item.ItemRenderer;
|
||||||
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
|
import net.minecraft.client.render.model.json.ModelTransformationMode;
|
||||||
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.RotationAxis;
|
||||||
|
import net.minecraft.client.render.WorldRenderer;
|
||||||
|
|
||||||
|
public class TGTrackerBlockRenderer implements BlockEntityRenderer<TrackerBlockEntity> {
|
||||||
|
|
||||||
|
private final ItemRenderer itemRenderer;
|
||||||
|
|
||||||
|
public TGTrackerBlockRenderer(BlockEntityRendererFactory.Context ctx) {
|
||||||
|
this.itemRenderer = ctx.getItemRenderer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(TrackerBlockEntity entity, float tickDelta, MatrixStack matrices,
|
||||||
|
VertexConsumerProvider vertexConsumers, int light, int overlay) {
|
||||||
|
|
||||||
|
MinecraftClient client = MinecraftClient.getInstance();
|
||||||
|
PlayerEntity player = client.player;
|
||||||
|
if (player == null) return;
|
||||||
|
|
||||||
|
boolean holding = player.getMainHandStack().isOf(Szar.TRACKER_BLOCK_ITEM.asItem())
|
||||||
|
|| player.getOffHandStack().isOf(Szar.TRACKER_BLOCK_ITEM.asItem());
|
||||||
|
if (!holding) return;
|
||||||
|
|
||||||
|
BlockPos pos = entity.getPos();
|
||||||
|
int lightLevel = WorldRenderer.getLightmapCoordinates(entity.getWorld(), pos);
|
||||||
|
|
||||||
|
// Use the actual camera yaw and pitch — this is what barrier does
|
||||||
|
// Camera yaw/pitch are already available from the camera object
|
||||||
|
float cameraYaw = client.gameRenderer.getCamera().getYaw();
|
||||||
|
float cameraPitch = client.gameRenderer.getCamera().getPitch();
|
||||||
|
|
||||||
|
matrices.push();
|
||||||
|
matrices.translate(0.5, 0.25, 0.5);
|
||||||
|
|
||||||
|
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-cameraYaw));
|
||||||
|
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(cameraPitch));
|
||||||
|
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180f));
|
||||||
|
|
||||||
|
matrices.scale(2f, 2f, 2f);
|
||||||
|
|
||||||
|
ItemStack stack = new ItemStack(Szar.TRACKER_BLOCK_ITEM.asItem());
|
||||||
|
BakedModel model = itemRenderer.getModel(stack, entity.getWorld(), null, 0);
|
||||||
|
|
||||||
|
itemRenderer.renderItem(
|
||||||
|
stack,
|
||||||
|
ModelTransformationMode.GROUND,
|
||||||
|
false,
|
||||||
|
matrices,
|
||||||
|
vertexConsumers,
|
||||||
|
lightLevel,
|
||||||
|
overlay,
|
||||||
|
model
|
||||||
|
);
|
||||||
|
|
||||||
|
matrices.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import org.spongepowered.asm.mixin.Shadow;
|
|||||||
import org.spongepowered.asm.mixin.Unique;
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
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.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
@Mixin(GameRenderer.class)
|
@Mixin(GameRenderer.class)
|
||||||
|
|||||||
235
src/main/java/dev/tggamesyt/szar/BackroomsChunkGenerator.java
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
package dev.tggamesyt.szar;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
|
import dev.tggamesyt.szar.Szar;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.Blocks;
|
||||||
|
import net.minecraft.registry.RegistryCodecs;
|
||||||
|
import net.minecraft.registry.RegistryKeys;
|
||||||
|
import net.minecraft.registry.entry.RegistryEntry;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.ChunkRegion;
|
||||||
|
import net.minecraft.world.HeightLimitView;
|
||||||
|
import net.minecraft.world.Heightmap;
|
||||||
|
import net.minecraft.world.biome.Biome;
|
||||||
|
import net.minecraft.world.biome.BiomeKeys;
|
||||||
|
import net.minecraft.world.biome.source.BiomeAccess;
|
||||||
|
import net.minecraft.world.biome.source.FixedBiomeSource;
|
||||||
|
import net.minecraft.world.chunk.Chunk;
|
||||||
|
import net.minecraft.world.gen.GenerationStep;
|
||||||
|
import net.minecraft.world.gen.StructureAccessor;
|
||||||
|
import net.minecraft.world.gen.chunk.Blender;
|
||||||
|
import net.minecraft.world.gen.chunk.ChunkGenerator;
|
||||||
|
import net.minecraft.world.gen.chunk.VerticalBlockSample;
|
||||||
|
import net.minecraft.world.gen.noise.NoiseConfig;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
public class BackroomsChunkGenerator extends ChunkGenerator {
|
||||||
|
|
||||||
|
// Y layout constants
|
||||||
|
private static final int FLOOR_Y = 4; // y=4 is the floor block
|
||||||
|
private static final int CEILING_Y = 9; // y=9 is the ceiling block (4 air blocks between: 5,6,7,8)
|
||||||
|
private static final int WALL_BASE_Y = 5; // y=5 is WALL_BOTTOM_BLOCK
|
||||||
|
private static final int WALL_TOP_Y = 8; // y=8 is top wall block (below ceiling)
|
||||||
|
|
||||||
|
// Glowstone grid spacing
|
||||||
|
private static final int GLOW_SPACING = 5;
|
||||||
|
|
||||||
|
public static final Codec<BackroomsChunkGenerator> CODEC =
|
||||||
|
RecordCodecBuilder.create(instance -> instance.group(
|
||||||
|
Biome.REGISTRY_CODEC
|
||||||
|
.fieldOf("biome")
|
||||||
|
.forGetter(g -> g.biomeEntry)
|
||||||
|
).apply(instance, BackroomsChunkGenerator::new));
|
||||||
|
|
||||||
|
private final RegistryEntry<Biome> biomeEntry;
|
||||||
|
|
||||||
|
public BackroomsChunkGenerator(RegistryEntry<Biome> biomeEntry) {
|
||||||
|
super(new FixedBiomeSource(biomeEntry));
|
||||||
|
this.biomeEntry = biomeEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Codec<? extends ChunkGenerator> getCodec() {
|
||||||
|
return CODEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Chunk> populateNoise(
|
||||||
|
Executor executor, Blender blender, NoiseConfig noiseConfig,
|
||||||
|
StructureAccessor structureAccessor, Chunk chunk) {
|
||||||
|
|
||||||
|
int chunkX = chunk.getPos().x;
|
||||||
|
int chunkZ = chunk.getPos().z;
|
||||||
|
|
||||||
|
for (int lx = 0; lx < 16; lx++) {
|
||||||
|
for (int lz = 0; lz < 16; lz++) {
|
||||||
|
int worldX = chunkX * 16 + lx;
|
||||||
|
int worldZ = chunkZ * 16 + lz;
|
||||||
|
|
||||||
|
// Deterministic per-column open/wall decision using world seed-like hash
|
||||||
|
boolean isOpen = isOpenSpace(worldX, worldZ);
|
||||||
|
|
||||||
|
// Floor — always placed
|
||||||
|
chunk.setBlockState(new BlockPos(lx, FLOOR_Y, lz),
|
||||||
|
Szar.PLASTIC.getDefaultState(), false);
|
||||||
|
|
||||||
|
// Below floor — fill with plastic so there's no void underneath
|
||||||
|
for (int y = 0; y < FLOOR_Y; y++) {
|
||||||
|
chunk.setBlockState(new BlockPos(lx, y, lz),
|
||||||
|
Szar.PLASTIC.getDefaultState(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ceiling
|
||||||
|
boolean isGlowstone = isGlowstonePos(worldX, worldZ);
|
||||||
|
BlockState ceilingBlock = isGlowstone
|
||||||
|
? Blocks.GLOWSTONE.getDefaultState()
|
||||||
|
: Szar.CEILING.getDefaultState();
|
||||||
|
chunk.setBlockState(new BlockPos(lx, CEILING_Y, lz), ceilingBlock, false);
|
||||||
|
|
||||||
|
// Above ceiling — solid wall block fill so there's no void above
|
||||||
|
for (int y = CEILING_Y + 1; y < 64; y++) {
|
||||||
|
chunk.setBlockState(new BlockPos(lx, y, lz),
|
||||||
|
Szar.CEILING.getDefaultState(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isOpen) {
|
||||||
|
// Air inside the room
|
||||||
|
for (int y = WALL_BASE_Y; y <= WALL_TOP_Y; y++) {
|
||||||
|
chunk.setBlockState(new BlockPos(lx, y, lz),
|
||||||
|
Blocks.AIR.getDefaultState(), false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Wall column
|
||||||
|
chunk.setBlockState(new BlockPos(lx, WALL_BASE_Y, lz),
|
||||||
|
Szar.WALL_BOTTOM_BLOCK.getDefaultState(), false);
|
||||||
|
for (int y = WALL_BASE_Y + 1; y <= WALL_TOP_Y; y++) {
|
||||||
|
chunk.setBlockState(new BlockPos(lx, y, lz),
|
||||||
|
Szar.WALL_BLOCK.getDefaultState(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CompletableFuture.completedFuture(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a world column is open space or a wall.
|
||||||
|
* Uses a combination of large-scale and small-scale noise simulation
|
||||||
|
* via a seeded hash to create wide rooms with occasional walls.
|
||||||
|
*/
|
||||||
|
private boolean isOpenSpace(int x, int z) {
|
||||||
|
// Smaller cells = more frequent walls
|
||||||
|
int cellSize = 8; // was 16
|
||||||
|
int cellX = Math.floorDiv(x, cellSize);
|
||||||
|
int cellZ = Math.floorDiv(z, cellSize);
|
||||||
|
int localX = Math.floorMod(x, cellSize);
|
||||||
|
int localZ = Math.floorMod(z, cellSize);
|
||||||
|
|
||||||
|
long cellHash = hash(cellX, cellZ);
|
||||||
|
|
||||||
|
// ~50% chance of vertical wall, ~50% chance of horizontal wall
|
||||||
|
boolean hasVerticalWall = (cellHash & 0x1) == 0;
|
||||||
|
boolean hasHorizontalWall = ((cellHash >> 1) & 0x1) == 0;
|
||||||
|
|
||||||
|
if (hasVerticalWall) {
|
||||||
|
int wallPos = 2 + (int) ((cellHash >> 4) & 0x3); // 2-5, keeps wall away from cell edge
|
||||||
|
int doorPos = (int) ((cellHash >> 8) & 0x7); // 0-7
|
||||||
|
int doorWidth = 2 + (int) ((cellHash >> 12) & 0x1); // 2-3 wide door
|
||||||
|
if (localX == wallPos) {
|
||||||
|
boolean inDoor = localZ >= doorPos && localZ < doorPos + doorWidth;
|
||||||
|
if (!inDoor) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasHorizontalWall) {
|
||||||
|
int wallPos = 2 + (int) ((cellHash >> 16) & 0x3);
|
||||||
|
int doorPos = (int) ((cellHash >> 20) & 0x7);
|
||||||
|
int doorWidth = 2 + (int) ((cellHash >> 24) & 0x1);
|
||||||
|
if (localZ == wallPos) {
|
||||||
|
boolean inDoor = localX >= doorPos && localX < doorPos + doorWidth;
|
||||||
|
if (!inDoor) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isGlowstonePos(int x, int z) {
|
||||||
|
// Grid every GLOW_SPACING blocks, offset slightly so it's not always on chunk borders
|
||||||
|
return (Math.floorMod(x + 2, GLOW_SPACING) == 0)
|
||||||
|
&& (Math.floorMod(z + 2, GLOW_SPACING) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple integer hash for deterministic world generation.
|
||||||
|
* Not seeded — same world always generates the same backrooms.
|
||||||
|
* If you want seed-dependent generation, pass in world seed too.
|
||||||
|
*/
|
||||||
|
private long hash(int x, int z) {
|
||||||
|
long h = 374761393L;
|
||||||
|
h += x * 2654435761L;
|
||||||
|
h ^= h >> 17;
|
||||||
|
h += z * 2246822519L;
|
||||||
|
h ^= h >> 13;
|
||||||
|
h *= 3266489917L;
|
||||||
|
h ^= h >> 16;
|
||||||
|
return h & 0xFFFFFFFFL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Required overrides ---
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void carve(ChunkRegion chunk, long seed, NoiseConfig noiseConfig,
|
||||||
|
BiomeAccess access, StructureAccessor structureAccessor,
|
||||||
|
Chunk chunk2, GenerationStep.Carver carver) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void buildSurface(ChunkRegion region, StructureAccessor structures,
|
||||||
|
NoiseConfig noiseConfig, Chunk chunk) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void populateEntities(ChunkRegion region) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWorldHeight() { return 64; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSeaLevel() { return -1; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMinimumY() { return 0; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight(int x, int z, Heightmap.Type heightmap,
|
||||||
|
HeightLimitView world, NoiseConfig noiseConfig) {
|
||||||
|
return CEILING_Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VerticalBlockSample getColumnSample(int x, int z,
|
||||||
|
HeightLimitView world,
|
||||||
|
NoiseConfig noiseConfig) {
|
||||||
|
BlockState[] states = new BlockState[64];
|
||||||
|
for (int y = 0; y < 64; y++) {
|
||||||
|
if (y < FLOOR_Y) states[y] = Szar.PLASTIC.getDefaultState();
|
||||||
|
else if (y == FLOOR_Y) states[y] = Szar.PLASTIC.getDefaultState();
|
||||||
|
else if (y <= WALL_TOP_Y) states[y] = isOpenSpace(x, z)
|
||||||
|
? Blocks.AIR.getDefaultState()
|
||||||
|
: Szar.WALL_BLOCK.getDefaultState();
|
||||||
|
else if (y == CEILING_Y) states[y] = Szar.CEILING.getDefaultState();
|
||||||
|
else states[y] = Szar.CEILING.getDefaultState();
|
||||||
|
}
|
||||||
|
return new VerticalBlockSample(0, states);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getDebugHudText(List<String> text, NoiseConfig noiseConfig,
|
||||||
|
BlockPos pos) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package dev.tggamesyt.szar;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
|
|
||||||
|
public class BackroomsChunkGeneratorConfig {
|
||||||
|
|
||||||
|
public static final Codec<BackroomsChunkGeneratorConfig> CODEC =
|
||||||
|
RecordCodecBuilder.create(instance -> instance.group(
|
||||||
|
Codec.INT.fieldOf("floor_y").forGetter(c -> c.floorY)
|
||||||
|
).apply(instance, BackroomsChunkGeneratorConfig::new));
|
||||||
|
|
||||||
|
public static final BackroomsChunkGeneratorConfig DEFAULT =
|
||||||
|
new BackroomsChunkGeneratorConfig(4);
|
||||||
|
|
||||||
|
public final int floorY;
|
||||||
|
|
||||||
|
public BackroomsChunkGeneratorConfig(int floorY) {
|
||||||
|
this.floorY = floorY;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import net.minecraft.block.Block;
|
|||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.ShapeContext;
|
import net.minecraft.block.ShapeContext;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.ItemEntity;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.entity.player.PlayerInventory;
|
import net.minecraft.entity.player.PlayerInventory;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
@@ -39,104 +40,103 @@ public class PortalBlock extends Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEntityCollision(BlockState state, World world, BlockPos pos,
|
public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity) {
|
||||||
Entity entity) {
|
|
||||||
if (world.isClient) return;
|
if (world.isClient) return;
|
||||||
if (!(entity instanceof ServerPlayerEntity player)) return;
|
if (!(entity instanceof ServerPlayerEntity player)) return;
|
||||||
|
|
||||||
// Cooldown check — 3 seconds
|
|
||||||
long now = world.getTime();
|
long now = world.getTime();
|
||||||
Long last = cooldowns.get(player.getUuid());
|
Long last = cooldowns.get(player.getUuid());
|
||||||
if (last != null && now - last < 60) return;
|
if (last != null && now - last < 60) return;
|
||||||
cooldowns.put(player.getUuid(), now);
|
cooldowns.put(player.getUuid(), now);
|
||||||
|
|
||||||
// Find the TrackerBlock above (within 5 blocks)
|
|
||||||
TrackerBlockEntity tracker = findTrackerAbove(world, pos);
|
TrackerBlockEntity tracker = findTrackerAbove(world, pos);
|
||||||
if (tracker == null) return;
|
if (tracker == null) return;
|
||||||
|
|
||||||
MinecraftServer server = world.getServer();
|
MinecraftServer server = world.getServer();
|
||||||
if (server == null) return;
|
if (server == null) return;
|
||||||
|
|
||||||
if (!tracker.isNetherSide) {
|
// Detect dimension instead of reading isNetherSide
|
||||||
// --- OVERWORLD → NETHER ---
|
if (world.getRegistryKey() == World.OVERWORLD) {
|
||||||
teleportToNether(player, tracker, server, pos);
|
teleportToNether(player, tracker, server, pos);
|
||||||
} else {
|
} else if (world.getRegistryKey() == Szar.BACKROOMS_KEY) {
|
||||||
// --- NETHER → OVERWORLD ---
|
|
||||||
teleportToOverworld(player, tracker, server);
|
teleportToOverworld(player, tracker, server);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void teleportToNether(ServerPlayerEntity player, TrackerBlockEntity tracker,
|
private void teleportToNether(ServerPlayerEntity player, TrackerBlockEntity tracker,
|
||||||
MinecraftServer server, BlockPos portalPos) {
|
MinecraftServer server, BlockPos portalPos) {
|
||||||
// Save return position (a few blocks above entry)
|
// Save where this player entered — stored persistently so nether portal can read it
|
||||||
tracker.returnX = player.getX();
|
NbtCompound tag = getOrCreateCustomData(player);
|
||||||
tracker.returnY = player.getY() + 3;
|
tag.putDouble("EntryX", player.getX());
|
||||||
tracker.returnZ = player.getZ();
|
tag.putDouble("EntryY", player.getY() + 6); // a few blocks above so they don't fall back in
|
||||||
tracker.markDirty();
|
tag.putDouble("EntryZ", player.getZ());
|
||||||
|
tag.putInt("OwnerTrackerX", tracker.getPos().getX());
|
||||||
|
tag.putInt("OwnerTrackerY", tracker.getPos().getY());
|
||||||
|
tag.putInt("OwnerTrackerZ", tracker.getPos().getZ());
|
||||||
|
|
||||||
// Save inventory
|
// Save inventory
|
||||||
NbtList savedInventory = saveInventory(player);
|
NbtList savedInventory = saveInventory(player);
|
||||||
|
saveInventoryToPlayer(player, savedInventory);
|
||||||
|
|
||||||
// Clear inventory
|
// Clear inventory
|
||||||
player.getInventory().clear();
|
player.getInventory().clear();
|
||||||
|
|
||||||
// Register player as inside
|
// Register player in tracker
|
||||||
tracker.addPlayer(player.getUuid());
|
tracker.addPlayer(player.getUuid());
|
||||||
|
|
||||||
// Teleport to nether
|
// Teleport
|
||||||
ServerWorld nether = server.getWorld(World.NETHER);
|
ServerWorld nether = server.getWorld(Szar.BACKROOMS_KEY);
|
||||||
if (nether == null) return;
|
if (nether == null) return;
|
||||||
|
|
||||||
double netherX = player.getX();
|
double netherX = player.getX();
|
||||||
double netherZ = player.getZ();
|
double netherZ = player.getZ();
|
||||||
double netherY = findSafeY(nether, (int) netherX, (int) netherZ);
|
double netherY = findSafeY(nether, (int) netherX, (int) netherZ);
|
||||||
|
|
||||||
// Store saved inventory in player's persistent data
|
player.teleport(nether, netherX, netherY, netherZ,
|
||||||
NbtCompound persistent = player.writeNbt(new NbtCompound());
|
|
||||||
// We use a custom data attachment via the player's nbt
|
|
||||||
saveInventoryToPlayer(player, savedInventory);
|
|
||||||
|
|
||||||
// Store which overworld tracker owns this player
|
|
||||||
NbtCompound tag = getOrCreateCustomData(player);
|
|
||||||
tag.putInt("OwnerTrackerX", tracker.getPos().getX());
|
|
||||||
tag.putInt("OwnerTrackerY", tracker.getPos().getY());
|
|
||||||
tag.putInt("OwnerTrackerZ", tracker.getPos().getZ());
|
|
||||||
|
|
||||||
// Generate nether-side portal structure
|
|
||||||
BlockPos netherPortalPos = new BlockPos((int) netherX, (int) netherY, (int) netherZ);
|
|
||||||
generateNetherPortal(nether, netherPortalPos, tracker);
|
|
||||||
|
|
||||||
// Teleport
|
|
||||||
player.teleport(nether, netherX, netherY + 1, netherZ,
|
|
||||||
player.getYaw(), player.getPitch());
|
player.getYaw(), player.getPitch());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void teleportToOverworld(ServerPlayerEntity player, TrackerBlockEntity tracker,
|
private void teleportToOverworld(ServerPlayerEntity player, TrackerBlockEntity netherTracker,
|
||||||
MinecraftServer server) {
|
MinecraftServer server) {
|
||||||
// Restore inventory
|
NbtCompound tag = getOrCreateCustomData(player);
|
||||||
restoreInventoryToPlayer(player);
|
double returnX = tag.getDouble("EntryX");
|
||||||
|
double returnY = tag.getDouble("EntryY");
|
||||||
|
double returnZ = tag.getDouble("EntryZ");
|
||||||
|
|
||||||
// Remove from nether tracker
|
// Read overworld tracker pos
|
||||||
tracker.removePlayer(player.getUuid());
|
BlockPos owTrackerPos = null;
|
||||||
|
if (tag.contains("OwnerTrackerX")) {
|
||||||
|
owTrackerPos = new BlockPos(
|
||||||
|
tag.getInt("OwnerTrackerX"),
|
||||||
|
tag.getInt("OwnerTrackerY"),
|
||||||
|
tag.getInt("OwnerTrackerZ")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
PortalBlock.restoreInventory(player, server);
|
||||||
|
netherTracker.removePlayer(player.getUuid());
|
||||||
|
|
||||||
// Find overworld paired tracker and remove from that too
|
|
||||||
ServerWorld overworld = server.getWorld(World.OVERWORLD);
|
ServerWorld overworld = server.getWorld(World.OVERWORLD);
|
||||||
if (overworld != null && tracker.pairedTrackerPos != null) {
|
ServerWorld nether = server.getWorld(Szar.BACKROOMS_KEY);
|
||||||
if (overworld.getBlockEntity(tracker.pairedTrackerPos)
|
|
||||||
instanceof TrackerBlockEntity owTracker) {
|
// Clean up nether side if empty
|
||||||
|
if (!netherTracker.hasPlayers() && nether != null) {
|
||||||
|
TrackerBlock.restoreAndCleanup(nether,
|
||||||
|
netherTracker.getPos(), netherTracker, server);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up overworld tracker too
|
||||||
|
if (owTrackerPos != null && overworld != null) {
|
||||||
|
if (overworld.getBlockEntity(owTrackerPos) instanceof TrackerBlockEntity owTracker) {
|
||||||
owTracker.removePlayer(player.getUuid());
|
owTracker.removePlayer(player.getUuid());
|
||||||
|
|
||||||
// If no players left, remove both trackers and their portal blocks
|
|
||||||
if (!owTracker.hasPlayers()) {
|
if (!owTracker.hasPlayers()) {
|
||||||
removePortalStructure(overworld, tracker.pairedTrackerPos);
|
TrackerBlock.restoreAndCleanup(overworld, owTrackerPos, owTracker, server);
|
||||||
removePortalStructure((ServerWorld) player.getWorld(), tracker.getPos());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Teleport back (a few blocks above entry)
|
if (overworld == null) return;
|
||||||
player.teleport(overworld,
|
player.teleport(overworld, returnX, returnY, returnZ,
|
||||||
tracker.returnX, tracker.returnY, tracker.returnZ,
|
|
||||||
player.getYaw(), player.getPitch());
|
player.getYaw(), player.getPitch());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,8 +155,9 @@ public class PortalBlock extends Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private double findSafeY(ServerWorld world, int x, int z) {
|
private double findSafeY(ServerWorld world, int x, int z) {
|
||||||
// Search from y=100 downward for solid ground with 2 air blocks above
|
// For backrooms, search from y=8 downward only
|
||||||
for (int y = 100; y > 10; y--) {
|
int startY = world.getRegistryKey() == Szar.BACKROOMS_KEY ? 8 : 100;
|
||||||
|
for (int y = startY; y > 1; y--) {
|
||||||
BlockPos feet = new BlockPos(x, y, z);
|
BlockPos feet = new BlockPos(x, y, z);
|
||||||
BlockPos head = feet.up();
|
BlockPos head = feet.up();
|
||||||
BlockPos ground = feet.down();
|
BlockPos ground = feet.down();
|
||||||
@@ -166,35 +167,7 @@ public class PortalBlock extends Block {
|
|||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 64; // fallback
|
return 5; // fallback to inside the backrooms
|
||||||
}
|
|
||||||
|
|
||||||
private void generateNetherPortal(ServerWorld nether, BlockPos portalPos,
|
|
||||||
TrackerBlockEntity overworldTracker) {
|
|
||||||
// Place TrackerBlock 4 blocks above portal
|
|
||||||
BlockPos trackerPos = portalPos.up(4);
|
|
||||||
nether.setBlockState(trackerPos, Szar.TRACKER_BLOCK.getDefaultState());
|
|
||||||
|
|
||||||
if (nether.getBlockEntity(trackerPos) instanceof TrackerBlockEntity netherTracker) {
|
|
||||||
netherTracker.isNetherSide = true;
|
|
||||||
netherTracker.returnX = overworldTracker.returnX;
|
|
||||||
netherTracker.returnY = overworldTracker.returnY;
|
|
||||||
netherTracker.returnZ = overworldTracker.returnZ;
|
|
||||||
netherTracker.pairedTrackerPos = overworldTracker.getPos();
|
|
||||||
overworldTracker.pairedTrackerPos = trackerPos;
|
|
||||||
overworldTracker.markDirty();
|
|
||||||
netherTracker.markDirty();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Place portal block at bottom
|
|
||||||
nether.setBlockState(portalPos, Szar.PORTAL_BLOCK.getDefaultState());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removePortalStructure(ServerWorld world, BlockPos trackerPos) {
|
|
||||||
// Remove tracker
|
|
||||||
world.removeBlock(trackerPos, false);
|
|
||||||
// Remove portal block (4 below)
|
|
||||||
world.removeBlock(trackerPos.down(4), false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inventory persistence via player NBT custom data
|
// Inventory persistence via player NBT custom data
|
||||||
@@ -249,4 +222,45 @@ public class PortalBlock extends Block {
|
|||||||
player.getServer().getWorld(World.OVERWORLD)
|
player.getServer().getWorld(World.OVERWORLD)
|
||||||
).getOrCreatePlayerData(player.getUuid());
|
).getOrCreatePlayerData(player.getUuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Change the signature in PortalBlock.java
|
||||||
|
public static void restoreInventory(ServerPlayerEntity player, MinecraftServer server) {
|
||||||
|
PortalDataState state = PortalDataState.getOrCreate(
|
||||||
|
server.getWorld(World.OVERWORLD)
|
||||||
|
);
|
||||||
|
NbtCompound tag = state.getOrCreatePlayerData(player.getUuid());
|
||||||
|
|
||||||
|
if (!tag.contains(INV_KEY)) return;
|
||||||
|
|
||||||
|
NbtList list = tag.getList(INV_KEY, 10);
|
||||||
|
|
||||||
|
// Build list of saved stacks
|
||||||
|
List<ItemStack> savedStacks = new ArrayList<>();
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
NbtCompound entry = list.getCompound(i);
|
||||||
|
ItemStack stack = ItemStack.fromNbt(entry);
|
||||||
|
if (!stack.isEmpty()) {
|
||||||
|
savedStacks.add(stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to insert each saved stack into the current inventory
|
||||||
|
PlayerInventory inv = player.getInventory();
|
||||||
|
for (ItemStack saved : savedStacks) {
|
||||||
|
// insertStack tries to stack with existing items first, then finds empty slot
|
||||||
|
boolean inserted = inv.insertStack(saved);
|
||||||
|
if (!inserted || !saved.isEmpty()) {
|
||||||
|
// Inventory full — drop remainder at player's position
|
||||||
|
ItemEntity drop = new ItemEntity(
|
||||||
|
player.getWorld(),
|
||||||
|
player.getX(), player.getY(), player.getZ(),
|
||||||
|
saved.copy()
|
||||||
|
);
|
||||||
|
drop.setPickupDelay(0);
|
||||||
|
player.getWorld().spawnEntity(drop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.removePlayerData(player.getUuid());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -172,7 +172,10 @@ public class Szar implements ModInitializer {
|
|||||||
new Identifier(MOD_ID, "play_video");
|
new Identifier(MOD_ID, "play_video");
|
||||||
public static final Identifier CONFIG_SYNC = new Identifier(MOD_ID, "config_sync");
|
public static final Identifier CONFIG_SYNC = new Identifier(MOD_ID, "config_sync");
|
||||||
|
|
||||||
|
public static final RegistryKey<World> BACKROOMS_KEY = RegistryKey.of(
|
||||||
|
RegistryKeys.WORLD,
|
||||||
|
new Identifier(MOD_ID, "backrooms")
|
||||||
|
);
|
||||||
public static final Block SZAR_BLOCK =
|
public static final Block SZAR_BLOCK =
|
||||||
new SzarBlock();
|
new SzarBlock();
|
||||||
public static final Block URANIUM_BLOCK =
|
public static final Block URANIUM_BLOCK =
|
||||||
@@ -349,36 +352,6 @@ public class Szar implements ModInitializer {
|
|||||||
.displayName(Text.translatable("itemgroup.szar_group"))
|
.displayName(Text.translatable("itemgroup.szar_group"))
|
||||||
.icon(() -> new ItemStack(Szar.CANNABIS_ITEM)) // icon item
|
.icon(() -> new ItemStack(Szar.CANNABIS_ITEM)) // icon item
|
||||||
.entries((displayContext, entries) -> {
|
.entries((displayContext, entries) -> {
|
||||||
// drugs
|
|
||||||
entries.add(Szar.CANNABIS_ITEM);
|
|
||||||
entries.add(Szar.WEED_ITEM);
|
|
||||||
entries.add(Szar.WEED_JOINT_ITEM);
|
|
||||||
entries.add(Szar.CHEMICAL_WORKBENCH_ITEM);
|
|
||||||
// racism
|
|
||||||
entries.add(Szar.CIGANYBLOCK);
|
|
||||||
entries.add(Szar.NWORD_PASS);
|
|
||||||
entries.add(Szar.HITTER_SPAWNEGG);
|
|
||||||
entries.add(Szar.NAZI_SPAWNEGG);
|
|
||||||
entries.add(Szar.STALIN_SPAWNEGG);
|
|
||||||
entries.add(Szar.COMMUNIST_SPAWNEGG);
|
|
||||||
entries.add(Szar.NIGGER_SPAWNEGG);
|
|
||||||
entries.add(Szar.GYPSY_SPAWNEGG);
|
|
||||||
entries.add(Szar.TERRORIST_SPAWNEGG);
|
|
||||||
entries.add(Szar.POLICE_SPAWNEGG);
|
|
||||||
entries.add(Szar.KEY_ITEM);
|
|
||||||
entries.add(Szar.HANDCUFF_ITEM);
|
|
||||||
// crazy weponary
|
|
||||||
entries.add(Szar.BULLET_ITEM);
|
|
||||||
entries.add(Szar.AK47);
|
|
||||||
entries.add(Szar.REVOLVER);
|
|
||||||
entries.add(Szar.ATOM_DETONATOR);
|
|
||||||
entries.add(Szar.URANIUM_ORE);
|
|
||||||
entries.add(Szar.URANIUM);
|
|
||||||
entries.add(Szar.URANIUM_ROD);
|
|
||||||
entries.add(Szar.ATOM_CORE);
|
|
||||||
entries.add(Szar.ATOM);
|
|
||||||
entries.add(Szar.WHEEL);
|
|
||||||
entries.add(Szar.PLANE);
|
|
||||||
// random ahh silly stuff
|
// random ahh silly stuff
|
||||||
entries.add(Szar.POPTART);
|
entries.add(Szar.POPTART);
|
||||||
entries.add(Szar.NYAN_SPAWNEGG);
|
entries.add(Szar.NYAN_SPAWNEGG);
|
||||||
@@ -391,13 +364,45 @@ public class Szar implements ModInitializer {
|
|||||||
entries.add(Szar.ROULETTE);
|
entries.add(Szar.ROULETTE);
|
||||||
entries.add(Szar.FIRTANA);
|
entries.add(Szar.FIRTANA);
|
||||||
entries.add(Szar.HELLO_DISC);
|
entries.add(Szar.HELLO_DISC);
|
||||||
|
entries.add(Szar.TRACKER_BLOCK_ITEM);
|
||||||
|
entries.add(Szar.PORTAL_BLOCK_ITEM);
|
||||||
|
entries.add(Szar.WALL_ITEM);
|
||||||
|
entries.add(Szar.WALL_BOTTOM_ITEM);
|
||||||
|
entries.add(Szar.CEILING_ITEM);
|
||||||
|
entries.add(Szar.PLASTIC_ITEM);
|
||||||
|
// crazy weponary
|
||||||
|
entries.add(Szar.BULLET_ITEM);
|
||||||
|
entries.add(Szar.AK47);
|
||||||
|
entries.add(Szar.REVOLVER);
|
||||||
|
entries.add(Szar.ATOM_DETONATOR);
|
||||||
|
entries.add(Szar.URANIUM_ORE);
|
||||||
|
entries.add(Szar.URANIUM);
|
||||||
|
entries.add(Szar.URANIUM_ROD);
|
||||||
|
entries.add(Szar.ATOM_CORE);
|
||||||
|
entries.add(Szar.ATOM);
|
||||||
|
entries.add(Szar.WHEEL);
|
||||||
|
entries.add(Szar.PLANE);
|
||||||
|
// drugs
|
||||||
|
entries.add(Szar.CANNABIS_ITEM);
|
||||||
|
entries.add(Szar.WEED_ITEM);
|
||||||
|
entries.add(Szar.WEED_JOINT_ITEM);
|
||||||
|
entries.add(Szar.CHEMICAL_WORKBENCH_ITEM);
|
||||||
|
// war guys
|
||||||
|
entries.add(Szar.HITTER_SPAWNEGG);
|
||||||
|
entries.add(Szar.NAZI_SPAWNEGG);
|
||||||
|
entries.add(Szar.STALIN_SPAWNEGG);
|
||||||
|
entries.add(Szar.COMMUNIST_SPAWNEGG);
|
||||||
entries.add(Szar.ERIKA_DISC);
|
entries.add(Szar.ERIKA_DISC);
|
||||||
entries.add(Szar.USSR_DISC);
|
entries.add(Szar.USSR_DISC);
|
||||||
// nsfw
|
// racism
|
||||||
entries.add(Szar.FASZITEM);
|
entries.add(Szar.CIGANYBLOCK);
|
||||||
entries.add(Szar.CNDM);
|
entries.add(Szar.NWORD_PASS);
|
||||||
entries.add(Szar.LATEX);
|
entries.add(Szar.NIGGER_SPAWNEGG);
|
||||||
entries.add(Szar.WHITE_LIQUID);
|
entries.add(Szar.GYPSY_SPAWNEGG);
|
||||||
|
entries.add(Szar.TERRORIST_SPAWNEGG);
|
||||||
|
entries.add(Szar.POLICE_SPAWNEGG);
|
||||||
|
entries.add(Szar.KEY_ITEM);
|
||||||
|
entries.add(Szar.HANDCUFF_ITEM);
|
||||||
// niggerite shits at the end
|
// niggerite shits at the end
|
||||||
entries.add(Szar.NIGGERITE_INGOT);
|
entries.add(Szar.NIGGERITE_INGOT);
|
||||||
entries.add(Szar.NIGGERITE_SWORD);
|
entries.add(Szar.NIGGERITE_SWORD);
|
||||||
@@ -410,12 +415,22 @@ public class Szar implements ModInitializer {
|
|||||||
entries.add(Szar.NIGGERITE_LEGGINGS);
|
entries.add(Szar.NIGGERITE_LEGGINGS);
|
||||||
entries.add(Szar.NIGGERITE_BOOTS);
|
entries.add(Szar.NIGGERITE_BOOTS);
|
||||||
entries.add(Szar.NIGGERITE_BLOCK);
|
entries.add(Szar.NIGGERITE_BLOCK);
|
||||||
|
// nsfw
|
||||||
|
entries.add(Szar.FASZITEM);
|
||||||
|
entries.add(Szar.CNDM);
|
||||||
|
entries.add(Szar.LATEX);
|
||||||
|
entries.add(Szar.WHITE_LIQUID);
|
||||||
})
|
})
|
||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
private final Map<UUID, BlockPos> sleepingPlayers = new HashMap<>();
|
private final Map<UUID, BlockPos> sleepingPlayers = new HashMap<>();
|
||||||
@Override
|
@Override
|
||||||
public void onInitialize() {
|
public void onInitialize() {
|
||||||
|
Registry.register(
|
||||||
|
Registries.CHUNK_GENERATOR,
|
||||||
|
new Identifier(MOD_ID, "backrooms"),
|
||||||
|
BackroomsChunkGenerator.CODEC
|
||||||
|
);
|
||||||
ServerPlayNetworking.registerGlobalReceiver(AK47_SHOOT, (server, player, handler, buf, responseSender) -> {
|
ServerPlayNetworking.registerGlobalReceiver(AK47_SHOOT, (server, player, handler, buf, responseSender) -> {
|
||||||
server.execute(() -> {
|
server.execute(() -> {
|
||||||
ItemStack stack = player.getMainHandStack();
|
ItemStack stack = player.getMainHandStack();
|
||||||
@@ -1068,15 +1083,18 @@ public class Szar implements ModInitializer {
|
|||||||
// 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"),
|
||||||
new TrackerBlock(FabricBlockSettings.create().noCollision().air())
|
new TrackerBlock(FabricBlockSettings.create()
|
||||||
// .air() makes it not render and not block light
|
.noCollision()
|
||||||
|
.nonOpaque()
|
||||||
|
.strength(2f, 2f))
|
||||||
);
|
);
|
||||||
|
|
||||||
public static final PortalBlock PORTAL_BLOCK = Registry.register(
|
public static final PortalBlock PORTAL_BLOCK = Registry.register(
|
||||||
Registries.BLOCK, new Identifier(MOD_ID, "portal"),
|
Registries.BLOCK, new Identifier(MOD_ID, "portal"),
|
||||||
new PortalBlock(FabricBlockSettings.create().noCollision()
|
new PortalBlock(FabricBlockSettings.create()
|
||||||
.strength(-1.0f) // indestructible by default, change if needed
|
.noCollision()
|
||||||
.luminance(state -> 11)) // slight glow so you can see it
|
.nonOpaque()
|
||||||
|
.strength(2f, 2f))
|
||||||
);
|
);
|
||||||
|
|
||||||
// Block items (so you can place them)
|
// Block items (so you can place them)
|
||||||
@@ -1097,6 +1115,42 @@ public class Szar implements ModInitializer {
|
|||||||
new Identifier(MOD_ID, "tracker"),
|
new Identifier(MOD_ID, "tracker"),
|
||||||
FabricBlockEntityTypeBuilder.create(TrackerBlockEntity::new, TRACKER_BLOCK).build()
|
FabricBlockEntityTypeBuilder.create(TrackerBlockEntity::new, TRACKER_BLOCK).build()
|
||||||
);
|
);
|
||||||
|
public static final Block WALL_BLOCK = Registry.register(
|
||||||
|
Registries.BLOCK, new Identifier(MOD_ID, "wall"),
|
||||||
|
new Block(AbstractBlock.Settings.create())
|
||||||
|
);
|
||||||
|
public static final Block WALL_BOTTOM_BLOCK = Registry.register(
|
||||||
|
Registries.BLOCK, new Identifier(MOD_ID, "wall_bottom"),
|
||||||
|
new Block(AbstractBlock.Settings.create())
|
||||||
|
);
|
||||||
|
public static final Block CEILING = Registry.register(
|
||||||
|
Registries.BLOCK, new Identifier(MOD_ID, "ceiling"),
|
||||||
|
new Block(AbstractBlock.Settings.create())
|
||||||
|
);
|
||||||
|
public static final Block PLASTIC = Registry.register(
|
||||||
|
Registries.BLOCK, new Identifier(MOD_ID, "plastic"),
|
||||||
|
new Block(AbstractBlock.Settings.create())
|
||||||
|
);
|
||||||
|
public static final Item WALL_ITEM = Registry.register(
|
||||||
|
Registries.ITEM,
|
||||||
|
new Identifier(MOD_ID, "wall"),
|
||||||
|
new BlockItem(WALL_BLOCK, new Item.Settings())
|
||||||
|
);
|
||||||
|
public static final Item WALL_BOTTOM_ITEM = Registry.register(
|
||||||
|
Registries.ITEM,
|
||||||
|
new Identifier(MOD_ID, "wall_bottom"),
|
||||||
|
new BlockItem(WALL_BOTTOM_BLOCK, new Item.Settings())
|
||||||
|
);
|
||||||
|
public static final Item CEILING_ITEM = Registry.register(
|
||||||
|
Registries.ITEM,
|
||||||
|
new Identifier(MOD_ID, "ceiling"),
|
||||||
|
new BlockItem(CEILING, new Item.Settings())
|
||||||
|
);
|
||||||
|
public static final Item PLASTIC_ITEM = Registry.register(
|
||||||
|
Registries.ITEM,
|
||||||
|
new Identifier(MOD_ID, "plastic"),
|
||||||
|
new BlockItem(PLASTIC, new Item.Settings())
|
||||||
|
);
|
||||||
|
|
||||||
// In your ModItems or wherever you register items
|
// In your ModItems or wherever you register items
|
||||||
public static final Item REVOLVER = Registry.register(
|
public static final Item REVOLVER = Registry.register(
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
package dev.tggamesyt.szar;
|
package dev.tggamesyt.szar;
|
||||||
|
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.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.BlockEntity;
|
||||||
import net.minecraft.entity.LivingEntity;
|
import net.minecraft.entity.LivingEntity;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.nbt.NbtCompound;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.server.world.ServerWorld;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.shape.VoxelShape;
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
import net.minecraft.util.shape.VoxelShapes;
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
@@ -15,6 +16,10 @@ import net.minecraft.world.BlockView;
|
|||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class TrackerBlock extends Block implements BlockEntityProvider {
|
public class TrackerBlock extends Block implements BlockEntityProvider {
|
||||||
|
|
||||||
public TrackerBlock(Settings settings) {
|
public TrackerBlock(Settings settings) {
|
||||||
@@ -22,17 +27,37 @@ public class TrackerBlock extends Block implements BlockEntityProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// No hitbox
|
// No hitbox
|
||||||
|
// 1x1x1 pixel cube — invisible in practice but gives particles a valid bounding box
|
||||||
|
private static final VoxelShape TINY = Block.createCuboidShape(7.9, 7.9, 7.9, 8.1, 8.1, 8.1);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VoxelShape getOutlineShape(BlockState state, BlockView world,
|
public VoxelShape getOutlineShape(BlockState state, BlockView world,
|
||||||
BlockPos pos, ShapeContext ctx) {
|
BlockPos pos, ShapeContext ctx) {
|
||||||
return VoxelShapes.empty();
|
if (ctx instanceof EntityShapeContext esc && esc.getEntity() instanceof PlayerEntity player) {
|
||||||
|
if (isHoldingTracker(player)) {
|
||||||
|
return VoxelShapes.fullCube();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Too small to see or select, but has valid bounds so particle manager doesn't crash
|
||||||
|
return TINY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No collision
|
|
||||||
@Override
|
@Override
|
||||||
public VoxelShape getCollisionShape(BlockState state, BlockView world,
|
public VoxelShape getCollisionShape(BlockState state, BlockView world,
|
||||||
BlockPos pos, ShapeContext ctx) {
|
BlockPos pos, ShapeContext ctx) {
|
||||||
return VoxelShapes.empty();
|
return VoxelShapes.empty(); // never has collision, only outline
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getRaycastShape(BlockState state, BlockView world, BlockPos pos) {
|
||||||
|
// This is what allows the player to actually target and break it
|
||||||
|
return VoxelShapes.fullCube();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isHoldingTracker(PlayerEntity player) {
|
||||||
|
return player.getMainHandStack().isOf(Szar.TRACKER_BLOCK_ITEM.asItem())
|
||||||
|
|| player.getOffHandStack().isOf(Szar.TRACKER_BLOCK_ITEM.asItem());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -45,8 +70,59 @@ public class TrackerBlock extends Block implements BlockEntityProvider {
|
|||||||
public void onPlaced(World world, BlockPos pos, BlockState state,
|
public void onPlaced(World world, BlockPos pos, BlockState state,
|
||||||
@Nullable LivingEntity placer, ItemStack itemStack) {
|
@Nullable LivingEntity placer, ItemStack itemStack) {
|
||||||
if (world.isClient) return;
|
if (world.isClient) return;
|
||||||
|
if (!(world.getBlockEntity(pos) instanceof TrackerBlockEntity tracker)) return;
|
||||||
|
|
||||||
|
// Only auto-place portal if a player placed this tracker
|
||||||
|
if (!tracker.placedByPlayer) return;
|
||||||
|
|
||||||
BlockPos portalPos = pos.down(4);
|
BlockPos portalPos = pos.down(4);
|
||||||
|
|
||||||
|
// Save the original block before replacing it
|
||||||
|
tracker.originalPortalBlock = world.getBlockState(portalPos);
|
||||||
|
tracker.markDirty();
|
||||||
|
|
||||||
world.setBlockState(portalPos, Szar.PORTAL_BLOCK.getDefaultState());
|
world.setBlockState(portalPos, Szar.PORTAL_BLOCK.getDefaultState());
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public void onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) {
|
||||||
|
// In survival, only break if holding the special item
|
||||||
|
|
||||||
|
if (!world.isClient && world.getBlockEntity(pos) instanceof TrackerBlockEntity tracker) {
|
||||||
|
restoreAndCleanup(world, pos, tracker, world.getServer());
|
||||||
|
}
|
||||||
|
super.onBreak(world, pos, state, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void restoreAndCleanup(World world, BlockPos trackerPos,
|
||||||
|
TrackerBlockEntity tracker, MinecraftServer server) {
|
||||||
|
if (server == null) return;
|
||||||
|
|
||||||
|
// Kick all players tracked here back to overworld
|
||||||
|
Set<UUID> players = new HashSet<>(tracker.getPlayersInside());
|
||||||
|
for (UUID uuid : players) {
|
||||||
|
ServerPlayerEntity player = server.getPlayerManager().getPlayer(uuid);
|
||||||
|
if (player == null) continue;
|
||||||
|
|
||||||
|
PortalBlock.restoreInventory(player, server);
|
||||||
|
|
||||||
|
ServerWorld overworld = server.getWorld(World.OVERWORLD);
|
||||||
|
if (overworld != null) {
|
||||||
|
NbtCompound tag = PortalDataState.getOrCreate(overworld)
|
||||||
|
.getOrCreatePlayerData(uuid);
|
||||||
|
double rx = tag.getDouble("EntryX");
|
||||||
|
double ry = tag.getDouble("EntryY");
|
||||||
|
double rz = tag.getDouble("EntryZ");
|
||||||
|
player.teleport(overworld, rx, ry, rz, player.getYaw(), player.getPitch());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore original block at portal position
|
||||||
|
BlockPos portalPos = trackerPos.down(4);
|
||||||
|
if (world.getBlockState(portalPos).getBlock() instanceof PortalBlock) {
|
||||||
|
world.setBlockState(portalPos, tracker.originalPortalBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the tracker itself
|
||||||
|
world.removeBlock(trackerPos, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
package dev.tggamesyt.szar;
|
package dev.tggamesyt.szar;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.block.entity.BlockEntity;
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
import net.minecraft.nbt.NbtCompound;
|
import net.minecraft.nbt.NbtCompound;
|
||||||
import net.minecraft.nbt.NbtList;
|
import net.minecraft.nbt.NbtList;
|
||||||
|
import net.minecraft.nbt.NbtOps;
|
||||||
import net.minecraft.nbt.NbtString;
|
import net.minecraft.nbt.NbtString;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
|
||||||
@@ -12,11 +14,12 @@ import java.util.Set;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class TrackerBlockEntity extends BlockEntity {
|
public class TrackerBlockEntity extends BlockEntity {
|
||||||
|
// Add these fields
|
||||||
|
public BlockState originalPortalBlock = Blocks.AIR.getDefaultState();
|
||||||
|
public boolean placedByPlayer = true; // false = auto-generated by the system
|
||||||
// The overworld entry coords (used by nether-side tracker to know where to send players back)
|
// The overworld entry coords (used by nether-side tracker to know where to send players back)
|
||||||
public double returnX, returnY, returnZ;
|
public double returnX, returnY, returnZ;
|
||||||
// Whether this tracker is in the nether or overworld
|
// Whether this tracker is in the nether or overworld
|
||||||
public boolean isNetherSide = false;
|
|
||||||
// BlockPos of the paired tracker in the other dimension
|
// BlockPos of the paired tracker in the other dimension
|
||||||
public BlockPos pairedTrackerPos = null;
|
public BlockPos pairedTrackerPos = null;
|
||||||
|
|
||||||
@@ -51,7 +54,6 @@ public class TrackerBlockEntity extends BlockEntity {
|
|||||||
nbt.putDouble("ReturnX", returnX);
|
nbt.putDouble("ReturnX", returnX);
|
||||||
nbt.putDouble("ReturnY", returnY);
|
nbt.putDouble("ReturnY", returnY);
|
||||||
nbt.putDouble("ReturnZ", returnZ);
|
nbt.putDouble("ReturnZ", returnZ);
|
||||||
nbt.putBoolean("IsNetherSide", isNetherSide);
|
|
||||||
|
|
||||||
if (pairedTrackerPos != null) {
|
if (pairedTrackerPos != null) {
|
||||||
nbt.putInt("PairedX", pairedTrackerPos.getX());
|
nbt.putInt("PairedX", pairedTrackerPos.getX());
|
||||||
@@ -64,6 +66,12 @@ public class TrackerBlockEntity extends BlockEntity {
|
|||||||
list.add(NbtString.of(uuid.toString()));
|
list.add(NbtString.of(uuid.toString()));
|
||||||
}
|
}
|
||||||
nbt.put("PlayersInside", list);
|
nbt.put("PlayersInside", list);
|
||||||
|
NbtCompound originalBlock = new NbtCompound();
|
||||||
|
BlockState.CODEC.encodeStart(NbtOps.INSTANCE, originalPortalBlock)
|
||||||
|
.result()
|
||||||
|
.ifPresent(nbt1 -> originalBlock.put("State", nbt1));
|
||||||
|
nbt.put("OriginalPortalBlock", originalBlock);
|
||||||
|
nbt.putBoolean("PlacedByPlayer", placedByPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -72,7 +80,6 @@ public class TrackerBlockEntity extends BlockEntity {
|
|||||||
returnX = nbt.getDouble("ReturnX");
|
returnX = nbt.getDouble("ReturnX");
|
||||||
returnY = nbt.getDouble("ReturnY");
|
returnY = nbt.getDouble("ReturnY");
|
||||||
returnZ = nbt.getDouble("ReturnZ");
|
returnZ = nbt.getDouble("ReturnZ");
|
||||||
isNetherSide = nbt.getBoolean("IsNetherSide");
|
|
||||||
|
|
||||||
if (nbt.contains("PairedX")) {
|
if (nbt.contains("PairedX")) {
|
||||||
pairedTrackerPos = new BlockPos(
|
pairedTrackerPos = new BlockPos(
|
||||||
@@ -87,5 +94,14 @@ public class TrackerBlockEntity extends BlockEntity {
|
|||||||
for (int i = 0; i < list.size(); i++) {
|
for (int i = 0; i < list.size(); i++) {
|
||||||
playersInside.add(UUID.fromString(list.getString(i)));
|
playersInside.add(UUID.fromString(list.getString(i)));
|
||||||
}
|
}
|
||||||
|
if (nbt.contains("OriginalPortalBlock")) {
|
||||||
|
NbtCompound originalBlock = nbt.getCompound("OriginalPortalBlock");
|
||||||
|
if (originalBlock.contains("State")) {
|
||||||
|
BlockState.CODEC.parse(NbtOps.INSTANCE, originalBlock.get("State"))
|
||||||
|
.result()
|
||||||
|
.ifPresent(s -> originalPortalBlock = s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
placedByPlayer = nbt.getBoolean("PlacedByPlayer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
7
src/main/resources/assets/szar/blockstates/ceiling.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "szar:block/ceiling"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/main/resources/assets/szar/blockstates/plastic.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "szar:block/plastic"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/main/resources/assets/szar/blockstates/portal.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "szar:block/portal"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/main/resources/assets/szar/blockstates/tracker.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "szar:block/tracker"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/main/resources/assets/szar/blockstates/wall.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "szar:block/wall"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "szar:block/wall_bottom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -136,5 +136,13 @@
|
|||||||
"item.szar.communist_spawn_egg":"Communist Spawn Egg",
|
"item.szar.communist_spawn_egg":"Communist Spawn Egg",
|
||||||
|
|
||||||
"item.szar.ussr": "Music Disc",
|
"item.szar.ussr": "Music Disc",
|
||||||
"item.szar.ussr.desc": "A. Alexandrov - USSR Anthem"
|
"item.szar.ussr.desc": "A. Alexandrov - USSR Anthem",
|
||||||
|
|
||||||
|
"block.szar.tracker": "Portal Tracker Block",
|
||||||
|
"block.szar.portal": "Portal",
|
||||||
|
|
||||||
|
"block.szar.plastic": "Plastic",
|
||||||
|
"block.szar.ceiling": "Ceiling",
|
||||||
|
"block.szar.wall": "Wall",
|
||||||
|
"block.szar.wall_bottom": "Wall Bottom"
|
||||||
}
|
}
|
||||||
|
|||||||
55
src/main/resources/assets/szar/models/block/ceiling.json
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.21.11",
|
||||||
|
"credit": "Made with Blockbench",
|
||||||
|
"texture_size": [512, 512],
|
||||||
|
"textures": {
|
||||||
|
"0": "szar:block/ceiling_tile_glitched_color",
|
||||||
|
"1": "szar:block/ceiling_tile_color",
|
||||||
|
"particle": "szar:block/ceiling_tile_color"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"from": [0, 0, 0],
|
||||||
|
"to": [16, 16, 16],
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [0, 0, 16, 16], "texture": "#0", "cullface": "north"},
|
||||||
|
"east": {"uv": [0, 0, 16, 16], "texture": "#0", "cullface": "east"},
|
||||||
|
"south": {"uv": [0, 0, 16, 16], "texture": "#0", "cullface": "south"},
|
||||||
|
"west": {"uv": [0, 0, 16, 16], "texture": "#0", "cullface": "west"},
|
||||||
|
"up": {"uv": [0, 0, 16, 16], "texture": "#1", "cullface": "up"},
|
||||||
|
"down": {"uv": [0, 0, 16, 16], "texture": "#1", "cullface": "down"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"display": {
|
||||||
|
"thirdperson_righthand": {
|
||||||
|
"rotation": [75, 45, 0],
|
||||||
|
"translation": [0, 2.5, 0],
|
||||||
|
"scale": [0.375, 0.375, 0.375]
|
||||||
|
},
|
||||||
|
"thirdperson_lefthand": {
|
||||||
|
"rotation": [75, 45, 0],
|
||||||
|
"translation": [0, 2.5, 0],
|
||||||
|
"scale": [0.375, 0.375, 0.375]
|
||||||
|
},
|
||||||
|
"firstperson_righthand": {
|
||||||
|
"rotation": [0, 45, 0],
|
||||||
|
"scale": [0.4, 0.4, 0.4]
|
||||||
|
},
|
||||||
|
"firstperson_lefthand": {
|
||||||
|
"rotation": [0, -135, 0],
|
||||||
|
"scale": [0.4, 0.4, 0.4]
|
||||||
|
},
|
||||||
|
"ground": {
|
||||||
|
"translation": [0, 3, 0],
|
||||||
|
"scale": [0.25, 0.25, 0.25]
|
||||||
|
},
|
||||||
|
"gui": {
|
||||||
|
"rotation": [30, -135, 0],
|
||||||
|
"scale": [0.625, 0.625, 0.625]
|
||||||
|
},
|
||||||
|
"fixed": {
|
||||||
|
"scale": [0.5, 0.5, 0.5]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/main/resources/assets/szar/models/block/plastic.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.21.11",
|
||||||
|
"credit": "Made with Blockbench",
|
||||||
|
"parent": "minecraft:block/cube_all",
|
||||||
|
"textures": {
|
||||||
|
"all": "szar:block/plastic"
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/main/resources/assets/szar/models/block/portal.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/cube_all",
|
||||||
|
"textures": {
|
||||||
|
"all": "szar:block/portal"
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/main/resources/assets/szar/models/block/tracker.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"parent": "block/air"
|
||||||
|
}
|
||||||
23
src/main/resources/assets/szar/models/block/wall.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.21.11",
|
||||||
|
"credit": "Made with Blockbench",
|
||||||
|
"parent": "block/block",
|
||||||
|
"textures": {
|
||||||
|
"all": "szar:block/wall_block",
|
||||||
|
"particle": "szar:block/wall_block"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"from": [0, 0, 0],
|
||||||
|
"to": [16, 16, 16],
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [0, 0, 16, 16], "texture": "#all", "cullface": "north"},
|
||||||
|
"east": {"uv": [0, 0, 16, 16], "texture": "#all", "cullface": "east"},
|
||||||
|
"south": {"uv": [0, 0, 16, 16], "texture": "#all", "cullface": "south"},
|
||||||
|
"west": {"uv": [0, 0, 16, 16], "texture": "#all", "cullface": "west"},
|
||||||
|
"up": {"uv": [0, 0, 16, 16], "texture": "#all"},
|
||||||
|
"down": {"uv": [0, 0, 16, 16], "texture": "#all", "cullface": "down"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
49
src/main/resources/assets/szar/models/block/wall_bottom.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.21.11",
|
||||||
|
"credit": "Made with Blockbench",
|
||||||
|
"texture_size": [64, 64],
|
||||||
|
"textures": {
|
||||||
|
"2": "szar:block/wallpaper_bottom_block_texture",
|
||||||
|
"particle": "szar:block/wallpaper_bottom_block_texture"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"from": [-1, 0, -1],
|
||||||
|
"to": [17, 2, 17],
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [0, 9, 4.5, 9.5], "texture": "#2"},
|
||||||
|
"east": {"uv": [0, 9.5, 4.5, 10], "texture": "#2"},
|
||||||
|
"south": {"uv": [0, 10, 4.5, 10.5], "texture": "#2"},
|
||||||
|
"west": {"uv": [0, 10.5, 4.5, 11], "texture": "#2"},
|
||||||
|
"up": {"uv": [4.5, 4.5, 0, 0], "texture": "#2"},
|
||||||
|
"down": {"uv": [4.5, 4.5, 0, 9], "texture": "#2"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [0, 0, 0],
|
||||||
|
"to": [16, 16, 16],
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [4.5, 0, 8.5, 4], "texture": "#2"},
|
||||||
|
"east": {"uv": [4.5, 4, 8.5, 8], "texture": "#2"},
|
||||||
|
"south": {"uv": [4.5, 8, 8.5, 12], "texture": "#2"},
|
||||||
|
"west": {"uv": [8.5, 0, 12.5, 4], "texture": "#2"},
|
||||||
|
"up": {"uv": [12.5, 8, 8.5, 4], "texture": "#2"},
|
||||||
|
"down": {"uv": [12.5, 8, 8.5, 12], "texture": "#2"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"display": {
|
||||||
|
"thirdperson_righthand": {
|
||||||
|
"rotation": [80.5, 45, 0],
|
||||||
|
"scale": [0.3, 0.3, 0.3]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "block",
|
||||||
|
"origin": [8, 8, 8],
|
||||||
|
"color": 0,
|
||||||
|
"children": [0, 1]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
3
src/main/resources/assets/szar/models/item/ceiling.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"parent": "szar:block/ceiling"
|
||||||
|
}
|
||||||
3
src/main/resources/assets/szar/models/item/plastic.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"parent": "szar:block/plastic"
|
||||||
|
}
|
||||||
3
src/main/resources/assets/szar/models/item/portal.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"parent": "szar:block/portal"
|
||||||
|
}
|
||||||
6
src/main/resources/assets/szar/models/item/tracker.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "szar:item/tracker"
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/main/resources/assets/szar/models/item/wall.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"parent": "szar:block/wall"
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"parent": "szar:block/wall_bottom"
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 420 KiB |
|
After Width: | Height: | Size: 16 KiB |
BIN
src/main/resources/assets/szar/textures/block/empty.png
Normal file
|
After Width: | Height: | Size: 528 B |
BIN
src/main/resources/assets/szar/textures/block/plastic.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
src/main/resources/assets/szar/textures/block/portal.png
Normal file
|
After Width: | Height: | Size: 688 B |
BIN
src/main/resources/assets/szar/textures/block/wall_block.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 87 KiB |
BIN
src/main/resources/assets/szar/textures/item/backrooms_wall.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 99 B |
|
After Width: | Height: | Size: 162 B |
|
After Width: | Height: | Size: 202 B |
|
After Width: | Height: | Size: 161 B |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 421 KiB |
|
After Width: | Height: | Size: 348 KiB |
|
After Width: | Height: | Size: 517 KiB |
|
After Width: | Height: | Size: 479 KiB |
|
After Width: | Height: | Size: 523 KiB |
|
After Width: | Height: | Size: 295 KiB |
|
After Width: | Height: | Size: 140 KiB |
|
After Width: | Height: | Size: 133 KiB |
|
After Width: | Height: | Size: 469 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 587 B |
|
After Width: | Height: | Size: 235 B |
|
After Width: | Height: | Size: 231 B |
|
After Width: | Height: | Size: 221 B |
|
After Width: | Height: | Size: 221 B |
|
After Width: | Height: | Size: 96 B |
|
After Width: | Height: | Size: 100 B |
|
After Width: | Height: | Size: 179 B |
|
After Width: | Height: | Size: 378 KiB |
|
After Width: | Height: | Size: 474 KiB |
|
After Width: | Height: | Size: 482 KiB |
|
After Width: | Height: | Size: 116 B |
|
After Width: | Height: | Size: 142 KiB |
|
After Width: | Height: | Size: 2.3 MiB |
|
After Width: | Height: | Size: 4.8 MiB |
|
After Width: | Height: | Size: 23 MiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 502 B |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 420 KiB |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 242 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 911 KiB |
|
After Width: | Height: | Size: 113 KiB |
|
After Width: | Height: | Size: 918 KiB |
|
After Width: | Height: | Size: 693 KiB |
|
After Width: | Height: | Size: 264 KiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 1.5 MiB |