Хостинг серверов Minecraft playvds.com
  1. Вы находитесь в русском сообществе Bukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на русский язык плагины наших собратьев из других стран.
    Dismiss Notice

Помогите Асинхронная отправка пакетов

Discussion in 'Разработка плагинов для новичков' started by BeYkeR, Jun 29, 2014.

  1. Автор темы
    BeYkeR

    BeYkeR Старожил Девелопер Пользователь

    Trophy Points:
    173
    После нескольких часов работы над минилизацией лагов для LightSource(при отправке пакета, сервер начинает сильно тормозить, или компьютер такой) у меня появилась одна мысль: Возможно ли отправить пакеты по асинхронному потоку ?
     
  2. Хостинг MineCraft
    <
  3. kirill2011s

    kirill2011s Старожил Пользователь

    Trophy Points:
    103
    Вы занимались когда-нибудь клиент-серверным программированием?

    Если нет, то вот вам ответ: весь ваш канал интернет-связи, однопоточен. Чем шире у вас канал, тем быстрее данные передаются. Но многопоточности тут и речи быть не может. Все данные выстраиваются в очередь и отправляются тоже по очереди.
     
  4. ptnk

    ptnk Старожил Пользователь

    Trophy Points:
    173
    Можно ссылку на источник данной глупости? Здесь автор говорит про прикладной уровень, когда в любой другой программе можно из нескольких потоков отправлять различную информацию, а ты говоришь уже про уровень железа и про уровень операционной системы, когда идёт формирование пакетов на отправку.
     
  5. kirill2011s

    kirill2011s Старожил Пользователь

    Trophy Points:
    103
    Через канал интернета всегда была отправка однопоточной. Все данные делятся на пакеты и отправляются. Если вы считаете что существует многопоточность, то это лишь иллюзия, пакеты могут добавляться асинхронно.[DOUBLEPOST=1404059695,1404059070][/DOUBLEPOST]В любом случае, если уж говорить о майнкрафте, то клиент как принимал все в 1 потоке, так и будет принимать.
     
  6. ptnk

    ptnk Старожил Пользователь

    Trophy Points:
    173
    Если у меня есть канал 100МБит, значит считается, что я смогу отправить одновременно столько данных, если у клиенте есть столько - значит он столько сможет получить одновременно.

    И мне, как java - программисту глубоко всё равно, как операционная система оперирует с каналом. У меня в секунду отправляется столько-то пакетов, за 1ms - столько-то данных, поэтому не нужно пудрить людям мозги с очередью и загружать их не нужной информации.
    Любые данные одновременно отправленные из разных потоков придут к одному и тому же получателю с минимальной разницей.
     
  7. kirill2011s

    kirill2011s Старожил Пользователь

    Trophy Points:
    103
    Хорошо, не буду пудрить никому мозг. Возможно, либо вы меня сначала не правильно поняли, либо я не очень понял автора.
     
  8. gamerforEA

    gamerforEA Старожил Пользователь

    Trophy Points:
    143
    Skype:
    sk2000sk1
    Имя в Minecraft:
    gamerforEA_MCPC
    Задача: обмен данными в отдельных потоках с целью снижения нагрузки на основной поток.
     
  9. Shevchik

    Shevchik Старожил Пользователь

    Trophy Points:
    173
    Имя в Minecraft:
    _Shevchik_
    Тормозить при отправке пакета? Нетворк итак в отдельных потоках выполняется.
    Ваша проблема точно не в отправке пакета.
     
  10. Автор темы
    BeYkeR

    BeYkeR Старожил Девелопер Пользователь

    Trophy Points:
    173
    BukkitDev
    Написал -Lite версию плагина:
    Code:
    package ykt.BeYkeRYkt.LightSourceLite;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import net.minecraft.server.v1_7_R2.Chunk;
    import net.minecraft.server.v1_7_R2.EnumSkyBlock;
    import net.minecraft.server.v1_7_R2.PacketPlayOutMapChunk;
    import net.minecraft.server.v1_7_R2.WorldServer;
    
    import org.bukkit.Bukkit;
    import org.bukkit.Location;
    import org.bukkit.Material;
    import org.bukkit.block.Block;
    import org.bukkit.block.BlockFace;
    import org.bukkit.craftbukkit.v1_7_R2.CraftChunk;
    import org.bukkit.craftbukkit.v1_7_R2.CraftServer;
    import org.bukkit.craftbukkit.v1_7_R2.CraftWorld;
    import org.bukkit.entity.Player;
    import org.bukkit.plugin.java.JavaPlugin;
    
    public class LSL extends JavaPlugin{
    
        public int task = 0;
        private static BlockFace[] SIDES = { BlockFace.UP, BlockFace.DOWN,
            BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST };
    
        private ArrayList<String> players = new ArrayList<String>();
    
        @Override
        public void onDisable() {
            getLogger().info("Disabled!");
            stopSyncTask();
        }
    
        @Override
        public void onEnable() {
            getLogger().info("Enabled!");
            startSyncTask();
        }
    
        public void stopSyncTask() {
            Bukkit.getScheduler().cancelTask(task);
        }
    
    
        public Block getAdjacentAirBlock(Block block) {
            for (BlockFace face : SIDES) {
                if (block.getY() == 0x0 && face == BlockFace.DOWN)
                    continue;
                if (block.getY() == 0xFF && face == BlockFace.UP)
                    continue;
    
                Block candidate = block.getRelative(face);
    
                if (candidate.getType().isTransparent()) {
                    return candidate;
                }
            }
            return block;
        }
    
        public void startSyncTask(){
            task = Bukkit.getScheduler().runTaskTimer(this, new Runnable(){
                @Override
                public void run(){
                    final List<String> playernames = new ArrayList<String>();
                    for (int p = 0; p < Bukkit.getOnlinePlayers().length; p++) {
                        playernames.add(Bukkit.getOnlinePlayers()[p].getName());
                    }
                    Player player = null;
                    for (final String playername : playernames) {
                        player = Bukkit.getPlayer(playername);
                        if (player != null) {
                            if (player.getInventory().getItemInHand().getType() == Material.TORCH) {
                            if(players.contains(player.getName())){
                              for(int x=-2; x <=2; x++){
                                for(int y=-2; y<=2; y++){
                                  for(int z=-2; z<=2; z++){
                                    Location loc = new Location(player.getWorld(), player.getLocation().getBlockX() + x, player.getLocation().getBlockY() + y, player.getLocation().getBlockZ() + z);
                                   resetLight(loc);
                                  }
                                }
                              }
                                    lightUp(player.getLocation(), 14);
                                    sendSyncPackets(player.getLocation());
                            }else{
                                players.add(player.getName());
                            }
                                }else{
                                if(players.contains(player.getName())){
                                for(int x=-2; x <=2; x++){
                                 for(int y=-2; y<=2; y++){
                                    for(int z=-2; z<=2; z++){
                                        Location loc = new Location(player.getWorld(), player.getLocation().getBlockX() + x, player.getLocation().getBlockY() + y, player.getLocation().getBlockZ() + z);
                                        resetLight(loc);
                                    }
                                 }
                                }
                                   //resetLight(player.getLocation());
                                    sendSyncPackets(player.getLocation());
                                    players.remove(player.getName());
                                }
                                }
                       
                        }
                    }
                }
            }, 0L, 7L).getTaskId();
        }
    
    
        public void lightUp(Location loc, int level) {
            WorldServer nmsWorld = ((CraftWorld) loc.getWorld()).getHandle();
       
            int x = loc.getBlockX();
            int y = loc.getBlockY();
            int z = loc.getBlockZ();
       
            nmsWorld.b(EnumSkyBlock.BLOCK, x, y, z, level);
        }
    
        public void resetLight(Location loc) {
            WorldServer nmsWorld = ((CraftWorld) loc.getWorld()).getHandle();
       
            int x = loc.getBlockX();
            int y = loc.getBlockY();
            int z = loc.getBlockZ();
       
            nmsWorld.c(EnumSkyBlock.BLOCK, x, y, z);   
        }
    
        public void sendSyncPackets(Location loc) {
            for(int x=-1; x<=1; x++) {
                for(int z=-1; z<=1; z++) {
                    long startTime = System.currentTimeMillis();
                    //Send       
                    Chunk chunk = ((CraftChunk)loc.clone().add(16 * x, 0, 16 * z).getChunk()).getHandle();
                    PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(chunk, false, '\uffff');
               
                    Block adjacent = getAdjacentAirBlock(loc.getBlock());
                    ((CraftWorld) loc.getWorld()).getHandle().t(adjacent.getX(), adjacent.getY(),adjacent.getZ());
                    ((CraftServer) Bukkit.getServer()).getServer().getPlayerList().sendPacketNearby(loc.getX(), loc.getY(), loc.getZ(), 64, ((CraftWorld) loc.getWorld()).getHandle().dimension, packet);
                    chunk.initLighting();
                    long endTime = System.currentTimeMillis();
                    getLogger().info("Sync: " + (endTime - startTime) + " ms!");
                }
            }
        }
    }
    
    
    Результат показывает ~10 - 20 миллисекунд. Со временем TPS падает до ~11 и держится там до тех пор, пока игрок не уберет факел. Во всех значениях period'a. Мне сейчас важно не вызывать частые лаги при использовании плагина.
     
    Last edited: Jun 30, 2014
  11. kirill2011s

    kirill2011s Старожил Пользователь

    Trophy Points:
    103
    Спасибо, я уже понял.
     
  12. Shevchik

    Shevchik Старожил Пользователь

    Trophy Points:
    173
    Имя в Minecraft:
    _Shevchik_
    Ваша проблема не в отправке пакета а в том что вы выполняете сложный расчётный таск каждый тик.
    Вы видели сходный код метода World.c(EnumSkyBlock....)? Так вот он:
    https://github.com/Bukkit/CraftBukk...in/java/net/minecraft/server/World.java#L2174
    А ещё и chunk.initLightning().
    https://github.com/Bukkit/CraftBukkit/blob/master/src/main/java/net/minecraft/server/Chunk.java#L174
    Неудивительно что у вас тпс адово проседает.
     
  13. Автор темы
    BeYkeR

    BeYkeR Старожил Девелопер Пользователь

    Trophy Points:
    173
    Да уж, уже начинаю забывать смотреть на исходный код).
    А что если я буду использовать старый метод вместо nmsWorld.c():
    Code:
    Location delete = new Location(loc.getWorld(), x, y, z);
    Material blockMaterial = delete.getBlock().getType();
    byte blockData = delete.getBlock().getData(); //Хотя зачем мне это ?
    delete.getBlock().setType(blockMaterial);
    delete.getBlock().setData(blockData);
    и уберу chunk.initLightning() , TPS повысится ?
     

Share This Page