package speedytools.clientside.selections;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraft.block.Block;
import net.minecraft.util.BlockPos;
import net.minecraft.world.World;
import speedytools.clientside.network.PacketHandlerRegistryClient;
import speedytools.clientside.network.PacketSenderClient;
import speedytools.clientside.tools.SelectionPacketSender;
import speedytools.common.blocks.BlockWithMetadata;
import speedytools.common.network.Packet250ServerSelectionGeneration;
import speedytools.common.network.Packet250Types;
import speedytools.common.network.multipart.MultipartOneAtATimeReceiver;
import speedytools.common.network.multipart.MultipartPacket;
import speedytools.common.network.multipart.Packet250MultipartSegment;
import speedytools.common.network.multipart.SelectionPacket;
import speedytools.common.selections.BlockVoxelMultiSelector;
import speedytools.common.selections.FillAlgorithmSettings;
import speedytools.common.selections.VoxelSelectionWithOrigin;
import speedytools.common.utilities.ErrorLog;
import speedytools.common.utilities.QuadOrientation;
import speedytools.common.utilities.ResultWithReason;
/**
* Created by TheGreyGhost on 26/09/14.
* Used by the client to track the current tool voxel selection and coordinate any updates with the server
*/
public class ClientVoxelSelection
{
public ClientVoxelSelection(PacketHandlerRegistryClient packetHandlerRegistryClient,
SelectionPacketSender i_selectionPacketSender, PacketSenderClient i_packetSenderClient)
{
selectionPacketSender = i_selectionPacketSender;
packetSenderClient = i_packetSenderClient;
incomingVoxelSelection = new MultipartOneAtATimeReceiver();
incomingVoxelSelection.registerPacketCreator(new SelectionPacket.SelectionPacketCreator());
incomingVoxelSelection.registerLinkageFactory(new IncomingSelectionLinkageFactory());
incomingVoxelSelection.setPacketSender(packetSenderClient);
incomingVoxelSelection.registerLinkageFactory(this.new IncomingSelectionLinkageFactory());
Packet250MultipartSegment.registerHandler(packetHandlerRegistryClient, this.new IncomingSelectionPacketHandler(), Side.CLIENT,
Packet250Types.PACKET250_SELECTION_PACKET);
Packet250ServerSelectionGeneration.registerHandler(packetHandlerRegistryClient, this.new IncomingPacketHandler(), Side.CLIENT);
}
private SelectionPacketSender selectionPacketSender;
private PacketSenderClient packetSenderClient;
private enum ClientSelectionState {IDLE, GENERATING, CREATING_RENDERLISTS, COMPLETE}
private enum OutgoingTransmissionState {IDLE, SENDING, COMPLETE, NOT_REQUIRED}
private enum ServerSelectionState {IDLE, WAITING_FOR_START, GENERATING, RECEIVING, CREATING_RENDERLISTS, COMPLETE}
public enum VoxelSelectionState {NO_SELECTION, GENERATING, READY_FOR_DISPLAY}
private ClientSelectionState clientSelectionState = ClientSelectionState.IDLE;
private OutgoingTransmissionState outgoingTransmissionState = OutgoingTransmissionState.IDLE;
private ServerSelectionState serverSelectionState = ServerSelectionState.IDLE;
private Packet250ServerSelectionGeneration packet250ServerSelectionGeneration; // if needed for server selection generation
/**
* find out whether the voxelselection is ready for display yet
* @return
*/
public VoxelSelectionState getReadinessForDisplaying()
{
assert checkInvariants();
switch (clientSelectionState) {
case IDLE: return VoxelSelectionState.NO_SELECTION;
case COMPLETE: {
return VoxelSelectionState.READY_FOR_DISPLAY;
}
case GENERATING:
case CREATING_RENDERLISTS: {
return VoxelSelectionState.GENERATING;
}
default: {
ErrorLog.defaultLog().severe("Invalid clientSelectionState " + clientSelectionState + " in " + this.getClass().getName());
return VoxelSelectionState.NO_SELECTION;
}
}
}
/**
* returns true if the server has a complete copy of the selection, ready for a tool action
* @return
*/
public boolean isSelectionCompleteOnServer()
{
if (clientSelectionState != ClientSelectionState.COMPLETE) return false;
// is complete if either:
// 1) the client selection has been fully sent, or
// 2) the client selection had missing voxels and the server selection has been generated
switch (outgoingTransmissionState) {
case COMPLETE: {
return true;
}
case NOT_REQUIRED: {
if (serverSelectionState == ServerSelectionState.RECEIVING
|| serverSelectionState == ServerSelectionState.CREATING_RENDERLISTS
|| serverSelectionState == ServerSelectionState.COMPLETE) {
return true;
}
return false;
}
case SENDING:
case IDLE: {
return false;
}
default: {
ErrorLog.defaultLog().severe("Invalid outgoingTransmissionState " + outgoingTransmissionState + " in " + this.getClass().getName());
return false;
}
}
}
/** return true if the selection is currently being generated, either locally or on the server.
* i.e. - returns false if IDLE or COMPLETE, true otherwise.
* @return
*/
public boolean isGenerationInProgress()
{
if ( (clientSelectionState != ClientSelectionState.IDLE && clientSelectionState != ClientSelectionState.COMPLETE)
|| (serverSelectionState != ServerSelectionState.IDLE && serverSelectionState != ServerSelectionState.COMPLETE
&& serverSelectionState != ServerSelectionState.CREATING_RENDERLISTS )
) {
return true;
} else {
return false;
}
}
public final float FULLY_COMPLETE = 1.000F;
private final float FULLY_COMPLETE_PLUS_DELTA = FULLY_COMPLETE + 0.001F;
/**
* returns the progress of the selection generation on (or transmission to ) server
* @return [0 .. 1] for the estimated fractional completion of the voxel selection generation / transmission
* returns 0 if not started yet, returns > FULLY_COMPLETE if complete
*/
public float getServerSelectionFractionComplete()
{
if (clientSelectionState != ClientSelectionState.COMPLETE) return 0.0F;
switch (outgoingTransmissionState) {
case IDLE: {
return 0.0F;
}
case COMPLETE: {
return FULLY_COMPLETE_PLUS_DELTA;
}
case NOT_REQUIRED: {
if (serverSelectionState == ServerSelectionState.RECEIVING
|| serverSelectionState == ServerSelectionState.CREATING_RENDERLISTS
|| serverSelectionState == ServerSelectionState.COMPLETE) {
return FULLY_COMPLETE_PLUS_DELTA;
}
return serverGenerationFractionComplete;
}
case SENDING: {
return selectionPacketSender.getCurrentPacketPercentComplete() / 100.0F;
}
default: {
ErrorLog.defaultLog().severe("Invalid outgoingTransmissionState " + outgoingTransmissionState + " in " + this.getClass().getName());
return 0.0F;
}
}
}
/**
* If the voxel selection is currently being generated, return the fraction complete (local selection, not server generation)
* @return [0 .. 1] for the estimated fractional completion of the voxel selection generation
* returns 0 if not started yet, returns 1.000F if complete
*/
public float getLocalGenerationFractionComplete()
{
final float SELECTION_GENERATION_FULL = 0.75F;
assert checkInvariants();
switch (clientSelectionState) {
case IDLE: return 0.0F;
case COMPLETE: return 1.000F;
case GENERATING: {
return localSelectionGenerationFractionComplete * SELECTION_GENERATION_FULL;
}
case CREATING_RENDERLISTS: {
float scaledProgress = SELECTION_GENERATION_FULL * localSelectionGenerationFractionComplete;
return scaledProgress + (1.0F - scaledProgress) * renderlistGenerationFractionComplete;
}
default: {
ErrorLog.defaultLog().severe("Invalid clientSelectionState " + clientSelectionState + " in " + this.getClass().getName());
return 0.0F;
}
}
}
/**
* test this class to see if all its invariants are still valid
* @return true if all invariants are fulfilled
*/
private boolean checkInvariants()
{
if (clientSelectionState == ClientSelectionState.IDLE && serverSelectionState != ServerSelectionState.IDLE) return false;
if (clientSelectionState != ClientSelectionState.IDLE && clientVoxelMultiSelector == null) return false;
if ((clientSelectionState == ClientSelectionState.CREATING_RENDERLISTS ||
clientSelectionState == ClientSelectionState.COMPLETE) && voxelSelectionRenderer == null) return false;
if (serverSelectionState == ServerSelectionState.COMPLETE && serverVoxelSelection == null) return false;
return true;
}
/**
* If there is a current selection, destroy it. No effect if waiting for the server to do something.
*/
public void reset()
{
clientVoxelMultiSelector = null;
if (voxelSelectionRenderer != null) {
voxelSelectionRenderer.releaseFinal();
voxelSelectionRenderer = null;
selectionBeingDisplayed = null;
}
clientSelectionState = ClientSelectionState.IDLE;
if (serverSelectionState != ServerSelectionState.IDLE) {
Packet250ServerSelectionGeneration abortPacket = Packet250ServerSelectionGeneration.abortSelectionGeneration(currentSelectionUniqueID);
packetSenderClient.sendPacket(abortPacket);
serverSelectionState = ServerSelectionState.IDLE;
}
outgoingTransmissionState = OutgoingTransmissionState.IDLE;
selectionPacketSender.reset();
}
/**
* If selection generation is underway, abort it. If already complete, do nothing.
*/
public void abortGenerationIfUnderway()
{
if (clientSelectionState == ClientSelectionState.GENERATING || clientSelectionState == ClientSelectionState.CREATING_RENDERLISTS) {
reset();
} else {
if (serverSelectionState != ServerSelectionState.IDLE
&& serverSelectionState != ServerSelectionState.COMPLETE
&& serverSelectionState != ServerSelectionState.CREATING_RENDERLISTS) {
Packet250ServerSelectionGeneration abortPacket = Packet250ServerSelectionGeneration.abortSelectionGeneration(currentSelectionUniqueID);
packetSenderClient.sendPacket(abortPacket);
serverSelectionState = ServerSelectionState.IDLE;
}
}
}
private void initialiseForGeneration()
{
reset();
selectionUpdatedFlag = false;
selectionBeingDisplayed = null;
clientSelectionState = ClientSelectionState.GENERATING;
outgoingTransmissionState = OutgoingTransmissionState.IDLE;
localSelectionGenerationFractionComplete = 0;
renderlistGenerationFractionComplete = 0;
clientVoxelMultiSelector = new BlockVoxelMultiSelector();
currentSelectionUniqueID = nextUniqueID++;
}
/**
* Create a new selection consisting of all non-air voxels in the given boundary region
* If a selection is already in place, cancel it.
* @param thePlayer
* @param boundaryCorner1
* @param boundaryCorner2
* @return
*/
public ResultWithReason createFullBoxSelection(EntityPlayerSP thePlayer, BlockPos boundaryCorner1, BlockPos boundaryCorner2)
{
initialiseForGeneration();
clientVoxelMultiSelector.selectAllInBoxStart(thePlayer.worldObj, boundaryCorner1, boundaryCorner2);
packet250ServerSelectionGeneration = Packet250ServerSelectionGeneration.performAllInBox(currentSelectionUniqueID, boundaryCorner1, boundaryCorner2);
return ResultWithReason.success();
}
/**
* initialise conversion of the selected fill to a VoxelSelection
* If a selection is already in place, cancel it.
* @param fillAlgorithmSettings the fill settings to use
* @param i_overrideTexture the block texture to use when displaying the selection; null for use world block at each [x,y,z]
*/
public ResultWithReason createUnboundFillSelection(EntityPlayerSP thePlayer, FillAlgorithmSettings fillAlgorithmSettings, IBlockState i_overrideTexture)
{
initialiseForGeneration();
overrideTexture = i_overrideTexture;
clientVoxelMultiSelector.selectUnboundFillStart(thePlayer.worldObj, fillAlgorithmSettings);
packet250ServerSelectionGeneration = Packet250ServerSelectionGeneration.performUnboundFill(fillAlgorithmSettings, currentSelectionUniqueID);
return ResultWithReason.success();
}
/**
* initialise conversion of the selected fill to a VoxelSelection
* Will not fill any blocks outside of the box defined by corner1 and corner2
* If a selection is already in place, cancel it.
* @param fillAlgorithmSettings the fill settings to use
* @param i_overrideTexture the block texture to use when displaying the selection; null for use world block at each [x,y,z]
* @param boundaryCorner1 first corner of the fill boundary
* @param boundaryCorner2 opposite corner of the fill boundary
*/
public ResultWithReason createBoundFillSelection(EntityPlayerSP thePlayer, FillAlgorithmSettings fillAlgorithmSettings, IBlockState i_overrideTexture,
BlockPos boundaryCorner1, BlockPos boundaryCorner2)
{
initialiseForGeneration();
overrideTexture = i_overrideTexture;
clientVoxelMultiSelector.selectBoundFillStart(thePlayer.worldObj, fillAlgorithmSettings, boundaryCorner1, boundaryCorner2);
packet250ServerSelectionGeneration = Packet250ServerSelectionGeneration.performBoundFill(fillAlgorithmSettings, currentSelectionUniqueID, boundaryCorner1, boundaryCorner2);
return ResultWithReason.success();
}
// public BlockVoxelMultiSelector.Matcher convertMatcherType(Packet250ServerSelectionGeneration.MatcherType matcherType)
// {
// switch (matcherType) {
// case ANY_NON_AIR: {
// return BlockVoxelMultiSelector.Matcher.ALL_NON_AIR;
// }
// case STARTING_BLOCK_ONLY: {
// return BlockVoxelMultiSelector.Matcher.STARTING_BLOCK_ONLY;
// }
// default: {
// ErrorLog.defaultLog().severe("Illegal matcherType:" + matcherType);
// return null;
// }
// }
// }
/**
* Returns true if the selection has been updated since the last call to this function; resets flag after the call.
* (If true, the selection render information, origin, and QuadOrientation will need to be re-retrieved).
* @return
*/
public boolean hasSelectionBeenUpdated() {
boolean retval = selectionUpdatedFlag;
selectionUpdatedFlag = false;
return retval;
}
/** return a copy of the selection's origin at the time of its creation from the world
* If not available (IDLE or GENERATING), causes an error
* @return
*/
public BlockPos getSourceWorldOrigin() {
if (clientSelectionState != ClientSelectionState.COMPLETE && clientSelectionState != ClientSelectionState.CREATING_RENDERLISTS) {
ErrorLog.defaultLog().severe("called getInitialOrigin for invalid state: " + clientSelectionState);
return new BlockPos(0, 0, 0);
}
return new BlockPos(selectionBeingDisplayed.getWxOrigin(), selectionBeingDisplayed.getWyOrigin(), selectionBeingDisplayed.getWzOrigin());
}
/** return a copy of the selection's QuadOrientation at the time of its creation from the world.
* If not available (IDLE or GENERATING), causes an error
*/
public QuadOrientation getSourceQuadOrientation() {
if (clientSelectionState != ClientSelectionState.COMPLETE && clientSelectionState != ClientSelectionState.CREATING_RENDERLISTS) {
ErrorLog.defaultLog().severe("called getInitialQuadOrientation for invalid state: " + clientSelectionState);
return new QuadOrientation(0, 0, 1, 1);
}
return new QuadOrientation(0, 0, selectionBeingDisplayed.getxSize(), selectionBeingDisplayed.getzSize());
}
/** called once per tick on the client side
* used to advance through the various states of the selection, eg generation, transmission, etc
* @param maxDurationInNS = the maximum time to spend on selection generation, in NS
*/
public void performTick(World world, long maxDurationInNS) {
++tickCount;
assert checkInvariants();
// System.out.println("Client:" + clientSelectionState + ", Server:" + serverSelectionState + ", Outgoing XmissionState:" + outgoingTransmissionState);
switch (clientSelectionState) {
case IDLE:
case COMPLETE: {
break;
}
case GENERATING: { // keep generating; if complete, switch to creation of rendering lists
float progress = clientVoxelMultiSelector.continueSelectionGeneration(world, maxDurationInNS);
if (progress >= 0) {
localSelectionGenerationFractionComplete = progress;
} else { // -1 means complete
localSelectionGenerationFractionComplete = 1.0F;
// selectionPacketSender.reset();
if (clientVoxelMultiSelector.isEmpty()) {
clientSelectionState = ClientSelectionState.IDLE;
} else {
VoxelSelectionWithOrigin clientVoxelSelection = clientVoxelMultiSelector.getSelection();
// System.out.println("Client selection origin: [" + clientVoxelSelection.getWxOrigin()
// + ", " + clientVoxelSelection.getWyOrigin()
// + ", " + clientVoxelSelection.getWzOrigin()+"]");
clientSelectionState = ClientSelectionState.CREATING_RENDERLISTS;
BlockPos selectionInitialOrigin = clientVoxelMultiSelector.getWorldOrigin();
if (voxelSelectionRenderer == null) {
TextureManager textureManager = Minecraft.getMinecraft().getTextureManager();
voxelSelectionRenderer = new BlockVoxelMultiSelectorRenderer(textureManager);
}
voxelSelectionRenderer.createRenderListStart(world, overrideTexture, selectionInitialOrigin.getX(), selectionInitialOrigin.getY(),
selectionInitialOrigin.getZ(), clientVoxelMultiSelector.getSelection(), clientVoxelMultiSelector.getUnavailableVoxels());
}
}
break;
}
case CREATING_RENDERLISTS: {
BlockPos wOrigin = clientVoxelMultiSelector.getWorldOrigin();
float progress = voxelSelectionRenderer.createRenderListContinue(world, wOrigin.getX(), wOrigin.getY(), wOrigin.getZ(),
clientVoxelMultiSelector.getSelection(), clientVoxelMultiSelector.getUnavailableVoxels(), maxDurationInNS);
if (progress >= 0) {
renderlistGenerationFractionComplete = progress;
} else { // -1 means finished
clientSelectionState = ClientSelectionState.COMPLETE;
selectionBeingDisplayed = clientVoxelMultiSelector.getSelection();
selectionUpdatedFlag = true;
}
break;
}
default: {
ErrorLog.defaultLog().severe("Invalid clientSelectionState " + clientSelectionState + " in " + this.getClass().getName());
break;
}
}
final int TICKS_BETWEEN_STATUS_REQUEST = 20;
switch (serverSelectionState) {
case IDLE: {
if (clientSelectionState != ClientSelectionState.IDLE && clientVoxelMultiSelector.containsUnavailableVoxels()) { // need the server to generate the selection.
serverSelectionState = ServerSelectionState.WAITING_FOR_START;
packetSenderClient.sendPacket(packet250ServerSelectionGeneration);
lastStatusRequestTick = tickCount;
serverGenerationFractionComplete = 0;
incomingSelectionFractionComplete = 0;
incomingSelectionUniqueID = null;
serverVoxelSelection = null;
}
break;
}
case WAITING_FOR_START: {
sendStatusRequestIfDue(TICKS_BETWEEN_STATUS_REQUEST);
if (serverGenerationFractionComplete > 0) {
serverSelectionState = ServerSelectionState.GENERATING;
}
break;
}
// for GENERATING and RECEIVING, the server 'pushes' the packet across - see code in IncomingSelectionLinkage
case GENERATING: {
if (incomingSelectionUniqueID != null) { // the packet linkage has started receiving a new selection
serverSelectionState = ServerSelectionState.RECEIVING;
}
sendStatusRequestIfDue(TICKS_BETWEEN_STATUS_REQUEST);
break;
}
case RECEIVING: {
if (serverVoxelSelection != null && clientSelectionState == ClientSelectionState.COMPLETE) { // incoming packet transmission has finished and client selection is done
serverSelectionState = ServerSelectionState.CREATING_RENDERLISTS;
voxelSelectionRenderer.resize(serverVoxelSelection.getWxOrigin(), serverVoxelSelection.getWyOrigin(), serverVoxelSelection.getWzOrigin(),
serverVoxelSelection.getxSize(), serverVoxelSelection.getySize(), serverVoxelSelection.getzSize());
voxelSelectionRenderer.refreshRenderListStart();
selectionBeingDisplayed = serverVoxelSelection;
selectionUpdatedFlag = true;
}
break;
}
case CREATING_RENDERLISTS: {
VoxelSelectionWithOrigin nullSelection = new VoxelSelectionWithOrigin(0, 0, 0, 1, 1, 1);
float progress = voxelSelectionRenderer.refreshRenderListContinue(world, serverVoxelSelection, nullSelection, maxDurationInNS);
if (progress < 0) {
boolean noFogLeft = voxelSelectionRenderer.updateWithLoadedChunks(world, serverVoxelSelection, nullSelection, maxDurationInNS);
if (noFogLeft) {
serverSelectionState = ServerSelectionState.COMPLETE;
}
}
break;
}
case COMPLETE: {
break;
}
default: {
ErrorLog.defaultLog().severe("Invalid serverSelectionState " + serverSelectionState + " in " + this.getClass().getName());
break;
}
}
switch (outgoingTransmissionState) {
case IDLE: {
if (clientSelectionState == ClientSelectionState.COMPLETE) {
if (clientVoxelMultiSelector.containsUnavailableVoxels()) {
outgoingTransmissionState = OutgoingTransmissionState.NOT_REQUIRED;
} else {
boolean success = selectionPacketSender.startSendingSelection(clientVoxelMultiSelector);
if (success) {
outgoingTransmissionState = OutgoingTransmissionState.SENDING;
}
}
}
break;
}
case NOT_REQUIRED:
case COMPLETE: {
break;
}
case SENDING: {
SelectionPacketSender.PacketProgress packetProgress = selectionPacketSender.getCurrentPacketProgress();
if (packetProgress != SelectionPacketSender.PacketProgress.SENDING) {
if (packetProgress == SelectionPacketSender.PacketProgress.COMPLETED) {
outgoingTransmissionState = OutgoingTransmissionState.COMPLETE;
} else {
outgoingTransmissionState = OutgoingTransmissionState.IDLE; // Abort or return to Idle
}
}
break;
}
default: {
ErrorLog.defaultLog().severe("Invalid outgoingTransmissionState " + outgoingTransmissionState + " in " + this.getClass().getName());
break;
}
}
if (clientSelectionState == ClientSelectionState.IDLE) {
selectionPacketSender.reset();
}
// // if the selection has been freshly generated, keep trying to transmit it until we successfully start transmission
// if (clientSelectionState == ClientSelectionState.COMPLETE
// && selectionPacketSender.getCurrentPacketProgress() == SelectionPacketSender.PacketProgress.IDLE) {
// selectionPacketSender.startSendingSelection(clientVoxelMultiSelector);
// }
selectionPacketSender.tick();
}
private void sendStatusRequestIfDue(int ticksBetweenStatusRequests)
{
if ((tickCount - lastStatusRequestTick) >= ticksBetweenStatusRequests) {
Packet250ServerSelectionGeneration packet = Packet250ServerSelectionGeneration.requestStatus(currentSelectionUniqueID);
packetSenderClient.sendPacket(packet);
lastStatusRequestTick = tickCount;
}
}
private BlockVoxelMultiSelector clientVoxelMultiSelector;
private int currentSelectionUniqueID;
private static int nextUniqueID = -2366236; // arbitrary
private int tickCount;
private int lastStatusRequestTick;
private IBlockState overrideTexture; // for the complex fill; the block that will fill the displayed selection; null for no override
public BlockVoxelMultiSelectorRenderer getVoxelSelectionRenderer() {
return voxelSelectionRenderer;
}
private BlockVoxelMultiSelectorRenderer voxelSelectionRenderer;
private float renderlistGenerationFractionComplete;
private float localSelectionGenerationFractionComplete;
private boolean selectionUpdatedFlag;
private VoxelSelectionWithOrigin selectionBeingDisplayed;
private float serverGenerationFractionComplete;
private float incomingSelectionFractionComplete;
private Integer incomingSelectionUniqueID;
private VoxelSelectionWithOrigin serverVoxelSelection;
public class IncomingSelectionPacketHandler implements Packet250MultipartSegment.PacketHandlerMethod {
@Override
public boolean handlePacket(Packet250MultipartSegment packet250MultipartSegment, MessageContext ctx) {
boolean success = incomingVoxelSelection.processIncomingPacket(packet250MultipartSegment);
return success;
}
}
private IncomingSelectionPacketHandler incomingSelectionPacketHandler;
private MultipartOneAtATimeReceiver incomingVoxelSelection;
// processes incoming status information about the server selection generation commands
public class IncomingPacketHandler implements Packet250ServerSelectionGeneration.PacketHandlerMethod
{
public Packet250ServerSelectionGeneration handlePacket(Packet250ServerSelectionGeneration packet, MessageContext ctx)
{
switch (packet.getCommand()) {
case STATUS_REPLY: {
if (packet.getUniqueID() == currentSelectionUniqueID) { // ignore any messages not about the current selection
serverGenerationFractionComplete = packet.getCompletedFraction();
}
break;
}
default: {
ErrorLog.defaultLog().severe("Invalid command received by ClientVoxelSelection: " + packet.getCommand());
return null;
}
}
return null;
}
}
/**
* The linkage is used to convey information about the process of the incoming selection
*/
public class IncomingSelectionLinkage implements MultipartOneAtATimeReceiver.PacketLinkage
{
public IncomingSelectionLinkage(SelectionPacket linkedPacket) {
// System.out.println("ClientVoxelSelection::VoxelPacketLinkage constructed for Selection Packet ID " + linkedPacket.getUniqueID()); //todo remove
myLinkedPacket = linkedPacket;
incomingSelectionUniqueID = linkedPacket.getUniqueID();
incomingSelectionFractionComplete = 0;
// myPlayer = new WeakReference<EntityPlayerMP>(player);
}
@Override
public void progressUpdate(int percentComplete) {
incomingSelectionFractionComplete = percentComplete;
}
@Override
public void packetCompleted() {
// System.out.println("ClientVoxelSelection::VoxelPacketLinkage - completed packet ID " + myLinkedPacket.getUniqueID()); // todo remove
if (myLinkedPacket == null) return;
serverVoxelSelection = myLinkedPacket.retrieveVoxelSelection();
}
@Override
public void packetAborted() {}
@Override
public int getPacketID() {return myLinkedPacket.getUniqueID();}
// private WeakReference<EntityPlayerMP> myPlayer;
private SelectionPacket myLinkedPacket;
}
/**
* The Factory creates a new linkage, which will be used to communicate the packet receiving progress to the recipient
*/
public class IncomingSelectionLinkageFactory implements MultipartOneAtATimeReceiver.PacketReceiverLinkageFactory
{
// public IncomingSelectionLinkageFactory() {
// myPlayer = new WeakReference<EntityPlayerMP>(playerMP);
// }
@Override
public IncomingSelectionLinkage createNewLinkage(MultipartPacket linkedPacket) {
assert linkedPacket instanceof SelectionPacket;
return ClientVoxelSelection.this.new IncomingSelectionLinkage((SelectionPacket)linkedPacket);
}
// private WeakReference<EntityPlayerMP> myPlayer;
}
}