package robombs.game;
import robombs.clientserver.*;
import robombs.game.model.*;
import com.threed.jpct.*;
/**
* An extended data container that offers support for transfering vectors, matrices and such. The container
* may contains multiple data sets.
*/
public class ExtendedDataContainer extends DataContainer {
private float[] dump = new float[16];
private final static float IDENTITY_FLAG=-9999999.12345f;
// If true, all matrices will be transfered as 3x3 instead of 4x4. In the context of this game,
// this should be sufficient.
private boolean transferCompressedMatrices=true;
/**
* Create a new container.
*/
public ExtendedDataContainer() {
super();
}
/**
* Build a new extended data container from the content of a generic data container.
* @param dc DataContainer the generic data container
*/
public ExtendedDataContainer(DataContainer dc) {
super(dc);
setClientInfo(dc.getClientInfo());
setMessageType(dc.getMessageType());
}
public void add(boolean val) {
if (val) {
add((byte)1);
} else {
add((byte)0);
}
}
/**
* Add a matrix to the container.
* @param mat Matrix the matrix to add
*/
public void add(Matrix mat) {
float[] rotDump = mat.getDump();
if (transferCompressedMatrices) {
if (mat.isIdentity()) {
add(IDENTITY_FLAG);
} else {
for (int i = 0; i < rotDump.length-4; i++) {
if ((i+1)%4!=0) {
add(rotDump[i]);
} else {
if (rotDump[i]!=0) {
throw new RuntimeException("This is a 4x4 matrix ("+i+")! Compressed mode isn't possible with such data!");
}
}
}
for (int i=rotDump.length-4; i<rotDump.length-1; i++) {
if (rotDump[i]!=0) {
throw new RuntimeException("This is a 4x4 matrix ("+i+")! Compressed mode isn't possible with such data!");
}
}
}
} else {
for (int i = 0; i < rotDump.length; i++) {
add(rotDump[i]);
}
}
}
/**
* Returns the next matrix from the container (if there is one, otherwise an identity matrix will be returned).
* @return Matrix the matrix
*/
public Matrix getMatrix() {
if (hasData()) {
if (transferCompressedMatrices) {
for (int i = 0; i < 12; i++) {
if ((i+1)%4!=0) {
dump[i] = getNextFloat();
if (dump[i]==IDENTITY_FLAG) {
return new Matrix();
}
} else {
dump[i]=0;
}
}
dump[12]=0;
dump[13]=0;
dump[14]=0;
dump[15]=1;
Matrix m = new Matrix();
m.setDump(dump);
return m;
} else {
for (int i = 0; i < 16; i++) {
dump[i] = getNextFloat();
}
Matrix m = new Matrix();
m.setDump(dump);
return m;
}
} else {
return new Matrix();
}
}
/**
* Adds a new SimpleVector to the container.
* @param sv SimpleVector the vector
*/
public void add(SimpleVector sv) {
if (sv.x==0 && sv.y==0 && sv.z==0) {
add(IDENTITY_FLAG);
} else {
add(sv.x);
add(sv.y);
add(sv.z);
}
}
/**
* Adds a new LocalObject to the container.
* @param lo LocalObject the object
*/
public void add(LocalObject lo) {
add(lo.getClientID());
add(lo.getObjectID());
add((byte)lo.getType());
add(lo.getAnimation());
add(lo.getAnimationSpeed());
add(lo.getRotation());
add(lo.getPosition());
add(lo.getSpeed());
add(lo.getValue());
add(lo.getSpecialValue());
add(lo.isInvincible());
}
public void add(long val) {
long v2=(val>>32);
int i1=(int) v2;
int i2=(int) (val-(v2<<32));
add(i1);
add(i2);
}
/**
* Fills an existing local object with the data from the container. The id will be ignored.
* @param lo LocalObject the object to fill
*/
public void fillLocalObject(LocalObject lo) {
skip(); // ID nicht!
lo.setObjectID(getNextInt());
lo.setType(getNextByte());
lo.setAnimation(getNextInt());
lo.setAnimationSpeed(getNextInt());
lo.setRotation(getMatrix());
lo.setPosition(getSimpleVector());
lo.setSpeed(getSimpleVector());
lo.setValue(getNextInt());
lo.setSpecialValue(getNextLong());
lo.setInvincible(getNextBoolean());
}
public long getNextLong() {
int i1=getNextInt();
int i2=getNextInt();
long res=((long)i1<<32)+(i2>=0?(long)i2:(4294967294L+(long)i2+2));
return res;
}
public boolean getNextBoolean() {
byte b=getNextByte();
return b==1;
}
/**
* Creates and returns a new LocalObject based on the data in the container.
* @return LocalObject the object
*/
public LocalObject getLocalObject() {
LocalObject lo = new LocalObject(getNextInt(), true);
lo.setObjectID(getNextInt());
lo.setType(getNextByte());
lo.setAnimation(getNextInt());
lo.setAnimationSpeed(getNextInt());
lo.setRotation(getMatrix());
lo.setPosition(getSimpleVector());
lo.setSpeed(getSimpleVector());
lo.setValue(getNextInt());
lo.setSpecialValue(getNextLong());
lo.setInvincible(getNextBoolean());
return lo;
}
/**
* Returns the next SimpleVector from the container (is there is one, otherwise a null-vector will be returned).
* @return SimpleVector the vector
*/
public SimpleVector getSimpleVector() {
if (hasData()) {
float f=getNextFloat();
if (f==IDENTITY_FLAG) {
return new SimpleVector();
}
return new SimpleVector(f, getNextFloat(), getNextFloat());
} else {
return new SimpleVector();
}
}
}