package common;
import common.messages.PlayerMotionMessage;
//import java.util.concurrent.*;
//import java.util.ConcurrentModificationException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.LinkedList;
import java.util.Queue;
/**
* This class describes a player who is playing the game via the network
*
*/
public class RemotePlayer extends Player {
public static Logger logger = Logger.getLogger(CLIENT_LOGGER_NAME);
/**
* The most messages that we want to use at any one time
*/
public static final int MAX_SAVED_MESSAGES = 20;
/**
* The oldest message we want to consider, in seconds
*/
public static final float OLDEST_SAVED_MESSAGE = 5;
public static final boolean JUST_USE_LAST_MESSAGE = false;
protected float currentTime;
protected Position currentPosition;
protected Position currentAim;
protected int nothingRendered;
protected Queue<PlayerMotionMessage> messageList;
protected Queue<PlayerMotionMessage> renderQueue;
// private Semaphore lock = new Semaphore(1);
/**
* Creates a RemotePlayer with the specified id and name
* @param playerID The id of this player
* @param name The text name of this player
*/
public RemotePlayer(byte playerID, String name)
{
super(playerID, name);
messageList = new LinkedList<PlayerMotionMessage>();
renderQueue = new LinkedList<PlayerMotionMessage>();
currentTime = -1;
nothingRendered = 1;
logger.log(Level.FINE,"Interpolation Size: " + INTERPOLATION_SIZE + " Resend Size: " + RESEND_DELAY);
}
public void addMotionPacket(PlayerMotionMessage msg)
{
//logger.log(Level.FINE,"Queue Size: " + renderQueue.size());
messageList.add(msg);
}
public boolean animate(float dTime, float currentTime)
{
// float weight;
/*
lock.acquire();
// for (PlayerMotionMessage m : messageList)
// if ((currentTime - m.getTime()) > OLDEST_SAVED_MESSAGE)
// messageList.remove(m);
// Don't process if we do not have at least on message
if (messageList.size() < 2)
return false;
if (JUST_USE_LAST_MESSAGE)
{
int index = messageList.size() - 1;
PlayerMotionMessage mostRecent = messageList.get(index);
/*
for (PlayerMotionMessage m : messageList)
{
if (mostRecent.getTime() < m.getTime())
mostRecent = m;
}
timeD = curTime - mostRecent.getTime();
x = mostRecent.getPosition().getX();
y = mostRecent.getPosition().getY();
totalWeight = 1;
}
else
{
for (PlayerMotionMessage m : messageList)
{
}
}
lock.release();*/
/*
}
// catch (InterruptedException er)
// {
// continue;
// }
catch (ConcurrentModificationException er)
{
//continue;
return false;
}
} while (false);*/
this.currentTime = currentTime;
float totalWeight;
totalWeight = 1;
// Do we have a starting position for this remote player yet?
if(currentPosition == null) {
// Do we have an initial message?
if(messageList.peek() != null) {
currentPosition = messageList.peek().getPosition();
currentAim = messageList.poll().getAim();
}
// Do nothing if we do not
else
return false;
}
// Check if we still have interpolating points to go through
else if(renderQueue.peek() != null) {
currentPosition = renderQueue.peek().getPosition();
currentAim = renderQueue.poll().getAim();
}
// Extrapolate the next point and then interpolate between the current
// position and that point. Add the points to the rendering queue.
else if(messageList.peek() != null) {
PlayerMotionMessage pm = messageList.poll();
nothingRendered = 1;
// Get 4 seperate interpolation points
Position msgPosition = pm.getPosition();
Position msgVelocity = pm.getVelocity();
Position msgAim = pm.getAim();
// Extrapolation not working.
//System.out.println(System.currentTimeMillis() - pm.getTime());
//float extrapolatedX = msgPosition.getX() + (msgVelocity.getX() / 3f);
//msgPosition = new Position(extrapolatedX,
// getLinearInterpolant(currentPosition,msgPosition,extrapolatedX));
// Divisions for the positions and aims respectively
float posDivs = (msgPosition.getX() - currentPosition.getX())
/ INTERPOLATION_SIZE;
//float aimDivs = (msgAim.getX() - currentAim.getX())
// / INTERPOLATION_SIZE;
// Avoid divide by zero!
if(posDivs != 0) {
// Go through all the divisions
for(float i = 1f; i <= INTERPOLATION_SIZE; i++) {
// Interpolate the position
float positionX = currentPosition.getX() + (posDivs * i);
float positionY = getLinearInterpolant(msgPosition,
currentPosition,positionX);
// Avoid division by zero
/*
if(aimDivs != 0) {
float aimX = currentAim.getX() + (aimDivs * i);
float aimY = getLinearInterpolant(msgAim,
currentAim,
aimX);
msgAim = new Position(aimX,aimY);
}*/
// Add the result to the rendering queue
renderQueue.add(makeMotionMessage(new Position(positionX,
positionY),
msgVelocity,
msgAim));
}
// Use the first interpolated position/aim
currentPosition = renderQueue.peek().getPosition();
currentAim = renderQueue.poll().getAim();
}
}
else {
//logger.log(Level.FINE,"No Interpolation: " + nothingRendered++);
}
/*
if (totalWeight < 0.0001f)
{
// TODO: Add hook for missing packets here
return false;
}*/
setPosition(currentPosition.getX()/totalWeight, currentPosition.getY()/totalWeight);
aimAt(currentAim);
//System.out.println(position);
return super.animate(dTime,currentTime);
}
protected PlayerMotionMessage makeMotionMessage(Position pos, Position velocity,Position aim) {
return new PlayerMotionMessage(playerID,pos,velocity,aim,(float)System.currentTimeMillis());
}
/**
* Used to find the y value of a position given two points and the desired x.
* @param p1 The initial position.
* @param p2 The final position.
* @param x The x value of the position.
* @param y The y value of the position.
*/
protected float getLinearInterpolant(Position p1, Position p2, float x) {
return p1.getY() + ((x - p1.getX()) * ((p2.getY() - p1.getY()) / (p2.getX() - p1.getX())));
}
}