package se.rhel.network.model;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Quaternion;
import com.badlogic.gdx.math.Vector3;
import se.rhel.event.EventType;
import se.rhel.event.Events;
import se.rhel.event.ModelEvent;
import se.rhel.model.*;
import se.rhel.model.component.GameObject;
import se.rhel.model.component.NetworkComponent;
import se.rhel.model.entity.ControlledPlayer;
import se.rhel.model.entity.IPlayer;
import se.rhel.model.entity.Player;
import se.rhel.model.physics.RayVector;
import se.rhel.model.weapon.Grenade;
import se.rhel.view.input.PlayerInput;
import java.util.HashMap;
/**
* Group: Multiplayer
*/
public class ClientWorldModel extends BaseWorldModel implements INetworkWorldModel {
private Vector3 mLastKnownPosition = Vector3.Zero;
private float mLastKnownRotation = 0f;
private HashMap<Integer, Matrix4> mTargetGrePositions = new HashMap<>();
private HashMap<Integer, Vector3[]> mTargetPlaPositions = new HashMap<>();
private Player mPlayer;
private int mClientId;
public ClientWorldModel(int clientId, Events events) {
super(events);
mClientId = clientId;
mPlayer = new Player(new Vector3(0, 10, 0), getBulletWorld());
setPlayer(clientId, mPlayer);
}
@Override
public void update(float delta) {
super.update(delta);
updatePlayer(delta);
for(IPlayer p : getControlledPlayers()) {
// p.update(delta);
int id = ((NetworkComponent)((ControlledPlayer)p).getComponent(NetworkComponent.class)).getID();
Vector3[] temp = mTargetPlaPositions.get(id);
if(temp != null && temp.length == 2) {
if(PlayerInput.CLIENT_INTERPOLATION) {
Vector3 v = p.getPosition().slerp(temp[1], 0.1f);
((ControlledPlayer) p).rotateAndTranslate(temp[0], v);
} else {
((ControlledPlayer) p).rotateAndTranslate(temp[0], temp[1]);
}
}
p.update(delta);
}
for (Grenade grenade : getGrenades()) {
// The grenade doesn't have to be updated on client
// g.update(delta);
int id = ((NetworkComponent)grenade.getComponent(NetworkComponent.class)).getID();
Matrix4 toTemp = mTargetGrePositions.get(id);
if(toTemp != null) {
if(PlayerInput.CLIENT_INTERPOLATION) {
// Interpolate position..
Vector3 v = new Vector3();
v = grenade.getPosition().slerp(toTemp.getTranslation(v), 0.1f);
// .. but just take the rotation from the server
Matrix4 newM = new Matrix4(v, toTemp.getRotation(new Quaternion()), new Vector3(1f, 1f, 1f));
grenade.getTransformation().set(newM);
} else {
grenade.getTransformation().set(toTemp);
}
}
if(!grenade.isAlive()) {
mEvents.notify(new ModelEvent(EventType.EXPLOSION, grenade.getPosition()));
destroyGameObject(grenade);
removeGrenade(grenade);
}
}
}
/**
* A Grenade should be updated on client from server
* @param grenadeId
* @param newPos
*/
public void updateGrenade(int grenadeId, Vector3 newPos, Quaternion newRotation, boolean isAlive) {
for (Grenade grenade : getGrenades()) {
// Check if the right component is there, well, it should
if(!grenade.hasComponent(NetworkComponent.class))
return;
// We're looking for a special grenade
int currId = ((NetworkComponent)grenade.getComponent(NetworkComponent.class)).getID();
if(currId == grenadeId) {
// Add the position to the hashmap
Matrix4 m = new Matrix4(newPos, newRotation, new Vector3(1f, 1f, 1f));
mTargetGrePositions.put(grenadeId, m);
// Set the grenade as dead
if(!isAlive) {
grenade.setAlive(isAlive);
}
}
}
}
@Override
public void transformEntity(int id, Vector3 position, Vector3 rotation) {
if(mClientId == id) {
mPlayer.rotateAndTranslate(rotation, position);
} else {
mTargetPlaPositions.put(id, new Vector3[] {rotation, position});
}
/*
GameObject obj = (mClient.getId() == id ? mPlayer : (GameObject)getPlayer(id));
obj.rotateAndTranslate(rotation, position);
*/
}
private void updatePlayer(float delta) {
mPlayer.update(delta);
if(hasPlayerMoved()) {
mLastKnownPosition = mPlayer.getPosition();
mLastKnownRotation = mPlayer.getRotation().x;
mEvents.notify(new ModelEvent(EventType.PLAYER_MOVE));
}
if(mPlayer.wantToShoot()) {
RayVector ray = new RayVector(mPlayer.getShootPosition(), mPlayer.getDirection(), 75f);
mEvents.notify(new ModelEvent(EventType.SHOOT, ray));
}
}
private boolean hasPlayerMoved() {
return (mLastKnownRotation != mPlayer.getRotation().x ||
RayVector.getDistance(mLastKnownPosition.cpy(), mPlayer.getPosition()) > 0.2f);
}
@Override
public void checkShootCollision(RayVector ray) {}
@Override
public void checkEntityStatus(GameObject entity) {}
public Player getPlayer() {
return mPlayer;
}
public void damageEntity(int id, int amount) {
GameObject obj = (mClientId == id ? mPlayer : (GameObject)getPlayer(id));
super.damageEntity(obj, amount);
mEvents.notify(new ModelEvent(EventType.DAMAGE, obj));
}
public void killEntity(int id) {
GameObject obj = (mClientId == id ? mPlayer : (GameObject)getPlayer(id));
super.killEntity(obj);
mEvents.notify(new ModelEvent(EventType.EXPLOSION, obj.getPosition()));
}
}