Package logisticspipes.ticks

Source Code of logisticspipes.ticks.ClientPacketBufferHandlerThread

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.LinkedList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
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.ClientTickEvent;
import cpw.mods.fml.common.gameevent.TickEvent.Phase;

public class ClientPacketBufferHandlerThread {

  private class ClientCompressorThread extends Thread {
    //list of C->S packets to be serialized and compressed
    private final LinkedList<ModernPacket> clientList = new LinkedList<ModernPacket>();
    //serialized but still uncompressed C->S data
    private byte[] clientBuffer = new 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 boolean clear = false;
   
    private Lock clearLock = new ReentrantLock();

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

    @Override
    public void run() {
      while(true) {
        try {
          synchronized(clientList) {
            if(!pause && clientList.size() > 0) {
              ByteArrayOutputStream out = new ByteArrayOutputStream();
              DataOutputStream data = new DataOutputStream(out);
              data.write(clientBuffer);
              LinkedList<ModernPacket> packets = clientList;
              clearLock.lock();
              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());
              }
              packets.clear();
              clearLock.unlock();
              clientBuffer = out.toByteArray();
            }
          }
          //Send Content
          if(clientBuffer.length > 0) {
            while(clientBuffer.length > 1024 * 32) {
              byte[] sendbuffer = Arrays.copyOf(clientBuffer, 1024 * 32);
              clientBuffer = Arrays.copyOfRange(clientBuffer, 1024 * 32, clientBuffer.length);
              byte[] compressed = compress(sendbuffer);
              MainProxy.sendPacketToServer(PacketHandler.getPacket(BufferTransfer.class).setContent(compressed));
            }
            byte[] sendbuffer = clientBuffer;
            clientBuffer = new byte[]{};
            byte[] compressed = compress(sendbuffer);
            MainProxy.sendPacketToServer(PacketHandler.getPacket(BufferTransfer.class).setContent(compressed));
          }
        } catch (IOException e) {
          e.printStackTrace();
        }
        synchronized(clientList) {
          while(pause || clientList.size() == 0) {
            try {
              clientList.wait();
            } catch (InterruptedException e) {}
          }
        }
        if(clear) {
          clear = false;
          clientBuffer = new byte[]{};
        }
      }
    }

    public void addPacketToCompressor(ModernPacket packet) {
      synchronized(clientList) {
        clientList.add(packet);
        if(!pause) {
          clientList.notify();
        }
      }
    }

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

    public void clear() {
      clear = true;
      new Thread() {
        @Override
        public void run() {
          clearLock.lock();
          clientList.clear();
          clearLock.unlock();
        }
      }.start();
    }
  }
  private final ClientCompressorThread clientCompressorThread = new ClientCompressorThread();

  private class ClientDecompressorThread extends Thread {
    //Received compressed S->C data
    private final LinkedList<byte[]> queue = new LinkedList<byte[]>();
    //decompressed serialized S->C data
    private byte[] ByteBuffer = new byte[]{};
    //FIFO for deserialized S->C packets, decompressor adds, tickEnd removes
    private final LinkedList<Pair<EntityPlayer, byte[]>> PacketBuffer = new LinkedList<Pair<EntityPlayer, byte[]>>();
    //List of packets that that should be reattempted to apply in the next tick
    private final LinkedList<Pair<EntityPlayer, ModernPacket>> retryPackets = new LinkedList<Pair<EntityPlayer,ModernPacket>>();
    //Clear content on next tick
    private boolean clear = false;

    public ClientDecompressorThread() {
      super("LogisticsPipes Packet Decompressor Client");
      this.setDaemon(true);
      this.start();
    }
   
    public void clientTickEnd() {
      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;
          synchronized(queue) {
            if(queue.size() > 0) {
              flag = true;
              buffer = queue.getFirst();
              queue.removeFirst();
            }
          }
          if(flag && buffer != null) {
            byte[] packetbytes = decompress(buffer);
            byte[] newBuffer = new byte[packetbytes.length + ByteBuffer.length];
            System.arraycopy(ByteBuffer, 0, newBuffer, 0, ByteBuffer.length);
            System.arraycopy(packetbytes, 0, newBuffer, ByteBuffer.length, packetbytes.length);
            ByteBuffer = newBuffer;
          }
        }
        while(flag);

        while(ByteBuffer.length >= 4) {
          int size = ((ByteBuffer[0] & 255) << 24) + ((ByteBuffer[1] & 255) << 16) + ((ByteBuffer[2] & 255) << 8) + ((ByteBuffer[3] & 255) << 0);
          if(size + 4 > ByteBuffer.length) {
            break;
          }
          byte[] packet = Arrays.copyOfRange(ByteBuffer, 4, size + 4);
          ByteBuffer = Arrays.copyOfRange(ByteBuffer, size + 4, ByteBuffer.length);
          synchronized (PacketBuffer) {
            PacketBuffer.add(new Pair<EntityPlayer, byte[]>(MainProxy.proxy.getClientPlayer(), packet));
          }
        }
        synchronized(queue) {
          while(queue.size() == 0) {
            try {
              queue.wait();
            } catch (InterruptedException e) {}
          }
        }
        if(clear) {
          clear = false;
          ByteBuffer = new byte[]{};
        }
      }
    }

    public void handlePacket(byte[] content) {
      synchronized(queue) {
        queue.addLast(content);
        queue.notify();
      }
    }

    public void clear() {
      clear = true;
      queue.clear();
      retryPackets.clear();
    }
   
    public void queueFailedPacket(ModernPacket packet, EntityPlayer player) {
      retryPackets.add(new Pair<EntityPlayer, ModernPacket>(player, packet));
    }
  }
  private final ClientDecompressorThread clientDecompressorThread = new ClientDecompressorThread();

  public ClientPacketBufferHandlerThread() {
  }

  public void clientTick(ClientTickEvent event) {
    if(event.phase != Phase.END) return;
    clientDecompressorThread.clientTickEnd();
  }
 
  public void setPause(boolean flag) {
    clientCompressorThread.setPause(flag);
  }

  public void addPacketToCompressor(ModernPacket packet) {
    clientCompressorThread.addPacketToCompressor(packet);
  }

  public void handlePacket(byte[] content) {
    clientDecompressorThread.handlePacket(content);
  }

  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() {
    clientCompressorThread.clear();
    clientDecompressorThread.clear();
  }
 
  public void queueFailedPacket(ModernPacket packet, EntityPlayer player) {
    clientDecompressorThread.queueFailedPacket(packet, player);
  }
}
TOP

Related Classes of logisticspipes.ticks.ClientPacketBufferHandlerThread

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.