Package logisticspipes.ticks

Source Code of logisticspipes.ticks.ServerPacketBufferHandlerThread$ServerCompressorThread

package logisticspipes.ticks;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import logisticspipes.network.LPDataInputStream;
import logisticspipes.network.LPDataOutputStream;
import logisticspipes.network.PacketHandler;
import logisticspipes.network.abstractpackets.ModernPacket;
import logisticspipes.network.packets.BufferTransfer;
import logisticspipes.proxy.MainProxy;
import logisticspipes.utils.tuples.Pair;
import net.minecraft.entity.player.EntityPlayer;
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
import cpw.mods.fml.common.gameevent.TickEvent.ServerTickEvent;

public class ServerPacketBufferHandlerThread {

  private class ServerCompressorThread extends Thread {
    //Map of Players to lists of S->C packets to be serialized and compressed
    private final HashMap<EntityPlayer, LinkedList<ModernPacket>> serverList = new HashMap<EntityPlayer, LinkedList<ModernPacket>>();
    //Map of Players to serialized but still uncompressed S->C data
    private final HashMap<EntityPlayer, byte[]> serverBuffer = new HashMap<EntityPlayer, byte[]>();
    //used to cork the compressor so we can queue up a whole bunch of packets at once
    private boolean pause = false;
    //Clear content on next tick
    private Queue<EntityPlayer> playersToClear = new LinkedList<EntityPlayer>();

    public ServerCompressorThread() {
      super("LogisticsPipes Packet Compressor Server");
      this.setDaemon(true);
      this.start();
    }

    @Override
    public void run() {
      while(true) {
        try {
          synchronized(serverList) {
            if(!pause) {
              for(Entry<EntityPlayer, LinkedList<ModernPacket>> player:serverList.entrySet()) {
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                DataOutputStream data = new DataOutputStream(out);
                byte[] towrite = serverBuffer.get(player.getKey());
                if(towrite != null) {
                  data.write(towrite);
                }
                LinkedList<ModernPacket> packets = player.getValue();
                for(ModernPacket packet:packets) {
                  LPDataOutputStream t = new LPDataOutputStream();
                  t.writeShort(packet.getId());
                  t.writeInt(packet.getDebugId());
                  packet.writeData(t);
                  data.writeInt(t.size());
                  data.write(t.toByteArray());
                }
                serverBuffer.put(player.getKey(), out.toByteArray());
              }
              serverList.clear();
            }
          }
          //Send Content
          for(Entry<EntityPlayer, byte[]> player:serverBuffer.entrySet()) {
            while(player.getValue().length > 32 * 1024) {
              byte[] sendbuffer = Arrays.copyOf(player.getValue(), 1024 * 32);
              byte[] newbuffer = Arrays.copyOfRange(player.getValue(), 1024 * 32, player.getValue().length);
              player.setValue(newbuffer);
              byte[] compressed = compress(sendbuffer);
              MainProxy.sendPacketToPlayer(PacketHandler.getPacket(BufferTransfer.class).setContent(compressed), player.getKey());
            }
            byte[] sendbuffer = player.getValue();
            byte[] compressed = compress(sendbuffer);
            MainProxy.sendPacketToPlayer(PacketHandler.getPacket(BufferTransfer.class).setContent(compressed), player.getKey());
          }
        } catch (IOException e) {
          e.printStackTrace();
        }
        serverBuffer.clear();
        synchronized(serverList) {
          while(pause || serverList.size() == 0) {
            try {
              serverList.wait();
            } catch (InterruptedException e) {}
          }
        }
        synchronized(playersToClear) {
          EntityPlayer player = null;
          do {
            player = playersToClear.poll();
            if(player != null) {
              serverBuffer.remove(player);
            }
          } while(player != null);
        }
      }
    }

    public void addPacketToCompressor(ModernPacket packet, EntityPlayer player) {
      synchronized(serverList) {
        LinkedList<ModernPacket> packetList = serverList.get(player);
        if(packetList == null) {
          packetList = new LinkedList<ModernPacket>();
          serverList.put(player, packetList);
        }
        packetList.add(packet);
        if(!pause) {
          serverList.notify();
        }
      }
    }

    public void setPause(boolean flag) {
      synchronized(serverList) {
        pause = flag;
        if(!pause) {
          serverList.notify();
        }
      }
    }

    public void clear(EntityPlayer player) {
      synchronized(serverList) {
        serverList.remove(player);
      }
      synchronized(playersToClear) {
        playersToClear.add(player);
      }
    }
  }
  private final ServerCompressorThread serverCompressorThread = new ServerCompressorThread();

  private class ServerDecompressorThread extends Thread {
    //Map of Player to received compressed C->S data
    private final HashMap<EntityPlayer, LinkedList<byte[]>> queue = new HashMap<EntityPlayer, LinkedList<byte[]>>();
    //Map of Player to decompressed serialized C->S data
    private final HashMap<EntityPlayer, byte[]> ByteBuffer = new HashMap<EntityPlayer, byte[]>();
    //FIFO for deserialized C->S packets, decompressor adds, tickEnd removes
    private final LinkedList<Pair<EntityPlayer,byte[]>> PacketBuffer = new LinkedList<Pair<EntityPlayer,byte[]>>();
    //Clear content on next tick
    private Queue<EntityPlayer> playersToClear = new LinkedList<EntityPlayer>();

    public ServerDecompressorThread() {
      super("LogisticsPipes Packet Decompressor Server");
      this.setDaemon(true);
      this.start();
    }
   
    public void serverTickEnd() {
      boolean flag = false;
      do {
        flag = false;
        Pair<EntityPlayer,byte[]> part = null;
        synchronized (PacketBuffer) {
          if(PacketBuffer.size() > 0) {
            flag = true;
            part = PacketBuffer.pop();
          }
        }
        if(flag) {
          try {
            PacketHandler.onPacketData(new LPDataInputStream(part.getValue2()), part.getValue1());
          } catch (IOException e) {
            e.printStackTrace();
          }
        }
      } while(flag);
    }

    @Override
    public void run() {
      while(true) {
        boolean flag = false;
        do {
          flag = false;
          byte[] buffer = null;
          EntityPlayer player = null;
          synchronized(queue) {
            if(queue.size() > 0) {
              for(Iterator<Entry<EntityPlayer, LinkedList<byte[]>>> it = queue.entrySet().iterator(); it.hasNext(); ) {
                Entry<EntityPlayer, LinkedList<byte[]>> lPlayer = it.next();
                if(lPlayer.getValue().size() > 0) {
                  flag = true;
                  buffer = lPlayer.getValue().getFirst();
                  player = lPlayer.getKey();
                  if(lPlayer.getValue().size() > 1) {
                    lPlayer.getValue().removeFirst();
                  } else {
                    it.remove();
                  }
                  break;
                } else {
                  it.remove();
                }
              }
            }
          }
          if(flag && buffer != null && player != null) {
            byte[] ByteBufferForPlayer = ByteBuffer.get(player);
            if(ByteBufferForPlayer==null) {
              ByteBufferForPlayer= new byte[]{};
              ByteBuffer.put(player,ByteBufferForPlayer);
            }
            byte[] packetbytes = decompress(buffer);
            byte[] newBuffer = new byte[packetbytes.length + ByteBufferForPlayer.length];
            System.arraycopy(ByteBufferForPlayer, 0, newBuffer, 0, ByteBufferForPlayer.length);
            System.arraycopy(packetbytes, 0, newBuffer, ByteBufferForPlayer.length, packetbytes.length);
            ByteBuffer.put(player, newBuffer);
          }
        }
        while(flag);

        for(Entry<EntityPlayer, byte[]> player:ByteBuffer.entrySet()) {
          while(player.getValue().length >= 4) {
            byte[] ByteBufferForPlayer = player.getValue();
            int size = ((ByteBufferForPlayer[0] & 255) << 24) + ((ByteBufferForPlayer[1] & 255) << 16) + ((ByteBufferForPlayer[2] & 255) << 8) + ((ByteBufferForPlayer[3] & 255) << 0);
            if(size + 4 > ByteBufferForPlayer.length) {
              break;
            }
            byte[] packet = Arrays.copyOfRange(ByteBufferForPlayer, 4, size + 4);
            ByteBufferForPlayer = Arrays.copyOfRange(ByteBufferForPlayer, size + 4, ByteBufferForPlayer.length);
            player.setValue(ByteBufferForPlayer);
            synchronized (PacketBuffer) {
              PacketBuffer.add(new Pair<EntityPlayer, byte[]>(player.getKey() ,packet));
            }
          }
        }
        for(Iterator<byte[]> it = ByteBuffer.values().iterator(); it.hasNext();) {
          byte[] ByteBufferForPlayer = it.next();
          if(ByteBufferForPlayer.length == 0) {
            it.remove();
          }
        }

        synchronized(queue) {
          while(queue.size() == 0) {
            try {
              queue.wait();
            } catch (InterruptedException e) {}
          }
        }
        synchronized(playersToClear) {
          EntityPlayer player = null;
          do {
            player = playersToClear.poll();
            if(player != null) {
              ByteBuffer.remove(player);
            }
          } while(player != null);
        }
      }
    }

    public void handlePacket(byte[] content, EntityPlayer player) {
      synchronized(queue) {
        LinkedList<byte[]> list=queue.get(player);
        if(list == null) {
          list = new LinkedList<byte[]>();
          queue.put(player, list);
        }
        list.addLast(content);
        queue.notify();
      }
    }

    public void clear(EntityPlayer player) {
      synchronized(queue) {
        queue.remove(player);
      }
      synchronized(playersToClear) {
        playersToClear.add(player);
      }
    }
  }
  private final ServerDecompressorThread serverDecompressorThread = new ServerDecompressorThread();

  public ServerPacketBufferHandlerThread() {
  }

  public void serverTick(ServerTickEvent event) {
    if(event.phase != Phase.END) return;
    serverDecompressorThread.serverTickEnd();
  }
 
  public void setPause(boolean flag) {
    serverCompressorThread.setPause(flag);
  }

  public void addPacketToCompressor(ModernPacket packet, EntityPlayer player) {
    serverCompressorThread.addPacketToCompressor(packet, player);
  }

  public void handlePacket(byte[] content, EntityPlayer player) {
    serverDecompressorThread.handlePacket(content, player);
  }

  private static byte[] compress(byte[] content){
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        try{
            GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
            gzipOutputStream.write(content);
            gzipOutputStream.close();
        } catch(IOException e){
            throw new RuntimeException(e);
        }
        return byteArrayOutputStream.toByteArray();
    }

  private static byte[] decompress(byte[] contentBytes){
      ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
          GZIPInputStream gzip = new GZIPInputStream(new ByteArrayInputStream(contentBytes));
          int buffer = 0;
          while((buffer = gzip.read()) != -1) {
            out.write(buffer);
          }
        } catch(IOException e){
            throw new RuntimeException(e);
        }
        return out.toByteArray();
    }
 
  public void clear(final EntityPlayer player) {
    new Thread() {
      @Override
      public void run() {
        serverCompressorThread.clear(player);
        serverDecompressorThread.clear(player);
      }
    }.start();
  }
}
TOP

Related Classes of logisticspipes.ticks.ServerPacketBufferHandlerThread$ServerCompressorThread

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.