Package nallar.patched.world.tracking

Source Code of nallar.patched.world.tracking.PatchPlayerInstance$LoadRunnable

package nallar.patched.world.tracking;

import nallar.patched.annotation.Public;
import nallar.tickthreading.Log;
import nallar.tickthreading.minecraft.TickThreading;
import nallar.tickthreading.patcher.Declare;
import nallar.tickthreading.util.ChunkLoadRunnable;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.Packet51MapChunk;
import net.minecraft.network.packet.Packet52MultiBlockChange;
import net.minecraft.network.packet.Packet53BlockChange;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.PlayerInstance;
import net.minecraft.server.management.PlayerManager;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.ChunkCoordIntPair;
import net.minecraft.world.WorldServer;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.common.ForgeDummyContainer;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.world.ChunkWatchEvent;

import java.util.*;
import java.util.concurrent.*;

@Public
public abstract class PatchPlayerInstance extends PlayerInstance {
  private ConcurrentLinkedQueue<TileEntity> tilesToUpdate;
  private static final boolean rateLimitChunkUpdates = TickThreading.instance.rateLimitChunkUpdates;
  private static final byte[] unloadSequence = {0x78, (byte) 0x9C, 0x63, 0x64, 0x1C, (byte) 0xD9, 0x00, 0x00, (byte) 0x81, (byte) 0x80, 0x01, 0x01};
  @Declare
  public boolean loaded_;
  private boolean watched;
  @Declare
  public net.minecraft.world.chunk.Chunk chunk_;
  private int startTime;
  private int sentUpdates;

  public PatchPlayerInstance(PlayerManager par1PlayerManager, int par2, int par3) {
    super(par1PlayerManager, par2, par3);
  }

  public void construct() {
    tilesToUpdate = new ConcurrentLinkedQueue<TileEntity>();
    thePlayerManager.getWorldServer().theChunkProviderServer.getChunkAt(chunkLocation.chunkXPos, chunkLocation.chunkZPos, new LoadRunnable(this));
    startTime = MinecraftServer.currentTick + 30;
  }

  @Override
  public void addPlayer(final EntityPlayerMP entityPlayerMP) {
    if (this.playersInChunk.contains(entityPlayerMP)) {
      throw new IllegalStateException("Failed to add player. " + entityPlayerMP + " already is in chunk " + this.chunkLocation.chunkXPos + ", " + this.chunkLocation.chunkZPos);
    } else {
      this.playersInChunk.add(entityPlayerMP);
      if (loaded) {
        Collection<ChunkCoordIntPair> loadedChunks = entityPlayerMP.loadedChunks;
        synchronized (loadedChunks) {
          loadedChunks.add(chunkLocation);
        }
      } else {
        thePlayerManager.getWorldServer().theChunkProviderServer.getChunkAt(chunkLocation.chunkXPos, chunkLocation.chunkZPos, new AddToPlayerRunnable(entityPlayerMP, chunkLocation));
      }
    }
  }

  @Override
  @Declare
  public synchronized void clearTileCount() {
    this.numberOfTilesToUpdate = 0;
    this.flagsYAreasToUpdate = 0;
    this.watched = false;
  }

  @Override
  public void removePlayer(EntityPlayerMP entityPlayerMP) {
    if (this.playersInChunk.remove(entityPlayerMP)) {
      Packet51MapChunk packet51MapChunk = new Packet51MapChunk();
      packet51MapChunk.includeInitialize = true;
      packet51MapChunk.xCh = chunkLocation.chunkXPos;
      packet51MapChunk.zCh = chunkLocation.chunkZPos;
      packet51MapChunk.yChMax = 0;
      packet51MapChunk.yChMin = 0;
      packet51MapChunk.setData(unloadSequence);
      entityPlayerMP.playerNetServerHandler.sendPacketToPlayer(packet51MapChunk);
      Collection<ChunkCoordIntPair> loadedChunks = entityPlayerMP.loadedChunks;
      synchronized (loadedChunks) {
        loadedChunks.remove(chunkLocation);
      }

      MinecraftForge.EVENT_BUS.post(new ChunkWatchEvent.UnWatch(chunkLocation, entityPlayerMP));

      if (this.playersInChunk.isEmpty()) {
        long var2 = (long) this.chunkLocation.chunkXPos + 2147483647L | (long) this.chunkLocation.chunkZPos + 2147483647L << 32;
        this.thePlayerManager.getChunkWatchers().remove(var2);

        if (watched) {
          this.thePlayerManager.getChunkWatcherWithPlayers().remove(this);
        }

        this.thePlayerManager.getWorldServer().theChunkProviderServer.unloadChunksIfNotNearSpawn(this.chunkLocation.chunkXPos, this.chunkLocation.chunkZPos);
      }
    }
  }

  @Override
  public String toString() {
    return chunkLocation + " watched by " + Arrays.toString(playersInChunk.toArray());
  }

  @Override
  @Declare
  public void forceUpdate() {
    this.sendToAllPlayersWatchingChunk(new Packet51MapChunk(thePlayerManager.getWorldServer().getChunkFromChunkCoords(this.chunkLocation.chunkXPos, this.chunkLocation.chunkZPos), true, Integer.MAX_VALUE));
  }

  public void sendTiles() {
    HashSet<TileEntity> tileEntities = new HashSet<TileEntity>();
    for (TileEntity tileEntity = tilesToUpdate.poll(); tileEntity != null; tileEntity = tilesToUpdate.poll()) {
      tileEntities.add(tileEntity);
    }
    for (TileEntity tileEntity : tileEntities) {
      this.sendTileToAllPlayersWatchingChunk(tileEntity);
    }
    tileEntities.clear();
  }

  @Override
  public void flagChunkForUpdate(int par1, int par2, int par3) {
    if (noUpdateRequired()) {
      return;
    }
    markRequiresUpdate();

    synchronized (this) {
      this.flagsYAreasToUpdate |= 1 << (par2 >> 4);

      short mask = (short) (par1 << 12 | par3 << 8 | par2);
      short[] locationOfBlockChange = this.locationOfBlockChange;

      int tiles = numberOfTilesToUpdate;
      for (int var5 = 0; var5 < tiles; ++var5) {
        if (locationOfBlockChange[var5] == mask) {
          return;
        }
      }

      if (tiles == locationOfBlockChange.length) {
        this.locationOfBlockChange = locationOfBlockChange = Arrays.copyOf(locationOfBlockChange, locationOfBlockChange.length << 1);
      }
      locationOfBlockChange[tiles++] = mask;
      numberOfTilesToUpdate = tiles;
    }
  }

  private void markRequiresUpdate() {
    boolean requiresWatch = false;
    synchronized (this) {
      if (!watched) {
        watched = requiresWatch = true;
      }
    }
    if (requiresWatch) {
      this.thePlayerManager.getChunkWatcherWithPlayers().add(this);
    }
  }

  @Override
  @Declare
  public void updateTile(TileEntity tileEntity) {
    if (noUpdateRequired()) {
      return;
    }
    markRequiresUpdate();
    tilesToUpdate.add(tileEntity);
  }

  @Override
  public void sendTileToAllPlayersWatchingChunk(TileEntity tileEntity) {
    if (tileEntity != null) {
      Packet descriptionPacket;
      try {
        descriptionPacket = tileEntity.getDescriptionPacket();
      } catch (Throwable t) {
        Log.severe("Failed to send TileEntity description for " + Log.toString(tileEntity) + " at chunk coords " + chunkLocation, t);
        return;
      }

      if (descriptionPacket != null) {
        this.sendToAllPlayersWatchingChunk(descriptionPacket);
      }
    }
  }

  private boolean noUpdateRequired() {
    Chunk chunk = this.chunk;
    if (chunk == null || !chunk.isTerrainPopulated || playersInChunk.isEmpty()) {
      return true;
    }
    if (chunk.partiallyUnloaded) {
      this.loaded = false;
      this.chunk = null;
      thePlayerManager.getWorldServer().theChunkProviderServer.getChunkAt(chunkLocation.chunkXPos, chunkLocation.chunkZPos, new ReloadRunnable(this));
      return true;
    }
    return false;
  }

  @Override
  @Declare
  public boolean shouldPostPone(boolean squash, int currentTick) {
    if (!rateLimitChunkUpdates) {
      return false;
    }
    int runningTicks = currentTick - startTime;
    if (squash) {
      startTime = currentTick - (runningTicks /= 2);
      sentUpdates /= 2;
    }
    return (sentUpdates / (float) runningTicks) > 0.2f;
  }

  @Override
  public void sendChunkUpdate() {
    if (noUpdateRequired()) {
      clearTileCount();
      return;
    }
    sentUpdates++;
    synchronized (this) {
      int numberOfTilesToUpdate = this.numberOfTilesToUpdate;
      if (numberOfTilesToUpdate != 0) {
        short[] locationOfBlockChange = this.locationOfBlockChange;
        if (numberOfTilesToUpdate > locationOfBlockChange.length) {
          Log.warning("numberOfTilesToUpdate set too high. Got " + numberOfTilesToUpdate + " should be <= " + locationOfBlockChange.length);
          numberOfTilesToUpdate = locationOfBlockChange.length;
        }

        WorldServer worldServer = thePlayerManager.getWorldServer();
        Chunk chunk = this.chunk;
        if (numberOfTilesToUpdate == 1) {
          int x = chunkLocation.chunkXPos * 16 + (locationOfBlockChange[0] >> 12 & 15);
          int y = locationOfBlockChange[0] & 255;
          int z = chunkLocation.chunkZPos * 16 + (locationOfBlockChange[0] >> 8 & 15);
          sendToAllPlayersWatchingChunk(new Packet53BlockChange(x, y, z, worldServer));

          TileEntity tileEntity = chunk.getChunkBlockTileEntity(locationOfBlockChange[0] >> 12 & 15, locationOfBlockChange[0] & 255, locationOfBlockChange[0] >> 8 & 15);
          if (tileEntity != null) {
            tilesToUpdate.add(tileEntity);
          }
        } else {
          if (numberOfTilesToUpdate >= ForgeDummyContainer.clumpingThreshold) {
            sendToAllPlayersWatchingChunk(new Packet51MapChunk(chunk, false, flagsYAreasToUpdate));
          } else {
            sendToAllPlayersWatchingChunk(new Packet52MultiBlockChange(chunkLocation.chunkXPos, chunkLocation.chunkZPos, locationOfBlockChange, numberOfTilesToUpdate, worldServer));
          }

          for (int i = 0; i < numberOfTilesToUpdate; ++i) {
            TileEntity tileEntity = chunk.getChunkBlockTileEntity(locationOfBlockChange[i] >> 12 & 15, locationOfBlockChange[i] & 255, locationOfBlockChange[i] >> 8 & 15);
            if (tileEntity != null) {
              tilesToUpdate.add(tileEntity);
            }
          }
        }
      }
      clearTileCount();
    }
    sendTiles();
  }

  public static class AddToPlayerRunnable implements Runnable {
    private final EntityPlayerMP entityPlayerMP;
    private final ChunkCoordIntPair chunkLocation;

    public AddToPlayerRunnable(EntityPlayerMP entityPlayerMP, ChunkCoordIntPair chunkLocation) {
      this.entityPlayerMP = entityPlayerMP;
      this.chunkLocation = chunkLocation;
    }

    @Override
    public void run() {
      Collection<ChunkCoordIntPair> loadedChunks = entityPlayerMP.loadedChunks;
      synchronized (loadedChunks) {
        loadedChunks.add(chunkLocation);
      }
    }
  }

  public static class LoadRunnable extends ChunkLoadRunnable {
    final PlayerInstance playerInstance;

    public LoadRunnable(PlayerInstance playerInstance) {
      this.playerInstance = playerInstance;
    }

    @Override
    public void onLoad(Chunk chunk) {
      playerInstance.loaded = true;
      playerInstance.chunk = chunk;
    }
  }

  public static class ReloadRunnable extends LoadRunnable {
    public ReloadRunnable(final PlayerInstance playerInstance) {
      super(playerInstance);
    }

    @Override
    public void onLoad(Chunk chunk) {
      super.onLoad(chunk);
      playerInstance.forceUpdate();
    }
  }
}
TOP

Related Classes of nallar.patched.world.tracking.PatchPlayerInstance$LoadRunnable

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.