package Hexel.things;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import Hexel.Engine;
import Hexel.LogData;
import Hexel.Resources;
import Hexel.blocks.BlockTools;
import Hexel.blocks.types.Block;
import Hexel.blocks.types.BlockEmpty;
import Hexel.chunk.Chunk;
import Hexel.chunk.Chunks;
import Hexel.math.Vector2i;
import Hexel.math.Vector3d;
import Hexel.math.Vector3i;
import Hexel.things.blockManipulation.AddBlock;
import Hexel.things.blockManipulation.BlockAction;
import Hexel.things.blockManipulation.BlockManipulator;
import Hexel.things.blockManipulation.RemoveBlock;
import Hexel.things.types.Cuboid;
import Hexel.things.types.Deer;
import Hexel.things.types.LinearCamera;
import Hexel.things.types.InventoryOwner;
import Hexel.things.types.Movable;
import Hexel.things.types.PaddedCuboid;
import Hexel.things.types.Player;
import Hexel.things.types.Thing;
import Hexel.things.types.Volumetric;
import Hexel.things.types.Zombie;
import Hexel.util.Cleanup;
public class ThingSimulator {
public Set<Thing> things = Collections.newSetFromMap(new ConcurrentHashMap<Thing, Boolean>());
private Chunks chunks;
public ThingBridge thingBridge;
private Engine engine;
private HashSet<Thing> thingsToRemove = new HashSet<Thing>();
private Set<Thing> thingsToAdd = Collections.newSetFromMap(new ConcurrentHashMap<Thing, Boolean>());
public ThingBridge getThingBridge() {
return this.thingBridge;
}
private ThingTools thingTools;
public ThingTools.FixOffsetTmps fixOffsetTmps;
public ThingSimulator(Cleanup cleanup, Engine engine, Chunks chunks) {
this.chunks = chunks;
this.engine = engine;
this.thingBridge = new ThingBridge(engine, chunks);
this.thingTools = new ThingTools(engine, chunks);
this.fixOffsetTmps = this.thingTools.new FixOffsetTmps();
cleanup.add(new Runnable() {
@Override
public void run() {
System.out.println(things.size());
synchronized (things){
ThingsFile.save(things);
}
}
});
}
public int getNumberOfThings(){
return this.things.size() + this.thingsToAdd.size();
}
public int getNumberOfThingsOfType(Class type){
int i = 0;
for (Thing t : this.things){
if (type.isInstance(t))
i++;
}
for (Thing t : this.thingsToAdd){
if (type.isInstance(t))
i++;
}
return i;
}
public void addThing(Thing thing) {
this.thingsToAdd.add(thing);
}
public void step(double fps) {
Vector3i tmp = Resources.vector3iResourcePool.aquire();
Vector3d tmp3d = Resources.vector3dResourcePool.aquire();
Vector2i tmp2 = Resources.vector2iResourcePool.aquire();
synchronized (this.things){
thingsToRemove.clear();
for (Thing t : this.thingsToAdd){
this.things.add(t);
if (t instanceof Player)
this.thingBridge.player = (Player)t;
}
this.thingsToAdd.clear();
Iterator<Thing> iter = this.things.iterator();
LogData.set("numberZombies", getNumberOfThingsOfType(Zombie.class));
while (iter.hasNext()) {
Thing thing = iter.next();
thing.step();
if (thing instanceof Volumetric){
if (this.thingTools.isOutOfRangeOfCamera((Volumetric)thing)){
thingsToRemove.add(thing);
continue;
}
}
if (thing instanceof Player){
Player player = (Player)thing;
player.hunger -= 1.0/(60*60*10);
if (player.isDead() && engine.camera == player){
LinearCamera fc = new LinearCamera(player.getCameraX(), player.getCameraY(), player.getCameraZ(), 0, 0,
0, 0, .01, 0, 0);
engine.addThing(fc);
engine.setCamera(fc);
}
}
else if (thing instanceof Zombie){
Zombie zombie = (Zombie)thing;
if (zombie.health <= 0){
thingsToRemove.add(zombie);
}
}
else if (thing instanceof Deer){
Deer deer = (Deer)thing;
if (deer.health <= 0){
thingsToRemove.add(deer);
}
}
if (thing instanceof Movable) {
Movable movable = (Movable) thing;
movable.accelerate(fps, 0, 0, -9.8);
Vector3d reqMoveVector = movable.getReqMoveVector(fps);
moveMovable(movable, reqMoveVector, tmp);
}
if (thing instanceof BlockManipulator) {
BlockAction action = ((BlockManipulator) thing)
.getBlockAction();
if (action instanceof AddBlock) {
AddBlock addBlockAction = (AddBlock) action;
Block original = this.chunks.getBlock(addBlockAction.x, addBlockAction.y, addBlockAction.z, tmp, (Chunk)null);
this.chunks.setBlock(addBlockAction.x, addBlockAction.y, addBlockAction.z, addBlockAction.block, tmp, tmp2, null);
if (thing instanceof Volumetric) {
if (thing instanceof Cuboid) {
Vector3d offset = Resources.vector3dResourcePool.aquire();
offset.x = 0;
offset.y = 0;
offset.z = 0;
if (this.thingTools.fixOffset((Cuboid) thing,
offset, false, this.fixOffsetTmps) != null)
this.chunks.setBlock(addBlockAction.x,
addBlockAction.y, addBlockAction.z,
original, tmp, tmp2, null);
else {
if (thing instanceof InventoryOwner) {
InventoryOwner inventoryOwner = (InventoryOwner) thing;
inventoryOwner.rmBlock(addBlockAction.block);
}
}
Resources.vector3dResourcePool.recycle(offset);
}
}
} else if (action instanceof RemoveBlock) {
RemoveBlock rmBlockAction = (RemoveBlock) action;
Block b = this.chunks.getBlock(rmBlockAction.x, rmBlockAction.y, rmBlockAction.z, tmp, (Chunk)null);
if (b.getHealth() < 0) {
this.chunks.setBlock(rmBlockAction.x, rmBlockAction.y, rmBlockAction.z, BlockEmpty.Make(0), tmp, tmp2, null);
if (thing instanceof InventoryOwner) {
InventoryOwner inventoryOwner = (InventoryOwner) thing;
inventoryOwner.addBlock(b);
}
} else {
Block newB = BlockTools.updateHealth(b, b.getHealth()-1);
this.chunks.setBlock(rmBlockAction.x, rmBlockAction.y, rmBlockAction.z, newB, tmp, tmp2, null);
}
}
}
}
this.things.removeAll(thingsToRemove);
Resources.vector3iResourcePool.recycle(tmp);
Resources.vector2iResourcePool.recycle(tmp2);
Resources.vector3dResourcePool.recycle(tmp3d);
// System.out.System.out.println(((b-a) + " " + (c-b)));
}
}
public boolean equal(double a, double b, double epsilon) {
return Math.abs(a - b) < epsilon;
}
public void moveMovable(Movable movable, Vector3d reqMoveVector, Vector3i tmp){
Vector3d partialMove = new Vector3d(reqMoveVector);
partialMove.unit();
partialMove.times(.2);
Vector3d leftToMove = new Vector3d(reqMoveVector);
while (leftToMove.mag() > 0){
if (leftToMove.mag() > partialMove.mag()){
Movement movement = getMovement((Volumetric) movable,
partialMove, tmp);
if (movement.stoppedZ) {
movable.stopZ();
}
movable.applyMoveVector(movement);
leftToMove.sub(partialMove);
}
else {
Movement movement = getMovement((Volumetric) movable,
leftToMove, tmp);
if (movement.stoppedZ) {
movable.stopZ();
}
movable.applyMoveVector(movement);
leftToMove.sub(leftToMove);
}
}
}
public Movement getMovement(Volumetric v, Vector3d reqMoveVector,
Vector3i tmp) {
Movement m = new Movement(reqMoveVector);
Vector3d toFix = null;
if (v instanceof Cuboid) {
toFix = this.thingTools.fixOffset(new PaddedCuboid((Cuboid)v, .1, .1, 0), reqMoveVector, true, this.fixOffsetTmps);
if (toFix != null) {
m.add(toFix);
Vector3d afterFix = this.thingTools.fixOffset((Cuboid) v, new Vector3d(m.x, m.y, m.z-.1), true, this.fixOffsetTmps);
m.stoppedZ = afterFix != null || toFix.mag() == Math.abs(toFix.z);
}
}
return m;
}
}