Public Access
This commit is contained in:
1 parent
9d5ff2a2cb
commit
2f1e6bd6f2
6 files changed
+58
-10
No files matched your search
+1
-1
@@ -36,7 +36,7 @@ mod_name=Rivencraft
|
||||
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
|
||||
mod_license=LGPL-3.0-or-later
|
||||
# The mod version. Rivencraft uses the x.y.z.b policy documented in README.md.
|
||||
mod_version=0.6.8.10
|
||||
mod_version=0.6.8.11
|
||||
immersive_portals_version=6.0.7
|
||||
terrablender_version=4.1.0.8
|
||||
serene_seasons_version_id=pHEgQQUE
|
||||
|
||||
@@ -36,6 +36,7 @@ import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
@@ -44,10 +45,11 @@ import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
public final class BookReceptacleBlock extends BaseEntityBlock {
|
||||
public static final MapCodec<BookReceptacleBlock> CODEC = simpleCodec(BookReceptacleBlock::new);
|
||||
public static final DirectionProperty FACING = BlockStateProperties.FACING;
|
||||
public static final BooleanProperty HAS_BOOK = BlockStateProperties.HAS_BOOK;
|
||||
|
||||
public BookReceptacleBlock(Properties properties) {
|
||||
super(properties);
|
||||
registerDefaultState(stateDefinition.any().setValue(FACING, Direction.NORTH));
|
||||
registerDefaultState(stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(HAS_BOOK, false));
|
||||
}
|
||||
|
||||
@Override protected MapCodec<? extends BaseEntityBlock> codec() { return CODEC; }
|
||||
@@ -64,7 +66,7 @@ public final class BookReceptacleBlock extends BaseEntityBlock {
|
||||
};
|
||||
}
|
||||
@Override protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||
builder.add(FACING);
|
||||
builder.add(FACING, HAS_BOOK);
|
||||
}
|
||||
@Override public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new BookReceptacleBlockEntity(pos, state);
|
||||
@@ -153,7 +155,7 @@ public final class BookReceptacleBlock extends BaseEntityBlock {
|
||||
if (!state.is(replacement.getBlock()) && level instanceof ServerLevel server) {
|
||||
CrystalPortalNetwork.shutdown(server, pos);
|
||||
if (level.getBlockEntity(pos) instanceof BookReceptacleBlockEntity holder) {
|
||||
ItemStack book = holder.takeBook();
|
||||
ItemStack book = holder.takeBookOnBreak();
|
||||
if (!book.isEmpty()) level.addFreshEntity(new ItemEntity(level, pos.getX()+0.5, pos.getY()+0.5,
|
||||
pos.getZ()+0.5, book));
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package net.dnorberg.rivencraft.block.entity;
|
||||
|
||||
import net.dnorberg.rivencraft.book.LinkTarget;
|
||||
import net.dnorberg.rivencraft.book.AgeEnvironmentCompiler;
|
||||
import net.dnorberg.rivencraft.block.BookReceptacleBlock;
|
||||
import net.dnorberg.rivencraft.registry.ModBlockEntities;
|
||||
import net.dnorberg.rivencraft.registry.ModBlocks;
|
||||
import net.dnorberg.rivencraft.portal.CrystalPortalNetwork;
|
||||
import net.minecraft.nbt.NbtOps;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@@ -52,18 +54,36 @@ public final class BookReceptacleBlockEntity extends BlockEntity {
|
||||
}
|
||||
|
||||
public ItemStack takeBook() {
|
||||
return removeBook(true);
|
||||
}
|
||||
|
||||
/** The block is already being replaced, so do not write its state back into the world. */
|
||||
public ItemStack takeBookOnBreak() {
|
||||
return removeBook(false);
|
||||
}
|
||||
|
||||
private ItemStack removeBook(boolean notify) {
|
||||
ItemStack result = book;
|
||||
book = ItemStack.EMPTY;
|
||||
destination = null;
|
||||
skyColor = 0xFFFFFF;
|
||||
sync();
|
||||
if (notify) sync();
|
||||
else setChanged();
|
||||
return result;
|
||||
}
|
||||
|
||||
private void sync() {
|
||||
setChanged();
|
||||
if (level != null && !level.isClientSide)
|
||||
level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 2);
|
||||
if (level instanceof ServerLevel server) {
|
||||
BlockState state = server.getBlockState(worldPosition);
|
||||
if (!state.is(ModBlocks.BOOK_RECEPTACLE.get())) return;
|
||||
boolean hasBook = !book.isEmpty();
|
||||
if (state.getValue(BookReceptacleBlock.HAS_BOOK) != hasBook) {
|
||||
state = state.setValue(BookReceptacleBlock.HAS_BOOK, hasBook);
|
||||
server.setBlock(worldPosition, state, 2);
|
||||
}
|
||||
server.sendBlockUpdated(worldPosition, state, state, 2);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,6 +118,10 @@ public final class BookReceptacleBlockEntity extends BlockEntity {
|
||||
public static void serverTick(net.minecraft.world.level.Level world, BlockPos pos, BlockState state,
|
||||
BookReceptacleBlockEntity holder) {
|
||||
if (!(world instanceof ServerLevel level)) return;
|
||||
// Reconcile receptacles saved before HAS_BOOK existed, including an
|
||||
// occupied receptacle restored from an older pre-release world.
|
||||
boolean hasBook = !holder.book.isEmpty();
|
||||
if (state.getValue(BookReceptacleBlock.HAS_BOOK) != hasBook) holder.sync();
|
||||
if (holder.book.isEmpty() || (!holder.restoreView && level.getGameTime() % 200 != 0)) return;
|
||||
// Startup maintenance must never turn a saved portal off while its
|
||||
// chunks and block entities are still arriving. Structural edits are
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.mojang.math.Axis;
|
||||
import net.dnorberg.rivencraft.block.BookReceptacleBlock;
|
||||
import net.dnorberg.rivencraft.block.entity.BookReceptacleBlockEntity;
|
||||
import net.dnorberg.rivencraft.registry.ModBlocks;
|
||||
import net.dnorberg.rivencraft.registry.ModItems;
|
||||
import net.minecraft.client.model.BookModel;
|
||||
import net.minecraft.client.model.geom.ModelLayers;
|
||||
@@ -30,11 +31,15 @@ public final class BookReceptacleRenderer implements BlockEntityRenderer<BookRec
|
||||
@Override
|
||||
public void render(BookReceptacleBlockEntity receptacle, float partialTick, PoseStack poseStack,
|
||||
MultiBufferSource buffers, int packedLight, int packedOverlay) {
|
||||
if (receptacle.getBook().isEmpty()) return;
|
||||
if (receptacle.getLevel() == null) return;
|
||||
var state = receptacle.getLevel().getBlockState(receptacle.getBlockPos());
|
||||
if (!state.is(ModBlocks.BOOK_RECEPTACLE.get())
|
||||
|| !state.getValue(BookReceptacleBlock.HAS_BOOK)
|
||||
|| receptacle.getBook().isEmpty()) return;
|
||||
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(0.5, 0.5, 0.5);
|
||||
Direction facing = receptacle.getBlockState().getValue(BookReceptacleBlock.FACING);
|
||||
Direction facing = state.getValue(BookReceptacleBlock.FACING);
|
||||
switch (facing) {
|
||||
case UP -> {
|
||||
// Rotate the whole assembled top-mounted receptacle/book pair
|
||||
|
||||
@@ -53,6 +53,8 @@ public final class CrystalPortalGameTests {
|
||||
helper.assertTrue(plan.valid(), "A closed crystal frame must form a portal");
|
||||
BookReceptacleBlockEntity holder = (BookReceptacleBlockEntity) level.getBlockEntity(holderPos);
|
||||
holder.setBook(new ItemStack(ModItems.LINKING_BOOK.get()));
|
||||
helper.assertTrue(level.getBlockState(holderPos).getValue(BookReceptacleBlock.HAS_BOOK),
|
||||
"An occupied receptacle must expose its book state to client renderers");
|
||||
LinkTarget destination = new LinkTarget(GlobalPos.of(level.dimension(), centerTarget(helper)), 0, 0);
|
||||
holder.setDestination(destination);
|
||||
BookReceptacleBlockEntity restored = new BookReceptacleBlockEntity(holderPos, holder.getBlockState());
|
||||
@@ -89,6 +91,12 @@ public final class CrystalPortalGameTests {
|
||||
"A north/south opening must only show its two player-facing sides");
|
||||
CrystalPortalNetwork.shutdown(level, holderPos);
|
||||
helper.assertTrue(level.getBlockState(center).isAir(), "Removing the book must release the portal");
|
||||
helper.assertTrue(holder.takeBook().is(ModItems.LINKING_BOOK.get()),
|
||||
"Removing the book must return the stored item");
|
||||
helper.assertTrue(!level.getBlockState(holderPos).getValue(BookReceptacleBlock.HAS_BOOK),
|
||||
"Removing the book must clear the client-visible model state");
|
||||
helper.assertTrue(!holder.getUpdateTag(level.registryAccess()).contains("Book"),
|
||||
"The block-entity update must also clear the old client-side book stack");
|
||||
helper.succeed();
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1,10 @@
|
||||
{"variants":{"facing=north":{"model":"rivencraft:block/book_receptacle","y":180},"facing=east":{"model":"rivencraft:block/book_receptacle","y":270},"facing=south":{"model":"rivencraft:block/book_receptacle"},"facing=west":{"model":"rivencraft:block/book_receptacle","y":90},"facing=up":{"model":"rivencraft:block/book_receptacle","x":90},"facing=down":{"model":"rivencraft:block/book_receptacle","x":270,"y":180}}}
|
||||
{
|
||||
"multipart": [
|
||||
{"when": {"facing": "north"}, "apply": {"model": "rivencraft:block/book_receptacle", "y": 180}},
|
||||
{"when": {"facing": "east"}, "apply": {"model": "rivencraft:block/book_receptacle", "y": 270}},
|
||||
{"when": {"facing": "south"}, "apply": {"model": "rivencraft:block/book_receptacle"}},
|
||||
{"when": {"facing": "west"}, "apply": {"model": "rivencraft:block/book_receptacle", "y": 90}},
|
||||
{"when": {"facing": "up"}, "apply": {"model": "rivencraft:block/book_receptacle", "x": 90}},
|
||||
{"when": {"facing": "down"}, "apply": {"model": "rivencraft:block/book_receptacle", "x": 270, "y": 180}}
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user