truffalo, hoverboard first drafts, underside music disc
This commit is contained in:
1 parent
5596a9187d
commit
0b75b1ab1d
554 files changed
+14118
-196
No files matched your search
+76
@@ -0,0 +1,76 @@
|
|||||||
|
package com.craisinlord.antarchy.content.block;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.block.entity.PortalGunPortalBaseBlockEntity;
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.BaseEntityBlock;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.RenderShape;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.Shapes;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
|
||||||
|
public class PortalGunPortalBaseBlock extends BaseEntityBlock {
|
||||||
|
private static final VoxelShape EMPTY = Shapes.empty();
|
||||||
|
private final Supplier<? extends BlockEntityType<PortalGunPortalBaseBlockEntity>> blockEntityTypeSupplier;
|
||||||
|
private final MapCodec<PortalGunPortalBaseBlock> codec;
|
||||||
|
|
||||||
|
public PortalGunPortalBaseBlock(Supplier<? extends BlockEntityType<PortalGunPortalBaseBlockEntity>> blockEntityTypeSupplier, BlockBehaviour.Properties properties) {
|
||||||
|
super(properties);
|
||||||
|
this.blockEntityTypeSupplier = blockEntityTypeSupplier;
|
||||||
|
this.codec = Block.simpleCodec(ignored -> this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapCodec<PortalGunPortalBaseBlock> codec() {
|
||||||
|
return this.codec;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RenderShape getRenderShape(BlockState state) {
|
||||||
|
return RenderShape.INVISIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
|
||||||
|
return EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
|
||||||
|
return EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
||||||
|
return new PortalGunPortalBaseBlockEntity(pos, state, this.blockEntityTypeSupplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
|
||||||
|
if (level.isClientSide) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return createTickerHelper(blockEntityType, this.blockEntityTypeSupplier.get(), (tickLevel, tickPos, tickState, blockEntity) -> {
|
||||||
|
if (tickLevel instanceof net.minecraft.server.level.ServerLevel serverLevel) {
|
||||||
|
PortalGunPortalBaseBlockEntity.serverTick(serverLevel, tickPos, tickState, blockEntity);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
|
||||||
|
if (!state.is(newState.getBlock()) && level.getBlockEntity(pos) instanceof PortalGunPortalBaseBlockEntity blockEntity) {
|
||||||
|
blockEntity.onBroken();
|
||||||
|
}
|
||||||
|
super.onRemove(state, level, pos, newState, movedByPiston);
|
||||||
|
}
|
||||||
|
}
|
||||||
+76
@@ -0,0 +1,76 @@
|
|||||||
|
package com.craisinlord.antarchy.content.block;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.block.entity.PortalGunPortalMasterBlockEntity;
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.BaseEntityBlock;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.RenderShape;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.Shapes;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
|
||||||
|
public class PortalGunPortalMasterBlock extends BaseEntityBlock {
|
||||||
|
private static final VoxelShape EMPTY = Shapes.empty();
|
||||||
|
private final Supplier<? extends BlockEntityType<PortalGunPortalMasterBlockEntity>> blockEntityTypeSupplier;
|
||||||
|
private final MapCodec<PortalGunPortalMasterBlock> codec;
|
||||||
|
|
||||||
|
public PortalGunPortalMasterBlock(Supplier<? extends BlockEntityType<PortalGunPortalMasterBlockEntity>> blockEntityTypeSupplier, BlockBehaviour.Properties properties) {
|
||||||
|
super(properties);
|
||||||
|
this.blockEntityTypeSupplier = blockEntityTypeSupplier;
|
||||||
|
this.codec = Block.simpleCodec(ignored -> this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapCodec<PortalGunPortalMasterBlock> codec() {
|
||||||
|
return this.codec;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RenderShape getRenderShape(BlockState state) {
|
||||||
|
return RenderShape.INVISIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
|
||||||
|
return EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
|
||||||
|
return EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
||||||
|
return new PortalGunPortalMasterBlockEntity(pos, state, this.blockEntityTypeSupplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
|
||||||
|
if (level.isClientSide) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return createTickerHelper(blockEntityType, this.blockEntityTypeSupplier.get(), (tickLevel, tickPos, tickState, blockEntity) -> {
|
||||||
|
if (tickLevel instanceof net.minecraft.server.level.ServerLevel serverLevel) {
|
||||||
|
PortalGunPortalMasterBlockEntity.serverTick(serverLevel, tickPos, tickState, blockEntity);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
|
||||||
|
if (!state.is(newState.getBlock()) && level.getBlockEntity(pos) instanceof PortalGunPortalMasterBlockEntity blockEntity) {
|
||||||
|
blockEntity.onBroken();
|
||||||
|
}
|
||||||
|
super.onRemove(state, level, pos, newState, movedByPiston);
|
||||||
|
}
|
||||||
|
}
|
||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
package com.craisinlord.antarchy.content.block;
|
||||||
|
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.tags.BlockTags;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.BushBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
|
||||||
|
public class RoyalSaplingBlock extends BushBlock {
|
||||||
|
public static final MapCodec<RoyalSaplingBlock> CODEC = Block.simpleCodec(RoyalSaplingBlock::new);
|
||||||
|
private static final VoxelShape SHAPE = Block.box(2.0D, 0.0D, 2.0D, 14.0D, 12.0D, 14.0D);
|
||||||
|
|
||||||
|
public RoyalSaplingBlock(BlockBehaviour.Properties properties) {
|
||||||
|
super(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapCodec<RoyalSaplingBlock> codec() {
|
||||||
|
return CODEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
|
||||||
|
return SHAPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos) {
|
||||||
|
return state.is(BlockTags.DIRT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
|
||||||
|
BlockState belowState = level.getBlockState(pos.below());
|
||||||
|
return belowState.is(BlockTags.DIRT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BlockState updateShape(
|
||||||
|
BlockState state,
|
||||||
|
Direction direction,
|
||||||
|
BlockState neighborState,
|
||||||
|
LevelAccessor level,
|
||||||
|
BlockPos pos,
|
||||||
|
BlockPos neighborPos
|
||||||
|
) {
|
||||||
|
return state.canSurvive(level, pos)
|
||||||
|
? super.updateShape(state, direction, neighborState, level, pos, neighborPos)
|
||||||
|
: Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
}
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
package com.craisinlord.antarchy.content.block;
|
||||||
|
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.RotatedPillarBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
|
||||||
|
public class TruffaloLogBlock extends RotatedPillarBlock {
|
||||||
|
public static final MapCodec<TruffaloLogBlock> CODEC = Block.simpleCodec(TruffaloLogBlock::new);
|
||||||
|
|
||||||
|
private static final VoxelShape SHAPE_Y = Block.box(4.0D, 0.0D, 4.0D, 12.0D, 16.0D, 12.0D);
|
||||||
|
private static final VoxelShape SHAPE_X = Block.box(0.0D, 4.0D, 4.0D, 16.0D, 12.0D, 12.0D);
|
||||||
|
private static final VoxelShape SHAPE_Z = Block.box(4.0D, 4.0D, 0.0D, 12.0D, 12.0D, 16.0D);
|
||||||
|
|
||||||
|
public TruffaloLogBlock(BlockBehaviour.Properties properties) {
|
||||||
|
super(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapCodec<TruffaloLogBlock> codec() {
|
||||||
|
return CODEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
|
||||||
|
return shapeFor(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
|
||||||
|
return shapeFor(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected VoxelShape getOcclusionShape(BlockState state, BlockGetter level, BlockPos pos) {
|
||||||
|
return shapeFor(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static VoxelShape shapeFor(BlockState state) {
|
||||||
|
return switch (state.getValue(AXIS)) {
|
||||||
|
case X -> SHAPE_X;
|
||||||
|
case Z -> SHAPE_Z;
|
||||||
|
default -> SHAPE_Y;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
+110
@@ -0,0 +1,110 @@
|
|||||||
|
package com.craisinlord.antarchy.content.block;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import com.craisinlord.antarchy.content.worldgen.truffalo.TruffaloTreeGrowers;
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.core.Holder;
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.tags.TagKey;
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.BonemealableBlock;
|
||||||
|
import net.minecraft.world.level.block.BushBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
|
||||||
|
public class TruffaloSaplingBlock extends BushBlock implements BonemealableBlock {
|
||||||
|
public static final MapCodec<TruffaloSaplingBlock> CODEC = Block.simpleCodec(TruffaloSaplingBlock::new);
|
||||||
|
private static final TagKey<Block> SUPPORTS = TagKey.create(
|
||||||
|
Registries.BLOCK,
|
||||||
|
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "truffalo_sapling_supports")
|
||||||
|
);
|
||||||
|
private static final VoxelShape SHAPE = Block.box(2.0D, 4.0D, 2.0D, 14.0D, 16.0D, 14.0D);
|
||||||
|
|
||||||
|
public TruffaloSaplingBlock(BlockBehaviour.Properties properties) {
|
||||||
|
super(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapCodec<TruffaloSaplingBlock> codec() {
|
||||||
|
return CODEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
|
||||||
|
return SHAPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos) {
|
||||||
|
return state.is(SUPPORTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
|
||||||
|
BlockPos supportPos = pos.below();
|
||||||
|
BlockState supportState = level.getBlockState(supportPos);
|
||||||
|
return supportState.is(SUPPORTS) && supportState.isFaceSturdy(level, supportPos, Direction.UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
|
||||||
|
if (random.nextInt(7) == 0) {
|
||||||
|
this.growConfiguredTree(level, pos, state, random);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BlockState updateShape(
|
||||||
|
BlockState state,
|
||||||
|
Direction direction,
|
||||||
|
BlockState neighborState,
|
||||||
|
LevelAccessor level,
|
||||||
|
BlockPos pos,
|
||||||
|
BlockPos neighborPos
|
||||||
|
) {
|
||||||
|
return state.canSurvive(level, pos)
|
||||||
|
? super.updateShape(state, direction, neighborState, level, pos, neighborPos)
|
||||||
|
: Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, BlockState state) {
|
||||||
|
return random.nextFloat() < 0.45F;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) {
|
||||||
|
this.growConfiguredTree(level, pos, state, random);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void growConfiguredTree(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) {
|
||||||
|
Holder.Reference<ConfiguredFeature<?, ?>> feature = level.registryAccess()
|
||||||
|
.lookupOrThrow(Registries.CONFIGURED_FEATURE)
|
||||||
|
.getOrThrow(TruffaloTreeGrowers.TRUFFALO_TREE);
|
||||||
|
|
||||||
|
level.removeBlock(pos, false);
|
||||||
|
if (feature.value().place(level, level.getChunkSource().getGenerator(), random, pos)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
level.setBlock(pos, state, Block.UPDATE_ALL);
|
||||||
|
}
|
||||||
|
}
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
package com.craisinlord.antarchy.content.block;
|
||||||
|
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ShearsItem;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
|
||||||
|
public class TruffaloTuftBlock extends Block {
|
||||||
|
public static final MapCodec<TruffaloTuftBlock> CODEC = Block.simpleCodec(TruffaloTuftBlock::new);
|
||||||
|
private static final float SHEARS_DESTROY_SPEED = 10.0F;
|
||||||
|
|
||||||
|
public TruffaloTuftBlock(BlockBehaviour.Properties properties) {
|
||||||
|
super(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapCodec<TruffaloTuftBlock> codec() {
|
||||||
|
return CODEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected float getDestroyProgress(BlockState state, Player player, BlockGetter level, BlockPos pos) {
|
||||||
|
if (player.getMainHandItem().getItem() instanceof ShearsItem) {
|
||||||
|
return SHEARS_DESTROY_SPEED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.getDestroyProgress(state, player, level, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
+148
@@ -0,0 +1,148 @@
|
|||||||
|
package com.craisinlord.antarchy.content.block.entity;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.HolderLookup;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||||
|
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
|
||||||
|
public class PortalGunPortalBaseBlockEntity extends BlockEntity {
|
||||||
|
private UUID ownerId;
|
||||||
|
private UUID portalId;
|
||||||
|
private PortalGunPortalEntity.PortalSide side = PortalGunPortalEntity.PortalSide.BLUE;
|
||||||
|
private BlockPos masterPos = BlockPos.ZERO;
|
||||||
|
private UUID linkedPortalId;
|
||||||
|
private int pairTime;
|
||||||
|
|
||||||
|
public PortalGunPortalBaseBlockEntity(BlockPos pos, BlockState state, Supplier<? extends BlockEntityType<PortalGunPortalBaseBlockEntity>> typeSupplier) {
|
||||||
|
super(typeSupplier.get(), pos, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void configure(UUID ownerId, UUID portalId, PortalGunPortalEntity.PortalSide side, BlockPos masterPos) {
|
||||||
|
this.ownerId = ownerId;
|
||||||
|
this.portalId = portalId;
|
||||||
|
this.side = side;
|
||||||
|
this.masterPos = masterPos.immutable();
|
||||||
|
this.setChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getOwnerId() {
|
||||||
|
return this.ownerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getPortalId() {
|
||||||
|
return this.portalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PortalGunPortalEntity.PortalSide getSide() {
|
||||||
|
return this.side;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockPos getMasterPos() {
|
||||||
|
return this.masterPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getLinkedPortalId() {
|
||||||
|
return this.linkedPortalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPairTime() {
|
||||||
|
return this.pairTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updatePair(UUID linkedPortalId, int pairTime) {
|
||||||
|
this.linkedPortalId = linkedPortalId;
|
||||||
|
this.pairTime = pairTime;
|
||||||
|
this.setChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(UUID ownerId, UUID portalId, PortalGunPortalEntity.PortalSide side) {
|
||||||
|
return ownerId != null && portalId != null && ownerId.equals(this.ownerId) && portalId.equals(this.portalId) && this.side == side;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onBroken() {
|
||||||
|
if (!(this.level instanceof ServerLevel serverLevel) || this.portalId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (serverLevel.getEntity(this.portalId) instanceof PortalGunPortalEntity portal && !portal.isRemoved()) {
|
||||||
|
portal.discard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void serverTick(ServerLevel level, BlockPos pos, BlockState state, PortalGunPortalBaseBlockEntity blockEntity) {
|
||||||
|
if (((level.getGameTime() + pos.asLong()) & 15L) != 0L) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!(level.getBlockEntity(blockEntity.masterPos) instanceof PortalGunPortalMasterBlockEntity master)
|
||||||
|
|| !master.matches(blockEntity.ownerId, blockEntity.portalId, blockEntity.side)
|
||||||
|
|| !pos.equals(master.getBasePos())) {
|
||||||
|
level.removeBlock(pos, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!(level.getEntity(blockEntity.portalId) instanceof PortalGunPortalEntity portal)
|
||||||
|
|| portal.isRemoved()
|
||||||
|
|| !pos.equals(portal.getBasePos())
|
||||||
|
|| blockEntity.ownerId == null
|
||||||
|
|| !blockEntity.ownerId.equals(portal.getOwnerId())
|
||||||
|
|| blockEntity.side != portal.getPortalSide()) {
|
||||||
|
level.removeBlock(pos, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
UUID linkedPortalId = portal.getLinkedPortalId();
|
||||||
|
if ((linkedPortalId == null && blockEntity.linkedPortalId != null)
|
||||||
|
|| (linkedPortalId != null && !linkedPortalId.equals(blockEntity.linkedPortalId))
|
||||||
|
|| blockEntity.pairTime != portal.getPairTime()) {
|
||||||
|
blockEntity.linkedPortalId = linkedPortalId;
|
||||||
|
blockEntity.pairTime = portal.getPairTime();
|
||||||
|
blockEntity.setChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
|
||||||
|
super.saveAdditional(tag, registries);
|
||||||
|
if (this.ownerId != null) {
|
||||||
|
tag.putUUID("OwnerId", this.ownerId);
|
||||||
|
}
|
||||||
|
if (this.portalId != null) {
|
||||||
|
tag.putUUID("PortalId", this.portalId);
|
||||||
|
}
|
||||||
|
if (this.linkedPortalId != null) {
|
||||||
|
tag.putUUID("LinkedPortalId", this.linkedPortalId);
|
||||||
|
}
|
||||||
|
tag.putInt("Side", this.side.ordinal());
|
||||||
|
tag.putInt("MasterX", this.masterPos.getX());
|
||||||
|
tag.putInt("MasterY", this.masterPos.getY());
|
||||||
|
tag.putInt("MasterZ", this.masterPos.getZ());
|
||||||
|
tag.putInt("PairTime", this.pairTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) {
|
||||||
|
super.loadAdditional(tag, registries);
|
||||||
|
this.ownerId = tag.hasUUID("OwnerId") ? tag.getUUID("OwnerId") : null;
|
||||||
|
this.portalId = tag.hasUUID("PortalId") ? tag.getUUID("PortalId") : null;
|
||||||
|
this.linkedPortalId = tag.hasUUID("LinkedPortalId") ? tag.getUUID("LinkedPortalId") : null;
|
||||||
|
this.side = tag.getInt("Side") == PortalGunPortalEntity.PortalSide.ORANGE.ordinal() ? PortalGunPortalEntity.PortalSide.ORANGE : PortalGunPortalEntity.PortalSide.BLUE;
|
||||||
|
this.masterPos = new BlockPos(tag.getInt("MasterX"), tag.getInt("MasterY"), tag.getInt("MasterZ"));
|
||||||
|
this.pairTime = tag.getInt("PairTime");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundTag getUpdateTag(HolderLookup.Provider registries) {
|
||||||
|
return this.saveWithoutMetadata(registries);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Packet<ClientGamePacketListener> getUpdatePacket() {
|
||||||
|
return ClientboundBlockEntityDataPacket.create(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
+300
@@ -0,0 +1,300 @@
|
|||||||
|
package com.craisinlord.antarchy.content.block.entity;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunPlacement;
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunSavedData;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.core.HolderLookup;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.ListTag;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||||
|
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public class PortalGunPortalMasterBlockEntity extends BlockEntity {
|
||||||
|
private UUID ownerId;
|
||||||
|
private UUID portalId;
|
||||||
|
private PortalGunPortalEntity.PortalSide side = PortalGunPortalEntity.PortalSide.BLUE;
|
||||||
|
private Direction facing = Direction.NORTH;
|
||||||
|
private Direction upAxis = Direction.UP;
|
||||||
|
private BlockPos basePos = BlockPos.ZERO;
|
||||||
|
private BlockPos[] portalSpots = new BlockPos[] {BlockPos.ZERO, BlockPos.ZERO};
|
||||||
|
private Set<BlockPos> compensatedSpots = Set.of();
|
||||||
|
private UUID linkedPortalId;
|
||||||
|
private int pairTime;
|
||||||
|
|
||||||
|
public PortalGunPortalMasterBlockEntity(BlockPos pos, BlockState state, Supplier<? extends BlockEntityType<PortalGunPortalMasterBlockEntity>> typeSupplier) {
|
||||||
|
super(typeSupplier.get(), pos, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void configure(
|
||||||
|
UUID ownerId,
|
||||||
|
UUID portalId,
|
||||||
|
PortalGunPortalEntity.PortalSide side,
|
||||||
|
Direction facing,
|
||||||
|
Direction upAxis,
|
||||||
|
BlockPos basePos,
|
||||||
|
BlockPos[] portalSpots,
|
||||||
|
Set<BlockPos> compensatedSpots,
|
||||||
|
int pairTime
|
||||||
|
) {
|
||||||
|
this.ownerId = ownerId;
|
||||||
|
this.portalId = portalId;
|
||||||
|
this.side = side;
|
||||||
|
this.facing = facing;
|
||||||
|
this.upAxis = upAxis;
|
||||||
|
this.basePos = basePos.immutable();
|
||||||
|
this.portalSpots = new BlockPos[] {portalSpots[0].immutable(), portalSpots[1].immutable()};
|
||||||
|
this.compensatedSpots = new HashSet<>(compensatedSpots);
|
||||||
|
this.pairTime = pairTime;
|
||||||
|
this.setChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getPortalId() {
|
||||||
|
return this.portalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getOwnerId() {
|
||||||
|
return this.ownerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PortalGunPortalEntity.PortalSide getSide() {
|
||||||
|
return this.side;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Direction getFacing() {
|
||||||
|
return this.facing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Direction getUpAxis() {
|
||||||
|
return this.upAxis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockPos getBasePos() {
|
||||||
|
return this.basePos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockPos[] getPortalSpots() {
|
||||||
|
return new BlockPos[] {this.portalSpots[0], this.portalSpots[1]};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<BlockPos> getCompensatedSpots() {
|
||||||
|
return Set.copyOf(this.compensatedSpots);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPairTime() {
|
||||||
|
return this.pairTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getLinkedPortalId() {
|
||||||
|
return this.linkedPortalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updatePair(UUID linkedPortalId, int pairTime) {
|
||||||
|
this.linkedPortalId = linkedPortalId;
|
||||||
|
this.pairTime = pairTime;
|
||||||
|
this.setChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(UUID ownerId, UUID portalId, PortalGunPortalEntity.PortalSide side) {
|
||||||
|
return ownerId != null && portalId != null && ownerId.equals(this.ownerId) && portalId.equals(this.portalId) && this.side == side;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onBroken() {
|
||||||
|
if (!(this.level instanceof ServerLevel serverLevel) || this.portalId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (serverLevel.getEntity(this.portalId) instanceof PortalGunPortalEntity portal && !portal.isRemoved()) {
|
||||||
|
portal.discard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void serverTick(ServerLevel level, BlockPos pos, BlockState state, PortalGunPortalMasterBlockEntity blockEntity) {
|
||||||
|
if (((level.getGameTime() + pos.asLong()) & 15L) != 0L) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!blockEntity.hasValidFootprint(level, pos)) {
|
||||||
|
level.removeBlock(pos, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PortalGunPortalEntity portal = blockEntity.ensurePortalEntity(level);
|
||||||
|
if (portal == null
|
||||||
|
|| portal.isRemoved()
|
||||||
|
|| !pos.equals(portal.getMasterPos())
|
||||||
|
|| blockEntity.ownerId == null
|
||||||
|
|| !blockEntity.ownerId.equals(portal.getOwnerId())
|
||||||
|
|| blockEntity.side != portal.getPortalSide()) {
|
||||||
|
level.removeBlock(pos, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
blockEntity.ensureLinkedPortal(level, portal);
|
||||||
|
UUID linkedPortalId = portal.getLinkedPortalId();
|
||||||
|
if ((linkedPortalId == null && blockEntity.linkedPortalId != null)
|
||||||
|
|| (linkedPortalId != null && !linkedPortalId.equals(blockEntity.linkedPortalId))
|
||||||
|
|| blockEntity.pairTime != portal.getPairTime()) {
|
||||||
|
blockEntity.linkedPortalId = linkedPortalId;
|
||||||
|
blockEntity.pairTime = portal.getPairTime();
|
||||||
|
blockEntity.setChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasValidFootprint(ServerLevel level, BlockPos pos) {
|
||||||
|
if (this.ownerId == null || this.portalId == null || !pos.equals(this.worldPosition)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(level.getBlockEntity(this.basePos) instanceof PortalGunPortalBaseBlockEntity base)
|
||||||
|
|| !base.matches(this.ownerId, this.portalId, this.side)
|
||||||
|
|| !pos.equals(base.getMasterPos())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
List<BlockPos> supportPositions = new ArrayList<>(2);
|
||||||
|
for (BlockPos portalSpot : this.portalSpots) {
|
||||||
|
if (portalSpot == null || BlockPos.ZERO.equals(portalSpot)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
supportPositions.add(portalSpot.relative(this.facing.getOpposite()));
|
||||||
|
}
|
||||||
|
for (BlockPos supportPos : supportPositions) {
|
||||||
|
BlockState supportState = level.getBlockState(supportPos);
|
||||||
|
if (!supportState.isFaceSturdy(level, supportPos, this.facing)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PortalGunPortalEntity ensurePortalEntity(ServerLevel level) {
|
||||||
|
if (this.portalId == null || this.ownerId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (level.getEntity(this.portalId) instanceof PortalGunPortalEntity portal && !portal.isRemoved()) {
|
||||||
|
return portal;
|
||||||
|
}
|
||||||
|
EntityType<?> rawType = BuiltInRegistries.ENTITY_TYPE.get(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "portal_gun_portal"));
|
||||||
|
if (!(rawType instanceof EntityType<?>)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
PortalGunPlacement placement = PortalGunPlacement.fromStored(this.facing, this.upAxis, this.worldPosition, this.basePos, this.compensatedSpots);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
PortalGunPortalEntity restored = new PortalGunPortalEntity((EntityType<? extends PortalGunPortalEntity>) rawType, level);
|
||||||
|
restored.setUUID(this.portalId);
|
||||||
|
restored.configure(this.ownerId, this.side, placement);
|
||||||
|
restored.restorePair(this.linkedPortalId, this.pairTime);
|
||||||
|
Vec3 center = placement.center();
|
||||||
|
restored.moveTo(center.x, center.y, center.z, placement.yaw(), 0.0F);
|
||||||
|
level.addFreshEntity(restored);
|
||||||
|
PortalGunSavedData.setPortal(level.getServer(), this.ownerId, this.side, restored.getUUID());
|
||||||
|
return restored;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureLinkedPortal(ServerLevel level, PortalGunPortalEntity portal) {
|
||||||
|
if (this.ownerId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PortalGunPortalEntity counterpart = PortalGunSavedData.findLoadedPortal(
|
||||||
|
level.getServer(),
|
||||||
|
this.ownerId,
|
||||||
|
this.side == PortalGunPortalEntity.PortalSide.BLUE ? PortalGunPortalEntity.PortalSide.ORANGE : PortalGunPortalEntity.PortalSide.BLUE
|
||||||
|
);
|
||||||
|
if (counterpart == null || counterpart == portal || counterpart.isRemoved()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!counterpart.getUUID().equals(portal.getLinkedPortalId()) || !portal.getUUID().equals(counterpart.getLinkedPortalId())) {
|
||||||
|
portal.linkTo(counterpart);
|
||||||
|
counterpart.linkTo(portal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
|
||||||
|
super.saveAdditional(tag, registries);
|
||||||
|
if (this.ownerId != null) {
|
||||||
|
tag.putUUID("OwnerId", this.ownerId);
|
||||||
|
}
|
||||||
|
if (this.portalId != null) {
|
||||||
|
tag.putUUID("PortalId", this.portalId);
|
||||||
|
}
|
||||||
|
if (this.linkedPortalId != null) {
|
||||||
|
tag.putUUID("LinkedPortalId", this.linkedPortalId);
|
||||||
|
}
|
||||||
|
tag.putInt("Side", this.side.ordinal());
|
||||||
|
tag.putInt("Facing", this.facing.get3DDataValue());
|
||||||
|
tag.putInt("UpAxis", this.upAxis.get3DDataValue());
|
||||||
|
tag.putInt("BaseX", this.basePos.getX());
|
||||||
|
tag.putInt("BaseY", this.basePos.getY());
|
||||||
|
tag.putInt("BaseZ", this.basePos.getZ());
|
||||||
|
tag.putInt("PairTime", this.pairTime);
|
||||||
|
ListTag spots = new ListTag();
|
||||||
|
for (BlockPos portalSpot : this.portalSpots) {
|
||||||
|
CompoundTag spot = new CompoundTag();
|
||||||
|
spot.putInt("X", portalSpot.getX());
|
||||||
|
spot.putInt("Y", portalSpot.getY());
|
||||||
|
spot.putInt("Z", portalSpot.getZ());
|
||||||
|
spots.add(spot);
|
||||||
|
}
|
||||||
|
tag.put("PortalSpots", spots);
|
||||||
|
ListTag compensated = new ListTag();
|
||||||
|
for (BlockPos compensatedSpot : this.compensatedSpots) {
|
||||||
|
CompoundTag spot = new CompoundTag();
|
||||||
|
spot.putInt("X", compensatedSpot.getX());
|
||||||
|
spot.putInt("Y", compensatedSpot.getY());
|
||||||
|
spot.putInt("Z", compensatedSpot.getZ());
|
||||||
|
compensated.add(spot);
|
||||||
|
}
|
||||||
|
tag.put("CompensatedSpots", compensated);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) {
|
||||||
|
super.loadAdditional(tag, registries);
|
||||||
|
this.ownerId = tag.hasUUID("OwnerId") ? tag.getUUID("OwnerId") : null;
|
||||||
|
this.portalId = tag.hasUUID("PortalId") ? tag.getUUID("PortalId") : null;
|
||||||
|
this.linkedPortalId = tag.hasUUID("LinkedPortalId") ? tag.getUUID("LinkedPortalId") : null;
|
||||||
|
this.side = tag.getInt("Side") == PortalGunPortalEntity.PortalSide.ORANGE.ordinal() ? PortalGunPortalEntity.PortalSide.ORANGE : PortalGunPortalEntity.PortalSide.BLUE;
|
||||||
|
this.facing = Direction.from3DDataValue(tag.getInt("Facing"));
|
||||||
|
this.upAxis = Direction.from3DDataValue(tag.getInt("UpAxis"));
|
||||||
|
this.basePos = new BlockPos(tag.getInt("BaseX"), tag.getInt("BaseY"), tag.getInt("BaseZ"));
|
||||||
|
this.pairTime = tag.getInt("PairTime");
|
||||||
|
ListTag spots = tag.getList("PortalSpots", Tag.TAG_COMPOUND);
|
||||||
|
for (int i = 0; i < Math.min(2, spots.size()); i++) {
|
||||||
|
CompoundTag spot = spots.getCompound(i);
|
||||||
|
this.portalSpots[i] = new BlockPos(spot.getInt("X"), spot.getInt("Y"), spot.getInt("Z"));
|
||||||
|
}
|
||||||
|
ListTag compensated = tag.getList("CompensatedSpots", Tag.TAG_COMPOUND);
|
||||||
|
Set<BlockPos> compensatedSpots = new HashSet<>();
|
||||||
|
for (int i = 0; i < compensated.size(); i++) {
|
||||||
|
CompoundTag spot = compensated.getCompound(i);
|
||||||
|
compensatedSpots.add(new BlockPos(spot.getInt("X"), spot.getInt("Y"), spot.getInt("Z")));
|
||||||
|
}
|
||||||
|
this.compensatedSpots = compensatedSpots;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundTag getUpdateTag(HolderLookup.Provider registries) {
|
||||||
|
return this.saveWithoutMetadata(registries);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Packet<ClientGamePacketListener> getUpdatePacket() {
|
||||||
|
return ClientboundBlockEntityDataPacket.create(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunWorldPortalShape;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Deque;
|
||||||
|
|
||||||
|
public final class PortalGunPortalRenderState {
|
||||||
|
private static final ThreadLocal<Deque<PortalGunWorldPortalShape>> ACTIVE_DESTINATION_SHAPES = ThreadLocal.withInitial(ArrayDeque::new);
|
||||||
|
private static final ThreadLocal<Deque<PortalGunWorldPortalShape>> ACTIVE_SOURCE_SHAPES = ThreadLocal.withInitial(ArrayDeque::new);
|
||||||
|
private static final ThreadLocal<Integer> RENDER_ALL_DEPTH = ThreadLocal.withInitial(() -> 0);
|
||||||
|
|
||||||
|
private PortalGunPortalRenderState() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void pushPortalView(PortalGunWorldPortalShape sourceShape, PortalGunWorldPortalShape destinationShape, boolean renderAll) {
|
||||||
|
ACTIVE_SOURCE_SHAPES.get().push(sourceShape);
|
||||||
|
ACTIVE_DESTINATION_SHAPES.get().push(destinationShape);
|
||||||
|
if (renderAll) {
|
||||||
|
RENDER_ALL_DEPTH.set(RENDER_ALL_DEPTH.get() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void popPortalView(boolean renderAll) {
|
||||||
|
Deque<PortalGunWorldPortalShape> sourceShapes = ACTIVE_SOURCE_SHAPES.get();
|
||||||
|
if (!sourceShapes.isEmpty()) {
|
||||||
|
sourceShapes.pop();
|
||||||
|
}
|
||||||
|
if (sourceShapes.isEmpty()) {
|
||||||
|
ACTIVE_SOURCE_SHAPES.remove();
|
||||||
|
}
|
||||||
|
Deque<PortalGunWorldPortalShape> destinationShapes = ACTIVE_DESTINATION_SHAPES.get();
|
||||||
|
if (!destinationShapes.isEmpty()) {
|
||||||
|
destinationShapes.pop();
|
||||||
|
}
|
||||||
|
if (destinationShapes.isEmpty()) {
|
||||||
|
ACTIVE_DESTINATION_SHAPES.remove();
|
||||||
|
}
|
||||||
|
if (renderAll) {
|
||||||
|
int depth = Math.max(0, RENDER_ALL_DEPTH.get() - 1);
|
||||||
|
if (depth == 0) {
|
||||||
|
RENDER_ALL_DEPTH.remove();
|
||||||
|
} else {
|
||||||
|
RENDER_ALL_DEPTH.set(depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void pushDestinationShape(PortalGunWorldPortalShape shape) {
|
||||||
|
ACTIVE_DESTINATION_SHAPES.get().push(shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void popDestinationShape() {
|
||||||
|
Deque<PortalGunWorldPortalShape> shapes = ACTIVE_DESTINATION_SHAPES.get();
|
||||||
|
if (!shapes.isEmpty()) {
|
||||||
|
shapes.pop();
|
||||||
|
}
|
||||||
|
if (shapes.isEmpty()) {
|
||||||
|
ACTIVE_DESTINATION_SHAPES.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PortalGunWorldPortalShape getDestinationShape() {
|
||||||
|
Deque<PortalGunWorldPortalShape> shapes = ACTIVE_DESTINATION_SHAPES.get();
|
||||||
|
return shapes.isEmpty() ? null : shapes.peek();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PortalGunWorldPortalShape getSourceShape() {
|
||||||
|
Deque<PortalGunWorldPortalShape> shapes = ACTIVE_SOURCE_SHAPES.get();
|
||||||
|
return shapes.isEmpty() ? null : shapes.peek();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean renderAll() {
|
||||||
|
return RENDER_ALL_DEPTH.get() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
+108
@@ -0,0 +1,108 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunTransformUtil;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.joml.Quaternionf;
|
||||||
|
|
||||||
|
public final class PortalGunRollClientState {
|
||||||
|
private static final int TELEPORT_COOLDOWN_TICKS = 15;
|
||||||
|
private static final float ROLL_DECAY = 0.85F;
|
||||||
|
private static final float ROLL_EPSILON = 0.05F;
|
||||||
|
private static final Map<UUID, Long> TELEPORT_COOLDOWNS = new HashMap<>();
|
||||||
|
private static float previousRollDegrees;
|
||||||
|
private static float rollDegrees;
|
||||||
|
|
||||||
|
private PortalGunRollClientState() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float getRollDegrees() {
|
||||||
|
return rollDegrees;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float getRollDegrees(float partialTick) {
|
||||||
|
return previousRollDegrees + (rollDegrees - previousRollDegrees) * partialTick;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEntityInsidePortal(Minecraft minecraft, Entity entity) {
|
||||||
|
if (minecraft.level == null || entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (Entity renderEntity : minecraft.level.entitiesForRendering()) {
|
||||||
|
if (renderEntity instanceof PortalGunPortalEntity portal && portal.isAlive() && portal.intersectsEntityBounds(entity)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isCameraInsidePortal(Minecraft minecraft) {
|
||||||
|
Entity cameraEntity = minecraft.getCameraEntity();
|
||||||
|
return cameraEntity != null && isEntityInsidePortal(minecraft, cameraEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clear() {
|
||||||
|
previousRollDegrees = 0.0F;
|
||||||
|
rollDegrees = 0.0F;
|
||||||
|
TELEPORT_COOLDOWNS.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void tick(Minecraft minecraft) {
|
||||||
|
if (minecraft.level == null || minecraft.player == null) {
|
||||||
|
clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Entity cameraEntity = minecraft.getCameraEntity();
|
||||||
|
if (cameraEntity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
previousRollDegrees = rollDegrees;
|
||||||
|
rollDegrees *= ROLL_DECAY;
|
||||||
|
if (Math.abs(rollDegrees) < ROLL_EPSILON) {
|
||||||
|
rollDegrees = 0.0F;
|
||||||
|
}
|
||||||
|
long gameTime = minecraft.level.getGameTime();
|
||||||
|
TELEPORT_COOLDOWNS.entrySet().removeIf(entry -> entry.getValue() <= gameTime);
|
||||||
|
for (Entity entity : minecraft.level.entitiesForRendering()) {
|
||||||
|
if (!(entity instanceof PortalGunPortalEntity portal) || !portal.isAlive()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PortalGunPortalEntity linkedPortal = portal.getLinkedPortal();
|
||||||
|
if (linkedPortal == null || !linkedPortal.isAlive()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!portal.shouldRenderFront(cameraEntity.position())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!canTeleport(cameraEntity, gameTime)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (portal.resolveCrossingProbe(cameraEntity) == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
applyPredictedTeleport(cameraEntity, portal, linkedPortal, gameTime);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean canTeleport(Entity entity, long gameTime) {
|
||||||
|
if (!entity.isAlive() || entity instanceof PortalGunPortalEntity || entity.isPassenger() || entity.isVehicle()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
long cooldownUntil = TELEPORT_COOLDOWNS.getOrDefault(entity.getUUID(), 0L);
|
||||||
|
return cooldownUntil <= gameTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void applyPredictedTeleport(Entity entity, PortalGunPortalEntity sourcePortal, PortalGunPortalEntity destinationPortal, long gameTime) {
|
||||||
|
Quaternionf transform = PortalGunTransformUtil.createTransform(sourcePortal, destinationPortal);
|
||||||
|
Vec3 transformedLook = PortalGunTransformUtil.transform(entity.getLookAngle(), transform).normalize();
|
||||||
|
Vec3 transformedUp = PortalGunTransformUtil.transform(PortalGunTransformUtil.upVectorFromLookAndRoll(entity.getLookAngle(), rollDegrees), transform).normalize();
|
||||||
|
rollDegrees = PortalGunTransformUtil.rollFromOrientation(transformedLook, transformedUp);
|
||||||
|
TELEPORT_COOLDOWNS.put(entity.getUUID(), gameTime + TELEPORT_COOLDOWN_TICKS);
|
||||||
|
}
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client.model;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import com.craisinlord.antarchy.content.entity.HoverboardEntity;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.DyeColor;
|
||||||
|
import software.bernie.geckolib.model.GeoModel;
|
||||||
|
|
||||||
|
public class HoverboardModel extends GeoModel<HoverboardEntity> {
|
||||||
|
private static final ResourceLocation MODEL = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/hoverboard.geo.json");
|
||||||
|
private static final ResourceLocation ANIMATION = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/hoverboard.animation.json");
|
||||||
|
private static final ResourceLocation BASE_TEXTURE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/hoverboard/hoverboard.png");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getModelResource(HoverboardEntity animatable) {
|
||||||
|
return MODEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getTextureResource(HoverboardEntity animatable) {
|
||||||
|
DyeColor color = animatable.getColor();
|
||||||
|
if (color == null) {
|
||||||
|
return BASE_TEXTURE;
|
||||||
|
}
|
||||||
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/hoverboard/hoverboard_" + color.getName() + ".png");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getAnimationResource(HoverboardEntity animatable) {
|
||||||
|
return ANIMATION;
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client.renderer;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.client.model.HoverboardModel;
|
||||||
|
import com.craisinlord.antarchy.content.entity.HoverboardEntity;
|
||||||
|
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||||
|
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
||||||
|
|
||||||
|
public class HoverboardRenderer extends GeoEntityRenderer<HoverboardEntity> {
|
||||||
|
public HoverboardRenderer(EntityRendererProvider.Context context) {
|
||||||
|
super(context, new HoverboardModel());
|
||||||
|
this.shadowRadius = 0.5F;
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
-7
@@ -3,13 +3,15 @@ package com.craisinlord.antarchy.content.client.renderer;
|
|||||||
import com.craisinlord.antarchy.content.client.model.PortalGunPortalModel;
|
import com.craisinlord.antarchy.content.client.model.PortalGunPortalModel;
|
||||||
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
|
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.math.Axis;
|
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.joml.Matrix3f;
|
||||||
|
import org.joml.Quaternionf;
|
||||||
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
||||||
|
|
||||||
public class PortalGunPortalRenderer extends GeoEntityRenderer<PortalGunPortalEntity> {
|
public class PortalGunPortalRenderer extends GeoEntityRenderer<PortalGunPortalEntity> {
|
||||||
@@ -20,13 +22,20 @@ public class PortalGunPortalRenderer extends GeoEntityRenderer<PortalGunPortalEn
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(PortalGunPortalEntity entity, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight) {
|
public void render(PortalGunPortalEntity entity, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight) {
|
||||||
Direction facing = entity.getFacingDirection();
|
|
||||||
poseStack.pushPose();
|
|
||||||
if (facing.getAxis() == Direction.Axis.Y) {
|
|
||||||
poseStack.mulPose(Axis.XP.rotationDegrees(facing == Direction.UP ? -90.0F : 90.0F));
|
|
||||||
}
|
|
||||||
super.render(entity, entityYaw, partialTick, poseStack, bufferSource, 0xF000F0);
|
super.render(entity, entityYaw, partialTick, poseStack, bufferSource, 0xF000F0);
|
||||||
poseStack.popPose();
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyRotations(PortalGunPortalEntity animatable, PoseStack poseStack, float ageInTicks, float rotationYaw, float partialTick, float nativeScale) {
|
||||||
|
Vec3 width = animatable.getWidthVec();
|
||||||
|
Vec3 up = animatable.getUpVec();
|
||||||
|
Vec3 normal = animatable.getNormalVec();
|
||||||
|
Matrix3f basis = new Matrix3f(
|
||||||
|
(float) width.x, (float) up.x, (float) -normal.x,
|
||||||
|
(float) width.y, (float) up.y, (float) -normal.y,
|
||||||
|
(float) width.z, (float) up.z, (float) -normal.z
|
||||||
|
);
|
||||||
|
poseStack.mulPose(basis.getNormalizedRotation(new Quaternionf()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+410
@@ -0,0 +1,410 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client.renderer;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import com.craisinlord.antarchy.content.client.PortalGunPortalRenderState;
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunTransformUtil;
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
|
||||||
|
import com.mojang.blaze3d.platform.GlStateManager;
|
||||||
|
import com.mojang.blaze3d.pipeline.TextureTarget;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||||
|
import com.mojang.blaze3d.vertex.BufferUploader;
|
||||||
|
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||||
|
import com.mojang.blaze3d.vertex.MeshData;
|
||||||
|
import com.mojang.blaze3d.vertex.Tesselator;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import net.minecraft.client.Camera;
|
||||||
|
import net.minecraft.client.DeltaTracker;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.GameRenderer;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.joml.Vector4f;
|
||||||
|
import org.joml.Quaternionf;
|
||||||
|
|
||||||
|
public final class PortalGunPortalViewRenderer {
|
||||||
|
private static final int MAX_RECURSION_DEPTH = 3;
|
||||||
|
private static final double SURFACE_OFFSET = 0.03125D;
|
||||||
|
private static final double CAMERA_OFFSET = 0.0625D;
|
||||||
|
private static final double OVERLAY_OFFSET = 0.03135D;
|
||||||
|
private static final ResourceLocation BLUE_OVERLAY = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/vfx/portal_gun_portal_blue.png");
|
||||||
|
private static final ResourceLocation ORANGE_OVERLAY = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/vfx/portal_gun_portal_orange.png");
|
||||||
|
private static final TextureTarget[] PORTAL_TARGETS = new TextureTarget[MAX_RECURSION_DEPTH + 1];
|
||||||
|
private static boolean renderingPortalView;
|
||||||
|
|
||||||
|
private PortalGunPortalViewRenderer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void render(Camera camera, Matrix4f poseMatrix, DeltaTracker tickCounter) {
|
||||||
|
if (renderingPortalView) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Minecraft minecraft = Minecraft.getInstance();
|
||||||
|
if (minecraft.level == null || minecraft.gameRenderer == null || camera == null || poseMatrix == null || tickCounter == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Entity cameraEntity = minecraft.getCameraEntity();
|
||||||
|
if (cameraEntity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<PortalGunPortalEntity> portals = collectVisiblePortals(minecraft, camera);
|
||||||
|
if (portals.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ensureTargets(minecraft);
|
||||||
|
if (PORTAL_TARGETS[0] == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Vec3 cameraPos = camera.getPosition();
|
||||||
|
Vec3 rootLook = new Vec3(camera.getLookVector()).normalize();
|
||||||
|
Vec3 rootUp = new Vec3(camera.getUpVector()).normalize();
|
||||||
|
Matrix4f rootViewMatrix = new Matrix4f().rotation(PortalGunTransformUtil.orientationQuaternion(rootLook, rootUp).conjugate(new Quaternionf()));
|
||||||
|
RenderContext rootContext = new RenderContext(cameraPos, rootLook, rootUp, rootViewMatrix);
|
||||||
|
renderingPortalView = true;
|
||||||
|
RenderSystem.backupProjectionMatrix();
|
||||||
|
for (PortalGunPortalEntity portal : portals) {
|
||||||
|
PortalGunPortalEntity linkedPortal = portal.getLinkedPortal();
|
||||||
|
if (linkedPortal == null || !linkedPortal.isAlive()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int textureId = renderPortalSurface(minecraft, cameraEntity, tickCounter, rootContext, portal, linkedPortal, 0);
|
||||||
|
minecraft.getMainRenderTarget().bindWrite(true);
|
||||||
|
drawPortalQuad(cameraPos, poseMatrix, portal, textureId);
|
||||||
|
drawPortalOverlay(minecraft, cameraPos, poseMatrix, portal);
|
||||||
|
}
|
||||||
|
RenderSystem.restoreProjectionMatrix();
|
||||||
|
renderingPortalView = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<PortalGunPortalEntity> collectVisiblePortals(Minecraft minecraft, Camera camera) {
|
||||||
|
return collectVisiblePortals(minecraft, camera.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<PortalGunPortalEntity> collectVisiblePortals(Minecraft minecraft, Vec3 cameraPos) {
|
||||||
|
List<PortalGunPortalEntity> portals = new ArrayList<>();
|
||||||
|
for (Entity entity : minecraft.level.entitiesForRendering()) {
|
||||||
|
if (!(entity instanceof PortalGunPortalEntity portal) || !portal.isAlive()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (portal.getLinkedPortalId() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!portal.shouldRenderFront(cameraPos)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
portals.add(portal);
|
||||||
|
}
|
||||||
|
portals.sort((left, right) -> Double.compare(left.distanceToSqr(cameraPos), right.distanceToSqr(cameraPos)));
|
||||||
|
return portals;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ensureTargets(Minecraft minecraft) {
|
||||||
|
int width = minecraft.getWindow().getWidth();
|
||||||
|
int height = minecraft.getWindow().getHeight();
|
||||||
|
if (width <= 0 || height <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < PORTAL_TARGETS.length; i++) {
|
||||||
|
TextureTarget target = PORTAL_TARGETS[i];
|
||||||
|
if (target == null) {
|
||||||
|
target = new TextureTarget(width, height, true, Minecraft.ON_OSX);
|
||||||
|
target.setClearColor(0.0F, 0.0F, 0.0F, 1.0F);
|
||||||
|
PORTAL_TARGETS[i] = target;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (target.width != width || target.height != height) {
|
||||||
|
target.resize(width, height, Minecraft.ON_OSX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int renderPortalSurface(
|
||||||
|
Minecraft minecraft,
|
||||||
|
Entity cameraEntity,
|
||||||
|
DeltaTracker tickCounter,
|
||||||
|
RenderContext currentContext,
|
||||||
|
PortalGunPortalEntity sourcePortal,
|
||||||
|
PortalGunPortalEntity destinationPortal,
|
||||||
|
int depth
|
||||||
|
) {
|
||||||
|
TextureTarget target = PORTAL_TARGETS[depth];
|
||||||
|
RenderContext transformedContext = transformContext(currentContext, sourcePortal, destinationPortal);
|
||||||
|
PortalCamera portalCamera = new PortalCamera();
|
||||||
|
portalCamera.setup(minecraft.level, cameraEntity, tickCounter.getGameTimeDeltaPartialTick(true), transformedContext.cameraPos(), transformedContext.look(), transformedContext.up());
|
||||||
|
target.bindWrite(true);
|
||||||
|
target.clear(Minecraft.ON_OSX);
|
||||||
|
double fov = minecraft.options.fov().get();
|
||||||
|
Matrix4f baseProjectionMatrix = minecraft.gameRenderer.getProjectionMatrix(fov);
|
||||||
|
Matrix4f clippedProjectionMatrix = applyPortalClipPlane(baseProjectionMatrix, transformedContext, destinationPortal);
|
||||||
|
minecraft.gameRenderer.resetProjectionMatrix(clippedProjectionMatrix);
|
||||||
|
ScreenClip clip = computeScreenClip(minecraft, currentContext.cameraPos(), currentContext.viewMatrix(), baseProjectionMatrix, sourcePortal);
|
||||||
|
boolean clipEnabled = clip != null;
|
||||||
|
boolean renderAll = clip == null || clip.area() >= widthTimesHeight(minecraft);
|
||||||
|
if (clipEnabled) {
|
||||||
|
RenderSystem.enableScissor(clip.x(), clip.y(), clip.width(), clip.height());
|
||||||
|
}
|
||||||
|
PortalGunPortalRenderState.pushPortalView(sourcePortal.getWorldPortalShape(), destinationPortal.getWorldPortalShape(), renderAll);
|
||||||
|
try {
|
||||||
|
minecraft.levelRenderer.prepareCullFrustum(portalCamera.getPosition(), transformedContext.viewMatrix(), clippedProjectionMatrix);
|
||||||
|
minecraft.levelRenderer.renderLevel(tickCounter, false, portalCamera, minecraft.gameRenderer, minecraft.gameRenderer.lightTexture(), transformedContext.viewMatrix(), clippedProjectionMatrix);
|
||||||
|
if (depth < MAX_RECURSION_DEPTH) {
|
||||||
|
List<PortalGunPortalEntity> nestedPortals = collectVisiblePortals(minecraft, transformedContext.cameraPos());
|
||||||
|
Matrix4f nestedPose = new Matrix4f().identity();
|
||||||
|
for (PortalGunPortalEntity nestedPortal : nestedPortals) {
|
||||||
|
PortalGunPortalEntity nestedLinked = nestedPortal.getLinkedPortal();
|
||||||
|
if (nestedLinked == null || !nestedLinked.isAlive() || nestedPortal == destinationPortal || nestedPortal == sourcePortal) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (clip != null && clip.area() < 6400) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int nestedTextureId = renderPortalSurface(minecraft, cameraEntity, tickCounter, transformedContext, nestedPortal, nestedLinked, depth + 1);
|
||||||
|
target.bindWrite(true);
|
||||||
|
drawPortalQuad(transformedContext.cameraPos(), nestedPose, nestedPortal, nestedTextureId);
|
||||||
|
drawPortalOverlay(minecraft, transformedContext.cameraPos(), nestedPose, nestedPortal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
PortalGunPortalRenderState.popPortalView(renderAll);
|
||||||
|
}
|
||||||
|
if (clipEnabled) {
|
||||||
|
RenderSystem.disableScissor();
|
||||||
|
}
|
||||||
|
return target.getColorTextureId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RenderContext transformContext(RenderContext currentContext, PortalGunPortalEntity sourcePortal, PortalGunPortalEntity destinationPortal) {
|
||||||
|
Quaternionf transform = PortalGunTransformUtil.createTransform(sourcePortal, destinationPortal);
|
||||||
|
Vec3 destinationNormal = destinationPortal.getNormalVec().normalize();
|
||||||
|
Vec3 relativeEye = currentContext.cameraPos().subtract(sourcePortal.position());
|
||||||
|
double depthOffset = Math.max(CAMERA_OFFSET, relativeEye.dot(sourcePortal.getNormalVec().normalize()));
|
||||||
|
Vec3 transformedEyeOffset = PortalGunTransformUtil.transformRelativePosition(sourcePortal, destinationPortal, relativeEye);
|
||||||
|
Vec3 destinationEye = destinationPortal.position()
|
||||||
|
.add(transformedEyeOffset)
|
||||||
|
.add(destinationNormal.scale(depthOffset + CAMERA_OFFSET - transformedEyeOffset.dot(destinationNormal)));
|
||||||
|
Vec3 transformedLook = PortalGunTransformUtil.transform(currentContext.look(), transform).normalize();
|
||||||
|
Vec3 transformedUp = PortalGunTransformUtil.transform(currentContext.up(), transform).normalize();
|
||||||
|
Matrix4f viewMatrix = new Matrix4f().rotation(PortalGunTransformUtil.orientationQuaternion(transformedLook, transformedUp).conjugate(new Quaternionf()));
|
||||||
|
return new RenderContext(destinationEye, transformedLook, transformedUp, viewMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Matrix4f applyPortalClipPlane(Matrix4f projectionMatrix, RenderContext renderContext, PortalGunPortalEntity destinationPortal) {
|
||||||
|
Vec3 planePointWorld = destinationPortal.position().add(destinationPortal.getNormalVec().normalize().scale(0.01D));
|
||||||
|
Vec3 planeNormalWorld = destinationPortal.getNormalVec().normalize();
|
||||||
|
Vector4f clipPlane = portalPlaneToCameraSpace(renderContext, planePointWorld, planeNormalWorld);
|
||||||
|
if (clipPlane.lengthSquared() <= 1.0E-6F) {
|
||||||
|
return projectionMatrix;
|
||||||
|
}
|
||||||
|
Matrix4f clippedProjection = new Matrix4f(projectionMatrix);
|
||||||
|
Vector4f q = new Vector4f(
|
||||||
|
signNonZero(clipPlane.x()) / clippedProjection.m00(),
|
||||||
|
signNonZero(clipPlane.y()) / clippedProjection.m11(),
|
||||||
|
-1.0F,
|
||||||
|
(1.0F + clippedProjection.m22()) / clippedProjection.m32()
|
||||||
|
);
|
||||||
|
float scale = 2.0F / clipPlane.dot(q);
|
||||||
|
Vector4f c = clipPlane.mul(scale, new Vector4f());
|
||||||
|
clippedProjection.m02(c.x());
|
||||||
|
clippedProjection.m12(c.y());
|
||||||
|
clippedProjection.m22(c.z() + 1.0F);
|
||||||
|
clippedProjection.m32(c.w());
|
||||||
|
return clippedProjection;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vector4f portalPlaneToCameraSpace(RenderContext renderContext, Vec3 planePointWorld, Vec3 planeNormalWorld) {
|
||||||
|
Vec3 look = renderContext.look().normalize();
|
||||||
|
Vec3 up = renderContext.up().normalize();
|
||||||
|
Vec3 right = up.cross(look).normalize();
|
||||||
|
Vec3 relativePoint = planePointWorld.subtract(renderContext.cameraPos());
|
||||||
|
Vector4f point = new Vector4f(
|
||||||
|
(float) relativePoint.dot(right),
|
||||||
|
(float) relativePoint.dot(up),
|
||||||
|
(float) -relativePoint.dot(look),
|
||||||
|
1.0F
|
||||||
|
);
|
||||||
|
Vector4f normal = new Vector4f(
|
||||||
|
(float) planeNormalWorld.dot(right),
|
||||||
|
(float) planeNormalWorld.dot(up),
|
||||||
|
(float) -planeNormalWorld.dot(look),
|
||||||
|
0.0F
|
||||||
|
);
|
||||||
|
if (normal.z() > 0.0F) {
|
||||||
|
normal.mul(-1.0F);
|
||||||
|
}
|
||||||
|
return new Vector4f(normal.x(), normal.y(), normal.z(), -(normal.x() * point.x() + normal.y() * point.y() + normal.z() * point.z()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float signNonZero(float value) {
|
||||||
|
return value >= 0.0F ? 1.0F : -1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ScreenClip computeScreenClip(Minecraft minecraft, Vec3 cameraPos, Matrix4f viewMatrix, Matrix4f projectionMatrix, PortalGunPortalEntity portal) {
|
||||||
|
Vec3[] worldCorners = portal.getWorldPortalShape().getCorners(SURFACE_OFFSET);
|
||||||
|
int width = minecraft.getWindow().getWidth();
|
||||||
|
int height = minecraft.getWindow().getHeight();
|
||||||
|
float minX = Float.POSITIVE_INFINITY;
|
||||||
|
float minY = Float.POSITIVE_INFINITY;
|
||||||
|
float maxX = Float.NEGATIVE_INFINITY;
|
||||||
|
float maxY = Float.NEGATIVE_INFINITY;
|
||||||
|
boolean visible = false;
|
||||||
|
Matrix4f combined = new Matrix4f(projectionMatrix).mul(viewMatrix);
|
||||||
|
for (Vec3 worldCorner : worldCorners) {
|
||||||
|
Vec3 corner = worldCorner.subtract(cameraPos);
|
||||||
|
Vector4f projected = new Vector4f((float) corner.x, (float) corner.y, (float) corner.z, 1.0F).mul(combined);
|
||||||
|
if (projected.w <= 0.001F) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
float invW = 1.0F / projected.w;
|
||||||
|
float ndcX = projected.x * invW;
|
||||||
|
float ndcY = projected.y * invW;
|
||||||
|
if (ndcX < -1.25F || ndcX > 1.25F || ndcY < -1.25F || ndcY > 1.25F) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
visible = true;
|
||||||
|
float screenX = (ndcX * 0.5F + 0.5F) * width;
|
||||||
|
float screenY = (ndcY * 0.5F + 0.5F) * height;
|
||||||
|
minX = Math.min(minX, screenX);
|
||||||
|
minY = Math.min(minY, screenY);
|
||||||
|
maxX = Math.max(maxX, screenX);
|
||||||
|
maxY = Math.max(maxY, screenY);
|
||||||
|
}
|
||||||
|
if (!visible) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int scissorX = Mth.clamp((int) Math.floor(minX), 0, width - 1);
|
||||||
|
int scissorMaxX = Mth.clamp((int) Math.ceil(maxX), scissorX + 1, width);
|
||||||
|
int scissorYTop = Mth.clamp((int) Math.floor(minY), 0, height - 1);
|
||||||
|
int scissorYBottom = Mth.clamp((int) Math.ceil(maxY), scissorYTop + 1, height);
|
||||||
|
int scissorY = height - scissorYBottom;
|
||||||
|
int scissorWidth = Math.max(1, scissorMaxX - scissorX);
|
||||||
|
int scissorHeight = Math.max(1, scissorYBottom - scissorYTop);
|
||||||
|
return new ScreenClip(scissorX, scissorY, scissorWidth, scissorHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawPortalQuad(Vec3 cameraPos, Matrix4f poseMatrix, PortalGunPortalEntity portal, int textureId) {
|
||||||
|
drawTexturedPortal(cameraPos, poseMatrix, portal, textureId, SURFACE_OFFSET, 1.0F, 1.0F, 1.0F, 1.0F, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int widthTimesHeight(Minecraft minecraft) {
|
||||||
|
return minecraft.getWindow().getWidth() * minecraft.getWindow().getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawPortalOverlay(Minecraft minecraft, Vec3 cameraPos, Matrix4f poseMatrix, PortalGunPortalEntity portal) {
|
||||||
|
float time = (minecraft.level.getGameTime() + minecraft.getTimer().getGameTimeDeltaPartialTick(false)) * 0.075F;
|
||||||
|
float pulse = 0.72F + 0.18F * (float) Math.sin(time);
|
||||||
|
float edge = 0.38F + 0.08F * (float) Math.cos(time * 1.7F);
|
||||||
|
if (portal.getPortalSide() == PortalGunPortalEntity.PortalSide.BLUE) {
|
||||||
|
drawTexturedPortal(cameraPos, poseMatrix, portal, BLUE_OVERLAY, OVERLAY_OFFSET, 0.78F, 0.94F, 1.0F, pulse, false);
|
||||||
|
drawTexturedPortal(cameraPos, poseMatrix, portal, BLUE_OVERLAY, OVERLAY_OFFSET + 0.0008D, 0.26F, 0.62F, 1.0F, edge, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
drawTexturedPortal(cameraPos, poseMatrix, portal, ORANGE_OVERLAY, OVERLAY_OFFSET, 1.0F, 0.84F, 0.46F, pulse, false);
|
||||||
|
drawTexturedPortal(cameraPos, poseMatrix, portal, ORANGE_OVERLAY, OVERLAY_OFFSET + 0.0008D, 1.0F, 0.48F, 0.16F, edge, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawTexturedPortal(Vec3 cameraPos, Matrix4f poseMatrix, PortalGunPortalEntity portal, ResourceLocation texture, double offset, float red, float green, float blue, float alpha, boolean additive) {
|
||||||
|
Vec3 widthVec = portal.getWidthVec().normalize().scale(0.5D);
|
||||||
|
Vec3 upVec = portal.getUpVec().normalize().scale(1.0D);
|
||||||
|
Vec3 normalVec = portal.getNormalVec().normalize().scale(offset);
|
||||||
|
Vec3 center = portal.position().add(normalVec);
|
||||||
|
Vec3 bottomLeft = center.subtract(widthVec).subtract(upVec).subtract(cameraPos);
|
||||||
|
Vec3 topLeft = center.subtract(widthVec).add(upVec).subtract(cameraPos);
|
||||||
|
Vec3 topRight = center.add(widthVec).add(upVec).subtract(cameraPos);
|
||||||
|
Vec3 bottomRight = center.add(widthVec).subtract(upVec).subtract(cameraPos);
|
||||||
|
|
||||||
|
RenderSystem.enableBlend();
|
||||||
|
if (additive) {
|
||||||
|
RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
|
||||||
|
} else {
|
||||||
|
RenderSystem.defaultBlendFunc();
|
||||||
|
}
|
||||||
|
RenderSystem.depthMask(false);
|
||||||
|
RenderSystem.disableCull();
|
||||||
|
RenderSystem.setShader(GameRenderer::getPositionTexShader);
|
||||||
|
RenderSystem.setShaderTexture(0, texture);
|
||||||
|
RenderSystem.setShaderColor(red, green, blue, alpha);
|
||||||
|
|
||||||
|
BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX);
|
||||||
|
buffer.addVertex(poseMatrix, (float) bottomLeft.x, (float) bottomLeft.y, (float) bottomLeft.z).setUv(0.0F, 1.0F);
|
||||||
|
buffer.addVertex(poseMatrix, (float) topLeft.x, (float) topLeft.y, (float) topLeft.z).setUv(0.0F, 0.0F);
|
||||||
|
buffer.addVertex(poseMatrix, (float) topRight.x, (float) topRight.y, (float) topRight.z).setUv(1.0F, 0.0F);
|
||||||
|
buffer.addVertex(poseMatrix, (float) bottomRight.x, (float) bottomRight.y, (float) bottomRight.z).setUv(1.0F, 1.0F);
|
||||||
|
MeshData mesh = buffer.build();
|
||||||
|
if (mesh != null) {
|
||||||
|
BufferUploader.drawWithShader(mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderSystem.enableCull();
|
||||||
|
RenderSystem.depthMask(true);
|
||||||
|
RenderSystem.disableBlend();
|
||||||
|
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawTexturedPortal(Vec3 cameraPos, Matrix4f poseMatrix, PortalGunPortalEntity portal, int textureId, double offset, float red, float green, float blue, float alpha, boolean additive) {
|
||||||
|
Vec3 widthVec = portal.getWidthVec().normalize().scale(0.5D);
|
||||||
|
Vec3 upVec = portal.getUpVec().normalize().scale(1.0D);
|
||||||
|
Vec3 normalVec = portal.getNormalVec().normalize().scale(offset);
|
||||||
|
Vec3 center = portal.position().add(normalVec);
|
||||||
|
Vec3 bottomLeft = center.subtract(widthVec).subtract(upVec).subtract(cameraPos);
|
||||||
|
Vec3 topLeft = center.subtract(widthVec).add(upVec).subtract(cameraPos);
|
||||||
|
Vec3 topRight = center.add(widthVec).add(upVec).subtract(cameraPos);
|
||||||
|
Vec3 bottomRight = center.add(widthVec).subtract(upVec).subtract(cameraPos);
|
||||||
|
|
||||||
|
RenderSystem.enableBlend();
|
||||||
|
if (additive) {
|
||||||
|
RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
|
||||||
|
} else {
|
||||||
|
RenderSystem.defaultBlendFunc();
|
||||||
|
}
|
||||||
|
RenderSystem.depthMask(false);
|
||||||
|
RenderSystem.disableCull();
|
||||||
|
RenderSystem.setShader(GameRenderer::getPositionTexShader);
|
||||||
|
RenderSystem.setShaderTexture(0, textureId);
|
||||||
|
RenderSystem.setShaderColor(red, green, blue, alpha);
|
||||||
|
|
||||||
|
BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX);
|
||||||
|
buffer.addVertex(poseMatrix, (float) bottomLeft.x, (float) bottomLeft.y, (float) bottomLeft.z).setUv(0.0F, 1.0F);
|
||||||
|
buffer.addVertex(poseMatrix, (float) topLeft.x, (float) topLeft.y, (float) topLeft.z).setUv(0.0F, 0.0F);
|
||||||
|
buffer.addVertex(poseMatrix, (float) topRight.x, (float) topRight.y, (float) topRight.z).setUv(1.0F, 0.0F);
|
||||||
|
buffer.addVertex(poseMatrix, (float) bottomRight.x, (float) bottomRight.y, (float) bottomRight.z).setUv(1.0F, 1.0F);
|
||||||
|
MeshData mesh = buffer.build();
|
||||||
|
if (mesh != null) {
|
||||||
|
BufferUploader.drawWithShader(mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderSystem.enableCull();
|
||||||
|
RenderSystem.depthMask(true);
|
||||||
|
RenderSystem.disableBlend();
|
||||||
|
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class PortalCamera extends Camera {
|
||||||
|
private void setup(net.minecraft.world.level.BlockGetter level, Entity cameraEntity, float partialTick, Vec3 position, Vec3 look, Vec3 up) {
|
||||||
|
super.setup(level, cameraEntity, false, false, partialTick);
|
||||||
|
Vec3 normalizedLook = look.normalize();
|
||||||
|
Vec3 normalizedUp = up.subtract(normalizedLook.scale(up.dot(normalizedLook))).normalize();
|
||||||
|
float yaw = PortalGunTransformUtil.yawFromLook(normalizedLook);
|
||||||
|
float pitch = PortalGunTransformUtil.pitchFromLook(normalizedLook);
|
||||||
|
this.setPosition(position);
|
||||||
|
this.setRotation(yaw, pitch);
|
||||||
|
Vec3 currentUp = new Vec3(this.getUpVector()).normalize();
|
||||||
|
if (currentUp.dot(normalizedUp) < 0.0D) {
|
||||||
|
this.setRotation(yaw + 180.0F, -pitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private record RenderContext(Vec3 cameraPos, Vec3 look, Vec3 up, Matrix4f viewMatrix) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private record ScreenClip(int x, int y, int width, int height) {
|
||||||
|
private int area() {
|
||||||
|
return this.width * this.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+80
@@ -0,0 +1,80 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client.renderer;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunProjectileEntity;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.renderer.entity.EntityRenderer;
|
||||||
|
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||||
|
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
|
||||||
|
public class PortalGunProjectileRenderer extends EntityRenderer<PortalGunProjectileEntity> {
|
||||||
|
private static final ResourceLocation BLUE_TEXTURE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/vfx/portal_gun_portal_blue.png");
|
||||||
|
private static final ResourceLocation ORANGE_TEXTURE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/vfx/portal_gun_portal_orange.png");
|
||||||
|
|
||||||
|
public PortalGunProjectileRenderer(EntityRendererProvider.Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(PortalGunProjectileEntity entity, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight) {
|
||||||
|
poseStack.pushPose();
|
||||||
|
poseStack.mulPose(this.entityRenderDispatcher.cameraOrientation());
|
||||||
|
float age = entity.tickCount + partialTick;
|
||||||
|
float pulse = 0.8F + 0.2F * (float) Math.sin(age * 0.9F);
|
||||||
|
float trailStretch = 1.1F + (float) Math.min(entity.getDeltaMovement().length() * 0.3D, 1.4D);
|
||||||
|
float baseScale = entity.getPortalSide() == com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity.PortalSide.BLUE ? 0.44F : 0.48F;
|
||||||
|
ResourceLocation texture = entity.getPortalSide() == com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity.PortalSide.BLUE ? BLUE_TEXTURE : ORANGE_TEXTURE;
|
||||||
|
float red = entity.getPortalSide() == com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity.PortalSide.BLUE ? 0.55F : 1.0F;
|
||||||
|
float green = entity.getPortalSide() == com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity.PortalSide.BLUE ? 0.82F : 0.56F;
|
||||||
|
float blue = entity.getPortalSide() == com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity.PortalSide.BLUE ? 1.0F : 0.18F;
|
||||||
|
|
||||||
|
poseStack.scale(baseScale * trailStretch, baseScale, baseScale);
|
||||||
|
PoseStack.Pose pose = poseStack.last();
|
||||||
|
Matrix4f matrix = pose.pose();
|
||||||
|
VertexConsumer core = bufferSource.getBuffer(RenderType.entityTranslucent(texture));
|
||||||
|
addQuad(core, pose, matrix, red, green, blue, 0.92F, packedLight, -0.9F, -0.5F, 0.9F, 0.5F);
|
||||||
|
VertexConsumer glow = bufferSource.getBuffer(RenderType.entityTranslucentEmissive(texture));
|
||||||
|
addQuad(glow, pose, matrix, 1.0F, 1.0F, 1.0F, 0.8F * pulse, 0xF000F0, -1.15F, -0.7F, 1.15F, 0.7F);
|
||||||
|
|
||||||
|
poseStack.mulPose(com.mojang.math.Axis.ZP.rotationDegrees(90.0F));
|
||||||
|
pose = poseStack.last();
|
||||||
|
matrix = pose.pose();
|
||||||
|
core = bufferSource.getBuffer(RenderType.entityTranslucent(texture));
|
||||||
|
addQuad(core, pose, matrix, red, green, blue, 0.74F, packedLight, -0.45F, -0.95F, 0.45F, 0.95F);
|
||||||
|
glow = bufferSource.getBuffer(RenderType.entityTranslucentEmissive(texture));
|
||||||
|
addQuad(glow, pose, matrix, 1.0F, 1.0F, 1.0F, 0.52F * pulse, 0xF000F0, -0.62F, -1.15F, 0.62F, 1.15F);
|
||||||
|
poseStack.popPose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getBlockLightLevel(PortalGunProjectileEntity entity, BlockPos pos) {
|
||||||
|
return 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getTextureLocation(PortalGunProjectileEntity entity) {
|
||||||
|
return entity.getPortalSide() == com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity.PortalSide.BLUE ? BLUE_TEXTURE : ORANGE_TEXTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addQuad(VertexConsumer consumer, PoseStack.Pose pose, Matrix4f matrix, float red, float green, float blue, float alpha, int packedLight, float minX, float minY, float maxX, float maxY) {
|
||||||
|
addVertex(consumer, pose, matrix, minX, minY, 0.0F, 1.0F, red, green, blue, alpha, packedLight);
|
||||||
|
addVertex(consumer, pose, matrix, maxX, minY, 1.0F, 1.0F, red, green, blue, alpha, packedLight);
|
||||||
|
addVertex(consumer, pose, matrix, maxX, maxY, 1.0F, 0.0F, red, green, blue, alpha, packedLight);
|
||||||
|
addVertex(consumer, pose, matrix, minX, maxY, 0.0F, 0.0F, red, green, blue, alpha, packedLight);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addVertex(VertexConsumer consumer, PoseStack.Pose pose, Matrix4f matrix, float x, float y, float u, float v, float red, float green, float blue, float alpha, int packedLight) {
|
||||||
|
consumer.addVertex(matrix, x, y, 0.0F)
|
||||||
|
.setColor(red, green, blue, alpha)
|
||||||
|
.setUv(u, v)
|
||||||
|
.setOverlay(OverlayTexture.NO_OVERLAY)
|
||||||
|
.setLight(packedLight)
|
||||||
|
.setNormal(pose, 0.0F, 0.0F, 1.0F);
|
||||||
|
}
|
||||||
|
}
|
||||||
+72
@@ -72,6 +72,40 @@ public final class CreativeTabContents {
|
|||||||
entry("peach_button", "building_blocks"),
|
entry("peach_button", "building_blocks"),
|
||||||
entry("peach_sign", "building_blocks"),
|
entry("peach_sign", "building_blocks"),
|
||||||
entry("peach_hanging_sign", "building_blocks"),
|
entry("peach_hanging_sign", "building_blocks"),
|
||||||
|
entry("truffalo_log", "building_blocks"),
|
||||||
|
entry("truffalo_wood", "building_blocks"),
|
||||||
|
entry("stripped_truffalo_log", "building_blocks"),
|
||||||
|
entry("stripped_truffalo_wood", "building_blocks"),
|
||||||
|
entry("truffalo_planks", "building_blocks"),
|
||||||
|
entry("truffalo_stairs", "building_blocks"),
|
||||||
|
entry("truffalo_slab", "building_blocks"),
|
||||||
|
entry("truffalo_fence", "building_blocks"),
|
||||||
|
entry("truffalo_fence_gate", "building_blocks"),
|
||||||
|
entry("truffalo_boat", "building_blocks"),
|
||||||
|
entry("truffalo_chest_boat", "building_blocks"),
|
||||||
|
entry("truffalo_door", "building_blocks"),
|
||||||
|
entry("truffalo_trapdoor", "building_blocks"),
|
||||||
|
entry("truffalo_pressure_plate", "building_blocks"),
|
||||||
|
entry("truffalo_button", "building_blocks"),
|
||||||
|
entry("truffalo_sign", "building_blocks"),
|
||||||
|
entry("truffalo_hanging_sign", "building_blocks"),
|
||||||
|
entry("royal_log", "building_blocks"),
|
||||||
|
entry("royal_wood", "building_blocks"),
|
||||||
|
entry("stripped_royal_log", "building_blocks"),
|
||||||
|
entry("stripped_royal_wood", "building_blocks"),
|
||||||
|
entry("royal_planks", "building_blocks"),
|
||||||
|
entry("royal_stairs", "building_blocks"),
|
||||||
|
entry("royal_slab", "building_blocks"),
|
||||||
|
entry("royal_fence", "building_blocks"),
|
||||||
|
entry("royal_fence_gate", "building_blocks"),
|
||||||
|
entry("royal_boat", "building_blocks"),
|
||||||
|
entry("royal_chest_boat", "building_blocks"),
|
||||||
|
entry("royal_door", "building_blocks"),
|
||||||
|
entry("royal_trapdoor", "building_blocks"),
|
||||||
|
entry("royal_pressure_plate", "building_blocks"),
|
||||||
|
entry("royal_button", "building_blocks"),
|
||||||
|
entry("royal_sign", "building_blocks"),
|
||||||
|
entry("royal_hanging_sign", "building_blocks"),
|
||||||
entry("shellstone", "building_blocks"),
|
entry("shellstone", "building_blocks"),
|
||||||
entry("shellstone_stairs", "building_blocks"),
|
entry("shellstone_stairs", "building_blocks"),
|
||||||
entry("shellstone_slab", "building_blocks"),
|
entry("shellstone_slab", "building_blocks"),
|
||||||
@@ -254,8 +288,28 @@ public final class CreativeTabContents {
|
|||||||
entry("ouranwood_acorn", "natural_blocks"),
|
entry("ouranwood_acorn", "natural_blocks"),
|
||||||
entry("peach_leaves", "natural_blocks"),
|
entry("peach_leaves", "natural_blocks"),
|
||||||
entry("peach_sapling", "natural_blocks"),
|
entry("peach_sapling", "natural_blocks"),
|
||||||
|
entry("truffalo_sapling", "natural_blocks"),
|
||||||
|
entry("royal_leaves", "natural_blocks"),
|
||||||
|
entry("royal_flowering_leaves", "natural_blocks"),
|
||||||
|
entry("royal_sapling", "natural_blocks"),
|
||||||
entry("nadir_veil", "natural_blocks"),
|
entry("nadir_veil", "natural_blocks"),
|
||||||
entry("nadir_sapling", "natural_blocks"),
|
entry("nadir_sapling", "natural_blocks"),
|
||||||
|
entry("white_truffalo_tuft", "natural_blocks"),
|
||||||
|
entry("orange_truffalo_tuft", "natural_blocks"),
|
||||||
|
entry("magenta_truffalo_tuft", "natural_blocks"),
|
||||||
|
entry("light_blue_truffalo_tuft", "natural_blocks"),
|
||||||
|
entry("yellow_truffalo_tuft", "natural_blocks"),
|
||||||
|
entry("lime_truffalo_tuft", "natural_blocks"),
|
||||||
|
entry("pink_truffalo_tuft", "natural_blocks"),
|
||||||
|
entry("gray_truffalo_tuft", "natural_blocks"),
|
||||||
|
entry("light_gray_truffalo_tuft", "natural_blocks"),
|
||||||
|
entry("cyan_truffalo_tuft", "natural_blocks"),
|
||||||
|
entry("purple_truffalo_tuft", "natural_blocks"),
|
||||||
|
entry("blue_truffalo_tuft", "natural_blocks"),
|
||||||
|
entry("brown_truffalo_tuft", "natural_blocks"),
|
||||||
|
entry("green_truffalo_tuft", "natural_blocks"),
|
||||||
|
entry("red_truffalo_tuft", "natural_blocks"),
|
||||||
|
entry("black_truffalo_tuft", "natural_blocks"),
|
||||||
entry("duplicator_log", "natural_blocks"),
|
entry("duplicator_log", "natural_blocks"),
|
||||||
entry("duplicator_sapling", "natural_blocks"),
|
entry("duplicator_sapling", "natural_blocks"),
|
||||||
entry("orange_milkweed", "natural_blocks"),
|
entry("orange_milkweed", "natural_blocks"),
|
||||||
@@ -300,6 +354,7 @@ public final class CreativeTabContents {
|
|||||||
entry("dead_star_coral_fan", "natural_blocks"),
|
entry("dead_star_coral_fan", "natural_blocks"),
|
||||||
entry("dead_star_coral_block", "natural_blocks"),
|
entry("dead_star_coral_block", "natural_blocks"),
|
||||||
entry("duct_tape", "tools_and_utilities", "shears"),
|
entry("duct_tape", "tools_and_utilities", "shears"),
|
||||||
|
entry("music_disc_underside", "tools_and_utilities"),
|
||||||
entry("diamond_minecart", "tools_and_utilities", "minecart"),
|
entry("diamond_minecart", "tools_and_utilities", "minecart"),
|
||||||
entry("bile_bucket", "tools_and_utilities"),
|
entry("bile_bucket", "tools_and_utilities"),
|
||||||
entry("ichor_bucket", "tools_and_utilities"),
|
entry("ichor_bucket", "tools_and_utilities"),
|
||||||
@@ -419,6 +474,23 @@ public final class CreativeTabContents {
|
|||||||
entry("big_bertha_blade", "ingredients"),
|
entry("big_bertha_blade", "ingredients"),
|
||||||
entry("big_bertha_handle", "ingredients"),
|
entry("big_bertha_handle", "ingredients"),
|
||||||
entry("big_bertha_hilt", "ingredients"),
|
entry("big_bertha_hilt", "ingredients"),
|
||||||
|
entry("hoverboard", "building_blocks"),
|
||||||
|
entry("hoverboard_white", "building_blocks"),
|
||||||
|
entry("hoverboard_orange", "building_blocks"),
|
||||||
|
entry("hoverboard_magenta", "building_blocks"),
|
||||||
|
entry("hoverboard_light_blue", "building_blocks"),
|
||||||
|
entry("hoverboard_yellow", "building_blocks"),
|
||||||
|
entry("hoverboard_lime", "building_blocks"),
|
||||||
|
entry("hoverboard_pink", "building_blocks"),
|
||||||
|
entry("hoverboard_gray", "building_blocks"),
|
||||||
|
entry("hoverboard_light_gray", "building_blocks"),
|
||||||
|
entry("hoverboard_cyan", "building_blocks"),
|
||||||
|
entry("hoverboard_purple", "building_blocks"),
|
||||||
|
entry("hoverboard_blue", "building_blocks"),
|
||||||
|
entry("hoverboard_brown", "building_blocks"),
|
||||||
|
entry("hoverboard_green", "building_blocks"),
|
||||||
|
entry("hoverboard_red", "building_blocks"),
|
||||||
|
entry("hoverboard_black", "building_blocks"),
|
||||||
entry("easter_bunny_spawn_egg", "spawn_eggs"),
|
entry("easter_bunny_spawn_egg", "spawn_eggs"),
|
||||||
entry("flying_squirrel_spawn_egg", "spawn_eggs"),
|
entry("flying_squirrel_spawn_egg", "spawn_eggs"),
|
||||||
entry("caterpillar_spawn_egg", "spawn_eggs"),
|
entry("caterpillar_spawn_egg", "spawn_eggs"),
|
||||||
|
|||||||
+243
@@ -0,0 +1,243 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import com.craisinlord.antarchy.mixins.LivingEntityJumpingAccessor;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||||
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||||
|
import net.minecraft.network.syncher.SynchedEntityData;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.sounds.SoundEvents;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
|
import net.minecraft.world.damagesource.DamageSource;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
import net.minecraft.world.entity.MoverType;
|
||||||
|
import net.minecraft.world.entity.PathfinderMob;
|
||||||
|
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||||
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.DyeColor;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import software.bernie.geckolib.animatable.GeoEntity;
|
||||||
|
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
||||||
|
import software.bernie.geckolib.animation.AnimatableManager;
|
||||||
|
import software.bernie.geckolib.animation.AnimationController;
|
||||||
|
import software.bernie.geckolib.animation.AnimationState;
|
||||||
|
import software.bernie.geckolib.animation.PlayState;
|
||||||
|
import software.bernie.geckolib.animation.RawAnimation;
|
||||||
|
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||||
|
|
||||||
|
public class HoverboardEntity extends PathfinderMob implements GeoEntity {
|
||||||
|
private static final EntityDataAccessor<Integer> COLOR = SynchedEntityData.defineId(HoverboardEntity.class, EntityDataSerializers.INT);
|
||||||
|
|
||||||
|
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
|
||||||
|
private static final RawAnimation MOVE_ANIM = RawAnimation.begin().thenLoop("move");
|
||||||
|
|
||||||
|
private static final double MAX_HOVER_HEIGHT = 5.0D;
|
||||||
|
private static final double ACCELERATION = 0.08D;
|
||||||
|
private static final double MAX_SPEED = 1.8D;
|
||||||
|
private static final double ASCEND_SPEED = 0.15D;
|
||||||
|
private static final double DAMPING = 0.955D;
|
||||||
|
private static final double RIDER_Y_OFFSET = 0.65D;
|
||||||
|
private static final float RIDER_FORWARD_HEAD_OFFSET = 90.0F;
|
||||||
|
|
||||||
|
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
|
|
||||||
|
public HoverboardEntity(EntityType<? extends HoverboardEntity> entityType, Level level) {
|
||||||
|
super(entityType, level);
|
||||||
|
this.setNoGravity(true);
|
||||||
|
this.setPersistenceRequired();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AttributeSupplier.Builder createAttributes() {
|
||||||
|
return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 6.0D);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hurt(DamageSource source, float amount) {
|
||||||
|
if (this.level().isClientSide || !this.isAlive()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.isInvulnerableTo(source)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.ejectPassengers();
|
||||||
|
this.playSound(SoundEvents.WOOD_BREAK, 1.0F, 1.0F);
|
||||||
|
this.spawnAtLocation(this.getDropStack());
|
||||||
|
this.discard();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void registerGoals() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
||||||
|
super.defineSynchedData(builder);
|
||||||
|
builder.define(COLOR, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public DyeColor getColor() {
|
||||||
|
int id = this.entityData.get(COLOR);
|
||||||
|
return id < 0 ? null : DyeColor.byId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor(@Nullable DyeColor color) {
|
||||||
|
this.entityData.set(COLOR, color == null ? -1 : color.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAdditionalSaveData(CompoundTag tag) {
|
||||||
|
super.addAdditionalSaveData(tag);
|
||||||
|
if (this.getColor() != null) {
|
||||||
|
tag.putString("Color", this.getColor().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readAdditionalSaveData(CompoundTag tag) {
|
||||||
|
super.readAdditionalSaveData(tag);
|
||||||
|
this.setColor(tag.contains("Color") ? DyeColor.byName(tag.getString("Color"), null) : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected InteractionResult mobInteract(Player player, InteractionHand hand) {
|
||||||
|
if (!this.isVehicle() && !player.isSecondaryUseActive()) {
|
||||||
|
if (!this.level().isClientSide) {
|
||||||
|
player.startRiding(this);
|
||||||
|
}
|
||||||
|
return InteractionResult.sidedSuccess(this.level().isClientSide);
|
||||||
|
}
|
||||||
|
return super.mobInteract(player, hand);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public LivingEntity getControllingPassenger() {
|
||||||
|
Entity passenger = this.getFirstPassenger();
|
||||||
|
return passenger instanceof Player player ? player : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canAddPassenger(Entity passenger) {
|
||||||
|
return this.getPassengers().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void positionRider(Entity passenger, MoveFunction moveFunction) {
|
||||||
|
if (!this.hasPassenger(passenger)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
moveFunction.accept(passenger, this.getX(), this.getY() + RIDER_Y_OFFSET, this.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void travel(Vec3 travelVector) {
|
||||||
|
if (this.getControllingPassenger() instanceof Player rider) {
|
||||||
|
this.setYRot(rider.getYRot());
|
||||||
|
this.yRotO = this.getYRot();
|
||||||
|
this.yBodyRot = this.getYRot();
|
||||||
|
this.yHeadRot = this.getYRot();
|
||||||
|
this.setXRot(0.0F);
|
||||||
|
rider.setYHeadRot(rider.getYRot() + RIDER_FORWARD_HEAD_OFFSET);
|
||||||
|
|
||||||
|
Vec3 look = Vec3.directionFromRotation(0.0F, this.getYRot());
|
||||||
|
float forward = rider.zza;
|
||||||
|
boolean holdingJump = ((LivingEntityJumpingAccessor) rider).antarchy$isJumping();
|
||||||
|
double ascend = holdingJump ? ASCEND_SPEED : (rider.isShiftKeyDown() ? -ASCEND_SPEED : 0.0D);
|
||||||
|
|
||||||
|
double groundHeight = this.findGroundHeight();
|
||||||
|
double maxY = groundHeight + MAX_HOVER_HEIGHT;
|
||||||
|
|
||||||
|
Vec3 currentHorizontal = new Vec3(this.getDeltaMovement().x, 0.0D, this.getDeltaMovement().z);
|
||||||
|
Vec3 horizontalMotion = currentHorizontal.scale(DAMPING).add(look.scale(forward * ACCELERATION));
|
||||||
|
|
||||||
|
double horizontalSpeed = horizontalMotion.horizontalDistance();
|
||||||
|
if (horizontalSpeed > MAX_SPEED) {
|
||||||
|
double scale = MAX_SPEED / horizontalSpeed;
|
||||||
|
horizontalMotion = new Vec3(horizontalMotion.x * scale, 0.0D, horizontalMotion.z * scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
double verticalMotion = ascend;
|
||||||
|
if (this.getY() >= maxY && verticalMotion > 0.0D) {
|
||||||
|
verticalMotion = 0.0D;
|
||||||
|
}
|
||||||
|
if (this.getY() <= groundHeight && verticalMotion < 0.0D) {
|
||||||
|
verticalMotion = 0.0D;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setDeltaMovement(horizontalMotion.x, verticalMotion, horizontalMotion.z);
|
||||||
|
this.move(MoverType.SELF, this.getDeltaMovement());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setDeltaMovement(this.getDeltaMovement().scale(DAMPING));
|
||||||
|
this.move(MoverType.SELF, this.getDeltaMovement());
|
||||||
|
}
|
||||||
|
|
||||||
|
private double findGroundHeight() {
|
||||||
|
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(Mth.floor(this.getX()), Mth.floor(this.getY()), Mth.floor(this.getZ()));
|
||||||
|
int minY = this.level().getMinBuildHeight();
|
||||||
|
while (pos.getY() > minY && this.level().getBlockState(pos).isAir()) {
|
||||||
|
pos.move(Direction.DOWN);
|
||||||
|
}
|
||||||
|
return pos.getY() + 1.0D;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean causeFallDamage(float fallDistance, float multiplier, DamageSource source) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeWhenFarAway(double distanceToClosestPlayer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void die(DamageSource damageSource) {
|
||||||
|
super.die(damageSource);
|
||||||
|
if (!this.level().isClientSide) {
|
||||||
|
this.spawnAtLocation(this.getDropStack());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemStack getDropStack() {
|
||||||
|
String path = this.getColor() == null ? "hoverboard" : "hoverboard_" + this.getColor().getName();
|
||||||
|
Item item = BuiltInRegistries.ITEM.get(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, path));
|
||||||
|
return new ItemStack(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack getPickResult() {
|
||||||
|
return this.getDropStack();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
|
||||||
|
controllers.add(new AnimationController<>(this, "movement", 0, this::movementController));
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlayState movementController(AnimationState<HoverboardEntity> state) {
|
||||||
|
return state.setAndContinue(this.getDeltaMovement().horizontalDistanceSqr() > 0.0025D ? MOVE_ANIM : IDLE_ANIM);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnimatableInstanceCache getAnimatableInstanceCache() {
|
||||||
|
return this.geoCache;
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.vehicle.Boat;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
|
||||||
|
public class RoyalBoatEntity extends Boat {
|
||||||
|
public RoyalBoatEntity(EntityType<? extends Boat> entityType, Level level) {
|
||||||
|
super(entityType, level);
|
||||||
|
this.setVariant(Type.OAK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Item getDropItem() {
|
||||||
|
return BuiltInRegistries.ITEM.get(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "royal_boat"));
|
||||||
|
}
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.vehicle.Boat;
|
||||||
|
import net.minecraft.world.entity.vehicle.ChestBoat;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
|
||||||
|
public class RoyalChestBoatEntity extends ChestBoat {
|
||||||
|
public RoyalChestBoatEntity(EntityType<? extends Boat> entityType, Level level) {
|
||||||
|
super(entityType, level);
|
||||||
|
this.setVariant(Type.OAK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Item getDropItem() {
|
||||||
|
return BuiltInRegistries.ITEM.get(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "royal_chest_boat"));
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.vehicle.Boat;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
|
||||||
|
public class TruffaloBoatEntity extends Boat {
|
||||||
|
public TruffaloBoatEntity(EntityType<? extends Boat> entityType, Level level) {
|
||||||
|
super(entityType, level);
|
||||||
|
this.setVariant(Type.OAK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Item getDropItem() {
|
||||||
|
return BuiltInRegistries.ITEM.get(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "truffalo_boat"));
|
||||||
|
}
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.vehicle.Boat;
|
||||||
|
import net.minecraft.world.entity.vehicle.ChestBoat;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
|
||||||
|
public class TruffaloChestBoatEntity extends ChestBoat {
|
||||||
|
public TruffaloChestBoatEntity(EntityType<? extends Boat> entityType, Level level) {
|
||||||
|
super(entityType, level);
|
||||||
|
this.setVariant(Type.OAK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Item getDropItem() {
|
||||||
|
return BuiltInRegistries.ITEM.get(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "truffalo_chest_boat"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package com.craisinlord.antarchy.content.item;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.entity.HoverboardEntity;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import net.minecraft.stats.Stats;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResultHolder;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntitySelector;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.DyeColor;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.ClipContext;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.gameevent.GameEvent;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import net.minecraft.world.phys.HitResult;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class HoverboardItem extends Item {
|
||||||
|
private static final Predicate<Entity> ENTITY_PREDICATE = EntitySelector.NO_SPECTATORS.and(Entity::isPickable);
|
||||||
|
|
||||||
|
private final EntityType<? extends HoverboardEntity> entityType;
|
||||||
|
@Nullable
|
||||||
|
private final DyeColor color;
|
||||||
|
|
||||||
|
public HoverboardItem(EntityType<? extends HoverboardEntity> entityType, @Nullable DyeColor color, Properties properties) {
|
||||||
|
super(properties);
|
||||||
|
this.entityType = entityType;
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
|
||||||
|
ItemStack stack = player.getItemInHand(hand);
|
||||||
|
BlockHitResult hitResult = getPlayerPOVHitResult(level, player, ClipContext.Fluid.ANY);
|
||||||
|
if (hitResult.getType() == HitResult.Type.MISS) {
|
||||||
|
return InteractionResultHolder.pass(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 viewVector = player.getViewVector(1.0F);
|
||||||
|
for (Entity entity : level.getEntities(player, player.getBoundingBox().expandTowards(viewVector.scale(5.0D)).inflate(1.0D), ENTITY_PREDICATE)) {
|
||||||
|
if (entity.getBoundingBox().inflate(entity.getPickRadius()).contains(player.getEyePosition())) {
|
||||||
|
return InteractionResultHolder.pass(stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hitResult.getType() != HitResult.Type.BLOCK) {
|
||||||
|
return InteractionResultHolder.pass(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
HoverboardEntity hoverboard = new HoverboardEntity(this.entityType, level);
|
||||||
|
Vec3 spawnPos = hitResult.getLocation();
|
||||||
|
hoverboard.moveTo(spawnPos.x, spawnPos.y, spawnPos.z, player.getYRot(), 0.0F);
|
||||||
|
hoverboard.setColor(this.color);
|
||||||
|
if (!level.noCollision(hoverboard, hoverboard.getBoundingBox())) {
|
||||||
|
return InteractionResultHolder.fail(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!level.isClientSide) {
|
||||||
|
level.addFreshEntity(hoverboard);
|
||||||
|
level.gameEvent(player, GameEvent.ENTITY_PLACE, hitResult.getLocation());
|
||||||
|
if (!player.getAbilities().instabuild) {
|
||||||
|
stack.consume(1, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
player.awardStat(Stats.ITEM_USED.get(this));
|
||||||
|
return InteractionResultHolder.sidedSuccess(stack, level.isClientSide());
|
||||||
|
}
|
||||||
|
}
|
||||||
+262
-54
@@ -1,14 +1,20 @@
|
|||||||
package com.craisinlord.antarchy.content.item;
|
package com.craisinlord.antarchy.content.item;
|
||||||
|
|
||||||
import com.craisinlord.antarchy.Antarchy;
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import com.craisinlord.antarchy.content.block.entity.PortalGunPortalBaseBlockEntity;
|
||||||
|
import com.craisinlord.antarchy.content.block.entity.PortalGunPortalMasterBlockEntity;
|
||||||
import com.craisinlord.antarchy.content.client.model.ResourceBackedGeoItemModel;
|
import com.craisinlord.antarchy.content.client.model.ResourceBackedGeoItemModel;
|
||||||
import com.craisinlord.antarchy.content.client.renderer.AnimatedHeldItemRenderer;
|
import com.craisinlord.antarchy.content.client.renderer.AnimatedHeldItemRenderer;
|
||||||
import com.craisinlord.antarchy.content.network.PortalGunPrimaryPayload;
|
import com.craisinlord.antarchy.content.network.PortalGunPrimaryPayload;
|
||||||
import com.craisinlord.antarchy.content.portalgun.PortalGunBlackHoleEntity;
|
import com.craisinlord.antarchy.content.portalgun.PortalGunBlackHoleEntity;
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunPlacement;
|
||||||
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
|
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunProjectileEntity;
|
||||||
import com.craisinlord.antarchy.content.portalgun.PortalGunSavedData;
|
import com.craisinlord.antarchy.content.portalgun.PortalGunSavedData;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
@@ -38,6 +44,9 @@ import net.minecraft.world.item.TooltipFlag;
|
|||||||
import net.minecraft.world.item.UseAnim;
|
import net.minecraft.world.item.UseAnim;
|
||||||
import net.minecraft.world.level.ClipContext;
|
import net.minecraft.world.level.ClipContext;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.material.FluidState;
|
import net.minecraft.world.level.material.FluidState;
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
@@ -58,17 +67,32 @@ public class PortalGunItem extends Item implements GeoItem {
|
|||||||
private static final String LED_CONTROLLER = "led_controller";
|
private static final String LED_CONTROLLER = "led_controller";
|
||||||
private static final String FIRE_CONTROLLER = "fire_controller";
|
private static final String FIRE_CONTROLLER = "fire_controller";
|
||||||
private static final String LAST_SIDE_TAG = "antarchy.portal_gun_last_side";
|
private static final String LAST_SIDE_TAG = "antarchy.portal_gun_last_side";
|
||||||
|
private static final String MOON_SIDE_TAG = "antarchy.portal_gun_moon_side";
|
||||||
|
public static final String GUN_ID_TAG = "antarchy.portal_gun_id";
|
||||||
private static final ResourceLocation MODEL_LOCATION = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/portal_gun.geo.json");
|
private static final ResourceLocation MODEL_LOCATION = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/portal_gun.geo.json");
|
||||||
private static final ResourceLocation TEXTURE_LOCATION = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/models/item/portal_gun.png");
|
private static final ResourceLocation TEXTURE_LOCATION = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/models/item/portal_gun.png");
|
||||||
private static final ResourceLocation ANIMATION_LOCATION = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/portal_gun.animation.json");
|
private static final ResourceLocation ANIMATION_LOCATION = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/portal_gun.animation.json");
|
||||||
private final Supplier<? extends EntityType<? extends PortalGunPortalEntity>> portalType;
|
private final Supplier<? extends EntityType<? extends PortalGunPortalEntity>> portalType;
|
||||||
private final Supplier<? extends EntityType<? extends PortalGunBlackHoleEntity>> blackHoleType;
|
private final Supplier<? extends EntityType<? extends PortalGunBlackHoleEntity>> blackHoleType;
|
||||||
|
private final Supplier<? extends EntityType<? extends PortalGunProjectileEntity>> projectileType;
|
||||||
|
private final Supplier<? extends Block> portalMasterBlock;
|
||||||
|
private final Supplier<? extends Block> portalBaseBlock;
|
||||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
|
|
||||||
public PortalGunItem(Item.Properties properties, Supplier<? extends EntityType<? extends PortalGunPortalEntity>> portalType, Supplier<? extends EntityType<? extends PortalGunBlackHoleEntity>> blackHoleType) {
|
public PortalGunItem(
|
||||||
|
Item.Properties properties,
|
||||||
|
Supplier<? extends EntityType<? extends PortalGunPortalEntity>> portalType,
|
||||||
|
Supplier<? extends EntityType<? extends PortalGunBlackHoleEntity>> blackHoleType,
|
||||||
|
Supplier<? extends EntityType<? extends PortalGunProjectileEntity>> projectileType,
|
||||||
|
Supplier<? extends Block> portalMasterBlock,
|
||||||
|
Supplier<? extends Block> portalBaseBlock
|
||||||
|
) {
|
||||||
super(properties);
|
super(properties);
|
||||||
this.portalType = portalType;
|
this.portalType = portalType;
|
||||||
this.blackHoleType = blackHoleType;
|
this.blackHoleType = blackHoleType;
|
||||||
|
this.projectileType = projectileType;
|
||||||
|
this.portalMasterBlock = portalMasterBlock;
|
||||||
|
this.portalBaseBlock = portalBaseBlock;
|
||||||
GeoItem.registerSyncedAnimatable(this);
|
GeoItem.registerSyncedAnimatable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +106,7 @@ public class PortalGunItem extends Item implements GeoItem {
|
|||||||
if (player.isShiftKeyDown()) {
|
if (player.isShiftKeyDown()) {
|
||||||
PortalGunSavedData.clearAllPortals(serverLevel.getServer(), player.getUUID());
|
PortalGunSavedData.clearAllPortals(serverLevel.getServer(), player.getUUID());
|
||||||
this.setLastSide(stack, null);
|
this.setLastSide(stack, null);
|
||||||
|
this.setMoonSide(stack, null);
|
||||||
level.playSound(null, player.getX(), player.getY(), player.getZ(), PortalGunPortalEntity.sound("portal_fizzle", SoundEvents.ENDER_CHEST_CLOSE), SoundSource.PLAYERS, 0.6F, 1.0F);
|
level.playSound(null, player.getX(), player.getY(), player.getZ(), PortalGunPortalEntity.sound("portal_fizzle", SoundEvents.ENDER_CHEST_CLOSE), SoundSource.PLAYERS, 0.6F, 1.0F);
|
||||||
return InteractionResultHolder.consume(stack);
|
return InteractionResultHolder.consume(stack);
|
||||||
}
|
}
|
||||||
@@ -94,66 +119,105 @@ public class PortalGunItem extends Item implements GeoItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean firePortal(ServerLevel level, Player player, ItemStack stack, PortalGunPortalEntity.PortalSide side) {
|
private boolean firePortal(ServerLevel level, Player player, ItemStack stack, PortalGunPortalEntity.PortalSide side) {
|
||||||
BlockHitResult hitResult = this.raycast(level, player);
|
if (this.raycast(level, player).getType() == HitResult.Type.MISS) {
|
||||||
if (hitResult.getType() == HitResult.Type.MISS) {
|
if (this.tryArmMoonShot(level, player, stack, side)) {
|
||||||
if (this.tryShootMoon(level, player, stack, side)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
level.playSound(null, player.getX(), player.getY(), player.getZ(), PortalGunPortalEntity.sound("portal_gun_invalid_surface", SoundEvents.DISPENSER_FAIL), SoundSource.PLAYERS, 0.55F, 1.0F);
|
level.playSound(null, player.getX(), player.getY(), player.getZ(), PortalGunPortalEntity.sound("portal_gun_invalid_surface", SoundEvents.DISPENSER_FAIL), SoundSource.PLAYERS, 0.55F, 1.0F);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.spawnShotTrail(level, player, hitResult.getLocation(), side);
|
this.triggerFireAnimation(level, player, stack);
|
||||||
Placement placement = this.findPlacement(level, player, hitResult);
|
this.setLastSide(stack, side);
|
||||||
if (placement == null) {
|
stack.hurtAndBreak(1, player, EquipmentSlot.MAINHAND);
|
||||||
level.playSound(null, player.getX(), player.getY(), player.getZ(), PortalGunPortalEntity.sound("portal_gun_invalid_surface", SoundEvents.DISPENSER_FAIL), SoundSource.PLAYERS, 0.55F, 1.0F);
|
player.awardStat(Stats.ITEM_USED.get(this));
|
||||||
return false;
|
player.getCooldowns().addCooldown(this, 6);
|
||||||
|
String firePath = side == PortalGunPortalEntity.PortalSide.BLUE ? "portal_gun_fire_blue" : "portal_gun_fire_orange";
|
||||||
|
level.playSound(null, player.getX(), player.getY(), player.getZ(), PortalGunPortalEntity.sound(firePath, SoundEvents.BEACON_ACTIVATE), SoundSource.PLAYERS, 0.65F, side == PortalGunPortalEntity.PortalSide.BLUE ? 1.15F : 0.88F);
|
||||||
|
this.spawnProjectile(level, player, stack, side);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void handlePortalImpact(ServerLevel level, Player player, ItemStack stack, PortalGunPortalEntity.PortalSide side, BlockHitResult hitResult, Vec3 impactPos) {
|
||||||
|
PortalGunPortalEntity existing = this.findPlacedPortal(level, player.getUUID(), side);
|
||||||
|
PortalGunPlacement placement = this.findPlacement(level, player, side, hitResult, existing);
|
||||||
|
if (placement == null) {
|
||||||
|
level.playSound(null, impactPos.x, impactPos.y, impactPos.z, PortalGunPortalEntity.sound("portal_gun_invalid_surface", SoundEvents.DISPENSER_FAIL), SoundSource.PLAYERS, 0.55F, 1.0F);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (existing != null) {
|
||||||
|
existing.discard();
|
||||||
|
}
|
||||||
|
if (this.isMoonSideArmed(stack, side)) {
|
||||||
|
this.setMoonSide(stack, null);
|
||||||
|
}
|
||||||
|
if (this.isMoonSideArmed(stack, this.otherSide(side))) {
|
||||||
|
this.spawnBlackHole(level, player, stack, side, placement.center());
|
||||||
|
return;
|
||||||
|
}
|
||||||
PortalGunPortalEntity portal = new PortalGunPortalEntity(this.portalType.get(), level);
|
PortalGunPortalEntity portal = new PortalGunPortalEntity(this.portalType.get(), level);
|
||||||
portal.configure(player.getUUID(), side, placement.facing(), placement.upAxis(), placement.supportOrigin());
|
portal.configure(player.getUUID(), side, placement);
|
||||||
portal.moveTo(placement.center().x, placement.center().y, placement.center().z, placement.yaw(), 0.0F);
|
portal.moveTo(placement.center().x, placement.center().y, placement.center().z, placement.yaw(), 0.0F);
|
||||||
|
if (!this.placePortalBlocks(level, player.getUUID(), side, portal, placement)) {
|
||||||
|
level.playSound(null, impactPos.x, impactPos.y, impactPos.z, PortalGunPortalEntity.sound("portal_gun_invalid_surface", SoundEvents.DISPENSER_FAIL), SoundSource.PLAYERS, 0.55F, 1.0F);
|
||||||
|
return;
|
||||||
|
}
|
||||||
level.addFreshEntity(portal);
|
level.addFreshEntity(portal);
|
||||||
PortalGunSavedData.setPortal(level.getServer(), player.getUUID(), side, portal.getUUID());
|
PortalGunSavedData.setPortal(level.getServer(), player.getUUID(), side, portal.getUUID());
|
||||||
PortalGunPortalEntity other = this.findCounterpart(level, player.getUUID(), side);
|
PortalGunPortalEntity other = this.findCounterpart(level, player.getUUID(), side);
|
||||||
if (other != null) {
|
if (other != null) {
|
||||||
portal.linkTo(other);
|
portal.linkTo(other);
|
||||||
other.linkTo(portal);
|
other.linkTo(portal);
|
||||||
|
this.syncPortalBlocks(level, portal);
|
||||||
|
this.syncPortalBlocks(level, other);
|
||||||
}
|
}
|
||||||
|
String openPath = side == PortalGunPortalEntity.PortalSide.BLUE ? "portal_open_blue" : "portal_open_orange";
|
||||||
|
level.playSound(null, portal.getX(), portal.getY(), portal.getZ(), PortalGunPortalEntity.sound(openPath, SoundEvents.END_PORTAL_SPAWN), SoundSource.PLAYERS, 0.45F, side == PortalGunPortalEntity.PortalSide.BLUE ? 1.05F : 0.92F);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemStack findMatchingGunStack(Player player, UUID gunId) {
|
||||||
|
ItemStack mainHand = player.getMainHandItem();
|
||||||
|
if (this.matchesGunId(mainHand, gunId)) {
|
||||||
|
return mainHand;
|
||||||
|
}
|
||||||
|
ItemStack offhand = player.getOffhandItem();
|
||||||
|
if (this.matchesGunId(offhand, gunId)) {
|
||||||
|
return offhand;
|
||||||
|
}
|
||||||
|
for (int slot = 0; slot < player.getInventory().getContainerSize(); slot++) {
|
||||||
|
ItemStack stack = player.getInventory().getItem(slot);
|
||||||
|
if (this.matchesGunId(stack, gunId)) {
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ItemStack.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean tryArmMoonShot(ServerLevel level, Player player, ItemStack stack, PortalGunPortalEntity.PortalSide side) {
|
||||||
|
if (!level.dimensionType().hasSkyLight() || !level.isNight() || player.getXRot() > -40.0F) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
PortalGunPortalEntity existing = this.findPlacedPortal(level, player.getUUID(), side);
|
||||||
|
if (existing != null) {
|
||||||
|
existing.discard();
|
||||||
|
}
|
||||||
|
this.setMoonSide(stack, side);
|
||||||
this.setLastSide(stack, side);
|
this.setLastSide(stack, side);
|
||||||
this.triggerFireAnimation(level, player, stack);
|
this.triggerFireAnimation(level, player, stack);
|
||||||
stack.hurtAndBreak(1, player, EquipmentSlot.MAINHAND);
|
stack.hurtAndBreak(1, player, EquipmentSlot.MAINHAND);
|
||||||
player.awardStat(Stats.ITEM_USED.get(this));
|
player.awardStat(Stats.ITEM_USED.get(this));
|
||||||
player.getCooldowns().addCooldown(this, 6);
|
player.getCooldowns().addCooldown(this, 6);
|
||||||
String firePath = side == PortalGunPortalEntity.PortalSide.BLUE ? "portal_gun_fire_blue" : "portal_gun_fire_orange";
|
level.playSound(null, player.getX(), player.getY(), player.getZ(), PortalGunPortalEntity.sound(side == PortalGunPortalEntity.PortalSide.BLUE ? "portal_gun_fire_blue" : "portal_gun_fire_orange", SoundEvents.BEACON_ACTIVATE), SoundSource.PLAYERS, 0.65F, side == PortalGunPortalEntity.PortalSide.BLUE ? 1.15F : 0.88F);
|
||||||
String openPath = side == PortalGunPortalEntity.PortalSide.BLUE ? "portal_open_blue" : "portal_open_orange";
|
this.spawnShotTrail(level, player, player.getEyePosition().add(player.getLookAngle().scale(64.0D)), side);
|
||||||
level.playSound(null, player.getX(), player.getY(), player.getZ(), PortalGunPortalEntity.sound(firePath, SoundEvents.BEACON_ACTIVATE), SoundSource.PLAYERS, 0.65F, side == PortalGunPortalEntity.PortalSide.BLUE ? 1.15F : 0.88F);
|
|
||||||
level.playSound(null, portal.getX(), portal.getY(), portal.getZ(), PortalGunPortalEntity.sound(openPath, SoundEvents.END_PORTAL_SPAWN), SoundSource.PLAYERS, 0.45F, side == PortalGunPortalEntity.PortalSide.BLUE ? 1.05F : 0.92F);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean tryShootMoon(ServerLevel level, Player player, ItemStack stack, PortalGunPortalEntity.PortalSide side) {
|
private boolean spawnBlackHole(ServerLevel level, Player player, ItemStack stack, PortalGunPortalEntity.PortalSide side, Vec3 spawnPos) {
|
||||||
if (!level.dimensionType().hasSkyLight() || !level.isNight() || player.getXRot() > -40.0F) {
|
this.setMoonSide(stack, null);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
PortalGunPortalEntity counterpart = this.findCounterpart(level, player.getUUID(), side);
|
|
||||||
Vec3 spawnPos;
|
|
||||||
if (counterpart != null) {
|
|
||||||
spawnPos = counterpart.position();
|
|
||||||
counterpart.discard();
|
|
||||||
} else {
|
|
||||||
spawnPos = player.getEyePosition().add(player.getLookAngle().scale(20.0D));
|
|
||||||
}
|
|
||||||
PortalGunBlackHoleEntity blackHole = new PortalGunBlackHoleEntity(this.blackHoleType.get(), level);
|
PortalGunBlackHoleEntity blackHole = new PortalGunBlackHoleEntity(this.blackHoleType.get(), level);
|
||||||
blackHole.configure(player.getUUID());
|
blackHole.configure(player.getUUID());
|
||||||
blackHole.moveTo(spawnPos.x, spawnPos.y, spawnPos.z, 0.0F, 0.0F);
|
blackHole.moveTo(spawnPos.x, spawnPos.y, spawnPos.z, 0.0F, 0.0F);
|
||||||
level.addFreshEntity(blackHole);
|
level.addFreshEntity(blackHole);
|
||||||
this.setLastSide(stack, side);
|
|
||||||
this.triggerFireAnimation(level, player, stack);
|
|
||||||
stack.hurtAndBreak(1, player, EquipmentSlot.MAINHAND);
|
|
||||||
player.awardStat(Stats.ITEM_USED.get(this));
|
|
||||||
player.getCooldowns().addCooldown(this, 6);
|
|
||||||
level.playSound(null, spawnPos.x, spawnPos.y, spawnPos.z, PortalGunPortalEntity.sound("portal_gun_black_hole", SoundEvents.WARDEN_SONIC_BOOM), SoundSource.PLAYERS, 0.6F, 0.6F);
|
level.playSound(null, spawnPos.x, spawnPos.y, spawnPos.z, PortalGunPortalEntity.sound("portal_gun_black_hole", SoundEvents.WARDEN_SONIC_BOOM), SoundSource.PLAYERS, 0.6F, 0.6F);
|
||||||
this.spawnShotTrail(level, player, spawnPos, side);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,6 +234,17 @@ public class PortalGunItem extends Item implements GeoItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void spawnProjectile(ServerLevel level, Player player, ItemStack stack, PortalGunPortalEntity.PortalSide side) {
|
||||||
|
UUID gunId = this.ensureGunId(stack);
|
||||||
|
PortalGunProjectileEntity projectile = new PortalGunProjectileEntity(this.projectileType.get(), player, level);
|
||||||
|
projectile.configure(side, gunId, stack);
|
||||||
|
Vec3 look = player.getLookAngle();
|
||||||
|
Vec3 start = player.getEyePosition().add(look.scale(0.4D));
|
||||||
|
projectile.setPos(start.x, start.y, start.z);
|
||||||
|
projectile.setDeltaMovement(look.scale(2.5D));
|
||||||
|
level.addFreshEntity(projectile);
|
||||||
|
}
|
||||||
|
|
||||||
private PortalGunPortalEntity findCounterpart(ServerLevel level, UUID owner, PortalGunPortalEntity.PortalSide side) {
|
private PortalGunPortalEntity findCounterpart(ServerLevel level, UUID owner, PortalGunPortalEntity.PortalSide side) {
|
||||||
PortalGunPortalEntity.PortalSide otherSide = side == PortalGunPortalEntity.PortalSide.BLUE ? PortalGunPortalEntity.PortalSide.ORANGE : PortalGunPortalEntity.PortalSide.BLUE;
|
PortalGunPortalEntity.PortalSide otherSide = side == PortalGunPortalEntity.PortalSide.BLUE ? PortalGunPortalEntity.PortalSide.ORANGE : PortalGunPortalEntity.PortalSide.BLUE;
|
||||||
Optional<UUID> otherId = PortalGunSavedData.getPortalId(level.getServer(), owner, otherSide);
|
Optional<UUID> otherId = PortalGunSavedData.getPortalId(level.getServer(), owner, otherSide);
|
||||||
@@ -180,37 +255,90 @@ public class PortalGunItem extends Item implements GeoItem {
|
|||||||
return entity instanceof PortalGunPortalEntity portal ? portal : null;
|
return entity instanceof PortalGunPortalEntity portal ? portal : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PortalGunPortalEntity findPlacedPortal(ServerLevel level, UUID owner, PortalGunPortalEntity.PortalSide side) {
|
||||||
|
Optional<UUID> portalId = PortalGunSavedData.getPortalId(level.getServer(), owner, side);
|
||||||
|
if (portalId.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Entity entity = level.getEntity(portalId.get());
|
||||||
|
return entity instanceof PortalGunPortalEntity portal ? portal : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PortalGunPortalEntity.PortalSide otherSide(PortalGunPortalEntity.PortalSide side) {
|
||||||
|
return side == PortalGunPortalEntity.PortalSide.BLUE ? PortalGunPortalEntity.PortalSide.ORANGE : PortalGunPortalEntity.PortalSide.BLUE;
|
||||||
|
}
|
||||||
|
|
||||||
private BlockHitResult raycast(Level level, Player player) {
|
private BlockHitResult raycast(Level level, Player player) {
|
||||||
Vec3 start = player.getEyePosition();
|
Vec3 start = player.getEyePosition();
|
||||||
Vec3 end = start.add(player.getLookAngle().scale(64.0D));
|
Vec3 end = start.add(player.getLookAngle().scale(64.0D));
|
||||||
return level.clip(new ClipContext(start, end, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, player));
|
return level.clip(new ClipContext(start, end, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, player));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Placement findPlacement(Level level, Player player, BlockHitResult hitResult) {
|
private PortalGunPlacement findPlacement(Level level, Player player, PortalGunPortalEntity.PortalSide side, BlockHitResult hitResult, PortalGunPortalEntity replacingPortal) {
|
||||||
Direction facing = hitResult.getDirection();
|
Direction facing = hitResult.getDirection();
|
||||||
Direction heightAxis;
|
Direction heightAxis = this.resolveUpAxis(player, facing);
|
||||||
float yaw;
|
Direction widthAxis = PortalGunPlacement.widthAxis(facing, heightAxis);
|
||||||
if (facing.getAxis() == Direction.Axis.Y) {
|
float yaw = PortalGunPlacement.yawFor(facing, heightAxis);
|
||||||
heightAxis = Direction.fromYRot(player.getYRot());
|
|
||||||
yaw = heightAxis.toYRot();
|
|
||||||
} else {
|
|
||||||
heightAxis = Direction.UP;
|
|
||||||
yaw = facing.toYRot();
|
|
||||||
}
|
|
||||||
BlockPos hitPos = hitResult.getBlockPos();
|
BlockPos hitPos = hitResult.getBlockPos();
|
||||||
for (int offset = -1; offset <= 0; offset++) {
|
Vec3 hitLocation = hitResult.getLocation();
|
||||||
BlockPos supportOrigin = hitPos.relative(heightAxis, offset);
|
UUID replacingPortalId = replacingPortal == null ? null : replacingPortal.getUUID();
|
||||||
if (this.canPlaceAt(level, supportOrigin, facing, heightAxis)) {
|
PortalGunPlacement bestPlacement = null;
|
||||||
Vec3 firstCellCenter = supportOrigin.relative(facing).getCenter();
|
double bestScore = Double.MAX_VALUE;
|
||||||
Vec3 halfStep = Vec3.atLowerCornerOf(heightAxis.getNormal()).scale(0.5D);
|
for (int widthOffset = -3; widthOffset <= 3; widthOffset++) {
|
||||||
Vec3 center = firstCellCenter.add(halfStep);
|
for (int heightOffset = -4; heightOffset <= 3; heightOffset++) {
|
||||||
return new Placement(center, facing, heightAxis, yaw, supportOrigin);
|
BlockPos supportOrigin = hitPos.relative(widthAxis, widthOffset).relative(heightAxis, heightOffset);
|
||||||
|
if (!this.canPlaceAt(level, player.getUUID(), side, supportOrigin, facing, heightAxis, replacingPortalId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BlockPos masterPos = supportOrigin.relative(facing);
|
||||||
|
BlockPos basePos = masterPos.relative(heightAxis);
|
||||||
|
BlockPos[] portalSpots = new BlockPos[] {masterPos, basePos};
|
||||||
|
Vec3 firstCellCenter = masterPos.getCenter();
|
||||||
|
Vec3 center = firstCellCenter
|
||||||
|
.add(Vec3.atLowerCornerOf(heightAxis.getNormal()).scale(0.5D))
|
||||||
|
.subtract(Vec3.atLowerCornerOf(facing.getNormal()).scale(0.5D));
|
||||||
|
Vec3 local = hitLocation.subtract(center);
|
||||||
|
double widthLocal = local.dot(Vec3.atLowerCornerOf(widthAxis.getNormal()));
|
||||||
|
double heightLocal = local.dot(Vec3.atLowerCornerOf(heightAxis.getNormal()));
|
||||||
|
double depthLocal = local.dot(Vec3.atLowerCornerOf(facing.getNormal()));
|
||||||
|
double widthDistance = Math.max(0.0D, Math.abs(widthLocal) - 0.5D);
|
||||||
|
double heightDistance = Math.max(0.0D, Math.abs(heightLocal) - 1.0D);
|
||||||
|
double score = widthDistance * widthDistance
|
||||||
|
+ heightDistance * heightDistance
|
||||||
|
+ Math.abs(depthLocal) * 0.25D
|
||||||
|
+ supportOrigin.distSqr(hitPos) * 0.12D
|
||||||
|
+ Math.abs(widthOffset) * 0.04D
|
||||||
|
+ Math.abs(heightOffset) * 0.025D
|
||||||
|
+ (widthOffset != 0 || heightOffset != 0 ? 0.02D : 0.0D);
|
||||||
|
if (score < bestScore) {
|
||||||
|
bestScore = score;
|
||||||
|
Set<BlockPos> compensatedSpots = new HashSet<>();
|
||||||
|
if (widthOffset != 0 || heightOffset != 0) {
|
||||||
|
compensatedSpots.add(hitPos.relative(facing));
|
||||||
|
compensatedSpots.add(masterPos);
|
||||||
|
compensatedSpots.add(basePos);
|
||||||
|
compensatedSpots.add(supportOrigin);
|
||||||
|
compensatedSpots.add(basePos.relative(facing.getOpposite()));
|
||||||
|
}
|
||||||
|
bestPlacement = new PortalGunPlacement(center, facing, heightAxis, widthAxis, yaw, supportOrigin, masterPos, basePos, portalSpots, compensatedSpots);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
}
|
||||||
|
return bestPlacement;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean canPlaceAt(Level level, BlockPos supportOrigin, Direction facing, Direction heightAxis) {
|
private Direction resolveUpAxis(Player player, Direction facing) {
|
||||||
|
if (facing.getAxis() != Direction.Axis.Y) {
|
||||||
|
return Direction.UP;
|
||||||
|
}
|
||||||
|
Direction horizontal = player.getDirection();
|
||||||
|
if (horizontal.getAxis() == Direction.Axis.Y) {
|
||||||
|
return Direction.NORTH;
|
||||||
|
}
|
||||||
|
return horizontal.getOpposite();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canPlaceAt(Level level, UUID ownerId, PortalGunPortalEntity.PortalSide side, BlockPos supportOrigin, Direction facing, Direction heightAxis, UUID replacingPortalId) {
|
||||||
for (int h = 0; h < 2; h++) {
|
for (int h = 0; h < 2; h++) {
|
||||||
BlockPos supportPos = supportOrigin.relative(heightAxis, h);
|
BlockPos supportPos = supportOrigin.relative(heightAxis, h);
|
||||||
BlockPos airPos = supportPos.relative(facing);
|
BlockPos airPos = supportPos.relative(facing);
|
||||||
@@ -220,7 +348,7 @@ public class PortalGunItem extends Item implements GeoItem {
|
|||||||
if (!supportState.isFaceSturdy(level, supportPos, facing)) {
|
if (!supportState.isFaceSturdy(level, supportPos, facing)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!airState.isAir() && !airState.canBeReplaced()) {
|
if (!this.isPortalSpaceAvailable(level, airPos, airState, ownerId, side, replacingPortalId)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!fluidState.isEmpty()) {
|
if (!fluidState.isEmpty()) {
|
||||||
@@ -230,6 +358,53 @@ public class PortalGunItem extends Item implements GeoItem {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isPortalSpaceAvailable(Level level, BlockPos pos, BlockState state, UUID ownerId, PortalGunPortalEntity.PortalSide side, UUID replacingPortalId) {
|
||||||
|
if (state.isAir() || state.canBeReplaced()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
BlockEntity blockEntity = level.getBlockEntity(pos);
|
||||||
|
if (blockEntity instanceof PortalGunPortalMasterBlockEntity master) {
|
||||||
|
return ownerId != null
|
||||||
|
&& ownerId.equals(master.getOwnerId())
|
||||||
|
&& master.getSide() == side
|
||||||
|
&& (replacingPortalId == null || replacingPortalId.equals(master.getPortalId()));
|
||||||
|
}
|
||||||
|
if (blockEntity instanceof PortalGunPortalBaseBlockEntity base) {
|
||||||
|
return ownerId != null
|
||||||
|
&& ownerId.equals(base.getOwnerId())
|
||||||
|
&& base.getSide() == side
|
||||||
|
&& (replacingPortalId == null || replacingPortalId.equals(base.getPortalId()));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean placePortalBlocks(ServerLevel level, UUID ownerId, PortalGunPortalEntity.PortalSide side, PortalGunPortalEntity portal, PortalGunPlacement placement) {
|
||||||
|
if (!level.setBlock(placement.masterPos(), this.portalMasterBlock.get().defaultBlockState(), 3)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!level.setBlock(placement.basePos(), this.portalBaseBlock.get().defaultBlockState(), 3)) {
|
||||||
|
level.setBlock(placement.masterPos(), Blocks.AIR.defaultBlockState(), 3);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(level.getBlockEntity(placement.masterPos()) instanceof PortalGunPortalMasterBlockEntity master) || !(level.getBlockEntity(placement.basePos()) instanceof PortalGunPortalBaseBlockEntity base)) {
|
||||||
|
level.setBlock(placement.masterPos(), Blocks.AIR.defaultBlockState(), 3);
|
||||||
|
level.setBlock(placement.basePos(), Blocks.AIR.defaultBlockState(), 3);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
master.configure(ownerId, portal.getUUID(), side, placement.facing(), placement.upAxis(), placement.basePos(), placement.portalSpots(), placement.compensatedSpots(), level.getServer().getTickCount());
|
||||||
|
base.configure(ownerId, portal.getUUID(), side, placement.masterPos());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void syncPortalBlocks(ServerLevel level, PortalGunPortalEntity portal) {
|
||||||
|
if (level.getBlockEntity(portal.getMasterPos()) instanceof PortalGunPortalMasterBlockEntity master) {
|
||||||
|
master.updatePair(portal.getLinkedPortalId(), portal.getPairTime());
|
||||||
|
}
|
||||||
|
if (level.getBlockEntity(portal.getBasePos()) instanceof PortalGunPortalBaseBlockEntity base) {
|
||||||
|
base.updatePair(portal.getLinkedPortalId(), portal.getPairTime());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void setLastSide(ItemStack stack, PortalGunPortalEntity.PortalSide side) {
|
private void setLastSide(ItemStack stack, PortalGunPortalEntity.PortalSide side) {
|
||||||
if (side == null) {
|
if (side == null) {
|
||||||
net.minecraft.world.item.component.CustomData.update(DataComponents.CUSTOM_DATA, stack, tag -> tag.remove(LAST_SIDE_TAG));
|
net.minecraft.world.item.component.CustomData.update(DataComponents.CUSTOM_DATA, stack, tag -> tag.remove(LAST_SIDE_TAG));
|
||||||
@@ -238,6 +413,14 @@ public class PortalGunItem extends Item implements GeoItem {
|
|||||||
net.minecraft.world.item.component.CustomData.update(DataComponents.CUSTOM_DATA, stack, tag -> tag.putString(LAST_SIDE_TAG, side.name()));
|
net.minecraft.world.item.component.CustomData.update(DataComponents.CUSTOM_DATA, stack, tag -> tag.putString(LAST_SIDE_TAG, side.name()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setMoonSide(ItemStack stack, PortalGunPortalEntity.PortalSide side) {
|
||||||
|
if (side == null) {
|
||||||
|
net.minecraft.world.item.component.CustomData.update(DataComponents.CUSTOM_DATA, stack, tag -> tag.remove(MOON_SIDE_TAG));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
net.minecraft.world.item.component.CustomData.update(DataComponents.CUSTOM_DATA, stack, tag -> tag.putString(MOON_SIDE_TAG, side.name()));
|
||||||
|
}
|
||||||
|
|
||||||
private PortalGunPortalEntity.PortalSide getLastSide(ItemStack stack) {
|
private PortalGunPortalEntity.PortalSide getLastSide(ItemStack stack) {
|
||||||
net.minecraft.world.item.component.CustomData customData = stack.get(DataComponents.CUSTOM_DATA);
|
net.minecraft.world.item.component.CustomData customData = stack.get(DataComponents.CUSTOM_DATA);
|
||||||
if (customData == null) {
|
if (customData == null) {
|
||||||
@@ -253,6 +436,33 @@ public class PortalGunItem extends Item implements GeoItem {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isMoonSideArmed(ItemStack stack, PortalGunPortalEntity.PortalSide side) {
|
||||||
|
net.minecraft.world.item.component.CustomData customData = stack.get(DataComponents.CUSTOM_DATA);
|
||||||
|
if (customData == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String sideName = customData.copyTag().getString(MOON_SIDE_TAG);
|
||||||
|
return side.name().equals(sideName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private UUID ensureGunId(ItemStack stack) {
|
||||||
|
net.minecraft.world.item.component.CustomData customData = stack.get(DataComponents.CUSTOM_DATA);
|
||||||
|
if (customData != null && customData.copyTag().hasUUID(GUN_ID_TAG)) {
|
||||||
|
return customData.copyTag().getUUID(GUN_ID_TAG);
|
||||||
|
}
|
||||||
|
UUID gunId = UUID.randomUUID();
|
||||||
|
net.minecraft.world.item.component.CustomData.update(DataComponents.CUSTOM_DATA, stack, tag -> tag.putUUID(GUN_ID_TAG, gunId));
|
||||||
|
return gunId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean matchesGunId(ItemStack stack, UUID gunId) {
|
||||||
|
if (stack.isEmpty() || stack.getItem() != this) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
net.minecraft.world.item.component.CustomData customData = stack.get(DataComponents.CUSTOM_DATA);
|
||||||
|
return customData != null && customData.copyTag().hasUUID(GUN_ID_TAG) && gunId.equals(customData.copyTag().getUUID(GUN_ID_TAG));
|
||||||
|
}
|
||||||
|
|
||||||
private void triggerFireAnimation(ServerLevel level, LivingEntity livingEntity, ItemStack stack) {
|
private void triggerFireAnimation(ServerLevel level, LivingEntity livingEntity, ItemStack stack) {
|
||||||
long animatableId = GeoItem.getOrAssignId(stack, level);
|
long animatableId = GeoItem.getOrAssignId(stack, level);
|
||||||
triggerAnim(livingEntity, animatableId, FIRE_CONTROLLER, "fire");
|
triggerAnim(livingEntity, animatableId, FIRE_CONTROLLER, "fire");
|
||||||
@@ -302,6 +512,4 @@ public class PortalGunItem extends Item implements GeoItem {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private record Placement(Vec3 center, Direction facing, Direction upAxis, float yaw, BlockPos supportOrigin) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
package com.craisinlord.antarchy.content.item;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.entity.RoyalBoatEntity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.entity.vehicle.Boat;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.HitResult;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public class RoyalBoatOnlyItem extends OuranwoodBoatItem {
|
||||||
|
private final EntityType<RoyalBoatEntity> entityType;
|
||||||
|
|
||||||
|
public RoyalBoatOnlyItem(EntityType<RoyalBoatEntity> entityType, Properties properties) {
|
||||||
|
super(properties);
|
||||||
|
this.entityType = entityType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boat createBoat(Level level, HitResult hitResult, ItemStack stack, Player player) {
|
||||||
|
Vec3 pos = hitResult.getLocation();
|
||||||
|
RoyalBoatEntity boat = new RoyalBoatEntity(this.entityType, level);
|
||||||
|
boat.setPos(pos.x, pos.y, pos.z);
|
||||||
|
boat.xo = pos.x;
|
||||||
|
boat.yo = pos.y;
|
||||||
|
boat.zo = pos.z;
|
||||||
|
this.applyDefaultStackConfig(level, stack, player, boat);
|
||||||
|
return boat;
|
||||||
|
}
|
||||||
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
package com.craisinlord.antarchy.content.item;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.entity.RoyalChestBoatEntity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.entity.vehicle.Boat;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.HitResult;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public class RoyalChestBoatItem extends OuranwoodBoatItem {
|
||||||
|
private final EntityType<RoyalChestBoatEntity> entityType;
|
||||||
|
|
||||||
|
public RoyalChestBoatItem(EntityType<RoyalChestBoatEntity> entityType, Properties properties) {
|
||||||
|
super(properties);
|
||||||
|
this.entityType = entityType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boat createBoat(Level level, HitResult hitResult, ItemStack stack, Player player) {
|
||||||
|
Vec3 pos = hitResult.getLocation();
|
||||||
|
RoyalChestBoatEntity boat = new RoyalChestBoatEntity(this.entityType, level);
|
||||||
|
boat.setPos(pos.x, pos.y, pos.z);
|
||||||
|
boat.xo = pos.x;
|
||||||
|
boat.yo = pos.y;
|
||||||
|
boat.zo = pos.z;
|
||||||
|
this.applyDefaultStackConfig(level, stack, player, boat);
|
||||||
|
return boat;
|
||||||
|
}
|
||||||
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
package com.craisinlord.antarchy.content.item;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.entity.TruffaloBoatEntity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.entity.vehicle.Boat;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.HitResult;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public class TruffaloBoatOnlyItem extends OuranwoodBoatItem {
|
||||||
|
private final EntityType<TruffaloBoatEntity> entityType;
|
||||||
|
|
||||||
|
public TruffaloBoatOnlyItem(EntityType<TruffaloBoatEntity> entityType, Properties properties) {
|
||||||
|
super(properties);
|
||||||
|
this.entityType = entityType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boat createBoat(Level level, HitResult hitResult, ItemStack stack, Player player) {
|
||||||
|
Vec3 pos = hitResult.getLocation();
|
||||||
|
TruffaloBoatEntity boat = new TruffaloBoatEntity(this.entityType, level);
|
||||||
|
boat.setPos(pos.x, pos.y, pos.z);
|
||||||
|
boat.xo = pos.x;
|
||||||
|
boat.yo = pos.y;
|
||||||
|
boat.zo = pos.z;
|
||||||
|
this.applyDefaultStackConfig(level, stack, player, boat);
|
||||||
|
return boat;
|
||||||
|
}
|
||||||
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
package com.craisinlord.antarchy.content.item;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.entity.TruffaloChestBoatEntity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.entity.vehicle.Boat;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.HitResult;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public class TruffaloChestBoatItem extends OuranwoodBoatItem {
|
||||||
|
private final EntityType<TruffaloChestBoatEntity> entityType;
|
||||||
|
|
||||||
|
public TruffaloChestBoatItem(EntityType<TruffaloChestBoatEntity> entityType, Properties properties) {
|
||||||
|
super(properties);
|
||||||
|
this.entityType = entityType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boat createBoat(Level level, HitResult hitResult, ItemStack stack, Player player) {
|
||||||
|
Vec3 pos = hitResult.getLocation();
|
||||||
|
TruffaloChestBoatEntity boat = new TruffaloChestBoatEntity(this.entityType, level);
|
||||||
|
boat.setPos(pos.x, pos.y, pos.z);
|
||||||
|
boat.xo = pos.x;
|
||||||
|
boat.yo = pos.y;
|
||||||
|
boat.zo = pos.z;
|
||||||
|
this.applyDefaultStackConfig(level, stack, player, boat);
|
||||||
|
return boat;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,6 +36,7 @@ public final class WormHookItem extends Item {
|
|||||||
WormHookProjectileEntity hook = new WormHookProjectileEntity(AntarchyObjects.WORM_HOOK_PROJECTILE.get(), player, level);
|
WormHookProjectileEntity hook = new WormHookProjectileEntity(AntarchyObjects.WORM_HOOK_PROJECTILE.get(), player, level);
|
||||||
hook.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0F, 2.2F, 0.5F);
|
hook.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0F, 2.2F, 0.5F);
|
||||||
level.addFreshEntity(hook);
|
level.addFreshEntity(hook);
|
||||||
|
WormHookTetherManager.launch(serverPlayer, hook);
|
||||||
|
|
||||||
stack.hurtAndBreak(1, serverPlayer, LivingEntity.getSlotForHand(hand));
|
stack.hurtAndBreak(1, serverPlayer, LivingEntity.getSlotForHand(hand));
|
||||||
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.FISHING_BOBBER_THROW, SoundSource.PLAYERS, 0.7F, 0.9F);
|
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.FISHING_BOBBER_THROW, SoundSource.PLAYERS, 0.7F, 0.9F);
|
||||||
|
|||||||
+46
-16
@@ -17,12 +17,16 @@ import net.minecraft.world.phys.Vec3;
|
|||||||
* a rope anchored to a stuck {@link WormHookProjectileEntity}, wrapping the rope around block
|
* a rope anchored to a stuck {@link WormHookProjectileEntity}, wrapping the rope around block
|
||||||
* corners via {@link WormHookRope} so the swing radius shortens realistically when the player
|
* corners via {@link WormHookRope} so the swing radius shortens realistically when the player
|
||||||
* swings around an obstacle.
|
* swings around an obstacle.
|
||||||
|
*
|
||||||
|
* A tether entry is created the moment the hook is thrown (so the rope can be rendered following
|
||||||
|
* the flying projectile) and only gains real swing physics once the hook sticks into a block.
|
||||||
*/
|
*/
|
||||||
public final class WormHookTetherManager {
|
public final class WormHookTetherManager {
|
||||||
private static final double DEFAULT_MAX_LEN = 24.0D;
|
|
||||||
private static final double MIN_LEN = 2.0D;
|
private static final double MIN_LEN = 2.0D;
|
||||||
private static final double REEL_SPEED = 0.12D;
|
private static final double REEL_SPEED = 0.12D;
|
||||||
|
private static final double REEL_PULL_STRENGTH = 0.16D;
|
||||||
private static final double BREAK_RANGE_MULTIPLIER = 1.5D;
|
private static final double BREAK_RANGE_MULTIPLIER = 1.5D;
|
||||||
|
private static final double DEFAULT_BREAK_RANGE = 48.0D;
|
||||||
private static final double SNAP_BUFFER = 4.0D;
|
private static final double SNAP_BUFFER = 4.0D;
|
||||||
private static final double PULL_CORRECTION = 0.35D;
|
private static final double PULL_CORRECTION = 0.35D;
|
||||||
|
|
||||||
@@ -44,18 +48,28 @@ public final class WormHookTetherManager {
|
|||||||
return hook instanceof WormHookProjectileEntity wormHook ? wormHook : null;
|
return hook instanceof WormHookProjectileEntity wormHook ? wormHook : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean attach(ServerPlayer player, WormHookProjectileEntity hook) {
|
/** Registers the hook the moment it's thrown, purely so the rope can be rendered following it. */
|
||||||
|
public static void launch(ServerPlayer player, WormHookProjectileEntity hook) {
|
||||||
clear(player);
|
clear(player);
|
||||||
|
TETHERS.put(player.getUUID(), new TetherState(hook.getId()));
|
||||||
|
WormHookTetherSync.send(player, hook.getId());
|
||||||
|
}
|
||||||
|
|
||||||
double dist = player.getEyePosition().distanceTo(hook.position());
|
/** Called once the hook sticks into a block; turns the cosmetic tether into real swing physics. */
|
||||||
if (dist < MIN_LEN) {
|
public static boolean attach(ServerPlayer player, WormHookProjectileEntity hook) {
|
||||||
|
TetherState state = TETHERS.get(player.getUUID());
|
||||||
|
if (state == null || state.hookEntityId != hook.getId()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TetherState state = new TetherState(hook.getId(), Math.max(DEFAULT_MAX_LEN, dist));
|
double dist = player.getEyePosition().distanceTo(hook.position());
|
||||||
|
if (dist < MIN_LEN) {
|
||||||
|
clear(player);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.maxLen = Math.max(MIN_LEN, dist);
|
||||||
state.rope = new WormHookRope(hook.position(), player.getEyePosition());
|
state.rope = new WormHookRope(hook.position(), player.getEyePosition());
|
||||||
TETHERS.put(player.getUUID(), state);
|
|
||||||
WormHookTetherSync.send(player, hook.getId());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +104,13 @@ public final class WormHookTetherManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player.isShiftKeyDown()) {
|
if (state.rope == null) {
|
||||||
|
// Hook is still flying; nothing to simulate yet, just tracking it for the render sync.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean reeling = player.isShiftKeyDown();
|
||||||
|
if (reeling) {
|
||||||
state.maxLen = Math.max(MIN_LEN, state.maxLen - REEL_SPEED);
|
state.maxLen = Math.max(MIN_LEN, state.maxLen - REEL_SPEED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +129,19 @@ public final class WormHookTetherManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vec3 towardPivot = toPlayer.scale(1.0D / dist);
|
||||||
|
|
||||||
|
// Sneaking actively winds the player in toward the anchor, not just shortening
|
||||||
|
// the max length (which alone has no effect until the rope goes taut).
|
||||||
|
if (reeling && dist > MIN_LEN) {
|
||||||
|
Vec3 pull = towardPivot.scale(-REEL_PULL_STRENGTH);
|
||||||
|
Vec3 reelMotion = player.getDeltaMovement().add(pull);
|
||||||
|
reelMotion = new Vec3(reelMotion.x, Mth.clamp(reelMotion.y, -0.6D, 0.6D), reelMotion.z);
|
||||||
|
player.setDeltaMovement(reelMotion);
|
||||||
|
player.hurtMarked = true;
|
||||||
|
player.fallDistance = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (dist <= remaining) {
|
if (dist <= remaining) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -121,14 +154,13 @@ public final class WormHookTetherManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 direction = toPlayer.scale(1.0D / dist);
|
|
||||||
Vec3 motion = player.getDeltaMovement();
|
Vec3 motion = player.getDeltaMovement();
|
||||||
double outward = motion.dot(direction);
|
double outward = motion.dot(towardPivot);
|
||||||
if (outward > 0) {
|
if (outward > 0) {
|
||||||
motion = motion.subtract(direction.scale(outward));
|
motion = motion.subtract(towardPivot.scale(outward));
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 correction = direction.scale(-overshoot * PULL_CORRECTION);
|
Vec3 correction = towardPivot.scale(-overshoot * PULL_CORRECTION);
|
||||||
Vec3 newMotion = motion.add(correction);
|
Vec3 newMotion = motion.add(correction);
|
||||||
newMotion = new Vec3(newMotion.x, Mth.clamp(newMotion.y, -1.0D, 1.0D), newMotion.z);
|
newMotion = new Vec3(newMotion.x, Mth.clamp(newMotion.y, -1.0D, 1.0D), newMotion.z);
|
||||||
player.setDeltaMovement(newMotion);
|
player.setDeltaMovement(newMotion);
|
||||||
@@ -137,12 +169,11 @@ public final class WormHookTetherManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isValid(ServerPlayer player, WormHookProjectileEntity hook, TetherState state) {
|
private static boolean isValid(ServerPlayer player, WormHookProjectileEntity hook, TetherState state) {
|
||||||
double breakRange = state.maxLen * BREAK_RANGE_MULTIPLIER;
|
double breakRange = (state.rope == null ? DEFAULT_BREAK_RANGE : state.maxLen) * BREAK_RANGE_MULTIPLIER;
|
||||||
return player.isAlive()
|
return player.isAlive()
|
||||||
&& hook != null
|
&& hook != null
|
||||||
&& hook.isAlive()
|
&& hook.isAlive()
|
||||||
&& !hook.isRemoved()
|
&& !hook.isRemoved()
|
||||||
&& hook.isStuck()
|
|
||||||
&& player.level() == hook.level()
|
&& player.level() == hook.level()
|
||||||
&& isHoldingHook(player)
|
&& isHoldingHook(player)
|
||||||
&& player.distanceToSqr(hook) <= breakRange * breakRange;
|
&& player.distanceToSqr(hook) <= breakRange * breakRange;
|
||||||
@@ -158,9 +189,8 @@ public final class WormHookTetherManager {
|
|||||||
private double maxLen;
|
private double maxLen;
|
||||||
private WormHookRope rope;
|
private WormHookRope rope;
|
||||||
|
|
||||||
private TetherState(int hookEntityId, double maxLen) {
|
private TetherState(int hookEntityId) {
|
||||||
this.hookEntityId = hookEntityId;
|
this.hookEntityId = hookEntityId;
|
||||||
this.maxLen = maxLen;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+203
@@ -0,0 +1,203 @@
|
|||||||
|
package com.craisinlord.antarchy.content.portalgun;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraft.world.phys.shapes.Shapes;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
|
||||||
|
public final class PortalGunCollisionHelper {
|
||||||
|
private static final double SEARCH_PADDING = 1.5D;
|
||||||
|
private static final double PLANE_TOLERANCE = 0.06D;
|
||||||
|
private static final double EDGE_PADDING = 0.2D;
|
||||||
|
private static final double DEPTH_PADDING = 0.45D;
|
||||||
|
private static final double BORDER_TOLERANCE = 0.02D;
|
||||||
|
private static final double BORDER_THICKNESS = 0.0125D;
|
||||||
|
|
||||||
|
private PortalGunCollisionHelper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vec3 resolveCollision(Entity entity, AABB startBox, Vec3 movement, Vec3 collided) {
|
||||||
|
if (movement.lengthSqr() <= 1.0E-7D) {
|
||||||
|
return collided;
|
||||||
|
}
|
||||||
|
AABB pathBox = startBox.expandTowards(movement).inflate(SEARCH_PADDING);
|
||||||
|
List<Entity> nearby = entity.level().getEntities(entity, pathBox, candidate -> candidate instanceof PortalGunPortalEntity && candidate.isAlive());
|
||||||
|
if (nearby.isEmpty()) {
|
||||||
|
return collided;
|
||||||
|
}
|
||||||
|
Vec3 adjusted = collided;
|
||||||
|
for (Entity candidate : nearby) {
|
||||||
|
PortalGunPortalEntity portal = (PortalGunPortalEntity) candidate;
|
||||||
|
Vec3 candidateAdjusted = resolveCollisionAgainstPortal(entity, startBox, movement, adjusted, portal);
|
||||||
|
if (candidateAdjusted.distanceToSqr(movement) < adjusted.distanceToSqr(movement)) {
|
||||||
|
adjusted = candidateAdjusted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return adjusted;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vec3 resolveCollisionAgainstPortal(Entity entity, AABB startBox, Vec3 movement, Vec3 collided, PortalGunPortalEntity portal) {
|
||||||
|
PortalGunWorldPortalShape shape = portal.getWorldPortalShape();
|
||||||
|
Vec3 normal = portal.getNormalVec().normalize();
|
||||||
|
double desiredNormal = movement.dot(normal);
|
||||||
|
double collidedNormal = collided.dot(normal);
|
||||||
|
if (desiredNormal >= -1.0E-5D || desiredNormal >= collidedNormal - 1.0E-5D) {
|
||||||
|
return collided;
|
||||||
|
}
|
||||||
|
if (!canUsePortalPassThrough(entity, startBox, movement, portal, shape)) {
|
||||||
|
return collided;
|
||||||
|
}
|
||||||
|
double restoreAmount = desiredNormal - collidedNormal;
|
||||||
|
Vec3 adjusted = collided.add(normal.scale(restoreAmount));
|
||||||
|
return applyBorderCollision(entity, startBox, adjusted, portal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean canUsePortalPassThrough(Entity entity, AABB startBox, Vec3 movement, PortalGunPortalEntity portal, PortalGunWorldPortalShape shape) {
|
||||||
|
AABB endBox = startBox.move(movement);
|
||||||
|
if (!portal.getPortalInsides(entity).intersects(startBox)
|
||||||
|
&& !portal.getPortalInsides(entity).intersects(endBox)
|
||||||
|
&& !intersectsPortalWindow(startBox, shape)
|
||||||
|
&& !intersectsPortalWindow(endBox, shape)
|
||||||
|
&& !segmentIntersectsPortalWindow(shape, startBox, endBox)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (crossesPortal(shape, entity, startBox, movement)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Vec3 startCenter = startBox.getCenter();
|
||||||
|
Vec3 endCenter = endBox.getCenter();
|
||||||
|
PortalGunWorldPortalShape.PortalLocalCoords startCoords = shape.localCoords(startCenter);
|
||||||
|
PortalGunWorldPortalShape.PortalLocalCoords endCoords = shape.localCoords(endCenter);
|
||||||
|
return startCoords.depth() < 0.0D
|
||||||
|
&& endCoords.depth() <= PLANE_TOLERANCE
|
||||||
|
&& Math.abs(endCoords.horizontal()) <= shape.halfWidth() + EDGE_PADDING
|
||||||
|
&& Math.abs(endCoords.vertical()) <= shape.halfHeight() + EDGE_PADDING
|
||||||
|
&& projectedWindowOverlap(shape, startBox, endBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean intersectsPortalWindow(AABB box, PortalGunWorldPortalShape shape) {
|
||||||
|
for (Vec3 corner : corners(box)) {
|
||||||
|
PortalGunWorldPortalShape.PortalLocalCoords coords = shape.localCoords(corner);
|
||||||
|
if (Math.abs(coords.horizontal()) <= shape.halfWidth() + EDGE_PADDING
|
||||||
|
&& Math.abs(coords.vertical()) <= shape.halfHeight() + EDGE_PADDING
|
||||||
|
&& coords.depth() >= -DEPTH_PADDING
|
||||||
|
&& coords.depth() <= PLANE_TOLERANCE) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean segmentIntersectsPortalWindow(PortalGunWorldPortalShape shape, AABB startBox, AABB endBox) {
|
||||||
|
for (Vec3 startCorner : corners(startBox)) {
|
||||||
|
Vec3 endCorner = matchSample(startCorner, startBox, endBox);
|
||||||
|
if (shape.crosses(startCorner, endCorner)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean projectedWindowOverlap(PortalGunWorldPortalShape shape, AABB startBox, AABB endBox) {
|
||||||
|
double minHorizontal = Double.POSITIVE_INFINITY;
|
||||||
|
double maxHorizontal = Double.NEGATIVE_INFINITY;
|
||||||
|
double minVertical = Double.POSITIVE_INFINITY;
|
||||||
|
double maxVertical = Double.NEGATIVE_INFINITY;
|
||||||
|
for (Vec3 corner : corners(startBox)) {
|
||||||
|
PortalGunWorldPortalShape.PortalLocalCoords coords = shape.localCoords(corner);
|
||||||
|
minHorizontal = Math.min(minHorizontal, coords.horizontal());
|
||||||
|
maxHorizontal = Math.max(maxHorizontal, coords.horizontal());
|
||||||
|
minVertical = Math.min(minVertical, coords.vertical());
|
||||||
|
maxVertical = Math.max(maxVertical, coords.vertical());
|
||||||
|
}
|
||||||
|
for (Vec3 corner : corners(endBox)) {
|
||||||
|
PortalGunWorldPortalShape.PortalLocalCoords coords = shape.localCoords(corner);
|
||||||
|
minHorizontal = Math.min(minHorizontal, coords.horizontal());
|
||||||
|
maxHorizontal = Math.max(maxHorizontal, coords.horizontal());
|
||||||
|
minVertical = Math.min(minVertical, coords.vertical());
|
||||||
|
maxVertical = Math.max(maxVertical, coords.vertical());
|
||||||
|
}
|
||||||
|
return maxHorizontal >= -shape.halfWidth() - BORDER_TOLERANCE
|
||||||
|
&& minHorizontal <= shape.halfWidth() + BORDER_TOLERANCE
|
||||||
|
&& maxVertical >= -shape.halfHeight() - BORDER_TOLERANCE
|
||||||
|
&& minVertical <= shape.halfHeight() + BORDER_TOLERANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vec3 applyBorderCollision(Entity entity, AABB startBox, Vec3 movement, PortalGunPortalEntity portal) {
|
||||||
|
if (movement.lengthSqr() <= 1.0E-7D) {
|
||||||
|
return movement;
|
||||||
|
}
|
||||||
|
AABB endBox = startBox.move(movement);
|
||||||
|
if (!portal.getPortalInsides(entity).intersects(startBox)
|
||||||
|
&& !portal.getPortalInsides(entity).intersects(endBox)
|
||||||
|
&& !intersectsPortalWindow(startBox, portal.getWorldPortalShape())
|
||||||
|
&& !intersectsPortalWindow(endBox, portal.getWorldPortalShape())) {
|
||||||
|
return movement;
|
||||||
|
}
|
||||||
|
List<VoxelShape> shapes = portal.getWorldPortalShape().getCollisionBoundaries(BORDER_THICKNESS).stream()
|
||||||
|
.map(Shapes::create)
|
||||||
|
.toList();
|
||||||
|
Vec3 collided = Entity.collideBoundingBox(entity, movement, startBox, entity.level(), shapes);
|
||||||
|
return collided.distanceToSqr(movement) < 1.0E-7D ? movement : collided;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean crossesPortal(PortalGunWorldPortalShape shape, Entity entity, AABB startBox, Vec3 movement) {
|
||||||
|
AABB endBox = startBox.move(movement);
|
||||||
|
for (Vec3 startSample : portalSamples(entity, startBox, true)) {
|
||||||
|
Vec3 endSample = matchSample(startSample, startBox, endBox);
|
||||||
|
if (shape.crosses(startSample, endSample)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Vec3> portalSamples(Entity entity, AABB box, boolean includeEye) {
|
||||||
|
Vec3 center = new Vec3((box.minX + box.maxX) * 0.5D, (box.minY + box.maxY) * 0.5D, (box.minZ + box.maxZ) * 0.5D);
|
||||||
|
Vec3 topCenter = new Vec3(center.x, box.maxY, center.z);
|
||||||
|
Vec3 bottomCenter = new Vec3(center.x, box.minY, center.z);
|
||||||
|
if (includeEye) {
|
||||||
|
Vec3 eye = new Vec3(entity.getX(), entity.getY() + entity.getEyeHeight(), entity.getZ());
|
||||||
|
return List.of(center, eye, topCenter, bottomCenter);
|
||||||
|
}
|
||||||
|
return List.of(center, topCenter, bottomCenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vec3 matchSample(Vec3 startSample, AABB startBox, AABB endBox) {
|
||||||
|
double xLerp = axisRatio(startSample.x, startBox.minX, startBox.maxX);
|
||||||
|
double yLerp = axisRatio(startSample.y, startBox.minY, startBox.maxY);
|
||||||
|
double zLerp = axisRatio(startSample.z, startBox.minZ, startBox.maxZ);
|
||||||
|
return new Vec3(
|
||||||
|
lerp(endBox.minX, endBox.maxX, xLerp),
|
||||||
|
lerp(endBox.minY, endBox.maxY, yLerp),
|
||||||
|
lerp(endBox.minZ, endBox.maxZ, zLerp)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double axisRatio(double value, double min, double max) {
|
||||||
|
double size = max - min;
|
||||||
|
if (Math.abs(size) < 1.0E-6D) {
|
||||||
|
return 0.5D;
|
||||||
|
}
|
||||||
|
return (value - min) / size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double lerp(double min, double max, double delta) {
|
||||||
|
return min + (max - min) * delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vec3[] corners(AABB box) {
|
||||||
|
return new Vec3[] {
|
||||||
|
new Vec3(box.minX, box.minY, box.minZ),
|
||||||
|
new Vec3(box.minX, box.minY, box.maxZ),
|
||||||
|
new Vec3(box.minX, box.maxY, box.minZ),
|
||||||
|
new Vec3(box.minX, box.maxY, box.maxZ),
|
||||||
|
new Vec3(box.maxX, box.minY, box.minZ),
|
||||||
|
new Vec3(box.maxX, box.minY, box.maxZ),
|
||||||
|
new Vec3(box.maxX, box.maxY, box.minZ),
|
||||||
|
new Vec3(box.maxX, box.maxY, box.maxZ)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
package com.craisinlord.antarchy.content.portalgun;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public record PortalGunPlacement(
|
||||||
|
Vec3 center,
|
||||||
|
Direction facing,
|
||||||
|
Direction upAxis,
|
||||||
|
Direction widthAxis,
|
||||||
|
float yaw,
|
||||||
|
BlockPos supportOrigin,
|
||||||
|
BlockPos masterPos,
|
||||||
|
BlockPos basePos,
|
||||||
|
BlockPos[] portalSpots,
|
||||||
|
Set<BlockPos> compensatedSpots
|
||||||
|
) {
|
||||||
|
public static PortalGunPlacement fromStored(Direction facing, Direction upAxis, BlockPos masterPos, BlockPos basePos, Set<BlockPos> compensatedSpots) {
|
||||||
|
Direction widthAxis = widthAxis(facing, upAxis);
|
||||||
|
BlockPos supportOrigin = masterPos.relative(facing.getOpposite());
|
||||||
|
Vec3 center = masterPos.getCenter()
|
||||||
|
.add(Vec3.atLowerCornerOf(upAxis.getNormal()).scale(0.5D))
|
||||||
|
.subtract(Vec3.atLowerCornerOf(facing.getNormal()).scale(0.5D));
|
||||||
|
return new PortalGunPlacement(
|
||||||
|
center,
|
||||||
|
facing,
|
||||||
|
upAxis,
|
||||||
|
widthAxis,
|
||||||
|
yawFor(facing, upAxis),
|
||||||
|
supportOrigin,
|
||||||
|
masterPos,
|
||||||
|
basePos,
|
||||||
|
new BlockPos[] {masterPos, basePos},
|
||||||
|
compensatedSpots
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Direction widthAxis(Direction facing, Direction upAxis) {
|
||||||
|
Vec3 normal = Vec3.atLowerCornerOf(facing.getNormal());
|
||||||
|
Vec3 up = Vec3.atLowerCornerOf(upAxis.getNormal());
|
||||||
|
Vec3 width = normal.cross(up);
|
||||||
|
return Direction.getNearest(width.x, width.y, width.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float yawFor(Direction facing, Direction upAxis) {
|
||||||
|
return facing.getAxis() == Direction.Axis.Y ? upAxis.toYRot() : facing.toYRot();
|
||||||
|
}
|
||||||
|
}
|
||||||
+354
-56
@@ -1,12 +1,22 @@
|
|||||||
package com.craisinlord.antarchy.content.portalgun;
|
package com.craisinlord.antarchy.content.portalgun;
|
||||||
|
|
||||||
import com.craisinlord.antarchy.Antarchy;
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import com.craisinlord.antarchy.content.block.entity.PortalGunPortalBaseBlockEntity;
|
||||||
|
import com.craisinlord.antarchy.content.block.entity.PortalGunPortalMasterBlockEntity;
|
||||||
|
import com.craisinlord.antarchy.mixins.AbstractArrowAccessor;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.ListTag;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||||
import net.minecraft.network.syncher.SynchedEntityData;
|
import net.minecraft.network.syncher.SynchedEntityData;
|
||||||
@@ -15,16 +25,18 @@ import net.minecraft.server.level.ServerLevel;
|
|||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.sounds.SoundEvent;
|
import net.minecraft.sounds.SoundEvent;
|
||||||
import net.minecraft.sounds.SoundEvents;
|
import net.minecraft.sounds.SoundEvents;
|
||||||
import net.minecraft.sounds.SoundSource;
|
|
||||||
import net.minecraft.world.damagesource.DamageSource;
|
import net.minecraft.world.damagesource.DamageSource;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.EntityType;
|
import net.minecraft.world.entity.EntityType;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.entity.projectile.AbstractArrow;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.material.FluidState;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.joml.Quaternionf;
|
||||||
import software.bernie.geckolib.animatable.GeoEntity;
|
import software.bernie.geckolib.animatable.GeoEntity;
|
||||||
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
||||||
import software.bernie.geckolib.animation.AnimatableManager;
|
import software.bernie.geckolib.animation.AnimatableManager;
|
||||||
@@ -51,15 +63,21 @@ public class PortalGunPortalEntity extends Entity implements GeoEntity {
|
|||||||
private static final int CLOSE_TICKS = 10;
|
private static final int CLOSE_TICKS = 10;
|
||||||
private static final int MAX_LIFETIME_TICKS = 20 * 60 * 20;
|
private static final int MAX_LIFETIME_TICKS = 20 * 60 * 20;
|
||||||
private static final int TELEPORT_COOLDOWN_TICKS = 15;
|
private static final int TELEPORT_COOLDOWN_TICKS = 15;
|
||||||
|
private static final double PLAYER_PORTAL_INSIDE_SHIFT = 0.05D;
|
||||||
private static final double HALF_WIDTH = 0.5D;
|
private static final double HALF_WIDTH = 0.5D;
|
||||||
private static final double HALF_HEIGHT = 1.0D;
|
private static final double HALF_HEIGHT = 1.0D;
|
||||||
private static final double HALF_DEPTH = 0.35D;
|
private static final double HALF_DEPTH = 0.35D;
|
||||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
|
private final Map<UUID, Integer> teleportCooldowns = new HashMap<>();
|
||||||
private UUID ownerId;
|
private UUID ownerId;
|
||||||
private UUID linkedPortalId;
|
private UUID linkedPortalId;
|
||||||
private int ageTicks;
|
private int ageTicks;
|
||||||
|
private int pairTime;
|
||||||
private BlockPos supportOrigin = BlockPos.ZERO;
|
private BlockPos supportOrigin = BlockPos.ZERO;
|
||||||
private static final java.util.Map<UUID, Long> TELEPORT_COOLDOWNS = new java.util.HashMap<>();
|
private BlockPos masterPos = BlockPos.ZERO;
|
||||||
|
private BlockPos basePos = BlockPos.ZERO;
|
||||||
|
private BlockPos[] portalSpots = new BlockPos[] {BlockPos.ZERO, BlockPos.ZERO};
|
||||||
|
private Set<BlockPos> compensatedSpots = Set.of();
|
||||||
|
|
||||||
public PortalGunPortalEntity(EntityType<? extends PortalGunPortalEntity> entityType, Level level) {
|
public PortalGunPortalEntity(EntityType<? extends PortalGunPortalEntity> entityType, Level level) {
|
||||||
super(entityType, level);
|
super(entityType, level);
|
||||||
@@ -76,16 +94,26 @@ public class PortalGunPortalEntity extends Entity implements GeoEntity {
|
|||||||
builder.define(CLOSING, false);
|
builder.define(CLOSING, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void configure(UUID ownerId, PortalSide side, Direction facing, Direction upAxis, BlockPos supportOrigin) {
|
public void configure(UUID ownerId, PortalSide side, PortalGunPlacement placement) {
|
||||||
this.ownerId = ownerId;
|
this.ownerId = ownerId;
|
||||||
this.entityData.set(SIDE, side.ordinal());
|
this.entityData.set(SIDE, side.ordinal());
|
||||||
this.entityData.set(FACING, facing.get3DDataValue());
|
this.entityData.set(FACING, placement.facing().get3DDataValue());
|
||||||
this.entityData.set(UP_AXIS, upAxis.get3DDataValue());
|
this.entityData.set(UP_AXIS, placement.upAxis().get3DDataValue());
|
||||||
this.supportOrigin = supportOrigin.immutable();
|
this.supportOrigin = placement.supportOrigin().immutable();
|
||||||
|
this.masterPos = placement.masterPos().immutable();
|
||||||
|
this.basePos = placement.basePos().immutable();
|
||||||
|
this.portalSpots = new BlockPos[] {placement.portalSpots()[0].immutable(), placement.portalSpots()[1].immutable()};
|
||||||
|
this.compensatedSpots = Set.copyOf(placement.compensatedSpots());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void linkTo(PortalGunPortalEntity other) {
|
public void linkTo(PortalGunPortalEntity other) {
|
||||||
this.linkedPortalId = other.getUUID();
|
this.linkedPortalId = other.getUUID();
|
||||||
|
this.pairTime = (int) this.level().getGameTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restorePair(UUID linkedPortalId, int pairTime) {
|
||||||
|
this.linkedPortalId = linkedPortalId;
|
||||||
|
this.pairTime = pairTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PortalSide getPortalSide() {
|
public PortalSide getPortalSide() {
|
||||||
@@ -101,6 +129,46 @@ public class PortalGunPortalEntity extends Entity implements GeoEntity {
|
|||||||
return Direction.from3DDataValue(this.entityData.get(UP_AXIS));
|
return Direction.from3DDataValue(this.entityData.get(UP_AXIS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UUID getLinkedPortalId() {
|
||||||
|
return this.linkedPortalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockPos getMasterPos() {
|
||||||
|
return this.masterPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getOwnerId() {
|
||||||
|
return this.ownerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockPos getBasePos() {
|
||||||
|
return this.basePos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockPos[] getPortalSpots() {
|
||||||
|
return new BlockPos[] {this.portalSpots[0], this.portalSpots[1]};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<BlockPos> getCompensatedSpots() {
|
||||||
|
return Set.copyOf(this.compensatedSpots);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPairTime() {
|
||||||
|
return this.pairTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PortalGunPortalEntity getLinkedPortal() {
|
||||||
|
if (this.linkedPortalId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<Entity> entities = this.level().getEntities(this, new AABB(-3.0E7D, -3.0E7D, -3.0E7D, 3.0E7D, 3.0E7D, 3.0E7D), entity -> this.linkedPortalId.equals(entity.getUUID()));
|
||||||
|
if (entities.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Entity entity = entities.getFirst();
|
||||||
|
return entity instanceof PortalGunPortalEntity portal ? portal : null;
|
||||||
|
}
|
||||||
|
|
||||||
public Vec3 getNormalVec() {
|
public Vec3 getNormalVec() {
|
||||||
return Vec3.atLowerCornerOf(this.getFacingDirection().getNormal());
|
return Vec3.atLowerCornerOf(this.getFacingDirection().getNormal());
|
||||||
}
|
}
|
||||||
@@ -113,16 +181,125 @@ public class PortalGunPortalEntity extends Entity implements GeoEntity {
|
|||||||
return this.getNormalVec().cross(this.getUpVec()).normalize();
|
return this.getNormalVec().cross(this.getUpVec()).normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PortalGunWorldPortalShape getWorldPortalShape() {
|
||||||
|
return new PortalGunWorldPortalShape(this.position(), this.getNormalVec().normalize(), this.getUpVec().normalize(), this.getWidthVec().normalize(), HALF_WIDTH, HALF_HEIGHT, HALF_DEPTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AABB getPlane() {
|
||||||
|
return this.getWorldPortalShape().getPlane();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AABB getFlatPlane() {
|
||||||
|
return this.getWorldPortalShape().getFlatPlane();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AABB getScanRange() {
|
||||||
|
return this.getWorldPortalShape().getScanRange();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AABB getPortalInsides() {
|
||||||
|
return this.getWorldPortalShape().getPortalInsides();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AABB getPortalInsides(Entity entity) {
|
||||||
|
if (!(entity instanceof Player)) {
|
||||||
|
return this.getPortalInsides();
|
||||||
|
}
|
||||||
|
double shiftAmount = Math.min(PLAYER_PORTAL_INSIDE_SHIFT, Math.abs(this.getWorldPortalShape().localCoords(entity.position()).depth()));
|
||||||
|
return this.getPortalInsides().move(this.getNormalVec().normalize().scale(shiftAmount));
|
||||||
|
}
|
||||||
|
|
||||||
|
public AABB getTeleportPlane(double offset) {
|
||||||
|
return this.getWorldPortalShape().getTeleportPlane(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AABB getCollisionRemovalAabbForEntity(Entity entity) {
|
||||||
|
double speed = entity.getDeltaMovement().length();
|
||||||
|
double extent = Math.max(1.0D, Math.max(entity.getBbWidth(), entity.getBbHeight()) + speed);
|
||||||
|
return this.getFlatPlane().expandTowards(this.getNormalVec().normalize().scale(-extent));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3 teleportProbePosition(Entity entity) {
|
||||||
|
if (entity instanceof Player player) {
|
||||||
|
return player.getEyePosition();
|
||||||
|
}
|
||||||
|
if (entity instanceof LivingEntity living) {
|
||||||
|
return entity.position().add(0.0D, living.getBbHeight() * 0.5D, 0.0D);
|
||||||
|
}
|
||||||
|
return entity.position();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3 previousTeleportProbePosition(Entity entity) {
|
||||||
|
double prevX = entity.xo;
|
||||||
|
double prevY = entity.yo;
|
||||||
|
double prevZ = entity.zo;
|
||||||
|
if (entity instanceof Player player) {
|
||||||
|
return new Vec3(prevX, prevY + player.getEyeHeight(player.getPose()), prevZ);
|
||||||
|
}
|
||||||
|
if (entity instanceof LivingEntity living) {
|
||||||
|
return new Vec3(prevX, prevY + living.getBbHeight() * 0.5D, prevZ);
|
||||||
|
}
|
||||||
|
return new Vec3(prevX, prevY, prevZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3 resolveCrossingProbe(Entity entity) {
|
||||||
|
AABB currentBox = entity.getBoundingBox();
|
||||||
|
AABB previousBox = currentBox.move(entity.xo - entity.getX(), entity.yo - entity.getY(), entity.zo - entity.getZ());
|
||||||
|
for (Vec3 currentSample : portalSamples(entity, currentBox, false)) {
|
||||||
|
Vec3 previousSample = matchPreviousSample(currentSample, currentBox, previousBox);
|
||||||
|
if (this.crossesPortal(previousSample, currentSample)) {
|
||||||
|
return currentSample;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Vec3 previousProbe = this.previousTeleportProbePosition(entity);
|
||||||
|
Vec3 currentProbe = this.teleportProbePosition(entity);
|
||||||
|
return this.crossesPortal(previousProbe, currentProbe) ? currentProbe : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsPoint(Vec3 position) {
|
||||||
|
return this.getWorldPortalShape().contains(position, 0.0D);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean intersectsEntityBounds(Entity entity) {
|
||||||
|
AABB bounds = entity.getBoundingBox();
|
||||||
|
for (Vec3 corner : new Vec3[] {
|
||||||
|
new Vec3(bounds.minX, bounds.minY, bounds.minZ),
|
||||||
|
new Vec3(bounds.minX, bounds.minY, bounds.maxZ),
|
||||||
|
new Vec3(bounds.minX, bounds.maxY, bounds.minZ),
|
||||||
|
new Vec3(bounds.minX, bounds.maxY, bounds.maxZ),
|
||||||
|
new Vec3(bounds.maxX, bounds.minY, bounds.minZ),
|
||||||
|
new Vec3(bounds.maxX, bounds.minY, bounds.maxZ),
|
||||||
|
new Vec3(bounds.maxX, bounds.maxY, bounds.minZ),
|
||||||
|
new Vec3(bounds.maxX, bounds.maxY, bounds.maxZ)
|
||||||
|
}) {
|
||||||
|
if (this.getWorldPortalShape().contains(corner, 0.08D)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.getPortalInsides(entity).intersects(bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean crossesPortal(Vec3 previousProbePosition, Vec3 currentProbePosition) {
|
||||||
|
return this.getWorldPortalShape().crosses(previousProbePosition, currentProbePosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldRenderFront(Vec3 cameraPos) {
|
||||||
|
return this.getWorldPortalShape().shouldRenderFront(cameraPos);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
super.tick();
|
super.tick();
|
||||||
this.ageTicks++;
|
this.ageTicks++;
|
||||||
|
this.yRotO = this.getYRot();
|
||||||
|
this.xRotO = this.getXRot();
|
||||||
if (this.level().isClientSide) {
|
if (this.level().isClientSide) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!(this.level() instanceof ServerLevel serverLevel)) {
|
if (!(this.level() instanceof ServerLevel serverLevel)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.tickTeleportCooldowns();
|
||||||
if (this.ownerId == null || !this.isStillRegistered(serverLevel)) {
|
if (this.ownerId == null || !this.isStillRegistered(serverLevel)) {
|
||||||
this.discard();
|
this.discard();
|
||||||
return;
|
return;
|
||||||
@@ -151,32 +328,35 @@ public class PortalGunPortalEntity extends Entity implements GeoEntity {
|
|||||||
|
|
||||||
private boolean hasValidSurface() {
|
private boolean hasValidSurface() {
|
||||||
Direction facing = this.getFacingDirection();
|
Direction facing = this.getFacingDirection();
|
||||||
Direction heightAxis = this.getUpAxis();
|
for (int i = 0; i < this.portalSpots.length; i++) {
|
||||||
for (int h = 0; h < 2; h++) {
|
BlockPos portalSpot = this.portalSpots[i];
|
||||||
BlockPos supportPos = this.supportOrigin.relative(heightAxis, h);
|
BlockPos supportPos = portalSpot.relative(facing.getOpposite());
|
||||||
BlockPos airPos = supportPos.relative(facing);
|
|
||||||
BlockState supportState = this.level().getBlockState(supportPos);
|
BlockState supportState = this.level().getBlockState(supportPos);
|
||||||
BlockState airState = this.level().getBlockState(airPos);
|
|
||||||
FluidState fluidState = this.level().getFluidState(airPos);
|
|
||||||
if (!supportState.isFaceSturdy(this.level(), supportPos, facing)) {
|
if (!supportState.isFaceSturdy(this.level(), supportPos, facing)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!airState.isAir() && !airState.canBeReplaced()) {
|
BlockEntity blockEntity = this.level().getBlockEntity(portalSpot);
|
||||||
|
if (i == 0) {
|
||||||
|
if (!(blockEntity instanceof PortalGunPortalMasterBlockEntity master) || !master.matches(this.ownerId, this.getUUID(), this.getPortalSide())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!fluidState.isEmpty()) {
|
} else {
|
||||||
|
if (!(blockEntity instanceof PortalGunPortalBaseBlockEntity base) || !base.matches(this.ownerId, this.getUUID(), this.getPortalSide())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tickTeleport(PortalGunPortalEntity linked) {
|
private void tickTeleport(PortalGunPortalEntity linked) {
|
||||||
List<Entity> entities = this.level().getEntities(this, this.getBoundingBox().inflate(0.75D), this::canTeleportEntity);
|
List<Entity> entities = this.level().getEntities(this, this.getScanRange(), this::canTeleportEntity);
|
||||||
for (Entity entity : entities) {
|
for (Entity entity : entities) {
|
||||||
if (this.isInsidePortal(entity.position())) {
|
Vec3 crossingProbe = this.resolveCrossingProbe(entity);
|
||||||
this.teleportEntity(entity, linked);
|
if (crossingProbe == null) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
this.teleportEntity(entity, linked, crossingProbe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,45 +364,109 @@ public class PortalGunPortalEntity extends Entity implements GeoEntity {
|
|||||||
if (!entity.isAlive() || entity instanceof PortalGunPortalEntity || entity.isPassenger() || entity.isVehicle()) {
|
if (!entity.isAlive() || entity instanceof PortalGunPortalEntity || entity.isPassenger() || entity.isVehicle()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
long gameTime = this.level().getGameTime();
|
return !this.teleportCooldowns.containsKey(entity.getUUID());
|
||||||
long cooldownUntil = TELEPORT_COOLDOWNS.getOrDefault(entity.getUUID(), 0L);
|
|
||||||
if (cooldownUntil <= gameTime) {
|
|
||||||
TELEPORT_COOLDOWNS.remove(entity.getUUID());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isInsidePortal(Vec3 position) {
|
private boolean isInsidePortal(Vec3 position) {
|
||||||
Vec3 relative = position.subtract(this.position());
|
return this.getWorldPortalShape().contains(position, 0.0D);
|
||||||
double horizontal = relative.dot(this.getWidthVec());
|
|
||||||
double vertical = relative.dot(this.getUpVec());
|
|
||||||
double depth = Math.abs(relative.dot(this.getNormalVec()));
|
|
||||||
return Math.abs(horizontal) <= HALF_WIDTH && Math.abs(vertical) <= HALF_HEIGHT && depth <= HALF_DEPTH;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void teleportEntity(Entity entity, PortalGunPortalEntity destination) {
|
private PortalLocalCoords localCoords(Vec3 position) {
|
||||||
Vec3 sourceNormal = this.getNormalVec();
|
PortalGunWorldPortalShape.PortalLocalCoords coords = this.getWorldPortalShape().localCoords(position);
|
||||||
Vec3 sourceUp = this.getUpVec();
|
return new PortalLocalCoords(coords.horizontal(), coords.vertical(), coords.depth());
|
||||||
Vec3 sourceWidth = this.getWidthVec();
|
}
|
||||||
Vec3 destinationNormal = destination.getNormalVec();
|
|
||||||
Vec3 destinationUp = destination.getUpVec();
|
private List<Vec3> portalSamples(Entity entity, AABB box, boolean previous) {
|
||||||
Vec3 destinationWidth = destination.getWidthVec();
|
Vec3 center = new Vec3((box.minX + box.maxX) * 0.5D, (box.minY + box.maxY) * 0.5D, (box.minZ + box.maxZ) * 0.5D);
|
||||||
Vec3 motion = entity.getDeltaMovement();
|
Vec3 topCenter = new Vec3(center.x, box.maxY, center.z);
|
||||||
double widthComponent = motion.dot(sourceWidth);
|
Vec3 bottomCenter = new Vec3(center.x, box.minY, center.z);
|
||||||
double upComponent = motion.dot(sourceUp);
|
if (entity instanceof Player player) {
|
||||||
double forward = -motion.dot(sourceNormal);
|
Vec3 eye = previous ? this.previousTeleportProbePosition(player) : this.teleportProbePosition(player);
|
||||||
Vec3 transformedMotion = destinationWidth.scale(widthComponent).add(destinationUp.scale(upComponent)).add(destinationNormal.scale(forward));
|
return List.of(center, eye, topCenter, bottomCenter);
|
||||||
Vec3 exitPos = destination.position().add(destinationNormal.scale(1.0D));
|
}
|
||||||
TELEPORT_COOLDOWNS.put(entity.getUUID(), this.level().getGameTime() + TELEPORT_COOLDOWN_TICKS);
|
if (entity instanceof LivingEntity) {
|
||||||
|
return List.of(center, topCenter, bottomCenter);
|
||||||
|
}
|
||||||
|
return List.of(center);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vec3 matchPreviousSample(Vec3 currentSample, AABB currentBox, AABB previousBox) {
|
||||||
|
double xLerp = axisRatio(currentSample.x, currentBox.minX, currentBox.maxX);
|
||||||
|
double yLerp = axisRatio(currentSample.y, currentBox.minY, currentBox.maxY);
|
||||||
|
double zLerp = axisRatio(currentSample.z, currentBox.minZ, currentBox.maxZ);
|
||||||
|
return new Vec3(
|
||||||
|
lerp(previousBox.minX, previousBox.maxX, xLerp),
|
||||||
|
lerp(previousBox.minY, previousBox.maxY, yLerp),
|
||||||
|
lerp(previousBox.minZ, previousBox.maxZ, zLerp)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double axisRatio(double value, double min, double max) {
|
||||||
|
double size = max - min;
|
||||||
|
if (Math.abs(size) < 1.0E-6D) {
|
||||||
|
return 0.5D;
|
||||||
|
}
|
||||||
|
return (value - min) / size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double lerp(double min, double max, double delta) {
|
||||||
|
return min + (max - min) * delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void teleportEntity(Entity entity, PortalGunPortalEntity destination, Vec3 currentProbe) {
|
||||||
|
Quaternionf transform = PortalGunTransformUtil.createTransform(this, destination);
|
||||||
|
Vec3 relativeProbe = currentProbe.subtract(this.position());
|
||||||
|
Vec3 transformedProbe = PortalGunTransformUtil.transform(relativeProbe, transform);
|
||||||
|
Vec3 entityOffsetFromProbe = entity.position().subtract(currentProbe);
|
||||||
|
Vec3 transformedEntityOffset = PortalGunTransformUtil.transform(entityOffsetFromProbe, transform);
|
||||||
|
Vec3 transformedLook = PortalGunTransformUtil.transform(entity.getLookAngle(), transform).normalize();
|
||||||
|
Vec3 transformedMotion = PortalGunTransformUtil.transform(entity.getDeltaMovement(), transform);
|
||||||
|
Vec3 exitProbe = destination.position().add(transformedProbe).add(destination.getNormalVec().normalize().scale(0.08D - transformedProbe.dot(destination.getNormalVec().normalize())));
|
||||||
|
Vec3 exitPos = exitProbe.add(transformedEntityOffset);
|
||||||
|
float yaw = PortalGunTransformUtil.yawFromLook(transformedLook);
|
||||||
|
float pitch = PortalGunTransformUtil.pitchFromLook(transformedLook);
|
||||||
|
this.applyTeleportCooldown(entity, destination);
|
||||||
if (entity instanceof ServerPlayer player && destination.level() instanceof ServerLevel destinationLevel) {
|
if (entity instanceof ServerPlayer player && destination.level() instanceof ServerLevel destinationLevel) {
|
||||||
player.teleportTo(destinationLevel, exitPos.x, exitPos.y, exitPos.z, player.getYRot(), player.getXRot());
|
player.teleportTo(destinationLevel, exitPos.x, exitPos.y, exitPos.z, yaw, pitch);
|
||||||
} else {
|
} else {
|
||||||
entity.teleportTo(exitPos.x, exitPos.y, exitPos.z);
|
entity.teleportTo(exitPos.x, exitPos.y, exitPos.z);
|
||||||
|
entity.setYRot(yaw);
|
||||||
|
entity.setXRot(pitch);
|
||||||
|
entity.setYHeadRot(yaw);
|
||||||
|
entity.setYBodyRot(yaw);
|
||||||
}
|
}
|
||||||
entity.setDeltaMovement(transformedMotion);
|
entity.setDeltaMovement(transformedMotion);
|
||||||
entity.hasImpulse = true;
|
entity.hasImpulse = true;
|
||||||
entity.fallDistance = 0.0F;
|
entity.fallDistance = 0.0F;
|
||||||
|
this.handleSpecialEntityPostTeleport(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tickTeleportCooldowns() {
|
||||||
|
Iterator<Map.Entry<UUID, Integer>> iterator = this.teleportCooldowns.entrySet().iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
Map.Entry<UUID, Integer> entry = iterator.next();
|
||||||
|
int cooldown = entry.getValue() - 1;
|
||||||
|
if (cooldown < 0) {
|
||||||
|
iterator.remove();
|
||||||
|
} else {
|
||||||
|
entry.setValue(cooldown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyTeleportCooldown(Entity entity, PortalGunPortalEntity destination) {
|
||||||
|
UUID entityId = entity.getUUID();
|
||||||
|
this.teleportCooldowns.put(entityId, TELEPORT_COOLDOWN_TICKS);
|
||||||
|
destination.teleportCooldowns.put(entityId, TELEPORT_COOLDOWN_TICKS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleSpecialEntityPostTeleport(Entity entity) {
|
||||||
|
if (entity instanceof AbstractArrow arrow) {
|
||||||
|
((AbstractArrowAccessor) arrow).antarchy$setInGround(false);
|
||||||
|
((AbstractArrowAccessor) arrow).antarchy$setInGroundTime(0);
|
||||||
|
((AbstractArrowAccessor) arrow).antarchy$setShakeTime(0);
|
||||||
|
arrow.setNoPhysics(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private PortalGunPortalEntity findLinkedPortal(ServerLevel level) {
|
private PortalGunPortalEntity findLinkedPortal(ServerLevel level) {
|
||||||
@@ -235,18 +479,12 @@ public class PortalGunPortalEntity extends Entity implements GeoEntity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AABB getBoundingBoxForCulling() {
|
public AABB getBoundingBoxForCulling() {
|
||||||
return this.getBoundingBox().inflate(1.5D);
|
return this.getWorldPortalShape().getBoundsForCulling();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AABB makeBoundingBox() {
|
protected AABB makeBoundingBox() {
|
||||||
Vec3 widthVec = this.getWidthVec();
|
return this.getPortalInsides();
|
||||||
Vec3 upVec = this.getUpVec();
|
|
||||||
Vec3 normalVec = this.getNormalVec();
|
|
||||||
double halfX = HALF_WIDTH * Math.abs(widthVec.x) + HALF_HEIGHT * Math.abs(upVec.x) + HALF_DEPTH * Math.abs(normalVec.x);
|
|
||||||
double halfY = HALF_WIDTH * Math.abs(widthVec.y) + HALF_HEIGHT * Math.abs(upVec.y) + HALF_DEPTH * Math.abs(normalVec.y);
|
|
||||||
double halfZ = HALF_WIDTH * Math.abs(widthVec.z) + HALF_HEIGHT * Math.abs(upVec.z) + HALF_DEPTH * Math.abs(normalVec.z);
|
|
||||||
return new AABB(this.getX() - halfX, this.getY() - halfY, this.getZ() - halfZ, this.getX() + halfX, this.getY() + halfY, this.getZ() + halfZ);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -258,11 +496,37 @@ public class PortalGunPortalEntity extends Entity implements GeoEntity {
|
|||||||
tag.putUUID("LinkedPortalId", this.linkedPortalId);
|
tag.putUUID("LinkedPortalId", this.linkedPortalId);
|
||||||
}
|
}
|
||||||
tag.putInt("AgeTicks", this.ageTicks);
|
tag.putInt("AgeTicks", this.ageTicks);
|
||||||
|
tag.putInt("PairTime", this.pairTime);
|
||||||
tag.putInt("Side", this.getPortalSide().ordinal());
|
tag.putInt("Side", this.getPortalSide().ordinal());
|
||||||
tag.putInt("Facing", this.getFacingDirection().get3DDataValue());
|
tag.putInt("Facing", this.getFacingDirection().get3DDataValue());
|
||||||
|
tag.putInt("UpAxis", this.getUpAxis().get3DDataValue());
|
||||||
tag.putInt("SupportX", this.supportOrigin.getX());
|
tag.putInt("SupportX", this.supportOrigin.getX());
|
||||||
tag.putInt("SupportY", this.supportOrigin.getY());
|
tag.putInt("SupportY", this.supportOrigin.getY());
|
||||||
tag.putInt("SupportZ", this.supportOrigin.getZ());
|
tag.putInt("SupportZ", this.supportOrigin.getZ());
|
||||||
|
tag.putInt("MasterX", this.masterPos.getX());
|
||||||
|
tag.putInt("MasterY", this.masterPos.getY());
|
||||||
|
tag.putInt("MasterZ", this.masterPos.getZ());
|
||||||
|
tag.putInt("BaseX", this.basePos.getX());
|
||||||
|
tag.putInt("BaseY", this.basePos.getY());
|
||||||
|
tag.putInt("BaseZ", this.basePos.getZ());
|
||||||
|
ListTag spots = new ListTag();
|
||||||
|
for (BlockPos portalSpot : this.portalSpots) {
|
||||||
|
CompoundTag spot = new CompoundTag();
|
||||||
|
spot.putInt("X", portalSpot.getX());
|
||||||
|
spot.putInt("Y", portalSpot.getY());
|
||||||
|
spot.putInt("Z", portalSpot.getZ());
|
||||||
|
spots.add(spot);
|
||||||
|
}
|
||||||
|
tag.put("PortalSpots", spots);
|
||||||
|
ListTag compensated = new ListTag();
|
||||||
|
for (BlockPos compensatedSpot : this.compensatedSpots) {
|
||||||
|
CompoundTag spot = new CompoundTag();
|
||||||
|
spot.putInt("X", compensatedSpot.getX());
|
||||||
|
spot.putInt("Y", compensatedSpot.getY());
|
||||||
|
spot.putInt("Z", compensatedSpot.getZ());
|
||||||
|
compensated.add(spot);
|
||||||
|
}
|
||||||
|
tag.put("CompensatedSpots", compensated);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -274,17 +538,48 @@ public class PortalGunPortalEntity extends Entity implements GeoEntity {
|
|||||||
this.linkedPortalId = tag.getUUID("LinkedPortalId");
|
this.linkedPortalId = tag.getUUID("LinkedPortalId");
|
||||||
}
|
}
|
||||||
this.ageTicks = tag.getInt("AgeTicks");
|
this.ageTicks = tag.getInt("AgeTicks");
|
||||||
|
this.pairTime = tag.getInt("PairTime");
|
||||||
this.entityData.set(SIDE, tag.getInt("Side"));
|
this.entityData.set(SIDE, tag.getInt("Side"));
|
||||||
this.entityData.set(FACING, tag.getInt("Facing"));
|
this.entityData.set(FACING, tag.getInt("Facing"));
|
||||||
|
this.entityData.set(UP_AXIS, tag.getInt("UpAxis"));
|
||||||
this.supportOrigin = new BlockPos(tag.getInt("SupportX"), tag.getInt("SupportY"), tag.getInt("SupportZ"));
|
this.supportOrigin = new BlockPos(tag.getInt("SupportX"), tag.getInt("SupportY"), tag.getInt("SupportZ"));
|
||||||
|
this.masterPos = new BlockPos(tag.getInt("MasterX"), tag.getInt("MasterY"), tag.getInt("MasterZ"));
|
||||||
|
this.basePos = new BlockPos(tag.getInt("BaseX"), tag.getInt("BaseY"), tag.getInt("BaseZ"));
|
||||||
|
ListTag spots = tag.getList("PortalSpots", Tag.TAG_COMPOUND);
|
||||||
|
for (int i = 0; i < Math.min(2, spots.size()); i++) {
|
||||||
|
CompoundTag spot = spots.getCompound(i);
|
||||||
|
this.portalSpots[i] = new BlockPos(spot.getInt("X"), spot.getInt("Y"), spot.getInt("Z"));
|
||||||
|
}
|
||||||
|
ListTag compensated = tag.getList("CompensatedSpots", Tag.TAG_COMPOUND);
|
||||||
|
Set<BlockPos> compensatedSpots = new HashSet<>();
|
||||||
|
for (int i = 0; i < compensated.size(); i++) {
|
||||||
|
CompoundTag spot = compensated.getCompound(i);
|
||||||
|
compensatedSpots.add(new BlockPos(spot.getInt("X"), spot.getInt("Y"), spot.getInt("Z")));
|
||||||
|
}
|
||||||
|
this.compensatedSpots = compensatedSpots;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove(Entity.RemovalReason reason) {
|
public void remove(Entity.RemovalReason reason) {
|
||||||
if (!this.level().isClientSide && this.ownerId != null && this.level() instanceof ServerLevel serverLevel) {
|
Level level = this.level();
|
||||||
PortalGunSavedData.clearPortal(serverLevel.getServer(), this.ownerId, this.getPortalSide(), this.getUUID());
|
UUID ownerId = this.ownerId;
|
||||||
}
|
|
||||||
super.remove(reason);
|
super.remove(reason);
|
||||||
|
if (!level.isClientSide && ownerId != null && level instanceof ServerLevel serverLevel) {
|
||||||
|
PortalGunSavedData.clearPortal(serverLevel.getServer(), ownerId, this.getPortalSide(), this.getUUID());
|
||||||
|
this.clearPortalBlocks(serverLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearPortalBlocks(ServerLevel level) {
|
||||||
|
for (BlockPos portalSpot : this.portalSpots) {
|
||||||
|
if (level.getBlockEntity(portalSpot) instanceof PortalGunPortalMasterBlockEntity master && this.getUUID().equals(master.getPortalId())) {
|
||||||
|
level.removeBlock(portalSpot, false);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (level.getBlockEntity(portalSpot) instanceof PortalGunPortalBaseBlockEntity base && this.getUUID().equals(base.getPortalId())) {
|
||||||
|
level.removeBlock(portalSpot, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -340,4 +635,7 @@ public class PortalGunPortalEntity extends Entity implements GeoEntity {
|
|||||||
public static SoundEvent sound(String path, SoundEvent fallback) {
|
public static SoundEvent sound(String path, SoundEvent fallback) {
|
||||||
return BuiltInRegistries.SOUND_EVENT.getOptional(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, path)).orElse(fallback);
|
return BuiltInRegistries.SOUND_EVENT.getOptional(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, path)).orElse(fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private record PortalLocalCoords(double horizontal, double vertical, double depth) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+166
@@ -0,0 +1,166 @@
|
|||||||
|
package com.craisinlord.antarchy.content.portalgun;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.item.PortalGunItem;
|
||||||
|
import java.util.UUID;
|
||||||
|
import net.minecraft.core.component.DataComponents;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||||
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||||
|
import net.minecraft.network.syncher.SynchedEntityData;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.entity.projectile.ThrowableItemProjectile;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import net.minecraft.world.phys.EntityHitResult;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public class PortalGunProjectileEntity extends ThrowableItemProjectile {
|
||||||
|
private static final EntityDataAccessor<Integer> SIDE = SynchedEntityData.defineId(PortalGunProjectileEntity.class, EntityDataSerializers.INT);
|
||||||
|
private static final int MAX_FLIGHT_TICKS = 80;
|
||||||
|
private UUID gunId;
|
||||||
|
|
||||||
|
public PortalGunProjectileEntity(EntityType<? extends PortalGunProjectileEntity> entityType, Level level) {
|
||||||
|
super(entityType, level);
|
||||||
|
this.configureProjectile();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PortalGunProjectileEntity(EntityType<? extends PortalGunProjectileEntity> entityType, LivingEntity owner, Level level) {
|
||||||
|
super(entityType, owner, level);
|
||||||
|
this.configureProjectile();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureProjectile() {
|
||||||
|
this.setNoGravity(true);
|
||||||
|
this.noCulling = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
||||||
|
super.defineSynchedData(builder);
|
||||||
|
builder.define(SIDE, PortalGunPortalEntity.PortalSide.BLUE.ordinal());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void configure(PortalGunPortalEntity.PortalSide side, UUID gunId, ItemStack gunStack) {
|
||||||
|
this.entityData.set(SIDE, side.ordinal());
|
||||||
|
this.gunId = gunId;
|
||||||
|
this.setItem(gunStack.copyWithCount(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PortalGunPortalEntity.PortalSide getPortalSide() {
|
||||||
|
return this.entityData.get(SIDE) == PortalGunPortalEntity.PortalSide.ORANGE.ordinal() ? PortalGunPortalEntity.PortalSide.ORANGE : PortalGunPortalEntity.PortalSide.BLUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Item getDefaultItem() {
|
||||||
|
return Items.AIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected double getDefaultGravity() {
|
||||||
|
return 0.0D;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canHitEntity(Entity target) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canBeCollidedWith() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAttackable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
if (this.tickCount > MAX_FLIGHT_TICKS) {
|
||||||
|
this.discard();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Vec3 motion = this.getDeltaMovement();
|
||||||
|
if (motion.lengthSqr() > 1.0E-6D) {
|
||||||
|
double horizontal = Math.sqrt(motion.x * motion.x + motion.z * motion.z);
|
||||||
|
this.setYRot((float) (net.minecraft.util.Mth.atan2(motion.z, motion.x) * (180.0D / Math.PI)) - 90.0F);
|
||||||
|
this.setXRot((float) (-(net.minecraft.util.Mth.atan2(motion.y, horizontal) * (180.0D / Math.PI))));
|
||||||
|
}
|
||||||
|
if (this.level().isClientSide) {
|
||||||
|
Vec3 point = this.position();
|
||||||
|
if (this.getPortalSide() == PortalGunPortalEntity.PortalSide.BLUE) {
|
||||||
|
this.level().addParticle(net.minecraft.core.particles.ParticleTypes.SOUL_FIRE_FLAME, point.x, point.y, point.z, 0.0D, 0.0D, 0.0D);
|
||||||
|
this.level().addParticle(net.minecraft.core.particles.ParticleTypes.END_ROD, point.x, point.y, point.z, 0.0D, 0.0D, 0.0D);
|
||||||
|
} else {
|
||||||
|
this.level().addParticle(net.minecraft.core.particles.ParticleTypes.FLAME, point.x, point.y, point.z, 0.0D, 0.0D, 0.0D);
|
||||||
|
this.level().addParticle(net.minecraft.core.particles.ParticleTypes.CRIT, point.x, point.y, point.z, 0.0D, 0.0D, 0.0D);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onHitEntity(EntityHitResult result) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onHitBlock(BlockHitResult result) {
|
||||||
|
if (!this.level().isClientSide && this.level() instanceof ServerLevel serverLevel) {
|
||||||
|
this.spawnImpactParticles(serverLevel, result.getLocation());
|
||||||
|
ItemStack sourceStack = this.resolveSourceStack();
|
||||||
|
if (this.getOwner() instanceof Player player && sourceStack.getItem() instanceof PortalGunItem portalGunItem) {
|
||||||
|
portalGunItem.handlePortalImpact(serverLevel, player, sourceStack, this.getPortalSide(), result, this.position());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.discard();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void spawnImpactParticles(ServerLevel level, Vec3 impactPos) {
|
||||||
|
if (this.getPortalSide() == PortalGunPortalEntity.PortalSide.BLUE) {
|
||||||
|
level.sendParticles(net.minecraft.core.particles.ParticleTypes.SOUL_FIRE_FLAME, impactPos.x, impactPos.y, impactPos.z, 10, 0.08D, 0.08D, 0.08D, 0.01D);
|
||||||
|
level.sendParticles(net.minecraft.core.particles.ParticleTypes.END_ROD, impactPos.x, impactPos.y, impactPos.z, 6, 0.04D, 0.04D, 0.04D, 0.01D);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
level.sendParticles(net.minecraft.core.particles.ParticleTypes.FLAME, impactPos.x, impactPos.y, impactPos.z, 10, 0.08D, 0.08D, 0.08D, 0.01D);
|
||||||
|
level.sendParticles(net.minecraft.core.particles.ParticleTypes.CRIT, impactPos.x, impactPos.y, impactPos.z, 6, 0.04D, 0.04D, 0.04D, 0.01D);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemStack resolveSourceStack() {
|
||||||
|
ItemStack projectileStack = this.getItem();
|
||||||
|
if (!(this.getOwner() instanceof Player player) || !(projectileStack.getItem() instanceof PortalGunItem portalGunItem) || this.gunId == null) {
|
||||||
|
return projectileStack;
|
||||||
|
}
|
||||||
|
ItemStack matching = portalGunItem.findMatchingGunStack(player, this.gunId);
|
||||||
|
return matching.isEmpty() ? projectileStack : matching;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAdditionalSaveData(CompoundTag tag) {
|
||||||
|
super.addAdditionalSaveData(tag);
|
||||||
|
tag.putInt("Side", this.entityData.get(SIDE));
|
||||||
|
if (this.gunId != null) {
|
||||||
|
tag.putUUID("GunId", this.gunId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readAdditionalSaveData(CompoundTag tag) {
|
||||||
|
super.readAdditionalSaveData(tag);
|
||||||
|
this.entityData.set(SIDE, tag.getInt("Side"));
|
||||||
|
if (tag.hasUUID("GunId")) {
|
||||||
|
this.gunId = tag.getUUID("GunId");
|
||||||
|
}
|
||||||
|
ItemStack itemStack = this.getItem();
|
||||||
|
if (this.gunId != null && !itemStack.isEmpty()) {
|
||||||
|
net.minecraft.world.item.component.CustomData.update(DataComponents.CUSTOM_DATA, itemStack, customData -> customData.putUUID(PortalGunItem.GUN_ID_TAG, this.gunId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
@@ -9,6 +9,7 @@ import net.minecraft.nbt.CompoundTag;
|
|||||||
import net.minecraft.nbt.ListTag;
|
import net.minecraft.nbt.ListTag;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.level.saveddata.SavedData;
|
import net.minecraft.world.level.saveddata.SavedData;
|
||||||
|
|
||||||
public final class PortalGunSavedData extends SavedData {
|
public final class PortalGunSavedData extends SavedData {
|
||||||
@@ -119,6 +120,20 @@ public final class PortalGunSavedData extends SavedData {
|
|||||||
discardIfLoaded(server, current.orangePortalId());
|
discardIfLoaded(server, current.orangePortalId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PortalGunPortalEntity findLoadedPortal(MinecraftServer server, UUID owner, PortalGunPortalEntity.PortalSide side) {
|
||||||
|
Optional<UUID> portalId = getPortalId(server, owner, side);
|
||||||
|
if (portalId.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (ServerLevel level : server.getAllLevels()) {
|
||||||
|
Entity entity = level.getEntity(portalId.get());
|
||||||
|
if (entity instanceof PortalGunPortalEntity portal && !portal.isRemoved()) {
|
||||||
|
return portal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private static void discardIfLoaded(MinecraftServer server, UUID portalId) {
|
private static void discardIfLoaded(MinecraftServer server, UUID portalId) {
|
||||||
if (portalId == null) {
|
if (portalId == null) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
+93
@@ -0,0 +1,93 @@
|
|||||||
|
package com.craisinlord.antarchy.content.portalgun;
|
||||||
|
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.joml.Matrix3f;
|
||||||
|
import org.joml.Quaternionf;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
public final class PortalGunTransformUtil {
|
||||||
|
private static final Vec3 WORLD_UP = new Vec3(0.0D, 1.0D, 0.0D);
|
||||||
|
private static final Vec3 WORLD_FORWARD_FALLBACK = new Vec3(0.0D, 0.0D, 1.0D);
|
||||||
|
|
||||||
|
private PortalGunTransformUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Quaternionf createTransform(PortalGunPortalEntity sourcePortal, PortalGunPortalEntity destinationPortal) {
|
||||||
|
return createTransform(sourcePortal.getWidthVec(), sourcePortal.getUpVec(), sourcePortal.getNormalVec().scale(-1.0D), destinationPortal.getWidthVec(), destinationPortal.getUpVec(), destinationPortal.getNormalVec());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Quaternionf createTransform(Vec3 sourceWidth, Vec3 sourceUp, Vec3 sourceForward, Vec3 destinationWidth, Vec3 destinationUp, Vec3 destinationForward) {
|
||||||
|
Matrix3f sourceBasis = new Matrix3f(
|
||||||
|
(float) sourceWidth.x, (float) sourceUp.x, (float) sourceForward.x,
|
||||||
|
(float) sourceWidth.y, (float) sourceUp.y, (float) sourceForward.y,
|
||||||
|
(float) sourceWidth.z, (float) sourceUp.z, (float) sourceForward.z
|
||||||
|
);
|
||||||
|
Matrix3f destinationBasis = new Matrix3f(
|
||||||
|
(float) destinationWidth.x, (float) destinationUp.x, (float) destinationForward.x,
|
||||||
|
(float) destinationWidth.y, (float) destinationUp.y, (float) destinationForward.y,
|
||||||
|
(float) destinationWidth.z, (float) destinationUp.z, (float) destinationForward.z
|
||||||
|
);
|
||||||
|
Matrix3f transform = destinationBasis.mul(sourceBasis.transpose(new Matrix3f()), new Matrix3f());
|
||||||
|
return transform.getNormalizedRotation(new Quaternionf());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vec3 transform(Vec3 vector, Quaternionf quaternion) {
|
||||||
|
Vector3f rotated = new Vector3f((float) vector.x, (float) vector.y, (float) vector.z).rotate(quaternion);
|
||||||
|
return new Vec3(rotated.x(), rotated.y(), rotated.z());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vec3 transformRelativePosition(PortalGunPortalEntity sourcePortal, PortalGunPortalEntity destinationPortal, Vec3 relativePosition) {
|
||||||
|
return transform(relativePosition, createTransform(sourcePortal, destinationPortal));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float yawFromLook(Vec3 look) {
|
||||||
|
return (float) Math.toDegrees(Math.atan2(-look.x, look.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float pitchFromLook(Vec3 look) {
|
||||||
|
return (float) Math.toDegrees(-Math.asin(Mth.clamp(look.y, -1.0D, 1.0D)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vec3 upVectorFromLookAndRoll(Vec3 look, float rollDegrees) {
|
||||||
|
Vec3 normalizedLook = look.normalize();
|
||||||
|
Vec3 referenceUp = Math.abs(normalizedLook.dot(WORLD_UP)) > 0.999D ? WORLD_FORWARD_FALLBACK : WORLD_UP;
|
||||||
|
Vec3 right = referenceUp.cross(normalizedLook).normalize();
|
||||||
|
Vec3 up = normalizedLook.cross(right).normalize();
|
||||||
|
if (Math.abs(rollDegrees) <= 1.0E-4F) {
|
||||||
|
return up;
|
||||||
|
}
|
||||||
|
Quaternionf roll = new Quaternionf().fromAxisAngleDeg((float) normalizedLook.x, (float) normalizedLook.y, (float) normalizedLook.z, rollDegrees);
|
||||||
|
return transform(up, roll).normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float rollFromOrientation(Vec3 look, Vec3 up) {
|
||||||
|
Vec3 normalizedLook = look.normalize();
|
||||||
|
Vec3 normalizedUp = up.normalize();
|
||||||
|
Vec3 baseUp = upVectorFromLookAndRoll(normalizedLook, 0.0F);
|
||||||
|
Vec3 projectedUp = normalizedUp.subtract(normalizedLook.scale(normalizedUp.dot(normalizedLook)));
|
||||||
|
if (projectedUp.lengthSqr() < 1.0E-8D) {
|
||||||
|
return 0.0F;
|
||||||
|
}
|
||||||
|
projectedUp = projectedUp.normalize();
|
||||||
|
double sin = normalizedLook.dot(baseUp.cross(projectedUp));
|
||||||
|
double cos = Mth.clamp(baseUp.dot(projectedUp), -1.0D, 1.0D);
|
||||||
|
return normalizeDegrees((float) Math.toDegrees(Math.atan2(sin, cos)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Quaternionf orientationQuaternion(Vec3 look, Vec3 up) {
|
||||||
|
Vec3 forward = look.normalize();
|
||||||
|
Vec3 correctedUp = up.subtract(forward.scale(up.dot(forward))).normalize();
|
||||||
|
Vec3 right = correctedUp.cross(forward).normalize();
|
||||||
|
Matrix3f basis = new Matrix3f(
|
||||||
|
(float) right.x, (float) correctedUp.x, (float) (-forward.x),
|
||||||
|
(float) right.y, (float) correctedUp.y, (float) (-forward.y),
|
||||||
|
(float) right.z, (float) correctedUp.z, (float) (-forward.z)
|
||||||
|
);
|
||||||
|
return basis.getNormalizedRotation(new Quaternionf());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float normalizeDegrees(float degrees) {
|
||||||
|
return Mth.wrapDegrees(degrees);
|
||||||
|
}
|
||||||
|
}
|
||||||
+165
@@ -0,0 +1,165 @@
|
|||||||
|
package com.craisinlord.antarchy.content.portalgun;
|
||||||
|
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record PortalGunWorldPortalShape(
|
||||||
|
Vec3 center,
|
||||||
|
Vec3 normal,
|
||||||
|
Vec3 up,
|
||||||
|
Vec3 right,
|
||||||
|
double halfWidth,
|
||||||
|
double halfHeight,
|
||||||
|
double halfDepth
|
||||||
|
) {
|
||||||
|
public static final double DEFAULT_SCAN_DISTANCE = 3.0D;
|
||||||
|
|
||||||
|
public AABB getPlane() {
|
||||||
|
return this.createPlaneAround(0.0D, 0.0125D);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AABB getFlatPlane() {
|
||||||
|
return this.createPlaneAround(0.0D, 0.0D);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AABB getScanRange() {
|
||||||
|
return this.getFlatPlane().expandTowards(this.normal.scale(-DEFAULT_SCAN_DISTANCE));
|
||||||
|
}
|
||||||
|
|
||||||
|
public AABB getPortalInsides() {
|
||||||
|
return this.createPlaneAround(0.0D, this.halfDepth);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AABB getTeleportPlane(double offset) {
|
||||||
|
return this.createPlaneAround(offset, this.halfDepth);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3[] getCorners(double normalOffset) {
|
||||||
|
Vec3 center = this.center.add(this.normal.scale(normalOffset));
|
||||||
|
Vec3 width = this.right.scale(this.halfWidth);
|
||||||
|
Vec3 height = this.up.scale(this.halfHeight);
|
||||||
|
return new Vec3[] {
|
||||||
|
center.subtract(width).subtract(height),
|
||||||
|
center.subtract(width).add(height),
|
||||||
|
center.add(width).add(height),
|
||||||
|
center.add(width).subtract(height)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public PortalLocalCoords localCoords(Vec3 position) {
|
||||||
|
Vec3 relative = position.subtract(this.center);
|
||||||
|
return new PortalLocalCoords(relative.dot(this.right), relative.dot(this.up), relative.dot(this.normal));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(Vec3 position, double depthPadding) {
|
||||||
|
PortalLocalCoords coords = this.localCoords(position);
|
||||||
|
return Math.abs(coords.horizontal()) <= this.halfWidth
|
||||||
|
&& Math.abs(coords.vertical()) <= this.halfHeight
|
||||||
|
&& Math.abs(coords.depth()) <= this.halfDepth + depthPadding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean crosses(Vec3 previousPosition, Vec3 currentPosition) {
|
||||||
|
PortalLocalCoords previous = this.localCoords(previousPosition);
|
||||||
|
PortalLocalCoords current = this.localCoords(currentPosition);
|
||||||
|
double depthDelta = current.depth() - previous.depth();
|
||||||
|
if (depthDelta > -1.0E-6D || previous.depth() <= 0.0D || current.depth() > 0.0D) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
double t = -previous.depth() / depthDelta;
|
||||||
|
if (t < 0.0D || t > 1.0D) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
double horizontal = previous.horizontal() + (current.horizontal() - previous.horizontal()) * t;
|
||||||
|
double vertical = previous.vertical() + (current.vertical() - previous.vertical()) * t;
|
||||||
|
return Math.abs(horizontal) <= this.halfWidth && Math.abs(vertical) <= this.halfHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldRenderFront(Vec3 cameraPos) {
|
||||||
|
PortalLocalCoords coords = this.localCoords(cameraPos);
|
||||||
|
if (coords.depth() <= 0.0D) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
double depthScale = Math.min(DEFAULT_SCAN_DISTANCE, Math.max(0.0D, coords.depth()));
|
||||||
|
return Math.abs(coords.horizontal()) <= this.halfWidth + depthScale
|
||||||
|
&& Math.abs(coords.vertical()) <= this.halfHeight + depthScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean intersectsFront(AABB box, double tolerance) {
|
||||||
|
double maxDepth = Double.NEGATIVE_INFINITY;
|
||||||
|
for (Vec3 corner : corners(box)) {
|
||||||
|
maxDepth = Math.max(maxDepth, this.localCoords(corner).depth());
|
||||||
|
if (maxDepth >= -tolerance) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AABB getBoundsForCulling() {
|
||||||
|
return this.createPlaneAround(0.0D, this.halfDepth).inflate(1.5D);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AABB> getCollisionBoundaries(double borderThickness) {
|
||||||
|
double horizontalOuter = this.halfWidth + borderThickness;
|
||||||
|
double verticalOuter = this.halfHeight + borderThickness;
|
||||||
|
return List.of(
|
||||||
|
this.createLocalBox(-horizontalOuter, this.halfWidth, -verticalOuter, verticalOuter, -this.halfDepth, this.halfDepth),
|
||||||
|
this.createLocalBox(-this.halfWidth, horizontalOuter, -verticalOuter, verticalOuter, -this.halfDepth, this.halfDepth),
|
||||||
|
this.createLocalBox(-this.halfWidth, this.halfWidth, -verticalOuter, -this.halfHeight, -this.halfDepth, this.halfDepth),
|
||||||
|
this.createLocalBox(-this.halfWidth, this.halfWidth, this.halfHeight, verticalOuter, -this.halfDepth, this.halfDepth)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AABB createPlaneAround(double planeOffset, double thickness) {
|
||||||
|
Vec3 boxCenter = this.center.add(this.normal.scale(planeOffset));
|
||||||
|
double halfX = this.halfWidth * Math.abs(this.right.x) + this.halfHeight * Math.abs(this.up.x) + thickness * Math.abs(this.normal.x);
|
||||||
|
double halfY = this.halfWidth * Math.abs(this.right.y) + this.halfHeight * Math.abs(this.up.y) + thickness * Math.abs(this.normal.y);
|
||||||
|
double halfZ = this.halfWidth * Math.abs(this.right.z) + this.halfHeight * Math.abs(this.up.z) + thickness * Math.abs(this.normal.z);
|
||||||
|
return new AABB(boxCenter.x - halfX, boxCenter.y - halfY, boxCenter.z - halfZ, boxCenter.x + halfX, boxCenter.y + halfY, boxCenter.z + halfZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AABB createLocalBox(double minHorizontal, double maxHorizontal, double minVertical, double maxVertical, double minDepth, double maxDepth) {
|
||||||
|
Vec3[] corners = new Vec3[] {
|
||||||
|
this.center.add(this.right.scale(minHorizontal)).add(this.up.scale(minVertical)).add(this.normal.scale(minDepth)),
|
||||||
|
this.center.add(this.right.scale(minHorizontal)).add(this.up.scale(minVertical)).add(this.normal.scale(maxDepth)),
|
||||||
|
this.center.add(this.right.scale(minHorizontal)).add(this.up.scale(maxVertical)).add(this.normal.scale(minDepth)),
|
||||||
|
this.center.add(this.right.scale(minHorizontal)).add(this.up.scale(maxVertical)).add(this.normal.scale(maxDepth)),
|
||||||
|
this.center.add(this.right.scale(maxHorizontal)).add(this.up.scale(minVertical)).add(this.normal.scale(minDepth)),
|
||||||
|
this.center.add(this.right.scale(maxHorizontal)).add(this.up.scale(minVertical)).add(this.normal.scale(maxDepth)),
|
||||||
|
this.center.add(this.right.scale(maxHorizontal)).add(this.up.scale(maxVertical)).add(this.normal.scale(minDepth)),
|
||||||
|
this.center.add(this.right.scale(maxHorizontal)).add(this.up.scale(maxVertical)).add(this.normal.scale(maxDepth))
|
||||||
|
};
|
||||||
|
double minX = Double.POSITIVE_INFINITY;
|
||||||
|
double minY = Double.POSITIVE_INFINITY;
|
||||||
|
double minZ = Double.POSITIVE_INFINITY;
|
||||||
|
double maxX = Double.NEGATIVE_INFINITY;
|
||||||
|
double maxY = Double.NEGATIVE_INFINITY;
|
||||||
|
double maxZ = Double.NEGATIVE_INFINITY;
|
||||||
|
for (Vec3 corner : corners) {
|
||||||
|
minX = Math.min(minX, corner.x);
|
||||||
|
minY = Math.min(minY, corner.y);
|
||||||
|
minZ = Math.min(minZ, corner.z);
|
||||||
|
maxX = Math.max(maxX, corner.x);
|
||||||
|
maxY = Math.max(maxY, corner.y);
|
||||||
|
maxZ = Math.max(maxZ, corner.z);
|
||||||
|
}
|
||||||
|
return new AABB(minX, minY, minZ, maxX, maxY, maxZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vec3[] corners(AABB box) {
|
||||||
|
return new Vec3[] {
|
||||||
|
new Vec3(box.minX, box.minY, box.minZ),
|
||||||
|
new Vec3(box.minX, box.minY, box.maxZ),
|
||||||
|
new Vec3(box.minX, box.maxY, box.minZ),
|
||||||
|
new Vec3(box.minX, box.maxY, box.maxZ),
|
||||||
|
new Vec3(box.maxX, box.minY, box.minZ),
|
||||||
|
new Vec3(box.maxX, box.minY, box.maxZ),
|
||||||
|
new Vec3(box.maxX, box.maxY, box.minZ),
|
||||||
|
new Vec3(box.maxX, box.maxY, box.maxZ)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public record PortalLocalCoords(double horizontal, double vertical, double depth) {
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package com.craisinlord.antarchy.content.worldgen.truffalo;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
|
import net.minecraft.util.valueproviders.IntProvider;
|
||||||
|
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
|
||||||
|
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
|
||||||
|
|
||||||
|
public record TruffaloTreeConfiguration(
|
||||||
|
BlockStateProvider trunkProvider,
|
||||||
|
IntProvider height
|
||||||
|
) implements FeatureConfiguration {
|
||||||
|
public static final Codec<TruffaloTreeConfiguration> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||||
|
BlockStateProvider.CODEC.fieldOf("trunk_provider").forGetter(TruffaloTreeConfiguration::trunkProvider),
|
||||||
|
IntProvider.codec(4, 9).fieldOf("height").forGetter(TruffaloTreeConfiguration::height)
|
||||||
|
).apply(instance, TruffaloTreeConfiguration::new));
|
||||||
|
}
|
||||||
+88
@@ -0,0 +1,88 @@
|
|||||||
|
package com.craisinlord.antarchy.content.worldgen.truffalo;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
|
import net.minecraft.world.item.DyeColor;
|
||||||
|
import net.minecraft.world.level.WorldGenLevel;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||||
|
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||||
|
|
||||||
|
public class TruffaloTreeFeature extends Feature<TruffaloTreeConfiguration> {
|
||||||
|
private static final DyeColor[] TUFT_COLORS = {
|
||||||
|
DyeColor.MAGENTA,
|
||||||
|
DyeColor.ORANGE,
|
||||||
|
DyeColor.RED,
|
||||||
|
DyeColor.YELLOW,
|
||||||
|
DyeColor.LIME,
|
||||||
|
DyeColor.GREEN,
|
||||||
|
DyeColor.BLUE,
|
||||||
|
DyeColor.CYAN,
|
||||||
|
DyeColor.LIGHT_BLUE,
|
||||||
|
DyeColor.PINK,
|
||||||
|
DyeColor.PURPLE
|
||||||
|
};
|
||||||
|
|
||||||
|
public TruffaloTreeFeature(Codec<TruffaloTreeConfiguration> codec) {
|
||||||
|
super(codec);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean place(FeaturePlaceContext<TruffaloTreeConfiguration> context) {
|
||||||
|
WorldGenLevel level = context.level();
|
||||||
|
BlockPos origin = context.origin();
|
||||||
|
BlockPos supportPos = origin.below();
|
||||||
|
if (!level.getBlockState(supportPos).isFaceSturdy(level, supportPos, Direction.UP)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RandomSource random = context.random();
|
||||||
|
TruffaloTreeConfiguration config = context.config();
|
||||||
|
int height = config.height().sample(random);
|
||||||
|
DyeColor color = TUFT_COLORS[random.nextInt(TUFT_COLORS.length)];
|
||||||
|
|
||||||
|
BlockPos[] trunk = new BlockPos[height];
|
||||||
|
for (int i = 0; i < height; i++) {
|
||||||
|
trunk[i] = origin.above(i);
|
||||||
|
}
|
||||||
|
BlockPos capCenter = trunk[height - 1].above();
|
||||||
|
|
||||||
|
for (BlockPos pos : trunk) {
|
||||||
|
if (!canReplace(level, pos)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int dx = -1; dx <= 1; dx++) {
|
||||||
|
for (int dz = -1; dz <= 1; dz++) {
|
||||||
|
if (!canReplace(level, capCenter.offset(dx, 0, dz))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BlockPos pos : trunk) {
|
||||||
|
setBlock(level, pos, config.trunkProvider().getState(random, pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
Block tuft = BuiltInRegistries.BLOCK.get(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, color.getName() + "_truffalo_tuft"));
|
||||||
|
BlockState tuftState = tuft.defaultBlockState();
|
||||||
|
for (int dx = -1; dx <= 1; dx++) {
|
||||||
|
for (int dz = -1; dz <= 1; dz++) {
|
||||||
|
setBlock(level, capCenter.offset(dx, 0, dz), tuftState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean canReplace(WorldGenLevel level, BlockPos pos) {
|
||||||
|
BlockState state = level.getBlockState(pos);
|
||||||
|
return state.isAir() || state.canBeReplaced();
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
package com.craisinlord.antarchy.content.worldgen.truffalo;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
|
||||||
|
|
||||||
|
public final class TruffaloTreeGrowers {
|
||||||
|
public static final ResourceKey<ConfiguredFeature<?, ?>> TRUFFALO_TREE = featureKey("truffalo_tree");
|
||||||
|
|
||||||
|
private TruffaloTreeGrowers() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ResourceKey<ConfiguredFeature<?, ?>> featureKey(String path) {
|
||||||
|
return ResourceKey.create(Registries.CONFIGURED_FEATURE, ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, path));
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.projectile.AbstractArrow;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
|
|
||||||
|
@Mixin(AbstractArrow.class)
|
||||||
|
public interface AbstractArrowAccessor {
|
||||||
|
@Accessor("inGround")
|
||||||
|
void antarchy$setInGround(boolean inGround);
|
||||||
|
|
||||||
|
@Accessor("inGroundTime")
|
||||||
|
void antarchy$setInGroundTime(int inGroundTime);
|
||||||
|
|
||||||
|
@Accessor("shakeTime")
|
||||||
|
void antarchy$setShakeTime(int shakeTime);
|
||||||
|
}
|
||||||
+86
-2
@@ -38,6 +38,22 @@ public abstract class BlockEntityTypeSignMixin {
|
|||||||
private static Block antarchy$nadirHangingSign;
|
private static Block antarchy$nadirHangingSign;
|
||||||
@Unique
|
@Unique
|
||||||
private static Block antarchy$nadirWallHangingSign;
|
private static Block antarchy$nadirWallHangingSign;
|
||||||
|
@Unique
|
||||||
|
private static Block antarchy$royalSign;
|
||||||
|
@Unique
|
||||||
|
private static Block antarchy$royalWallSign;
|
||||||
|
@Unique
|
||||||
|
private static Block antarchy$royalHangingSign;
|
||||||
|
@Unique
|
||||||
|
private static Block antarchy$royalWallHangingSign;
|
||||||
|
@Unique
|
||||||
|
private static Block antarchy$truffaloSign;
|
||||||
|
@Unique
|
||||||
|
private static Block antarchy$truffaloWallSign;
|
||||||
|
@Unique
|
||||||
|
private static Block antarchy$truffaloHangingSign;
|
||||||
|
@Unique
|
||||||
|
private static Block antarchy$truffaloWallHangingSign;
|
||||||
|
|
||||||
@Inject(method = "isValid", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "isValid", at = @At("HEAD"), cancellable = true)
|
||||||
private void antarchy$allowOuranwoodSigns(BlockState state, CallbackInfoReturnable<Boolean> cir) {
|
private void antarchy$allowOuranwoodSigns(BlockState state, CallbackInfoReturnable<Boolean> cir) {
|
||||||
@@ -45,13 +61,17 @@ public abstract class BlockEntityTypeSignMixin {
|
|||||||
if (self == BlockEntityType.SIGN) {
|
if (self == BlockEntityType.SIGN) {
|
||||||
if (state.is(antarchy$sign()) || state.is(antarchy$wallSign())
|
if (state.is(antarchy$sign()) || state.is(antarchy$wallSign())
|
||||||
|| state.is(antarchy$peachSign()) || state.is(antarchy$peachWallSign())
|
|| state.is(antarchy$peachSign()) || state.is(antarchy$peachWallSign())
|
||||||
|| state.is(antarchy$nadirSign()) || state.is(antarchy$nadirWallSign())) {
|
|| state.is(antarchy$nadirSign()) || state.is(antarchy$nadirWallSign())
|
||||||
|
|| state.is(antarchy$royalSign()) || state.is(antarchy$royalWallSign())
|
||||||
|
|| state.is(antarchy$truffaloSign()) || state.is(antarchy$truffaloWallSign())) {
|
||||||
cir.setReturnValue(true);
|
cir.setReturnValue(true);
|
||||||
}
|
}
|
||||||
} else if (self == BlockEntityType.HANGING_SIGN) {
|
} else if (self == BlockEntityType.HANGING_SIGN) {
|
||||||
if (state.is(antarchy$hangingSign()) || state.is(antarchy$wallHangingSign())
|
if (state.is(antarchy$hangingSign()) || state.is(antarchy$wallHangingSign())
|
||||||
|| state.is(antarchy$peachHangingSign()) || state.is(antarchy$peachWallHangingSign())
|
|| state.is(antarchy$peachHangingSign()) || state.is(antarchy$peachWallHangingSign())
|
||||||
|| state.is(antarchy$nadirHangingSign()) || state.is(antarchy$nadirWallHangingSign())) {
|
|| state.is(antarchy$nadirHangingSign()) || state.is(antarchy$nadirWallHangingSign())
|
||||||
|
|| state.is(antarchy$royalHangingSign()) || state.is(antarchy$royalWallHangingSign())
|
||||||
|
|| state.is(antarchy$truffaloHangingSign()) || state.is(antarchy$truffaloWallHangingSign())) {
|
||||||
cir.setReturnValue(true);
|
cir.setReturnValue(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,6 +173,70 @@ public abstract class BlockEntityTypeSignMixin {
|
|||||||
return antarchy$nadirWallHangingSign;
|
return antarchy$nadirWallHangingSign;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static Block antarchy$royalSign() {
|
||||||
|
if (antarchy$royalSign == null) {
|
||||||
|
antarchy$royalSign = antarchy$resolve("royal_sign");
|
||||||
|
}
|
||||||
|
return antarchy$royalSign;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static Block antarchy$royalWallSign() {
|
||||||
|
if (antarchy$royalWallSign == null) {
|
||||||
|
antarchy$royalWallSign = antarchy$resolve("royal_wall_sign");
|
||||||
|
}
|
||||||
|
return antarchy$royalWallSign;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static Block antarchy$royalHangingSign() {
|
||||||
|
if (antarchy$royalHangingSign == null) {
|
||||||
|
antarchy$royalHangingSign = antarchy$resolve("royal_hanging_sign");
|
||||||
|
}
|
||||||
|
return antarchy$royalHangingSign;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static Block antarchy$royalWallHangingSign() {
|
||||||
|
if (antarchy$royalWallHangingSign == null) {
|
||||||
|
antarchy$royalWallHangingSign = antarchy$resolve("royal_wall_hanging_sign");
|
||||||
|
}
|
||||||
|
return antarchy$royalWallHangingSign;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static Block antarchy$truffaloSign() {
|
||||||
|
if (antarchy$truffaloSign == null) {
|
||||||
|
antarchy$truffaloSign = antarchy$resolve("truffalo_sign");
|
||||||
|
}
|
||||||
|
return antarchy$truffaloSign;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static Block antarchy$truffaloWallSign() {
|
||||||
|
if (antarchy$truffaloWallSign == null) {
|
||||||
|
antarchy$truffaloWallSign = antarchy$resolve("truffalo_wall_sign");
|
||||||
|
}
|
||||||
|
return antarchy$truffaloWallSign;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static Block antarchy$truffaloHangingSign() {
|
||||||
|
if (antarchy$truffaloHangingSign == null) {
|
||||||
|
antarchy$truffaloHangingSign = antarchy$resolve("truffalo_hanging_sign");
|
||||||
|
}
|
||||||
|
return antarchy$truffaloHangingSign;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static Block antarchy$truffaloWallHangingSign() {
|
||||||
|
if (antarchy$truffaloWallHangingSign == null) {
|
||||||
|
antarchy$truffaloWallHangingSign = antarchy$resolve("truffalo_wall_hanging_sign");
|
||||||
|
}
|
||||||
|
return antarchy$truffaloWallHangingSign;
|
||||||
|
}
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private static Block antarchy$resolve(String path) {
|
private static Block antarchy$resolve(String path) {
|
||||||
return BuiltInRegistries.BLOCK.get(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, path));
|
return BuiltInRegistries.BLOCK.get(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, path));
|
||||||
|
|||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
|
|
||||||
|
@Mixin(LivingEntity.class)
|
||||||
|
public interface LivingEntityJumpingAccessor {
|
||||||
|
@Accessor("jumping")
|
||||||
|
boolean antarchy$isJumping();
|
||||||
|
}
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunCollisionHelper;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(Entity.class)
|
||||||
|
public abstract class PortalGunEntityCollisionMixin {
|
||||||
|
@Unique
|
||||||
|
private AABB antarchy$portalGunStartBox;
|
||||||
|
|
||||||
|
@Inject(method = "collide", at = @At("HEAD"))
|
||||||
|
private void antarchy$capturePortalGunStartBox(Vec3 movement, CallbackInfoReturnable<Vec3> cir) {
|
||||||
|
this.antarchy$portalGunStartBox = ((Entity) (Object) this).getBoundingBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "collide", at = @At("RETURN"), cancellable = true)
|
||||||
|
private void antarchy$restorePortalCrossingMotion(Vec3 movement, CallbackInfoReturnable<Vec3> cir) {
|
||||||
|
Entity entity = (Entity) (Object) this;
|
||||||
|
if (this.antarchy$portalGunStartBox == null || AntarchyGravityApi.isGravityInverted(entity)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Vec3 adjusted = PortalGunCollisionHelper.resolveCollision(entity, this.antarchy$portalGunStartBox, movement, cir.getReturnValue());
|
||||||
|
cir.setReturnValue(adjusted);
|
||||||
|
}
|
||||||
|
}
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(Entity.class)
|
||||||
|
public abstract class PortalGunEntityInWallMixin {
|
||||||
|
@Inject(method = "isInWall", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$ignorePortalInWall(CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
Entity entity = (Entity) (Object) this;
|
||||||
|
if (entity.level() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (PortalGunPortalEntity portal : entity.level().getEntitiesOfClass(PortalGunPortalEntity.class, entity.getBoundingBox().inflate(2.0D), PortalGunPortalEntity::isAlive)) {
|
||||||
|
if (portal.intersectsEntityBounds(entity) || portal.getCollisionRemovalAabbForEntity(entity).intersects(entity.getBoundingBox())) {
|
||||||
|
cir.setReturnValue(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.client;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.client.PortalGunPortalRenderState;
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunWorldPortalShape;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(BlockEntityRenderDispatcher.class)
|
||||||
|
public abstract class BlockEntityRenderDispatcherPortalMixin {
|
||||||
|
@Inject(method = "render(Lnet/minecraft/world/level/block/entity/BlockEntity;FLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;)V", at = @At("HEAD"), cancellable = true)
|
||||||
|
private <E extends BlockEntity> void antarchy$clipPortalViewBlockEntities(E blockEntity, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource, CallbackInfo ci) {
|
||||||
|
if (PortalGunPortalRenderState.renderAll() || blockEntity == null || blockEntity.isRemoved()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PortalGunWorldPortalShape destinationShape = PortalGunPortalRenderState.getDestinationShape();
|
||||||
|
PortalGunWorldPortalShape sourceShape = PortalGunPortalRenderState.getSourceShape();
|
||||||
|
if (destinationShape == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BlockPos pos = blockEntity.getBlockPos();
|
||||||
|
AABB bounds = new AABB(pos);
|
||||||
|
if (!destinationShape.intersectsFront(bounds, 0.1D)) {
|
||||||
|
ci.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sourceShape != null && sourceShape.intersectsFront(bounds, -0.02D)) {
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.client;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.client.PortalGunPortalRenderState;
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity;
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunWorldPortalShape;
|
||||||
|
import net.minecraft.client.renderer.culling.Frustum;
|
||||||
|
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(EntityRenderDispatcher.class)
|
||||||
|
public abstract class EntityRenderDispatcherPortalMixin {
|
||||||
|
@Inject(method = "shouldRender", at = @At("HEAD"), cancellable = true)
|
||||||
|
private <E extends Entity> void antarchy$clipPortalViewEntities(E entity, Frustum frustum, double x, double y, double z, CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
if (PortalGunPortalRenderState.renderAll() || entity instanceof PortalGunPortalEntity) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PortalGunWorldPortalShape destinationShape = PortalGunPortalRenderState.getDestinationShape();
|
||||||
|
PortalGunWorldPortalShape sourceShape = PortalGunPortalRenderState.getSourceShape();
|
||||||
|
if (destinationShape == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!destinationShape.intersectsFront(entity.getBoundingBox(), 0.1D)) {
|
||||||
|
cir.setReturnValue(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sourceShape != null && sourceShape.intersectsFront(entity.getBoundingBox(), -0.02D)) {
|
||||||
|
cir.setReturnValue(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.client;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.entity.HoverboardEntity;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.minecraft.client.model.EntityModel;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import com.mojang.math.Axis;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(LivingEntityRenderer.class)
|
||||||
|
public abstract class HoverboardRiderPoseMixin<T extends LivingEntity, M extends EntityModel<T>> {
|
||||||
|
private static final float HOVERBOARD_RIDER_RENDER_YAW = -90.0F;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public abstract M getModel();
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "setupRotations(Lnet/minecraft/world/entity/LivingEntity;Lcom/mojang/blaze3d/vertex/PoseStack;FFFF)V",
|
||||||
|
at = @At("TAIL")
|
||||||
|
)
|
||||||
|
private void antarchy$rotateHoverboardRider(T entity, PoseStack poseStack, float ageInTicks, float rotationYaw, float partialTick, float scale, CallbackInfo ci) {
|
||||||
|
if (entity.getVehicle() instanceof HoverboardEntity) {
|
||||||
|
poseStack.mulPose(Axis.YP.rotationDegrees(HOVERBOARD_RIDER_RENDER_YAW));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "render(Lnet/minecraft/world/entity/LivingEntity;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V",
|
||||||
|
at = @At(
|
||||||
|
value = "FIELD",
|
||||||
|
target = "Lnet/minecraft/client/model/EntityModel;riding:Z",
|
||||||
|
opcode = Opcodes.PUTFIELD,
|
||||||
|
shift = At.Shift.AFTER
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private void antarchy$standOnHoverboard(T entity, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, CallbackInfo ci) {
|
||||||
|
if (entity.getVehicle() instanceof HoverboardEntity) {
|
||||||
|
this.getModel().riding = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.client;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.client.PortalGunRollClientState;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.player.LocalPlayer;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(LocalPlayer.class)
|
||||||
|
public abstract class LocalPlayerPortalMixin {
|
||||||
|
@Inject(method = "suffocatesAt", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$ignorePortalSuffocation(BlockPos pos, CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
Minecraft minecraft = Minecraft.getInstance();
|
||||||
|
if (minecraft.player != null && PortalGunRollClientState.isEntityInsidePortal(minecraft, minecraft.player)) {
|
||||||
|
cir.setReturnValue(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "moveTowardsClosestSpace", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$cancelPortalPushOut(double x, double z, CallbackInfo ci) {
|
||||||
|
Minecraft minecraft = Minecraft.getInstance();
|
||||||
|
if (minecraft.player != null && PortalGunRollClientState.isEntityInsidePortal(minecraft, minecraft.player)) {
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.client;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.client.PortalGunRollClientState;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.ScreenEffectRenderer;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(ScreenEffectRenderer.class)
|
||||||
|
public abstract class ScreenEffectRendererPortalMixin {
|
||||||
|
@Inject(method = "getViewBlockingState", at = @At("HEAD"), cancellable = true)
|
||||||
|
private static void antarchy$ignorePortalViewBlock(Player player, CallbackInfoReturnable<net.minecraft.world.level.block.state.BlockState> cir) {
|
||||||
|
Minecraft minecraft = Minecraft.getInstance();
|
||||||
|
if (player != null && PortalGunRollClientState.isEntityInsidePortal(minecraft, player)) {
|
||||||
|
cir.setReturnValue(Blocks.AIR.defaultBlockState());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-3
@@ -4,6 +4,7 @@ import com.craisinlord.antarchy.content.fluid.AntarchyFluidChecks;
|
|||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
|
||||||
|
import com.craisinlord.antarchy.content.portalgun.PortalGunCollisionHelper;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
@@ -174,7 +175,7 @@ public abstract class EntityMoveMixin {
|
|||||||
float maxUpStep = entity.maxUpStep();
|
float maxUpStep = entity.maxUpStep();
|
||||||
|
|
||||||
if (!(maxUpStep > 0.0F) || !(pressingIntoCeiling || entity.onGround()) || !(movedX || movedZ)) {
|
if (!(maxUpStep > 0.0F) || !(pressingIntoCeiling || entity.onGround()) || !(movedX || movedZ)) {
|
||||||
cir.setReturnValue(collided);
|
cir.setReturnValue(PortalGunCollisionHelper.resolveCollision(entity, aabb, movement, collided));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,12 +194,12 @@ public abstract class EntityMoveMixin {
|
|||||||
Vec3 stepped = Entity.collideBoundingBox(entity, new Vec3(movement.x, -(double) candidate, movement.z), steppedBox, entity.level(), stepShapes);
|
Vec3 stepped = Entity.collideBoundingBox(entity, new Vec3(movement.x, -(double) candidate, movement.z), steppedBox, entity.level(), stepShapes);
|
||||||
if (stepped.horizontalDistanceSqr() > collided.horizontalDistanceSqr()) {
|
if (stepped.horizontalDistanceSqr() > collided.horizontalDistanceSqr()) {
|
||||||
double offset = steppedBox.maxY - aabb.maxY;
|
double offset = steppedBox.maxY - aabb.maxY;
|
||||||
cir.setReturnValue(stepped.add(0.0, offset, 0.0));
|
cir.setReturnValue(PortalGunCollisionHelper.resolveCollision(entity, aabb, movement, stepped.add(0.0, offset, 0.0)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cir.setReturnValue(collided);
|
cir.setReturnValue(PortalGunCollisionHelper.resolveCollision(entity, aabb, movement, collided));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
|
|||||||
+4
@@ -1,5 +1,6 @@
|
|||||||
package com.craisinlord.antarchy.mixins.gravity.client;
|
package com.craisinlord.antarchy.mixins.gravity.client;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.client.PortalGunRollClientState;
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
|
||||||
import net.minecraft.client.Camera;
|
import net.minecraft.client.Camera;
|
||||||
@@ -128,9 +129,12 @@ public abstract class CameraGravityMixin {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!AntarchyGravityApi.isGravityInverted(this.entity) && AntarchyGravityApi.getGravityFlipProgress(this.entity, this.antarchy$storedTickDelta) <= 0.0F) {
|
if (!AntarchyGravityApi.isGravityInverted(this.entity) && AntarchyGravityApi.getGravityFlipProgress(this.entity, this.antarchy$storedTickDelta) <= 0.0F) {
|
||||||
|
this.rotation.premul(new Quaternionf().fromAxisAngleDeg(0.0F, 0.0F, -1.0F, PortalGunRollClientState.getRollDegrees(this.antarchy$storedTickDelta)));
|
||||||
|
this.antarchy$gravityApplied = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.rotation.premul(AntarchyGravityRotationUtil.getCameraRotationQuaternion(this.entity, this.antarchy$storedTickDelta));
|
this.rotation.premul(AntarchyGravityRotationUtil.getCameraRotationQuaternion(this.entity, this.antarchy$storedTickDelta));
|
||||||
|
this.rotation.premul(new Quaternionf().fromAxisAngleDeg(0.0F, 0.0F, -1.0F, PortalGunRollClientState.getRollDegrees(this.antarchy$storedTickDelta)));
|
||||||
this.antarchy$gravityApplied = true;
|
this.antarchy$gravityApplied = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
"compatibilityLevel": "JAVA_21",
|
"compatibilityLevel": "JAVA_21",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"AbstractMinecartMixin",
|
"AbstractMinecartMixin",
|
||||||
|
"AbstractArrowAccessor",
|
||||||
"AccessorFireBlock",
|
"AccessorFireBlock",
|
||||||
"AccessorRangedAttribute",
|
"AccessorRangedAttribute",
|
||||||
"AmericanFoodConsumeMixin",
|
"AmericanFoodConsumeMixin",
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
"GlowSquidLumenSpawnMixin",
|
"GlowSquidLumenSpawnMixin",
|
||||||
"GlowVinesUnderLeavesMixin",
|
"GlowVinesUnderLeavesMixin",
|
||||||
"GrindstoneMenuMixin",
|
"GrindstoneMenuMixin",
|
||||||
|
"LivingEntityJumpingAccessor",
|
||||||
"MantisClawWallClimbMixin",
|
"MantisClawWallClimbMixin",
|
||||||
"MilkBucketSizeResetMixin",
|
"MilkBucketSizeResetMixin",
|
||||||
"MinecartItemMixin",
|
"MinecartItemMixin",
|
||||||
@@ -35,6 +37,8 @@
|
|||||||
"NightmareSwordDamageMixin",
|
"NightmareSwordDamageMixin",
|
||||||
"NightmareArmorEffectImmunityMixin",
|
"NightmareArmorEffectImmunityMixin",
|
||||||
"PotionBrewingMixin",
|
"PotionBrewingMixin",
|
||||||
|
"PortalGunEntityCollisionMixin",
|
||||||
|
"PortalGunEntityInWallMixin",
|
||||||
"RedStoneWireBlockMixin",
|
"RedStoneWireBlockMixin",
|
||||||
"StinkyCrouchMixin",
|
"StinkyCrouchMixin",
|
||||||
"VillagerTradesMixin",
|
"VillagerTradesMixin",
|
||||||
@@ -78,9 +82,11 @@
|
|||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"client.AbstractMinecartRendererMixin",
|
"client.AbstractMinecartRendererMixin",
|
||||||
|
"client.BlockEntityRenderDispatcherPortalMixin",
|
||||||
"client.EntityLightProbeMixin",
|
"client.EntityLightProbeMixin",
|
||||||
"client.CustomBossBarMixin",
|
"client.CustomBossBarMixin",
|
||||||
"client.DimensionMusicMixin",
|
"client.DimensionMusicMixin",
|
||||||
|
"client.EntityRenderDispatcherPortalMixin",
|
||||||
"client.CavarynSkyMixin",
|
"client.CavarynSkyMixin",
|
||||||
"client.CavarynHordeFogMixin",
|
"client.CavarynHordeFogMixin",
|
||||||
"client.CavarynHordeLightTextureMixin",
|
"client.CavarynHordeLightTextureMixin",
|
||||||
@@ -93,8 +99,11 @@
|
|||||||
"client.LightningBoltRendererMixin",
|
"client.LightningBoltRendererMixin",
|
||||||
"client.MountedVehicleCameraMixin",
|
"client.MountedVehicleCameraMixin",
|
||||||
"client.ParalyzedMouseTurnMixin",
|
"client.ParalyzedMouseTurnMixin",
|
||||||
|
"client.LocalPlayerPortalMixin",
|
||||||
|
"client.ScreenEffectRendererPortalMixin",
|
||||||
"client.ScreenEffectRendererFireVisualMixin",
|
"client.ScreenEffectRendererFireVisualMixin",
|
||||||
"client.GlimmeringTranslucencyMixin",
|
"client.GlimmeringTranslucencyMixin",
|
||||||
|
"client.HoverboardRiderPoseMixin",
|
||||||
"client.SplashManagerMixin",
|
"client.SplashManagerMixin",
|
||||||
"client.ThoraxisFogMixin",
|
"client.ThoraxisFogMixin",
|
||||||
"client.TigerEyeArmorHideMixin",
|
"client.TigerEyeArmorHideMixin",
|
||||||
|
|||||||
+361
@@ -0,0 +1,361 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.8.0",
|
||||||
|
"animations": {
|
||||||
|
"idle": {
|
||||||
|
"loop": true,
|
||||||
|
"animation_length": 1,
|
||||||
|
"bones": {
|
||||||
|
"hoverboard": {
|
||||||
|
"rotation": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.25": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, -9.85]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.7083": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 7.5]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"1.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 2, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.5": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 3, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"1.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 2, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"disk_front": {
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.6667": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0.35282, -2.97918, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"1.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"disk_back": {
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.5": {
|
||||||
|
"post": {
|
||||||
|
"vector": [-0.00833, -1.99998, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"1.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"motor_right": {
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.25": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1.1, 1, 1.1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.5": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.75": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1.1, 1, 1.1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"1.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"motor_left": {
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.25": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1.1, 1, 1.1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.5": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.75": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1.1, 1, 1.1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"1.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"move": {
|
||||||
|
"loop": true,
|
||||||
|
"animation_length": 1,
|
||||||
|
"bones": {
|
||||||
|
"hoverboard": {
|
||||||
|
"rotation": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.25": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, -9.85]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.7083": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 7.5]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"1.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 2, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.125": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 3.16, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.3333": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 2.2, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.5": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 4, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.7083": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 2.28, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.875": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 2.94, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"1.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 2, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"disk_front": {
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.6667": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0.35282, -2.97918, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"1.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"disk_back": {
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.5": {
|
||||||
|
"post": {
|
||||||
|
"vector": [-0.00833, -1.99998, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"1.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"motor_right": {
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.25": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1.1, 1, 1.4]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.5": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.75": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1.1, 1, 1.4]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"1.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"motor_left": {
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.25": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1.1, 1, 1.4]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.5": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.75": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1.1, 1, 1.4]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"1.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-14
@@ -4,20 +4,7 @@
|
|||||||
"idle": {
|
"idle": {
|
||||||
"loop": true,
|
"loop": true,
|
||||||
"animation_length": 4.0,
|
"animation_length": 4.0,
|
||||||
"bones": {
|
"bones": {}
|
||||||
"Portal_Layer": {
|
|
||||||
"rotation": {
|
|
||||||
"0.0": {"vector": [0, 0, 0]},
|
|
||||||
"4.0": {"vector": [0, 0, 360]}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Portal_Layer2": {
|
|
||||||
"rotation": {
|
|
||||||
"0.0": {"vector": [0, 0, 0]},
|
|
||||||
"4.0": {"vector": [0, 0, -360]}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"open": {
|
"open": {
|
||||||
"loop": false,
|
"loop": false,
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/truffalo_tuft_black"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/truffalo_tuft_blue"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/truffalo_tuft_brown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/truffalo_tuft_cyan"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/truffalo_tuft_gray"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/truffalo_tuft_green"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/truffalo_tuft_light_blue"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/truffalo_tuft_light_gray"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/truffalo_tuft_lime"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/truffalo_tuft_magenta"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/truffalo_tuft_orange"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/truffalo_tuft_pink"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/potted_royal_sapling"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/potted_truffalo_sapling"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/truffalo_tuft_purple"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/truffalo_tuft_red"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"face=ceiling,facing=east,powered=false": {
|
||||||
|
"model": "antarchy:block/royal_button",
|
||||||
|
"x": 180,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"face=ceiling,facing=east,powered=true": {
|
||||||
|
"model": "antarchy:block/royal_button_pressed",
|
||||||
|
"x": 180,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"face=ceiling,facing=north,powered=false": {
|
||||||
|
"model": "antarchy:block/royal_button",
|
||||||
|
"x": 180,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"face=ceiling,facing=north,powered=true": {
|
||||||
|
"model": "antarchy:block/royal_button_pressed",
|
||||||
|
"x": 180,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"face=ceiling,facing=south,powered=false": {
|
||||||
|
"model": "antarchy:block/royal_button",
|
||||||
|
"x": 180
|
||||||
|
},
|
||||||
|
"face=ceiling,facing=south,powered=true": {
|
||||||
|
"model": "antarchy:block/royal_button_pressed",
|
||||||
|
"x": 180
|
||||||
|
},
|
||||||
|
"face=ceiling,facing=west,powered=false": {
|
||||||
|
"model": "antarchy:block/royal_button",
|
||||||
|
"x": 180,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"face=ceiling,facing=west,powered=true": {
|
||||||
|
"model": "antarchy:block/royal_button_pressed",
|
||||||
|
"x": 180,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"face=floor,facing=east,powered=false": {
|
||||||
|
"model": "antarchy:block/royal_button",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"face=floor,facing=east,powered=true": {
|
||||||
|
"model": "antarchy:block/royal_button_pressed",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"face=floor,facing=north,powered=false": {
|
||||||
|
"model": "antarchy:block/royal_button"
|
||||||
|
},
|
||||||
|
"face=floor,facing=north,powered=true": {
|
||||||
|
"model": "antarchy:block/royal_button_pressed"
|
||||||
|
},
|
||||||
|
"face=floor,facing=south,powered=false": {
|
||||||
|
"model": "antarchy:block/royal_button",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"face=floor,facing=south,powered=true": {
|
||||||
|
"model": "antarchy:block/royal_button_pressed",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"face=floor,facing=west,powered=false": {
|
||||||
|
"model": "antarchy:block/royal_button",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"face=floor,facing=west,powered=true": {
|
||||||
|
"model": "antarchy:block/royal_button_pressed",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"face=wall,facing=east,powered=false": {
|
||||||
|
"model": "antarchy:block/royal_button",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 90,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"face=wall,facing=east,powered=true": {
|
||||||
|
"model": "antarchy:block/royal_button_pressed",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 90,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"face=wall,facing=north,powered=false": {
|
||||||
|
"model": "antarchy:block/royal_button",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 90
|
||||||
|
},
|
||||||
|
"face=wall,facing=north,powered=true": {
|
||||||
|
"model": "antarchy:block/royal_button_pressed",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 90
|
||||||
|
},
|
||||||
|
"face=wall,facing=south,powered=false": {
|
||||||
|
"model": "antarchy:block/royal_button",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 90,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"face=wall,facing=south,powered=true": {
|
||||||
|
"model": "antarchy:block/royal_button_pressed",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 90,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"face=wall,facing=west,powered=false": {
|
||||||
|
"model": "antarchy:block/royal_button",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 90,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"face=wall,facing=west,powered=true": {
|
||||||
|
"model": "antarchy:block/royal_button_pressed",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 90,
|
||||||
|
"y": 270
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"facing=east,half=lower,hinge=left,open=false": {
|
||||||
|
"model": "antarchy:block/royal_door_bottom_left"
|
||||||
|
},
|
||||||
|
"facing=east,half=lower,hinge=left,open=true": {
|
||||||
|
"model": "antarchy:block/royal_door_bottom_left_open",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=east,half=lower,hinge=right,open=false": {
|
||||||
|
"model": "antarchy:block/royal_door_bottom_right"
|
||||||
|
},
|
||||||
|
"facing=east,half=lower,hinge=right,open=true": {
|
||||||
|
"model": "antarchy:block/royal_door_bottom_right_open",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=east,half=upper,hinge=left,open=false": {
|
||||||
|
"model": "antarchy:block/royal_door_top_left"
|
||||||
|
},
|
||||||
|
"facing=east,half=upper,hinge=left,open=true": {
|
||||||
|
"model": "antarchy:block/royal_door_top_left_open",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=east,half=upper,hinge=right,open=false": {
|
||||||
|
"model": "antarchy:block/royal_door_top_right"
|
||||||
|
},
|
||||||
|
"facing=east,half=upper,hinge=right,open=true": {
|
||||||
|
"model": "antarchy:block/royal_door_top_right_open",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=north,half=lower,hinge=left,open=false": {
|
||||||
|
"model": "antarchy:block/royal_door_bottom_left",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=north,half=lower,hinge=left,open=true": {
|
||||||
|
"model": "antarchy:block/royal_door_bottom_left_open"
|
||||||
|
},
|
||||||
|
"facing=north,half=lower,hinge=right,open=false": {
|
||||||
|
"model": "antarchy:block/royal_door_bottom_right",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=north,half=lower,hinge=right,open=true": {
|
||||||
|
"model": "antarchy:block/royal_door_bottom_right_open",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=north,half=upper,hinge=left,open=false": {
|
||||||
|
"model": "antarchy:block/royal_door_top_left",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=north,half=upper,hinge=left,open=true": {
|
||||||
|
"model": "antarchy:block/royal_door_top_left_open"
|
||||||
|
},
|
||||||
|
"facing=north,half=upper,hinge=right,open=false": {
|
||||||
|
"model": "antarchy:block/royal_door_top_right",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=north,half=upper,hinge=right,open=true": {
|
||||||
|
"model": "antarchy:block/royal_door_top_right_open",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=south,half=lower,hinge=left,open=false": {
|
||||||
|
"model": "antarchy:block/royal_door_bottom_left",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=south,half=lower,hinge=left,open=true": {
|
||||||
|
"model": "antarchy:block/royal_door_bottom_left_open",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=south,half=lower,hinge=right,open=false": {
|
||||||
|
"model": "antarchy:block/royal_door_bottom_right",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=south,half=lower,hinge=right,open=true": {
|
||||||
|
"model": "antarchy:block/royal_door_bottom_right_open"
|
||||||
|
},
|
||||||
|
"facing=south,half=upper,hinge=left,open=false": {
|
||||||
|
"model": "antarchy:block/royal_door_top_left",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=south,half=upper,hinge=left,open=true": {
|
||||||
|
"model": "antarchy:block/royal_door_top_left_open",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=south,half=upper,hinge=right,open=false": {
|
||||||
|
"model": "antarchy:block/royal_door_top_right",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=south,half=upper,hinge=right,open=true": {
|
||||||
|
"model": "antarchy:block/royal_door_top_right_open"
|
||||||
|
},
|
||||||
|
"facing=west,half=lower,hinge=left,open=false": {
|
||||||
|
"model": "antarchy:block/royal_door_bottom_left",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=west,half=lower,hinge=left,open=true": {
|
||||||
|
"model": "antarchy:block/royal_door_bottom_left_open",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=west,half=lower,hinge=right,open=false": {
|
||||||
|
"model": "antarchy:block/royal_door_bottom_right",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=west,half=lower,hinge=right,open=true": {
|
||||||
|
"model": "antarchy:block/royal_door_bottom_right_open",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=west,half=upper,hinge=left,open=false": {
|
||||||
|
"model": "antarchy:block/royal_door_top_left",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=west,half=upper,hinge=left,open=true": {
|
||||||
|
"model": "antarchy:block/royal_door_top_left_open",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=west,half=upper,hinge=right,open=false": {
|
||||||
|
"model": "antarchy:block/royal_door_top_right",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=west,half=upper,hinge=right,open=true": {
|
||||||
|
"model": "antarchy:block/royal_door_top_right_open",
|
||||||
|
"y": 90
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"multipart": [
|
||||||
|
{
|
||||||
|
"apply": {
|
||||||
|
"model": "antarchy:block/royal_fence_post"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"apply": {
|
||||||
|
"model": "antarchy:block/royal_fence_side",
|
||||||
|
"uvlock": true
|
||||||
|
},
|
||||||
|
"when": {
|
||||||
|
"north": "true"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"apply": {
|
||||||
|
"model": "antarchy:block/royal_fence_side",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"when": {
|
||||||
|
"east": "true"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"apply": {
|
||||||
|
"model": "antarchy:block/royal_fence_side",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"when": {
|
||||||
|
"south": "true"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"apply": {
|
||||||
|
"model": "antarchy:block/royal_fence_side",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"when": {
|
||||||
|
"west": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"facing=east,in_wall=false,open=false": {
|
||||||
|
"model": "antarchy:block/royal_fence_gate",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=east,in_wall=false,open=true": {
|
||||||
|
"model": "antarchy:block/royal_fence_gate_open",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=east,in_wall=true,open=false": {
|
||||||
|
"model": "antarchy:block/royal_fence_gate_wall",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=east,in_wall=true,open=true": {
|
||||||
|
"model": "antarchy:block/royal_fence_gate_wall_open",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=north,in_wall=false,open=false": {
|
||||||
|
"model": "antarchy:block/royal_fence_gate",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=north,in_wall=false,open=true": {
|
||||||
|
"model": "antarchy:block/royal_fence_gate_open",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=north,in_wall=true,open=false": {
|
||||||
|
"model": "antarchy:block/royal_fence_gate_wall",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=north,in_wall=true,open=true": {
|
||||||
|
"model": "antarchy:block/royal_fence_gate_wall_open",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=south,in_wall=false,open=false": {
|
||||||
|
"model": "antarchy:block/royal_fence_gate",
|
||||||
|
"uvlock": true
|
||||||
|
},
|
||||||
|
"facing=south,in_wall=false,open=true": {
|
||||||
|
"model": "antarchy:block/royal_fence_gate_open",
|
||||||
|
"uvlock": true
|
||||||
|
},
|
||||||
|
"facing=south,in_wall=true,open=false": {
|
||||||
|
"model": "antarchy:block/royal_fence_gate_wall",
|
||||||
|
"uvlock": true
|
||||||
|
},
|
||||||
|
"facing=south,in_wall=true,open=true": {
|
||||||
|
"model": "antarchy:block/royal_fence_gate_wall_open",
|
||||||
|
"uvlock": true
|
||||||
|
},
|
||||||
|
"facing=west,in_wall=false,open=false": {
|
||||||
|
"model": "antarchy:block/royal_fence_gate",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=west,in_wall=false,open=true": {
|
||||||
|
"model": "antarchy:block/royal_fence_gate_open",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=west,in_wall=true,open=false": {
|
||||||
|
"model": "antarchy:block/royal_fence_gate_wall",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=west,in_wall=true,open=true": {
|
||||||
|
"model": "antarchy:block/royal_fence_gate_wall_open",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 90
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": { "model": "antarchy:block/royal_flowering_leaves" }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/royal_hanging_sign"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": { "model": "antarchy:block/royal_leaves" }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"axis=x": {
|
||||||
|
"model": "antarchy:block/royal_log_horizontal",
|
||||||
|
"x": 90,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"axis=y": {
|
||||||
|
"model": "antarchy:block/royal_log"
|
||||||
|
},
|
||||||
|
"axis=z": {
|
||||||
|
"model": "antarchy:block/royal_log_horizontal",
|
||||||
|
"x": 90
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/royal_planks"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"powered=false": {
|
||||||
|
"model": "antarchy:block/royal_pressure_plate"
|
||||||
|
},
|
||||||
|
"powered=true": {
|
||||||
|
"model": "antarchy:block/royal_pressure_plate_down"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/royal_sapling"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/royal_sign"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"type=bottom": {
|
||||||
|
"model": "antarchy:block/royal_slab"
|
||||||
|
},
|
||||||
|
"type=double": {
|
||||||
|
"model": "antarchy:block/royal_planks"
|
||||||
|
},
|
||||||
|
"type=top": {
|
||||||
|
"model": "antarchy:block/royal_slab_top"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"facing=east,half=bottom,shape=inner_left": {
|
||||||
|
"model": "antarchy:block/royal_stairs_inner",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=east,half=bottom,shape=inner_right": {
|
||||||
|
"model": "antarchy:block/royal_stairs_inner"
|
||||||
|
},
|
||||||
|
"facing=east,half=bottom,shape=outer_left": {
|
||||||
|
"model": "antarchy:block/royal_stairs_outer",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=east,half=bottom,shape=outer_right": {
|
||||||
|
"model": "antarchy:block/royal_stairs_outer"
|
||||||
|
},
|
||||||
|
"facing=east,half=bottom,shape=straight": {
|
||||||
|
"model": "antarchy:block/royal_stairs"
|
||||||
|
},
|
||||||
|
"facing=east,half=top,shape=inner_left": {
|
||||||
|
"model": "antarchy:block/royal_stairs_inner",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180
|
||||||
|
},
|
||||||
|
"facing=east,half=top,shape=inner_right": {
|
||||||
|
"model": "antarchy:block/royal_stairs_inner",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=east,half=top,shape=outer_left": {
|
||||||
|
"model": "antarchy:block/royal_stairs_outer",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180
|
||||||
|
},
|
||||||
|
"facing=east,half=top,shape=outer_right": {
|
||||||
|
"model": "antarchy:block/royal_stairs_outer",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=east,half=top,shape=straight": {
|
||||||
|
"model": "antarchy:block/royal_stairs",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180
|
||||||
|
},
|
||||||
|
"facing=north,half=bottom,shape=inner_left": {
|
||||||
|
"model": "antarchy:block/royal_stairs_inner",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=north,half=bottom,shape=inner_right": {
|
||||||
|
"model": "antarchy:block/royal_stairs_inner",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=north,half=bottom,shape=outer_left": {
|
||||||
|
"model": "antarchy:block/royal_stairs_outer",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=north,half=bottom,shape=outer_right": {
|
||||||
|
"model": "antarchy:block/royal_stairs_outer",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=north,half=bottom,shape=straight": {
|
||||||
|
"model": "antarchy:block/royal_stairs",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=north,half=top,shape=inner_left": {
|
||||||
|
"model": "antarchy:block/royal_stairs_inner",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=north,half=top,shape=inner_right": {
|
||||||
|
"model": "antarchy:block/royal_stairs_inner",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180
|
||||||
|
},
|
||||||
|
"facing=north,half=top,shape=outer_left": {
|
||||||
|
"model": "antarchy:block/royal_stairs_outer",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=north,half=top,shape=outer_right": {
|
||||||
|
"model": "antarchy:block/royal_stairs_outer",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180
|
||||||
|
},
|
||||||
|
"facing=north,half=top,shape=straight": {
|
||||||
|
"model": "antarchy:block/royal_stairs",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=south,half=bottom,shape=inner_left": {
|
||||||
|
"model": "antarchy:block/royal_stairs_inner"
|
||||||
|
},
|
||||||
|
"facing=south,half=bottom,shape=inner_right": {
|
||||||
|
"model": "antarchy:block/royal_stairs_inner",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=south,half=bottom,shape=outer_left": {
|
||||||
|
"model": "antarchy:block/royal_stairs_outer"
|
||||||
|
},
|
||||||
|
"facing=south,half=bottom,shape=outer_right": {
|
||||||
|
"model": "antarchy:block/royal_stairs_outer",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=south,half=bottom,shape=straight": {
|
||||||
|
"model": "antarchy:block/royal_stairs",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=south,half=top,shape=inner_left": {
|
||||||
|
"model": "antarchy:block/royal_stairs_inner",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=south,half=top,shape=inner_right": {
|
||||||
|
"model": "antarchy:block/royal_stairs_inner",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=south,half=top,shape=outer_left": {
|
||||||
|
"model": "antarchy:block/royal_stairs_outer",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=south,half=top,shape=outer_right": {
|
||||||
|
"model": "antarchy:block/royal_stairs_outer",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=south,half=top,shape=straight": {
|
||||||
|
"model": "antarchy:block/royal_stairs",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=west,half=bottom,shape=inner_left": {
|
||||||
|
"model": "antarchy:block/royal_stairs_inner",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=west,half=bottom,shape=inner_right": {
|
||||||
|
"model": "antarchy:block/royal_stairs_inner",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=west,half=bottom,shape=outer_left": {
|
||||||
|
"model": "antarchy:block/royal_stairs_outer",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=west,half=bottom,shape=outer_right": {
|
||||||
|
"model": "antarchy:block/royal_stairs_outer",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=west,half=bottom,shape=straight": {
|
||||||
|
"model": "antarchy:block/royal_stairs",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=west,half=top,shape=inner_left": {
|
||||||
|
"model": "antarchy:block/royal_stairs_inner",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=west,half=top,shape=inner_right": {
|
||||||
|
"model": "antarchy:block/royal_stairs_inner",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=west,half=top,shape=outer_left": {
|
||||||
|
"model": "antarchy:block/royal_stairs_outer",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=west,half=top,shape=outer_right": {
|
||||||
|
"model": "antarchy:block/royal_stairs_outer",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=west,half=top,shape=straight": {
|
||||||
|
"model": "antarchy:block/royal_stairs",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 180,
|
||||||
|
"y": 180
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"facing=east,half=bottom,open=false": {
|
||||||
|
"model": "antarchy:block/royal_trapdoor_bottom",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=east,half=bottom,open=true": {
|
||||||
|
"model": "antarchy:block/royal_trapdoor_open",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=east,half=top,open=false": {
|
||||||
|
"model": "antarchy:block/royal_trapdoor_top",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=east,half=top,open=true": {
|
||||||
|
"model": "antarchy:block/royal_trapdoor_open",
|
||||||
|
"x": 180,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=north,half=bottom,open=false": {
|
||||||
|
"model": "antarchy:block/royal_trapdoor_bottom"
|
||||||
|
},
|
||||||
|
"facing=north,half=bottom,open=true": {
|
||||||
|
"model": "antarchy:block/royal_trapdoor_open"
|
||||||
|
},
|
||||||
|
"facing=north,half=top,open=false": {
|
||||||
|
"model": "antarchy:block/royal_trapdoor_top"
|
||||||
|
},
|
||||||
|
"facing=north,half=top,open=true": {
|
||||||
|
"model": "antarchy:block/royal_trapdoor_open",
|
||||||
|
"x": 180,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=south,half=bottom,open=false": {
|
||||||
|
"model": "antarchy:block/royal_trapdoor_bottom",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=south,half=bottom,open=true": {
|
||||||
|
"model": "antarchy:block/royal_trapdoor_open",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=south,half=top,open=false": {
|
||||||
|
"model": "antarchy:block/royal_trapdoor_top",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=south,half=top,open=true": {
|
||||||
|
"model": "antarchy:block/royal_trapdoor_open",
|
||||||
|
"x": 180,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"facing=west,half=bottom,open=false": {
|
||||||
|
"model": "antarchy:block/royal_trapdoor_bottom",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=west,half=bottom,open=true": {
|
||||||
|
"model": "antarchy:block/royal_trapdoor_open",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=west,half=top,open=false": {
|
||||||
|
"model": "antarchy:block/royal_trapdoor_top",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=west,half=top,open=true": {
|
||||||
|
"model": "antarchy:block/royal_trapdoor_open",
|
||||||
|
"x": 180,
|
||||||
|
"y": 90
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/royal_wall_hanging_sign"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/royal_wall_sign"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"axis=x": {
|
||||||
|
"model": "antarchy:block/royal_wood",
|
||||||
|
"x": 90,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"axis=y": {
|
||||||
|
"model": "antarchy:block/royal_wood"
|
||||||
|
},
|
||||||
|
"axis=z": {
|
||||||
|
"model": "antarchy:block/royal_wood",
|
||||||
|
"x": 90
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"axis=x": {
|
||||||
|
"model": "antarchy:block/stripped_royal_log_horizontal",
|
||||||
|
"x": 90,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"axis=y": {
|
||||||
|
"model": "antarchy:block/stripped_royal_log"
|
||||||
|
},
|
||||||
|
"axis=z": {
|
||||||
|
"model": "antarchy:block/stripped_royal_log_horizontal",
|
||||||
|
"x": 90
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/stripped_royal_wood"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"axis=x": {
|
||||||
|
"model": "antarchy:block/stripped_truffalo_log_horizontal"
|
||||||
|
},
|
||||||
|
"axis=y": {
|
||||||
|
"model": "antarchy:block/stripped_truffalo_log"
|
||||||
|
},
|
||||||
|
"axis=z": {
|
||||||
|
"model": "antarchy:block/stripped_truffalo_log_horizontal",
|
||||||
|
"y": 90
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/stripped_truffalo_wood"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"face=ceiling,facing=east,powered=false": {
|
||||||
|
"model": "antarchy:block/truffalo_button",
|
||||||
|
"x": 180,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"face=ceiling,facing=east,powered=true": {
|
||||||
|
"model": "antarchy:block/truffalo_button_pressed",
|
||||||
|
"x": 180,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"face=ceiling,facing=north,powered=false": {
|
||||||
|
"model": "antarchy:block/truffalo_button",
|
||||||
|
"x": 180,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"face=ceiling,facing=north,powered=true": {
|
||||||
|
"model": "antarchy:block/truffalo_button_pressed",
|
||||||
|
"x": 180,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"face=ceiling,facing=south,powered=false": {
|
||||||
|
"model": "antarchy:block/truffalo_button",
|
||||||
|
"x": 180
|
||||||
|
},
|
||||||
|
"face=ceiling,facing=south,powered=true": {
|
||||||
|
"model": "antarchy:block/truffalo_button_pressed",
|
||||||
|
"x": 180
|
||||||
|
},
|
||||||
|
"face=ceiling,facing=west,powered=false": {
|
||||||
|
"model": "antarchy:block/truffalo_button",
|
||||||
|
"x": 180,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"face=ceiling,facing=west,powered=true": {
|
||||||
|
"model": "antarchy:block/truffalo_button_pressed",
|
||||||
|
"x": 180,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"face=floor,facing=east,powered=false": {
|
||||||
|
"model": "antarchy:block/truffalo_button",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"face=floor,facing=east,powered=true": {
|
||||||
|
"model": "antarchy:block/truffalo_button_pressed",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"face=floor,facing=north,powered=false": {
|
||||||
|
"model": "antarchy:block/truffalo_button"
|
||||||
|
},
|
||||||
|
"face=floor,facing=north,powered=true": {
|
||||||
|
"model": "antarchy:block/truffalo_button_pressed"
|
||||||
|
},
|
||||||
|
"face=floor,facing=south,powered=false": {
|
||||||
|
"model": "antarchy:block/truffalo_button",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"face=floor,facing=south,powered=true": {
|
||||||
|
"model": "antarchy:block/truffalo_button_pressed",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"face=floor,facing=west,powered=false": {
|
||||||
|
"model": "antarchy:block/truffalo_button",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"face=floor,facing=west,powered=true": {
|
||||||
|
"model": "antarchy:block/truffalo_button_pressed",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"face=wall,facing=east,powered=false": {
|
||||||
|
"model": "antarchy:block/truffalo_button",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 90,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"face=wall,facing=east,powered=true": {
|
||||||
|
"model": "antarchy:block/truffalo_button_pressed",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 90,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"face=wall,facing=north,powered=false": {
|
||||||
|
"model": "antarchy:block/truffalo_button",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 90
|
||||||
|
},
|
||||||
|
"face=wall,facing=north,powered=true": {
|
||||||
|
"model": "antarchy:block/truffalo_button_pressed",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 90
|
||||||
|
},
|
||||||
|
"face=wall,facing=south,powered=false": {
|
||||||
|
"model": "antarchy:block/truffalo_button",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 90,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"face=wall,facing=south,powered=true": {
|
||||||
|
"model": "antarchy:block/truffalo_button_pressed",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 90,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"face=wall,facing=west,powered=false": {
|
||||||
|
"model": "antarchy:block/truffalo_button",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 90,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"face=wall,facing=west,powered=true": {
|
||||||
|
"model": "antarchy:block/truffalo_button_pressed",
|
||||||
|
"uvlock": true,
|
||||||
|
"x": 90,
|
||||||
|
"y": 270
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"facing=east,half=lower,hinge=left,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_door_bottom_left"
|
||||||
|
},
|
||||||
|
"facing=east,half=lower,hinge=left,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_door_bottom_left_open",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=east,half=lower,hinge=right,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_door_bottom_right"
|
||||||
|
},
|
||||||
|
"facing=east,half=lower,hinge=right,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_door_bottom_right_open",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=east,half=upper,hinge=left,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_door_top_left"
|
||||||
|
},
|
||||||
|
"facing=east,half=upper,hinge=left,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_door_top_left_open",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=east,half=upper,hinge=right,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_door_top_right"
|
||||||
|
},
|
||||||
|
"facing=east,half=upper,hinge=right,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_door_top_right_open",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=north,half=lower,hinge=left,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_door_bottom_left",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=north,half=lower,hinge=left,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_door_bottom_left_open"
|
||||||
|
},
|
||||||
|
"facing=north,half=lower,hinge=right,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_door_bottom_right",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=north,half=lower,hinge=right,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_door_bottom_right_open",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=north,half=upper,hinge=left,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_door_top_left",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=north,half=upper,hinge=left,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_door_top_left_open"
|
||||||
|
},
|
||||||
|
"facing=north,half=upper,hinge=right,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_door_top_right",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=north,half=upper,hinge=right,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_door_top_right_open",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=south,half=lower,hinge=left,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_door_bottom_left",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=south,half=lower,hinge=left,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_door_bottom_left_open",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=south,half=lower,hinge=right,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_door_bottom_right",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=south,half=lower,hinge=right,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_door_bottom_right_open"
|
||||||
|
},
|
||||||
|
"facing=south,half=upper,hinge=left,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_door_top_left",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=south,half=upper,hinge=left,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_door_top_left_open",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=south,half=upper,hinge=right,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_door_top_right",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=south,half=upper,hinge=right,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_door_top_right_open"
|
||||||
|
},
|
||||||
|
"facing=west,half=lower,hinge=left,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_door_bottom_left",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=west,half=lower,hinge=left,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_door_bottom_left_open",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=west,half=lower,hinge=right,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_door_bottom_right",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=west,half=lower,hinge=right,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_door_bottom_right_open",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=west,half=upper,hinge=left,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_door_top_left",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=west,half=upper,hinge=left,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_door_top_left_open",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=west,half=upper,hinge=right,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_door_top_right",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=west,half=upper,hinge=right,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_door_top_right_open",
|
||||||
|
"y": 90
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"multipart": [
|
||||||
|
{
|
||||||
|
"apply": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_post"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"apply": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_side",
|
||||||
|
"uvlock": true
|
||||||
|
},
|
||||||
|
"when": {
|
||||||
|
"north": "true"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"apply": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_side",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"when": {
|
||||||
|
"east": "true"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"apply": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_side",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"when": {
|
||||||
|
"south": "true"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"apply": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_side",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"when": {
|
||||||
|
"west": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"facing=east,in_wall=false,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_gate",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=east,in_wall=false,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_gate_open",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=east,in_wall=true,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_gate_wall",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=east,in_wall=true,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_gate_wall_open",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=north,in_wall=false,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_gate",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=north,in_wall=false,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_gate_open",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=north,in_wall=true,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_gate_wall",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=north,in_wall=true,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_gate_wall_open",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=south,in_wall=false,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_gate",
|
||||||
|
"uvlock": true
|
||||||
|
},
|
||||||
|
"facing=south,in_wall=false,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_gate_open",
|
||||||
|
"uvlock": true
|
||||||
|
},
|
||||||
|
"facing=south,in_wall=true,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_gate_wall",
|
||||||
|
"uvlock": true
|
||||||
|
},
|
||||||
|
"facing=south,in_wall=true,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_gate_wall_open",
|
||||||
|
"uvlock": true
|
||||||
|
},
|
||||||
|
"facing=west,in_wall=false,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_gate",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=west,in_wall=false,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_gate_open",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=west,in_wall=true,open=false": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_gate_wall",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=west,in_wall=true,open=true": {
|
||||||
|
"model": "antarchy:block/truffalo_fence_gate_wall_open",
|
||||||
|
"uvlock": true,
|
||||||
|
"y": 90
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/truffalo_hanging_sign"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"axis=x": {
|
||||||
|
"model": "antarchy:block/truffalo_log_horizontal"
|
||||||
|
},
|
||||||
|
"axis=y": {
|
||||||
|
"model": "antarchy:block/truffalo_log"
|
||||||
|
},
|
||||||
|
"axis=z": {
|
||||||
|
"model": "antarchy:block/truffalo_log_horizontal",
|
||||||
|
"y": 90
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "antarchy:block/truffalo_planks"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"powered=false": {
|
||||||
|
"model": "antarchy:block/truffalo_pressure_plate"
|
||||||
|
},
|
||||||
|
"powered=true": {
|
||||||
|
"model": "antarchy:block/truffalo_pressure_plate_down"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loaded 100 of 554 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user