mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-23 21:38:00 +01:00
Crystal doors can now be locked by providing them a signed bangle of comradery.
When locked they will only let the owner or players wearing a signed bangle through. Also you can't cheat them
This commit is contained in:
parent
b99c6b6c29
commit
408c9d11c0
7 changed files with 182 additions and 28 deletions
|
@ -1,64 +1,182 @@
|
|||
package com.minelittlepony.unicopia.block;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.EquineContext;
|
||||
import com.minelittlepony.unicopia.Race;
|
||||
import com.minelittlepony.unicopia.USounds;
|
||||
import com.minelittlepony.unicopia.item.FriendshipBraceletItem;
|
||||
import com.minelittlepony.unicopia.item.UItems;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockEntityProvider;
|
||||
import net.minecraft.block.BlockSetType;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.DoorBlock;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.block.enums.DoubleBlockHalf;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.state.StateManager;
|
||||
import net.minecraft.state.property.BooleanProperty;
|
||||
import net.minecraft.state.property.Properties;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.event.GameEvent;
|
||||
|
||||
public class CrystalDoorBlock extends DoorBlock {
|
||||
public class CrystalDoorBlock extends DoorBlock implements BlockEntityProvider {
|
||||
public static final BooleanProperty LOCKED = Properties.LOCKED;
|
||||
|
||||
public CrystalDoorBlock(Settings settings, BlockSetType blockSet) {
|
||||
super(settings, blockSet);
|
||||
setDefaultState(getDefaultState().with(LOCKED, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||
super.appendProperties(builder);
|
||||
builder.add(LOCKED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRandomTicks(BlockState state) {
|
||||
return state.get(LOCKED);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void randomTick(BlockState state, ServerWorld world, BlockPos pos, Random random) {
|
||||
super.randomTick(state, world, pos, random);
|
||||
if (!isLocked(world, pos)) {
|
||||
setOnGuard(state, world, pos, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void neighborUpdate(BlockState state, World world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) {
|
||||
boolean powered = world.isReceivingRedstonePower(pos) || world.isReceivingRedstonePower(pos.offset(state.get(HALF) == DoubleBlockHalf.LOWER ? Direction.UP : Direction.DOWN));
|
||||
if (!getDefaultState().isOf(sourceBlock) && powered != state.get(POWERED)) {
|
||||
if (powered) {
|
||||
state = state.cycle(OPEN);
|
||||
playOpenCloseSound(null, world, pos, state.get(OPEN));
|
||||
world.emitGameEvent(null, state.get(OPEN) ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, pos);
|
||||
}
|
||||
if (!state.get(LOCKED)) {
|
||||
boolean powered = world.isReceivingRedstonePower(pos) || world.isReceivingRedstonePower(pos.offset(state.get(HALF) == DoubleBlockHalf.LOWER ? Direction.UP : Direction.DOWN));
|
||||
if (!getDefaultState().isOf(sourceBlock) && powered != state.get(POWERED)) {
|
||||
if (powered) {
|
||||
state = state.cycle(OPEN);
|
||||
playOpenCloseSound(null, world, pos, state.get(OPEN));
|
||||
world.emitGameEvent(null, state.get(OPEN) ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, pos);
|
||||
}
|
||||
|
||||
world.setBlockState(pos, state.with(POWERED, powered), Block.NOTIFY_LISTENERS);
|
||||
world.setBlockState(pos, state.with(POWERED, powered), Block.NOTIFY_LISTENERS);
|
||||
}
|
||||
}
|
||||
|
||||
if (state.get(HALF) == DoubleBlockHalf.LOWER && sourcePos.getY() == pos.getY() - 1) {
|
||||
if (!canPlaceAt(state, world, pos) && world.isAir(sourcePos)) {
|
||||
world.setBlockState(sourcePos, Blocks.DIRT.getDefaultState());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
|
||||
if (!EquineContext.of(player).getCompositeRace().any(Race::canCast)) {
|
||||
|
||||
if (!player.getStackInHand(hand).isOf(UItems.MEADOWBROOKS_STAFF)) {
|
||||
if (!shouldProvideAccess(world, pos, player)) {
|
||||
if (isLocked(world, pos) || !player.getStackInHand(hand).isOf(UItems.MEADOWBROOKS_STAFF)) {
|
||||
playOpenCloseSound(player, world, pos, false);
|
||||
return ActionResult.FAIL;
|
||||
setOnGuard(state, world, pos, true);
|
||||
return ActionResult.CONSUME;
|
||||
} else {
|
||||
world.playSound(player, pos, USounds.ENTITY_CRYSTAL_SHARDS_AMBIENT, SoundCategory.BLOCKS, 1, world.getRandom().nextFloat() * 0.1F + 0.9F);
|
||||
}
|
||||
} else if (!isLocked(world, pos)) {
|
||||
ItemStack heldStack = player.getStackInHand(hand);
|
||||
if (heldStack.isOf(UItems.FRIENDSHIP_BRACELET)) {
|
||||
@Nullable
|
||||
UUID signator = FriendshipBraceletItem.getSignatorId(heldStack);
|
||||
if (signator != null) {
|
||||
BlockEntityUtil.getOrCreateBlockEntity(world, state.get(HALF) == DoubleBlockHalf.LOWER ? pos.up() : pos, UBlockEntities.CRYSTAL_DOOR).ifPresent(data -> {
|
||||
data.setSignator(signator);
|
||||
setOnGuard(state, world, pos, true);
|
||||
world.playSound(player, pos, USounds.ENTITY_CRYSTAL_SHARDS_AMBIENT, SoundCategory.BLOCKS, 1, world.getRandom().nextFloat() * 0.1F + 0.9F);
|
||||
});
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
} else {
|
||||
setOnGuard(state, world, pos, false);
|
||||
}
|
||||
}
|
||||
return super.onUse(state, world, pos, player, hand, hit);
|
||||
}
|
||||
|
||||
private void setOnGuard(BlockState state, World world, BlockPos pos, boolean locked) {
|
||||
world.setBlockState(pos, state.with(LOCKED, locked));
|
||||
pos = pos.offset(state.get(HALF) == DoubleBlockHalf.LOWER ? Direction.UP : Direction.DOWN);
|
||||
state = world.getBlockState(pos);
|
||||
if (state.isOf(this)) {
|
||||
world.setBlockState(pos, state.with(LOCKED, locked));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldProvideAccess(World world, BlockPos pos, PlayerEntity player) {
|
||||
UUID signator = getSignator(world, pos);
|
||||
if (signator != null) {
|
||||
return signator.equals(player.getUuid()) || FriendshipBraceletItem.isComrade(signator, player);
|
||||
}
|
||||
return EquineContext.of(player).getCompositeRace().any(Race::canCast);
|
||||
}
|
||||
|
||||
private boolean isLocked(World world, BlockPos pos) {
|
||||
return getSignator(world, pos) != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private UUID getSignator(World world, BlockPos pos) {
|
||||
pos = world.getBlockState(pos).get(HALF) == DoubleBlockHalf.LOWER ? pos.up() : pos;
|
||||
var d = world.getBlockEntity(pos, UBlockEntities.CRYSTAL_DOOR);
|
||||
return d.map(data -> data.signator).orElse(null);
|
||||
}
|
||||
|
||||
private void playOpenCloseSound(@Nullable Entity entity, World world, BlockPos pos, boolean open) {
|
||||
world.playSound(entity, pos, open ? getBlockSetType().doorOpen() : getBlockSetType().doorClose(), SoundCategory.BLOCKS, 1, world.getRandom().nextFloat() * 0.1f + 0.9f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new TileData(pos, state);
|
||||
}
|
||||
|
||||
public static class TileData extends BlockEntity {
|
||||
@Nullable
|
||||
private UUID signator;
|
||||
|
||||
public TileData(BlockPos pos, BlockState state) {
|
||||
super(UBlockEntities.CRYSTAL_DOOR, pos, state);
|
||||
}
|
||||
|
||||
public void setSignator(UUID signator) {
|
||||
this.signator = signator;
|
||||
markDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readNbt(NbtCompound nbt) {
|
||||
signator = nbt.containsUuid("signator") ? nbt.getUuid("signator") : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeNbt(NbtCompound nbt) {
|
||||
if (signator != null) {
|
||||
nbt.putUuid("signator", signator);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ public interface UBlockEntities {
|
|||
BlockEntityType<ChestBlockEntity> CLOUD_CHEST = create("cloud_chest", BlockEntityType.Builder.create(CloudChestBlock.TileData::new, UBlocks.CLOUD_CHEST));
|
||||
BlockEntityType<HiveBlock.TileData> HIVE_STORAGE = create("hive_storage", BlockEntityType.Builder.create(HiveBlock.TileData::new, UBlocks.HIVE));
|
||||
BlockEntityType<ItemJarBlock.TileData> ITEM_JAR = create("item_jar", BlockEntityType.Builder.create(ItemJarBlock.TileData::new, UBlocks.JAR));
|
||||
BlockEntityType<CrystalDoorBlock.TileData> CRYSTAL_DOOR = create("crystal_door", BlockEntityType.Builder.create(CrystalDoorBlock.TileData::new, UBlocks.CRYSTAL_DOOR));
|
||||
|
||||
static <T extends BlockEntity> BlockEntityType<T> create(String id, Builder<T> builder) {
|
||||
return Registry.register(Registries.BLOCK_ENTITY_TYPE, id, builder.build(null));
|
||||
|
|
|
@ -34,6 +34,7 @@ import net.minecraft.data.client.Model;
|
|||
import net.minecraft.data.client.ModelIds;
|
||||
import net.minecraft.data.client.Models;
|
||||
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||
import net.minecraft.data.client.TextureKey;
|
||||
import net.minecraft.data.client.TextureMap;
|
||||
import net.minecraft.data.client.TexturedModel;
|
||||
import net.minecraft.data.client.VariantSettings;
|
||||
|
@ -89,7 +90,8 @@ public class UBlockStateModelGenerator extends BlockStateModelGenerator {
|
|||
registerAll((g, block) -> g.registerParentedItemModel(block, ModelIds.getBlockModelId(block)), UBlocks.SHAPING_BENCH, UBlocks.SURFACE_CHITIN);
|
||||
registerAll(UBlockStateModelGenerator::registerSimpleState, UBlocks.SHAPING_BENCH, UBlocks.BANANAS);
|
||||
// doors
|
||||
registerAll(UBlockStateModelGenerator::registerStableDoor, UBlocks.STABLE_DOOR, UBlocks.DARK_OAK_DOOR, UBlocks.CRYSTAL_DOOR, UBlocks.CLOUD_DOOR);
|
||||
registerAll(UBlockStateModelGenerator::registerStableDoor, UBlocks.STABLE_DOOR, UBlocks.DARK_OAK_DOOR, UBlocks.CLOUD_DOOR);
|
||||
registerLockingDoor(UBlocks.CRYSTAL_DOOR);
|
||||
|
||||
// cloud blocks
|
||||
createCustomTexturePool(UBlocks.CLOUD, TexturedModel.CUBE_ALL).same(UBlocks.UNSTABLE_CLOUD).slab(UBlocks.CLOUD_SLAB).stairs(UBlocks.CLOUD_STAIRS);
|
||||
|
@ -347,23 +349,37 @@ public class UBlockStateModelGenerator extends BlockStateModelGenerator {
|
|||
}
|
||||
|
||||
public void registerStableDoor(Block door) {
|
||||
TextureMap topTextures = TextureMap.topBottom(door);
|
||||
TextureMap bottomTextures = topTextures.copyAndAdd(TOP, topTextures.getTexture(BOTTOM));
|
||||
registerItemModel(door.asItem());
|
||||
var variants = BlockStateVariantMap.create(Properties.HORIZONTAL_FACING, Properties.DOUBLE_BLOCK_HALF, Properties.DOOR_HINGE, Properties.OPEN);
|
||||
fillStableDoorVariantMap(variants, DoubleBlockHalf.LOWER,
|
||||
BlockModels.DOOR_LEFT.upload(door, "_bottom_left", bottomTextures, modelCollector),
|
||||
BlockModels.DOOR_RIGHT.upload(door, "_bottom_right", bottomTextures, modelCollector)
|
||||
);
|
||||
fillStableDoorVariantMap(variants, DoubleBlockHalf.UPPER,
|
||||
BlockModels.DOOR_LEFT.upload(door, "_top_left", topTextures, modelCollector),
|
||||
BlockModels.DOOR_RIGHT.upload(door, "_top_right", topTextures, modelCollector)
|
||||
);
|
||||
registerItemModel(door.asItem());
|
||||
buildDoorStateModels(door, "", variants::register);
|
||||
blockStateCollector.accept(VariantsBlockStateSupplier.create(door).coordinate(variants));
|
||||
}
|
||||
|
||||
public static void fillStableDoorVariantMap(
|
||||
BlockStateVariantMap.QuadrupleProperty<Direction, DoubleBlockHalf, DoorHinge, Boolean> variantMap,
|
||||
public void registerLockingDoor(Block door) {
|
||||
var variants = BlockStateVariantMap.create(Properties.HORIZONTAL_FACING, Properties.DOUBLE_BLOCK_HALF, Properties.DOOR_HINGE, Properties.OPEN, Properties.LOCKED);
|
||||
registerItemModel(door.asItem());
|
||||
buildDoorStateModels(door, "", (facing, half, hinge, open, map) -> variants.register(facing, half, hinge, open, false, map));
|
||||
buildDoorStateModels(door, "_locked", (facing, half, hinge, open, map) -> variants.register(facing, half, hinge, open, true, map));
|
||||
blockStateCollector.accept(VariantsBlockStateSupplier.create(door).coordinate(variants));
|
||||
}
|
||||
|
||||
private void buildDoorStateModels(Block door, String suffex, DoorStateConsumer variants) {
|
||||
TextureMap topTextures = new TextureMap()
|
||||
.put(TextureKey.TOP, TextureMap.getSubId(door, "_top" + suffex))
|
||||
.put(TextureKey.BOTTOM, TextureMap.getSubId(door, "_bottom" + suffex));
|
||||
TextureMap bottomTextures = topTextures.copyAndAdd(TOP, topTextures.getTexture(BOTTOM));
|
||||
fillStableDoorVariantMap(variants, DoubleBlockHalf.LOWER,
|
||||
BlockModels.DOOR_LEFT.upload(door, "_bottom_left" + suffex, bottomTextures, modelCollector),
|
||||
BlockModels.DOOR_RIGHT.upload(door, "_bottom_right" + suffex, bottomTextures, modelCollector)
|
||||
);
|
||||
fillStableDoorVariantMap(variants, DoubleBlockHalf.UPPER,
|
||||
BlockModels.DOOR_LEFT.upload(door, "_top_left" + suffex, topTextures, modelCollector),
|
||||
BlockModels.DOOR_RIGHT.upload(door, "_top_right" + suffex, topTextures, modelCollector)
|
||||
);
|
||||
}
|
||||
|
||||
private static void fillStableDoorVariantMap(
|
||||
DoorStateConsumer variantMap,
|
||||
DoubleBlockHalf targetHalf, Identifier leftModelId, Identifier rightModelId) {
|
||||
fillStableDoorVariantMap(variantMap, targetHalf, DoorHinge.LEFT, false, R0, leftModelId);
|
||||
fillStableDoorVariantMap(variantMap, targetHalf, DoorHinge.RIGHT, false, R0, rightModelId);
|
||||
|
@ -373,7 +389,7 @@ public class UBlockStateModelGenerator extends BlockStateModelGenerator {
|
|||
}
|
||||
|
||||
public static void fillStableDoorVariantMap(
|
||||
BlockStateVariantMap.QuadrupleProperty<Direction, DoubleBlockHalf, DoorHinge, Boolean> variantMap,
|
||||
DoorStateConsumer variantMap,
|
||||
DoubleBlockHalf targetHalf,
|
||||
DoorHinge hinge, boolean open, Rotation rotation,
|
||||
Identifier modelId) {
|
||||
|
@ -386,6 +402,10 @@ public class UBlockStateModelGenerator extends BlockStateModelGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
interface DoorStateConsumer {
|
||||
void register(Direction direction, DoubleBlockHalf half, DoorHinge hinge, boolean open, BlockStateVariant variant);
|
||||
}
|
||||
|
||||
public void registerPillar(Block pillar) {
|
||||
TextureMap textures = new TextureMap()
|
||||
.put(SIDE, ModelIds.getBlockSubModelId(pillar, "_side"))
|
||||
|
|
|
@ -124,6 +124,10 @@ public class FriendshipBraceletItem extends WearableItem implements DyeableItem,
|
|||
.isPresent();
|
||||
}
|
||||
|
||||
public static boolean isComrade(UUID signator, Entity entity) {
|
||||
return entity instanceof LivingEntity l && getWornBangles(l).anyMatch(stack -> isSignedBy(stack, signator));
|
||||
}
|
||||
|
||||
public static Stream<Pony> getPartyMembers(Caster<?> caster, double radius) {
|
||||
return Pony.stream(caster.findAllEntitiesInRange(radius, entity -> isComrade(caster, entity)));
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 6.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"animation": {
|
||||
"frametime": 200,
|
||||
"frames": [
|
||||
0, 1, 2, 3,
|
||||
1, 2, 3, 0,
|
||||
2, 3, 0, 1,
|
||||
3, 0, 1, 2
|
||||
]
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue