package net.cis.client.game.ctrl.scene;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import net.cis.client.game.common.ctrl.IDispatcher;
import net.cis.client.game.common.ctrl.IObjectController;
import net.cis.client.game.common.model.co.AbstractControlledObject;
import net.cis.client.game.common.model.co.ControlledBackgroundSound;
import net.cis.client.game.common.model.co.ControlledCamera;
import net.cis.client.game.common.model.co.ControlledPlayer;
import net.cis.client.game.common.model.co.ControlledSpaceObject;
import net.cis.client.game.common.model.co.ControlledVisual;
import net.cis.client.game.common.model.event.ObjectEvent;
import net.cis.client.game.common.threading.IGameThreadCallback;
import net.cis.client.game.common.util.FilteredIterator;
import net.cis.client.game.common.util.GlobalObjectStore;
import net.cis.client.game.common.util.IFilter;
import net.cis.client.game.ctrl.GameApplication;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.jme3.scene.Node;
public class ObjectController implements IObjectController, IGameThreadCallback {
protected final GameApplication gameApp;
protected final IDispatcher dispatcher;
private final Log log = LogFactory.getLog(ObjectController.class);
private final Set<AbstractControlledObject<?, ?>> objectSet;
protected ConcurrentLinkedQueue<AbstractObjectTask> updateTasks = new ConcurrentLinkedQueue<AbstractObjectTask>();
private Node visualEffectsNode;
private Node playerNode;
private Node spaceObjectsNode;
private ControlledPlayer cp;
public ObjectController(GameApplication game) {
objectSet = new HashSet<AbstractControlledObject<?, ?>>();
this.gameApp = game;
this.dispatcher = GlobalObjectStore.<IDispatcher>getObject(IDispatcher.class);
gameApp.getRootNode().attachChild(
visualEffectsNode = new Node("VisualEffects"));
gameApp.getRootNode().attachChild(playerNode = new Node("PlayerNode"));
gameApp.getRootNode().attachChild(
spaceObjectsNode = new Node("SpaceObjectsNode"));
gameApp.addGameThreadCallback(this);
}
@Override
public float getUpdateTime() {
return .1f;
}
@Override
public void simpleUpdate(float tpf, float time) {
while (!updateTasks.isEmpty()) {
AbstractObjectTask cb = updateTasks.poll();
if (cb == null)
break;
cb.execute();
}
}
@Override
public void addVisualEffect(ControlledVisual cv, boolean addToScene) {
addToHandlerList(cv, visualEffectsNode, addToScene);
}
@Override
public void addSpaceObject(ControlledSpaceObject cso, boolean addToScene) {
addToHandlerList(cso, spaceObjectsNode, addToScene);
}
@Override
public void addPlayer(ControlledPlayer cp, boolean addToScene) {
this.cp = cp;
addToHandlerList(cp, playerNode, addToScene);
}
@Override
public void addCamera(ControlledCamera cc, boolean addToScene) {
addToHandlerList(cc, playerNode, addToScene);
}
@Override
public void addBackgroundSound(ControlledBackgroundSound cs, boolean addToScene) {
addToHandlerList(cs, visualEffectsNode, addToScene);
}
private void addToHandlerList(AbstractControlledObject<?, ?> co, Node n, boolean addToScene) {
log.trace("Object queued for adding (Scene:"+addToScene+") " + co + " in node " + n);
co.setSceneNode(n);
updateTasks.add(new AddObjectTask(this, co));
if(addToScene)
updateTasks.add(new AddObjectToSceneTask(this, co));
}
@Override
public void removeControlledObjectFromScene(AbstractControlledObject<?, ?> co) {
log.trace("Object queued for removal from scene " + co);
if(!objectSet.contains(co))
{
log.error("Object cannot be removed from scene, object not found: " + co);
return;
}
updateTasks.add(new RemoveObjectFromSceneTask(this, co));
}
@Override
public void destroyControlledObject(AbstractControlledObject<?, ?> co) {
if(co.isAddedToScene())
removeControlledObjectFromScene(co);
log.trace("Object queued for destruction " + co);
if(!objectSet.contains(co))
{
log.error("Object cannot be destroyed, object not found: " + co);
return;
}
updateTasks.add(new DestroyObjectTask(this, co));
}
@Override
public ControlledPlayer getPlayer() {
return cp;
}
@Override
public Iterator<AbstractControlledObject<?,?>> getAllObjects(IFilter<AbstractControlledObject<?,?>> filter)
{
//FIXME: keyset should be cloned before use by 3rd parties
if(filter == null)
return objectSet.iterator();
return new FilteredIterator<AbstractControlledObject<?,?>>(filter, objectSet.iterator());
}
/**
* Called from the main render thread by the appropriate {@link AbstractObjectTask}, when the object is ready to be added.
*
* @param controlledObject
* @param handler
*/
protected void internalAddObject(AbstractControlledObject<?, ?> controlledObject)
{
objectSet.add(controlledObject);
dispatcher.publish(new ObjectEvent("ObjectAdded", controlledObject));
}
/**
* Called from the main render thread by the appropriate {@link AbstractObjectTask}, after the object is loaded and was added to the scene.
*
* @param controlledObject
* @param handler
*/
protected void internalAddObjectToScene(AbstractControlledObject<?, ?> controlledObject)
{
dispatcher.publish(new ObjectEvent("ObjectAddedToScene", controlledObject));
}
/**
* Called from the main render thread by the appropriate {@link AbstractObjectTask}, after the object is removed from the scene and unloaded.
*
* @param controlledObject
* @param handler
*/
protected void internalRemoveObjectFromScene(AbstractControlledObject<?, ?> controlledObject)
{
dispatcher.publish(new ObjectEvent("ObjectRemovedFromScene", controlledObject));
}
/**
* Called from the main render thread by the appropriate {@link AbstractObjectTask}, when the object is ready to be destroyed.
*
* @param controlledObject
* @param handler
*/
protected void internalDestroyObject(AbstractControlledObject<?, ?> controlledObject)
{
objectSet.remove(controlledObject);
dispatcher.publish(new ObjectEvent("ObjectDestroyed", controlledObject));
}
}