[1.7.10] Сидеть на стуле (слив кода)

timaxa007

Модератор
Сообщения
5,623
Лучшие ответы
371
Реакции
572

Уже не первый раз видел вопросы на счёт как сидеть на стуле или т.п. мебели.
По-этому я опять написал мод для примера, как можно сделать так, чтобы можно было сидеть на блоке.
(github.com) mod_sit
Да, есть недочёты. Я ставил цель, сделать пример кода, для того чтобы сесть на наш блок. А чтобы он сходил с места, где сидит моб/игрок на нашем блоке, если вдруг блок на котором он сидит сломан - я просто не делал.
 
Последнее редактирование:

timaxa007

Модератор
Сообщения
5,623
Лучшие ответы
371
Реакции
572
ModSit.java
Код:
@Mod(modid = ModSit.MODID, name = ModSit.NAME, version = ModSit.VERSION)
public class ModSit {

    public static final String
    MODID = "mod_sit",
    NAME = "On a chair to sit (Alpha)",
    VERSION = "0.001a"
    ;

    @Mod.Instance(value = ModSit.MODID)
    public static ModSit instance;

    @SidedProxy(modId = ModSit.MODID, serverSide = "timaxa007.mod_sit.ProxyCommon", clientSide = "timaxa007.mod_sit.ProxyClient")
    public static ProxyCommon proxy;

    public static Block block_sit;

    @Mod.EventHandler
    public void preInit(cpw.mods.fml.common.event.FMLPreInitializationEvent event) {

        block_sit = new BlockSit().setBlockName("sit").setBlockTextureName(MODID + ":sit").setHardness(0.15F).setCreativeTab(CreativeTabs.tabBlock);
        //Регистрируем наш блок.
        GameRegistry.registerBlock(block_sit, "block_sit");
        //Регистрируем наш TileEntity для рендера. Рендер для TileEntity в ProxyClient.
        GameRegistry.registerTileEntity(TileEntitySit.class, "TileEntitySit");
        //Регистрируем нашего Entity.
        EntityRegistry.registerModEntity(EntitySit.class, "EntitySit", 0, instance, 10, 1, true);

        proxy.preInit();

    }

}
ProxyCommon.java
Код:
public class ProxyCommon {

    public void preInit() {

    }

}
ProxyClient.java
Код:
public class ProxyClient extends ProxyCommon {

    public void preInit() {
        super.preInit();

        //Рендер для TileEntitySit в мире.
        ClientRegistry.bindTileEntitySpecialRenderer(TileEntitySit.class, new RenederTileEntitySit());
        //Рендер как Item для block_sit
        MinecraftForgeClient.registerItemRenderer(Item.getItemFromBlock(ModSit.block_sit), new RenederItemBlockSit());

    }

}
BlockSit.java
Код:
public class BlockSit extends Block implements ITileEntityProvider {

    public BlockSit() {
        super(Material.circuits);
    }

    @Override
    public TileEntity createNewTileEntity(World world, int metadata) {
        return new TileEntitySit();
    }

    @Override
    public int getRenderType() {
        return -1;
    }

    @Override
    public boolean isOpaqueCube() {
        return false;
    }

    @Override
    public boolean renderAsNormalBlock() {
        return false;
    }

    @Override
    public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float hitX, float hitY, float hitZ) {
        EntitySit sit = new EntitySit(world);//Создаём объект нашего EntitySit
        //Даём ему координаты
        sit.setPosition((double)x + 0.5D, (double)y + 0.5D, (double)z + 0.5D);
        if (!world.isRemote) {
            world.spawnEntityInWorld(sit);//спавним нашего EntitySit.
            player.mountEntity(sit);//Игрок оседлает нашего EntitySit
        }
        return super.onBlockActivated(world, x, y, z, player, side, hitX, hitY, hitZ);//просто false
    }

    @Override
    public void onBlockPlacedBy(World world, int x, int y, int z, EntityLivingBase entity, ItemStack is) {
        int l = MathHelper.floor_double((double)(entity.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3;
        /* Изменяем метудату от 0 до 3 зависимо от положения entity.
         * Будет использоваться для поворота нашей модели.*/
        world.setBlockMetadataWithNotify(x, y, z, l, 2);
    }

    /* Даже не зависимо, что указали для EntitySit точные координаты,
     * EntitySit будет пытаться встать на коллизию блока, а не будет оставаться в коллизии блока.
     * По-этому нужно сделать правильную коллизию для блока, но мне лень писать свой, я взял от котла.*/
    @Override
    public void addCollisionBoxesToList(World world, int x, int y, int z, AxisAlignedBB aabb, List list, Entity entity) {
        setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.3125F, 1.0F);
        super.addCollisionBoxesToList(world, x, y, z, aabb, list, entity);
        float f = 0.125F;
        setBlockBounds(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F);
        super.addCollisionBoxesToList(world, x, y, z, aabb, list, entity);
        setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f);
        super.addCollisionBoxesToList(world, x, y, z, aabb, list, entity);
        setBlockBounds(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
        super.addCollisionBoxesToList(world, x, y, z, aabb, list, entity);
        setBlockBounds(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F);
        super.addCollisionBoxesToList(world, x, y, z, aabb, list, entity);
        setBlockBoundsForItemRender();
    }

    @Override
    public void setBlockBoundsForItemRender() {
        setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
    }

}
EntitySit.java
Код:
public class EntitySit extends Entity {

    public EntitySit(World world) {
        super(world);
    }

    @Override
    public void entityInit() {
        /*У нашего Entity нет своего рендера, если размер не задать по 0F, то
        будет рендриться белый */
        setSize(0F, 0F);
        /*Не знаю точно зачем это нужно, но я написал.
        Знаю что оно используется для трекера Entity и ещё какого-то пакета*/
        myEntitySize = Entity.EnumEntitySize.SIZE_1;
    }

    @Override
    public void onEntityUpdate() {
        super.onEntityUpdate();
        if (riddenByEntity == null) {//Если не кто не оседал этот Entity
            setDead();//... то этот Entity умирает.
            /* Это надо если игрок/моб сошёл/выпал с этого Entity, 
            или иначе этот Entity остаётся жить и захламлять своим прибытием в мире.
            Так как его повторно не оседлать. */
        }
    }

    @SideOnly(Side.CLIENT)
    @Override
    public float getShadowSize() {
        return 0.0F;//Чтобы не было тени от этого Entity.
    }

    @Override
    public void readEntityFromNBT(NBTTagCompound nbt) {
        // TODO Auto-generated method stub
    }

    @Override
    public void writeEntityToNBT(NBTTagCompound nbt) {
        // TODO Auto-generated method stub
    }

}
TileEntitySit.java
Код:
public class TileEntitySit extends TileEntity {

    @Override
    public boolean canUpdate() {
        return false;
    }

}
RenederItemBlockSit.java
Код:
public class RenederItemBlockSit implements IItemRenderer {

    @Override
    public boolean handleRenderType(ItemStack item, ItemRenderType type) {
        return true;
    }

    @Override
    public boolean shouldUseRenderHelper(ItemRenderType type, ItemStack item, ItemRendererHelper helper) {
        return true;
    }

    @Override
    public void renderItem(ItemRenderType type, ItemStack item, Object... data) {
        GL11.glPushMatrix();
        GL11.glTranslatef(0.5F, 1.375F, 0.5F);
        GL11.glRotatef(180F, 0.0F, 0.0F, 1.0F);
        GL11.glRotatef(-180F, 0.0F, 1.0F, 0.0F);
        Minecraft.getMinecraft().renderEngine.bindTexture(RenederTileEntitySit.texture);
        RenederTileEntitySit.model.render(0.0625F);
        GL11.glPopMatrix();
    }

}
RenederTileEntitySit.java
Код:
public class RenederTileEntitySit extends TileEntitySpecialRenderer {

    //Модель
    public static final ModelSit model = new ModelSit();
    //Текстура
    public static final ResourceLocation texture = new ResourceLocation(ModSit.MODID, "textures/blocks/sit.png");

    @Override
    public void renderTileEntityAt(TileEntity tile, double x, double y, double z, float f) {
        render((TileEntitySit)tile, x, y, z, f);
    }

    private void render(TileEntitySit tile, double x, double y, double z, float f) {
        GL11.glPushMatrix();
        GL11.glTranslated(x, y, z);
        GL11.glTranslatef(0.5F, 1.5F, 0.5F);
        GL11.glRotatef(180F, 0.0F, 0.0F, 1.0F);
        if (tile != null) {
            switch(tile.getBlockMetadata()) {
            case 0:{GL11.glRotatef(0F, 0.0F, 1.0F, 0.0F);break;}
            case 1:{GL11.glRotatef(90F, 0.0F, 1.0F, 0.0F);break;}
            case 2:{GL11.glRotatef(180F, 0.0F, 1.0F, 0.0F);break;}
            case 3:{GL11.glRotatef(180F + 90F, 0.0F, 1.0F, 0.0F);break;}
            }
        }
        bindTexture(texture);
        model.render(0.0625F);
        GL11.glPopMatrix();
    }

}
ModelSit - Это модель, думаю сами сообразите что надо.
[merge_posts_bbcode]Добавлено: 18.03.2016 13:17:12[/merge_posts_bbcode]

Тему отредактировал.
 

timaxa007

Модератор
Сообщения
5,623
Лучшие ответы
371
Реакции
572
Поэкспериментировав, выяснилось что на клиенте мы садимся, а вот со стороны другого игрока мы не сели на стул. Слева как мы видим, с права как видит нас другой игрок:

Исправляется отправкой от сервера клиентам игрокам, о том что этот игрок/моб сел(/оседлал) на EntitySit.
Код:
   @Override
   public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float hitX, float hitY, float hitZ) {
// Тут была проверка на то, что этот стул занят
   if (!world.isRemote) {
       EntitySit sit = new EntitySit(world);
       sit.setPosition((double)x + 0.5D, (double)y + 0.5D, (double)z + 0.5D);
       world.spawnEntityInWorld(sit);
       player.mountEntity(sit);
       SMTDecorative.network.sendToDimension(new MessageSyncSit(player, sit), world.provider.dimensionId);// Пока-что использовал это,
// Так как на определённое расстояния, не хотел создавать для частоты эксперимента.
// В дальнейшим проверю и другой вариант и более менее рабочий код.
   }
   return true;
}
Код:
public class MessageSyncSit implements IMessage {

   private int entityID, sitID;

   public MessageSyncSit() {}

   public MessageSyncSit(int entityID, int sitID) {
       this.entityID = entityID;
       this.sitID = sitID;
   }

   public MessageSyncSit(Entity entity, Entity sit) {
       this.entityID = entity.getEntityId();
       this.sitID = sit.getEntityId();
   }

   @Override
   public void toBytes(ByteBuf buf) {
       buf.writeInt(entityID);
       buf.writeInt(sitID);
   }

   @Override
   public void fromBytes(ByteBuf buf) {
       entityID = buf.readInt();
       sitID = buf.readInt();
   }

   public static class Handler implements IMessageHandler<MessageSyncSit, IMessage> {

       @Override
       public IMessage onMessage(MessageSyncSit packet, MessageContext message) {
           act(packet.entityID, packet.sitID);
           return null;
       }

       @SideOnly(Side.CLIENT)
       private static void act(int entityID, int sitID) {
           Minecraft mc = Minecraft.getMinecraft();
           Entity entity = mc.theWorld.getEntityByID(entityID);
           Entity sit = mc.theWorld.getEntityByID(sitID);
           mc.theWorld.spawnEntityInWorld(sit);
           entity.mountEntity(sit);
       }

   }

}
Код:
public static SimpleNetworkWrapper network;

@Mod.EventHandler
public void preInit(cpw.mods.fml.common.event.FMLPreInitializationEvent event) {
   network = NetworkRegistry.INSTANCE.newSimpleChannel(MODID);
   network.registerMessage(MessageSyncSit.Handler.class, MessageSyncSit.class, 0, Side.CLIENT);
}
В итоге мы можем сидеть, но вот опять со стороны другого игрока выглядит странно:
Мы раскачиваем руки со стороны у другого игрока, так-же как и сидя на свинье. Хотя затем это я проверил на лодке, там подобное раскачивания руками нету и работает лучше. Как-нибудь проверю и исправлю у себя.

Написал, чтобы про информировать.
 
Последнее редактирование:
Сообщения
1,138
Лучшие ответы
5
Реакции
2
Вроде это из-за motionX/Y/Z и рендера
 

timaxa007

Модератор
Сообщения
5,623
Лучшие ответы
371
Реакции
572
моя твоя не понимать
 
Сообщения
1,138
Лучшие ответы
5
Реакции
2
Ну я вот что заметил: чем быстрее едешь на вагонетке, тем сильнее руки дергаются. Попробуй отдебажить рендер и посмотреть от чего угол поворота зависит. И, заодно, мою теорию проверь
 
Сверху