Версия Minecraft
1.12.2
Я начал заниматься моддингом 3 дня назад, поэтому я тут не особо шарю.
Я перерыл уже наверное всё, что только можно было, смотрел на гитхабе другие моды как это делают, но у меня не работает ничего.
В общем, у меня есть стол, в который надо положить кристалл, и сверху на него бросить что-нибудь. Стол зачарует предмет (ну на самом деле удалит предыдущий и создаст новый предмет), потратив при этом один кристалл. При этом зачаровании создаётся звук и частицы.
Со звуком проблем нет, но вот частицы спавнятся странным образом. Частицы при зачаровании спавнятся только у тех, кто поставил этот стол или открыл его. Вот видео:
.
Если даже забыть про то, что я сейчас сказал, то я хочу узнать, как спавнить частицы (не только из TileEntity, а вообще отовсюду, где только можно их заспавнить), чтобы они были видны у всех клиентов на сервере.

Вот мой код для блока стола и для TileEntity стола. (PS - Я юзаю mcreator, гореть мне в аду, наверное)
BlockMagicEnhancer.java:
package net.mcreator.substance_and_mind.block;

import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.client.event.ModelRegistryEvent;

import net.minecraft.world.World;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.NonNullList;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.tileentity.TileEntityLockableLoot;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
import net.minecraft.network.NetworkManager;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.Item;
import net.minecraft.inventory.ItemStackHelper;
import net.minecraft.inventory.InventoryHelper;
import net.minecraft.inventory.Container;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.block.state.IBlockState;
import net.minecraft.block.material.Material;
import net.minecraft.block.SoundType;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.Block;

import net.mcreator.substance_and_mind.gui.GuiMagicEnhancerGUI;
import net.mcreator.substance_and_mind.creativetab.TabSubstanceAndMindTab;
import net.mcreator.substance_and_mind.SubstanceMind;
import net.mcreator.substance_and_mind.ElementsSubstanceMind;
import net.mcreator.substance_and_mind.TileEntityMagicEnhancer;

@ElementsSubstanceMind.ModElement.Tag
public class BlockMagicEnhancer extends ElementsSubstanceMind.ModElement {
    @GameRegistry.ObjectHolder("substance_and_mind:magicenhancer")
    public static final Block block = null;
    public BlockMagicEnhancer(ElementsSubstanceMind instance) {
        super(instance, 3);
    }

    @Override
    public void initElements() {
        elements.blocks.add(() -> new BlockCustom().setRegistryName("magicenhancer"));
        elements.items.add(() -> new ItemBlock(block).setRegistryName(block.getRegistryName()));
    }

    @Override
    public void init(FMLInitializationEvent event) {
        GameRegistry.registerTileEntity(TileEntityMagicEnhancer.class, "substance_and_mind:tileentitymagicenhancer");
    }

    @SideOnly(Side.CLIENT)
    @Override
    public void registerModels(ModelRegistryEvent event) {
        ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(block), 0,
                new ModelResourceLocation("substance_and_mind:magicenhancer", "inventory"));
    }
    public static class BlockCustom extends Block implements ITileEntityProvider {
        public BlockCustom() {
            super(Material.WOOD);
            setUnlocalizedName("magicenhancer");
            setSoundType(SoundType.WOOD);
            setHardness(2F);
            setResistance(10F);
            setLightLevel(0F);
            setLightOpacity(255);
            setCreativeTab(TabSubstanceAndMindTab.tab);
        }

        @Override
        public TileEntity createNewTileEntity(World worldIn, int meta) {
            return new TileEntityMagicEnhancer();
        }

        @Override
        public boolean eventReceived(IBlockState state, World worldIn, BlockPos pos, int eventID, int eventParam) {
            super.eventReceived(state, worldIn, pos, eventID, eventParam);
            TileEntity tileentity = worldIn.getTileEntity(pos);
            return tileentity == null ? false : tileentity.receiveClientEvent(eventID, eventParam);
        }

        @Override
        public EnumBlockRenderType getRenderType(IBlockState state) {
            return EnumBlockRenderType.MODEL;
        }

        @Override
        public void breakBlock(World world, BlockPos pos, IBlockState state) {
            TileEntity tileentity = world.getTileEntity(pos);
            if (tileentity instanceof TileEntityMagicEnhancer)
                InventoryHelper.dropInventoryItems(world, pos, (TileEntityMagicEnhancer) tileentity);
            world.removeTileEntity(pos);
            super.breakBlock(world, pos, state);
        }

        @Override
        public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer entity, EnumHand hand, EnumFacing direction,
                float hitX, float hitY, float hitZ) {
            super.onBlockActivated(world, pos, state, entity, hand, direction, hitX, hitY, hitZ);
            int x = pos.getX();
            int y = pos.getY();
            int z = pos.getZ();
            if (entity instanceof EntityPlayer) {
                ((EntityPlayer) entity).openGui(SubstanceMind.instance, GuiMagicEnhancerGUI.GUIID, world, x, y, z);
            }
            return true;
        }
    }
}

TileEntityMagicEnhancer.java:
package net.mcreator.substance_and_mind;

import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.client.event.ModelRegistryEvent;

import net.minecraft.world.gen.IChunkGenerator;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.World;

import net.mcreator.substance_and_mind.TileEntityUtil;

import java.util.Random;
import net.minecraft.util.ITickable;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntityLockableLoot;

import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Container;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.entity.player.EntityPlayer;
import net.mcreator.substance_and_mind.gui.GuiMagicEnhancerGUI.GuiContainerMod;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
import javax.annotation.Nullable;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.inventory.ItemStackHelper;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraft.util.NonNullList;

import net.mcreator.substance_and_mind.gui.GuiMagicEnhancerGUI;
import net.mcreator.substance_and_mind.item.*;
import net.mcreator.substance_and_mind.block.*;
import net.mcreator.substance_and_mind.SaMSoundHandler;
import net.mcreator.substance_and_mind.ResourcePath;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.util.math.AxisAlignedBB;
import java.util.List;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.item.ItemBook;
import net.minecraft.block.material.Material;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.util.SoundCategory;
import net.minecraft.init.SoundEvents;
import net.minecraft.util.SoundEvent;


public class TileEntityMagicEnhancer extends TileEntityLockableLoot implements ITickable {
    private NonNullList<ItemStack> stacks = NonNullList.<ItemStack>withSize(1, ItemStack.EMPTY);
    
    public Item nowCrafting = null; //Предмет, который сейчас создаётся на столе
    public Item craftingFrom = null;
    public int craftingCount = 0;
    
    public int craftCounter = 0;
    
    
    @Override
    public void update()
    {
        ItemStack stack = getStackInSlot(0); //Берется ItemStack в слоте 0
        List<EntityItem> list = this.world.getEntitiesWithinAABB(EntityItem.class, new AxisAlignedBB(getPos()).expand(0, 0.5, 0).contract(0, -1, 0)); //Берутся EntityItem над столом
        
        if(!(nowCrafting == null)) //Если что-то крафтится
        {
            if (craftCounter >= 20)
            {
                craftItem(list, stack);
            }
            else
            {
                craftCounter += 1;
                spawnProcessingParticles();
            }
        }
        else //Если идет простой
        {
            if(list.isEmpty() == false && stack.getItem() == new ItemStack(ItemPowerGem.block, 1).getItem()) //Если на столе лежат предмет или предметы и внутри стола есть powergem или powergem'ы
            {
                for (int i = 0; i < list.size(); i++) //Проходится по всем предметам в ItemStack'е
                {
                    if((list.get(i).getItem()).getItem() == new ItemStack(Items.STICK, 1).getItem()) //Крафт стержня ифрита из палки
                    {
                        nowCrafting = Items.BLAZE_ROD;
                        craftingFrom = Items.STICK;
                        craftingCount = 1;
                        playMagicEnhancerCraftingSound();
                        
                    }
                }
            }
            else //Если на столе ничего не лежит или нет powergem'ов
            {
                
            }
        }
    }

    public void spawnEnhanceParticles()
    {
        for (int i = 0; i < 10; i++)
        {
            world.spawnParticle(EnumParticleTypes.CRIT_MAGIC,
            getPos().getX() + 1F - world.rand.nextFloat(),
            getPos().getY() + 1.5F + 0.5F - world.rand.nextFloat(),
            getPos().getZ() + 1F - world.rand.nextFloat(),
            (0.5F - world.rand.nextFloat())/10,
            (0.5F - world.rand.nextFloat())/10,
            (0.5F - world.rand.nextFloat()/10));
        }
        for (int i = 0; i < 5; i++)
        {
            world.spawnParticle(EnumParticleTypes.CLOUD,
            getPos().getX() + 1F - world.rand.nextFloat(),
            getPos().getY() + 1.5F + 0.5F - world.rand.nextFloat(),
            getPos().getZ() + 1F - world.rand.nextFloat(),
            (0.5F - world.rand.nextFloat())/8,
            (1F - world.rand.nextFloat())/6,
            (0.5F - world.rand.nextFloat())/8);
        }
    }

    public void spawnProcessingParticles()
    {
        float rand = world.rand.nextFloat();
        if (rand < 0.25)
        {
            world.spawnParticle(EnumParticleTypes.END_ROD,
            getPos().getX() + 1.0f - world.rand.nextFloat(),
            getPos().getY() + 1.0f,
            getPos().getZ() - 0.05f,
            0.0f,
            -0.01f,
            0.0f);
        }
        else if(rand > 0.25 && rand < 0.5)
        {
            world.spawnParticle(EnumParticleTypes.END_ROD,
            getPos().getX() + 1.05f,
            getPos().getY() + 1.0f,
            getPos().getZ() + 1.0f - world.rand.nextFloat(),
            0.0f,
            -0.01f,
            0.0f);
        }
        else if(rand > 0.5 && rand < 0.75)
        {
            world.spawnParticle(EnumParticleTypes.END_ROD,
            getPos().getX() + 1.0f - world.rand.nextFloat(),
            getPos().getY() + 1.0f,
            getPos().getZ() + 1.05f,
            0.0f,
            -0.01f,
            0.0f);
        }
        else if(rand > 0.75)
        {
            world.spawnParticle(EnumParticleTypes.END_ROD,
            getPos().getX() - 0.05f,
            getPos().getY() + 1.0f,
            getPos().getZ() + 1.0f - world.rand.nextFloat(),
            0.0f,
            -0.01f,
            0.0f);
        }
    }

    public void decrCraftingFromItemStack(EntityItem enItem)
    {
        if ((enItem.getItem()).getCount() > 1)
        {
            (enItem.getItem()).setCount((enItem.getItem()).getCount() - 1);
        }
        else
        {
            enItem.setDead();
        }
    }

    public void resetCraftingValues()
    {
        nowCrafting = null;
        craftingFrom = null;
        craftingCount = 0;
    }

    public void craftItem(List<EntityItem> list, ItemStack stack)
    {
        for (int i = 0; i < list.size(); i++) //Перепроверяет, если предмет, из которого крафтят, всё ещё на месте; а то вдруг какой-нибудь шалун стырил его
        {
            if((list.get(i).getItem()).getItem() == new ItemStack(craftingFrom, 1).getItem())
            {
                if (stack.getCount() > 0)
                {
                    spawnEnhanceParticles();
                    stack.setCount(stack.getCount() - 1);
                    decrCraftingFromItemStack(list.get(i));
                    if(world.isRemote == false)
                    {
                        world.spawnEntity(new EntityItem(world, pos.getX() + 0.5, pos.getY() + 1.05, pos.getZ() + 0.5, new ItemStack(nowCrafting, craftingCount)));
                    }
                    resetCraftingValues();
                }
                else
                {
                    resetCraftingValues();
                }
                break;
            }
        }
        resetCraftingValues();
        craftCounter = 0;
    }

    public void playMagicEnhancerCraftingSound()
    {
        Random rand = new Random();
        float randomVolume = rand.nextInt(50)/100f + 0.5f;
        float randomPitch = rand.nextInt(20)/100f + 0.8f;
        world.playSound(null, pos, SaMSoundHandler.magicEnhancerCrafting, SoundCategory.MASTER, randomVolume, randomPitch);
    }
    
    @Override
    public int getSizeInventory() {
        return 1;
    }

    @Override
    public boolean isEmpty() {
        for (ItemStack itemstack : this.stacks)
            if (!itemstack.isEmpty())
                return false;
        return true;
    }

    @Override
    public boolean isItemValidForSlot(int index, ItemStack stack) {
        return true;
    }

    @Override
    public ItemStack getStackInSlot(int slot) {
        return stacks.get(slot);
    }

    @Override
    public String getName() {
        return "container.magicenhancer";
    }

    @Override
    public void readFromNBT(NBTTagCompound compound) {
        super.readFromNBT(compound);
        this.stacks = NonNullList.<ItemStack>withSize(this.getSizeInventory(), ItemStack.EMPTY);
        if (!this.checkLootAndRead(compound))
            ItemStackHelper.loadAllItems(compound, this.stacks);
    }

    @Override
    public NBTTagCompound writeToNBT(NBTTagCompound compound) {
        super.writeToNBT(compound);
        if (!this.checkLootAndWrite(compound))
            ItemStackHelper.saveAllItems(compound, this.stacks);
        return compound;
    }

    @Override
    public SPacketUpdateTileEntity getUpdatePacket() {
        return new SPacketUpdateTileEntity(this.pos, 0, this.getUpdateTag());
    }

    @Override
    public NBTTagCompound getUpdateTag() {
        return this.writeToNBT(new NBTTagCompound());
    }

    @Override
    public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) {
        this.readFromNBT(pkt.getNbtCompound());
    }

    @Override
    public void handleUpdateTag(NBTTagCompound tag) {
        this.readFromNBT(tag);
    }

    @Override
    public int getInventoryStackLimit() {
        return 64;
    }

    @Override
    public String getGuiID() {
        return "substance_and_mind:magicenhancer";
    }

    @Override
    public Container createContainer(InventoryPlayer playerInventory, EntityPlayer playerIn) {
        return new GuiMagicEnhancerGUI.GuiContainerMod(this.getWorld(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ(),
                playerIn);
    }

    @Override
    protected NonNullList<ItemStack> getItems() {
        return this.stacks;
    }
}
 
Сверху