package robombs.game;
import java.net.InetAddress;
import java.util.*;
import robombs.clientserver.*;
import robombs.game.model.*;
import robombs.game.util.*;
import robombs.game.view.*;
import robombs.game.ai.*;
import com.threed.jpct.*;
import java.io.*;
public class BotClient extends AbstractClient implements DataTransferListener, ClientPreProcessor, EventProcessor {
private int botCnt=0;
private List<Bot> players = new ArrayList<Bot>();
private String[] names=new String[]{"Unknown soldier"};
private boolean speedMode=false;
private Ticker speedModeTimer=new Ticker(50);
private Set<SimpleVector> spawnsUsed=new HashSet<SimpleVector>();
public BotClient(BlueThunderServer serverImpl) throws Exception {
this.serverImpl=serverImpl;
try {
List<String> names=new ArrayList<String>();
SimpleStream ss=new SimpleStream("botnames.txt");
BufferedReader br=new BufferedReader(new InputStreamReader(ss.getStream()));
while(br.ready()) {
String name=br.readLine().trim();
if (name.length()>0) {
names.add(name);
}
}
br.close();
ss.close();
this.names=names.toArray(this.names);
} catch(Exception e) {
NetLogger.log("BotClient: Names file is missing!");
}
}
public synchronized void addBot() {
Bot player = new Bot();
players.add(player);
serverImpl.addPlayer(names[botCnt%names.length], this.getClientID(), player.getObjectID(), true);
botCnt++;
NetLogger.log("BotClient: Added bot number "+botCnt);
}
public synchronized void removeBot(PlayerInfo pi) {
for (Iterator<Bot> itty=players.iterator(); itty.hasNext();) {
LocalPlayerObject bot=itty.next();
if (pi.getObjectID()==bot.getObjectID()) {
serverImpl.removePlayer(pi);
itty.remove();
botCnt--;
break;
}
}
}
public void connect(ServerEntry server) throws Exception {
if (!disConnectScheduled) {
try {
synchronized (world) {
world.removeAllObjects();
world.removeAllLights();
selectedMaps.clear();
}
state.reset();
NetLogger.log("BotClient Connecting...");
shouldBeConnected = true;
firstTransferFinished = false;
entitiesUpdated = false;
DataContainer dc = new DataContainer();
dc.add("BotClient");
dc.add(mapList.getCheckSum());
dc.add(1); // 1==isBotClient
dc.add(0); // Not used for bots
clientImpl = new SimpleClient(server, false, dc); // The bot client is local, no need to zip the data
clientImpl.addListener(this);
clientImpl.addPreProcessor(this);
clientImpl.connect();
eventQueue.clear();
state.setState(NetState.STATE_CONNECTED);
ready(true);
} catch (Exception e) {
if (clientImpl != null) {
clientImpl.disconnect();
}
shouldBeConnected = false;
clientImpl = null;
throw e;
}
}
}
public int getBotCount() {
return botCnt;
}
public void prepare() {
try {
long start=Ticker.getTime();
state.setState(NetState.STATE_PREPARING);
reInit();
state.setState(NetState.STATE_LEVEL_LOADED);
for (LocalPlayerObject player: players) {
player.setPosition(new SimpleVector(0, Globals.skyLimit*10f, 0));
player.setClientID(clientImpl.getClientID());
}
state.setState(NetState.STATE_WAITING);
Event ev = new Event(Event.LEVEL_LOADED, -99, -99, clientImpl.getClientID());
ev.setSourceClientID(clientImpl.getClientID());
synchronized (SYNC) {
eventQueue.add(ev);
}
for (LocalPlayerObject player: players) {
player.setSpecialValue(Globals.LIVES);
}
waitTimer.reset();
NetLogger.log("Level prepared in "+(Ticker.getTime()-start)+"ms.");
} catch (Exception e) {
throw new RuntimeException("Error while preparing level", e);
}
}
public void begin() {
for (LocalPlayerObject player: players) {
player.activate();
}
respawn(players);
try {
// Give the respawn thread 100ms to breath...
Thread.sleep(100);
} catch (Exception e) {
}
state.setState(NetState.STATE_RUNNING);
}
public void disconnect() throws Exception {
synchronized (SYNC) {
state.reset();
ready(false);
shouldBeConnected = false;
if (coMan != null) {
coMan.removeAll(world);
}
for (LocalPlayerObject player: players) {
player.setAlive();
player.deactivate();
}
synchronized (world) {
world.removeAllObjects();
world.removeAllLights();
}
roundCompleted=false;
}
if (clientImpl != null) {
clientImpl.disconnect();
while (clientImpl.isConnected()) {
// Wait for the disconnect to finish...
Thread.sleep(100);
}
clientImpl = null;
if (disConnectScheduled) {
disConnectScheduled = false;
}
//
}
//TeamAssigner.clear();
disConnectScheduled = false;
}
public void quit() {
try {
disconnect();
} catch (Exception e) {
// We are on our way to exit...no time for exceptions...
}
quit = true;
}
/**
* Runs the client.
* @throws Exception
*/
public void run() throws Exception {
new Thread() {
public void run() {
try {
mapList = new MapList();
initBuffer();
ServerEntry serv=new ServerEntry(null, InetAddress.getLocalHost(),serverImpl.getPort(), 0);
try {
connect(serv);
addBot();
gameLoop();
} finally {
NetLogger.log("BotClient: Client thread terminated!");
}
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}.start();
}
/**
* Processes an info message from the server.
* @param il InfoLine the info
*/
protected void processInfo(InfoLine il) {
if (il.getType() == InfoLine.SERVER_STARTED_GAME
&& state.getState() <= NetState.STATE_WAITING) {
NetLogger.log("Server has started the game!");
reloadScheduled = true;
}
if (il.getType() == InfoLine.NEXT_LEVEL
&& state.getState() == NetState.STATE_RUNNING) {
NetLogger.log("Server switches to the next level!");
nextMap();
reloadScheduled = true;
}
if (il.getType() == InfoLine.ALL_CLIENTS_READY
&& state.getState() == NetState.STATE_WAITING) {
NetLogger.log("Client " + clientImpl.getClientID()
+ ": All clients are ready to go!");
playerCount=Integer.parseInt(il.getValue());
respawnCount=0;
begin();
}
if (il.getType() == InfoLine.END_GAME
&& state.getState() == NetState.STATE_RUNNING) {
NetLogger.log("Server wants to end game!");
disConnectScheduled = true;
}
if (il.getType() == InfoLine.ROUND_COMPLETED) {
NetLogger.log("Round completed");
roundCompleted=true;
speedMode=false;
}
if (il.getType() == InfoLine.PLAYER_REMOVED) {
NetLogger.log("'" + il.getValue() + "' removed!");
int cid = Integer.parseInt(il.getKey());
if (cid == clientImpl.getClientID()) {
// Somehow, a message arrived that this client's player has been disconnected.
// This can be a server-side drop, we have to process it...
try {
disconnect();
} catch (Exception e) {
NetLogger.log("Unable to disconnect - already disconnected?");
}
}
respawnCount++;
}
if (il.getType() == InfoLine.MAP_ENTRY) {
// This logic is a bit unsafe, because it assumes, that the entries arrive in the
// correct order. However, this is always the case and the way how the server works
// ensures this, so it doesn't matter...
if (il.getCount() == 0) {
selectedMaps.clear();
firstMap();
}
selectedMaps.add(new MapInfo(il.getKey(), il.getValue()));
}
}
/**
* Processes an event from the server. An event if something like "player fires a shot" or "player has died".
* @param event Event the event
*/
public void processEvent(Event event) {
switch (event.getType()) {
case Event.ONLY_BOTS_LEFT:
speedMode=true;
NetLogger.log("BotClient: Only bots left...speeding up the game!");
break;
case Event.PLAYER_DAMAGE:
if (event.getTargetClientID() == clientImpl.getClientID()) {
// Myself
for (LocalPlayerObject player: players) {
if (player.getObjectID()==event.getTargetID()) {
player.addToValue(event.getValue());
break;
}
}
}
break;
case Event.PLAYER_DEAD:
if (!roundCompleted) {
if (event.getTargetClientID() != clientImpl.getClientID()) {
// Somebody else hit
ClientObject obj = coMan.getClientObject(event.getTargetID(), event.getTargetClientID());
if (obj != null) {
// Can't be null anyway...
obj.setCollisionMode(Object3D.COLLISION_CHECK_NONE);
}
} else {
// Myself
for (LocalPlayerObject player: players) {
if (player.getObjectID()==event.getTargetID()) {
player.setDead();
player.getView().setCollisionMode(Object3D.COLLISION_CHECK_NONE);
if (player.getSpecialValue()<=0) {
// All lives lost? Tell the server that we are out for this round.
Event ev = new Event(Event.ROUND_LOST, player, player);
eventQueue.add(ev);
}
break;
}
}
}
}
break;
case Event.BOMB_HIT:
if (event.getTargetClientID() == clientImpl.getClientID()) {
// Created by myself
bombMan.explode(event.getTargetID());
} else {
throw new RuntimeException("Client received an event for another client!?");
}
break;
case Event.BOMB_DISABLED:
if (event.getTargetClientID() == clientImpl.getClientID()) {
// Created by myself
bombMan.defuse(event.getTargetID());
}
break;
case Event.BOMB_TOUCHED:
boolean boom=false;
for (LocalPlayerObject player: players) {
if (player.isInvincible() && event.getSourceClientID()==clientImpl.getClientID() && player.getObjectID()==event.getSourceID() && !player.getPlayerPowers().canKick()) {
// The local player is inVincible and has touched some bomb? Make it explode!
Event eve = new Event(Event.BOMB_OVERLOADED, event.getSourceID(), event.getTargetID(), event.getTargetClientID());
eventQueue.add(eve);
boom=true;
break;
}
}
if (!boom && event.getTargetClientID() == clientImpl.getClientID() /*&& player.getPlayerPowers().canKick()*/) {
// Created by myself
bombMan.startMoving(event.getTargetID(), event);
break;
}
break;
case Event.REMOVE_CRATE:
level.getCrateManager().explode(event, level);
break;
case Event.COLLECT_ITEM:
boolean wasLocal=false;
for (LocalPlayerObject player: players) {
if (player.getObjectID()==event.getSourceID()) {
wasLocal=true;
level.getItemManager().collect(event, level, event.getSourceClientID() == clientImpl.getClientID(), player);
break;
}
}
if (!wasLocal) {
// Not collected by a local player? Remove it anyway.
level.getItemManager().collect(event, level, false, null);
}
break;
case Event.LOGIN_REJECTED:
if (event.getTargetClientID() == clientImpl.getClientID()) {
NetLogger.log("Client login rejected by server!");
try {
disconnect();
} catch (Exception e) {
NetLogger.log("Unable to disconnect from server!");
}
}
break;
case Event.FIRE:
if (event.getSourceClientID() != clientImpl.getClientID()) {
// Someone else has fired!
}
break;
case Event.PLACE_BOMB:
if (event.getSourceClientID() != clientImpl.getClientID()) {
NetLogger.log("Bomb placed at " + event.getOrigin());
GridPosition gp=bombMan.getBombMask().getGrid(event.getOrigin().x, event.getOrigin().z);
bombMan.getBombMask().setMaskAt(gp, MapMask.BOMB);
}
break;
case Event.ENTITY_REMOVE:
if (event.getSourceClientID() != clientImpl.getClientID()) {
// Someone else has removed a bomb...
ClientObject co=coMan.getClientObject(event.getSourceID(), event.getSourceClientID());
GridPosition gp2=null;
if (co!=null) {
SimpleVector sv=co.getTransformedCenter();
gp2=bombMan.getBombMask().getGrid(sv.x, sv.z);
}
NetLogger.log("Bomb removed at " + event.getOrigin());
GridPosition gp=bombMan.getBombMask().getGrid(event.getOrigin().x, event.getOrigin().z);
if (gp2!=null && !gp.equals(gp2)) {
// This is a little bit kludgy, but i had so many problems with bombs remaining in
// the grid that were long gone, that i want to be 110% sure now...:-)
NetLogger.log("Local and remote grid don't match...cleaning both!");
bombMan.getBombMask().setMaskAt(gp, MapMask.NO_BOMB);
bombMan.getBombMask().setMaskAt(gp2, MapMask.NO_BOMB);
} else {
bombMan.getBombMask().setMaskAt(gp, MapMask.NO_BOMB);
}
}
break;
case Event.PLAYER_RESET_HEALTH:
if (event.getSourceClientID() == clientImpl.getClientID()) {
for (LocalPlayerObject player: players) {
if (player.getObjectID()==event.getSourceID()) {
player.setValue(100);
break;
}
}
} else {
ClientObject obj = coMan.getClientObject(event.getSourceID(),
event.getSourceClientID());
if (obj != null) {
obj.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS
| Object3D.COLLISION_CHECK_SELF);
}
}
respawnCount++;
int clients=serverImpl.getClientCount()-1; // One client is this one...
int known=BotClient.this.coMan.getPlayerCount();
if (clients!=known) {
spawnsUsed.add(event.getOrigin());
NetLogger.log("BotClient: Spawnpoint "+event.getOrigin()+" reserved for human player. Count is now: "+spawnsUsed.size());
}
break;
}
}
/**
* Initializes the client.
*/
private void initClient() {
coMan = new ClientObjectManager(null, true);
bombMan = new LocalBombManager(level, null);
timeout = new Ticker(2000);
}
/**
* Prepares the data from the client that should be send to the server.
*/
protected void prepareClientData() {
if (clientImpl != null) {
if (state.getState() >= NetState.STATE_LEVEL_LOADED) {
ExtendedDataContainer playerAndObjects = new ExtendedDataContainer();
for (LocalPlayerObject player: players) {
playerAndObjects.add(player);
}
synchronized (KILL_SYNC) {
toKill.addAll(bombMan.fillOrKill(playerAndObjects, eventQueue));
}
DataContainer edc = eventQueue.getEvents(clientImpl.getClientID());
eventQueue.clear();
clientImpl.setContainers(new DataContainer[] {playerAndObjects, edc });
} else {
// Events only..
DataContainer edc = eventQueue.getEvents(
clientImpl.getClientID());
eventQueue.clear();
clientImpl.setContainers(new DataContainer[] {
new ExtendedDataContainer(), edc });
}
}
}
private void initBuffer() {
Logger.setOnError(Logger.ON_ERROR_THROW_EXCEPTION);
fireTicker = new Ticker(400);
bombTicker = new Ticker(200);
}
/**
* Initializes the game world.
*/
private void initWorld() {
dummy = new PlayerDummy(this.getClientID());
dummy.setEventQueue(eventQueue);
world.addObject(dummy);
dummy.setCollisionMode(Object3D.COLLISION_CHECK_SELF);
level.addToWorld(world);
}
/**
* Initializes the player. The local player on the client is, opposed to remote players, no real 3D object but
* just a data representation.
*/
private void initPlayers() {
for (LocalPlayerObject player:players) {
// Reinit
player.reset();
}
}
private void initPlayerView() {
for (LocalPlayerObject player: players) {
ClientObject playerView = ClientObjectManager.createLocalPlayerObject(player, world, eventQueue);
playerView.setCollisionMode(Object3D.COLLISION_CHECK_SELF | Object3D.COLLISION_CHECK_OTHERS);
playerView.addCollisionListener(new ClientObjectCollisionListener(player, true));
player.setView(playerView);
playerView.setAnimationSequence(null);
dummy.setMaster(playerView);
}
}
/*
private void fireBullet() {
player.setAnimation(Animations.FIRE);
player.setAnimationSpeed(20);
if (fireTicker.getTicks() > 0) {
LocalObject bul = bulMan.addBullet(player, world);
Event ev = new Event(Event.FIRE, player, bul);
ev.setOrigin(player.getPosition());
ClientEventQueue.getInstance().add(ev);
fireTicker.reset();
}
}
*/
public void placeBomb(Bot bot) {
if (bombTicker.getTicks() > 0) {
if (bombMan.getCount(bot.getObjectID())<bot.getPlayerPowers().getBombCount()) {
// Only do this, if you are allowed to...
LocalObject bomb = bombMan.addBomb(clientImpl, bot, world, eventQueue);
if (bomb != null) {
Event ev = new Event(Event.PLACE_BOMB, bot, bomb);
ev.setOrigin(new SimpleVector(bot.getPosition()));
eventQueue.add(ev);
}
}
}
}
/**
* Respawn!
*/
private void respawn(final List<Bot> locals) {
if (!roundCompleted && clientImpl!=null) {
// Do this in another thread to make sure, that the server has send its data at least once
// before respawning.
entitiesUpdated = false;
respawnRunning=true;
new Thread() {
public void run() {
setPriority(Thread.MAX_PRIORITY);
SimpleVector respawn = null;
int cnt = 0;
try {
boolean ok=false;
do {
// This should ensure that the bot client knows the positions of the other player...this
// may not always work...we'll see...
int clients=serverImpl.getClientCount()-1; // One client is this one...
int known=BotClient.this.coMan.getPlayerCount();
if (clients==known && entitiesUpdated) {
ok=true;
}
if (!ok) {
if (clients-known!=0) {
NetLogger.log("BotClient: Waiting for "+(clients-known)+" client(s) to appear!");
}
Thread.sleep(125);
cnt++;
}
} while(!ok && cnt < 60);
} catch (Exception e) {
e.printStackTrace();
}
if (cnt == 30) {
respawnRunning=false;
throw new RuntimeException("BotClient: Unable to respawn. Some remote data is missing!");
}
List<Event> events=new ArrayList<Event>();
synchronized (SYNC) {
Set<SimpleVector> used=new HashSet<SimpleVector>(spawnsUsed);
int cnty=0;
for (LocalPlayerObject local:players) {
if (locals.contains(local)) { // Do this sh**t to ensure the order
int its = 0;
respawn=null;
do {
int index=((clientImpl.getClientID()-1)+cnty + its)%spawnPoints.length;
SimpleVector s=null;
if (index<spawnPoints.length && its<=15) {
s = new SimpleVector(spawnPoints[index]);
} else {
// No defined spawn point available? Spawn anywhere on the map...
MapMask mask=level.getMask();
int height=mask.getHeight();
int width=mask.getWidth();
GridPosition gp=new GridPosition();
boolean tFound=false;
do {
int newX=(int) (Math.random()*(float) width-1);
int newY=(int) (Math.random()*(float) height-1);
tFound=newX!=0 && newY!=0 && !mask.isBlocked(newX, newY) && !mask.isObstacle(newX, newY);
gp.set(newX, newY);
s=gp.convertTo3D();
s.y=-10;
tFound&=isFree(s, level.getCrateManager(), bombMan, BotClient.this.coMan);
tFound&=!used.contains(s);
} while(!tFound);
}
SimpleVector ss = new SimpleVector();
ss.y=-3;
if ((isFree(s, level.getCrateManager(), bombMan, BotClient.this.coMan) && world.checkCollisionSpherical(s, ss, 3f).equals(ss) && !used.contains(s)) || its > 15) {
respawn = s;
used.add(s);
} else {
its++;
NetLogger.log("BotClient: "+s + " is blocked!");
}
} while (respawn == null);
local.setPosition(respawn);
local.setSpeed(new SimpleVector());
local.getView().setCollisionMode(Object3D.COLLISION_CHECK_SELF | Object3D.COLLISION_CHECK_OTHERS);
local.setAlive();
local.setInvincible(true);
Event ev = new Event(Event.PLAYER_RESPAWNED, local, local);
events.add(ev);
}
cnty++;
}
for (Event ev:events) {
eventQueue.add(ev);
}
}
fireTicker.reset();
respawnRunning=false;
}
}.start();
}
}
private void checkRespawns() {
if (respawnRunning) {
return;
}
List<Bot> locals=null;
for (Bot player:players) {
if (player.isDead() && Ticker.hasPassed(player.deadSince(), 2000) && player.getSpecialValue() > 0 && !roundCompleted) {
if (locals==null) {
locals=new ArrayList<Bot>();
}
locals.add(player);
}
}
if (locals!=null) {
respawn(locals);
}
}
/**
* The game loop. This is where the game...well...loops...:-)
* @throws Exception
*/
private void gameLoop() throws Exception {
Ticker ticker = new Ticker(20);
Ticker sec=new Ticker(10000);
long time=0;
long aiTime=0;
int sleepy=(int)((1000f/((float)Globals.frameLimit/*0.075f*/))+0.5f);
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
while (!quit) {
long s=Ticker.getTime();
checkWaitingState();
if (disConnectScheduled) {
try {
quit();
} catch (Exception e) {
// Don't care...
}
}
if (reloadScheduled) {
reloadScheduled = false;
prepare();
}
int ticks = ticker.getTicks();
if (ticks > 0) {
if (state.getState() >= NetState.STATE_WAITING) {
synchronized (SYNC) {
long ait=Ticker.getTime();
updatePlayer(ticks);
ait=Ticker.getTime()-ait;
aiTime+=ait;
checkRespawns();
updatePlayerView(ticks);
updateRemoteEntities(ticks, true);
updateCrates(ticks);
updateBombs(ticks);
checkTimeout();
updateExplosions(ticks);
eventQueue.processLocalEvents(this, clientImpl.getClientID());
}
cleanUp();
}
modified=true;
if (clientImpl!=null && Globals.activeTransferForBots) {
clientImpl.triggerTransfer();
}
}
if (clientImpl != null && !clientImpl.isConnected()
&& shouldBeConnected) {
shouldBeConnected = false;
}
s=Ticker.getTime()-s;
time+=s;
if (sec.getTicks()>0 || s<0) {
NetLogger.log("BotClient: Bot load is "+(int)(((float)time/10000f)*100f)+"% ("+(int)(((float)aiTime/(float)time)*100f)+"% used by bot AI)");
time=0;
aiTime=0;
}
Thread.sleep(sleepy);
}
}
private void loadLevel() throws Exception {
MapInfo mi = selectedMaps.get(getMapNumber());
Logger.log("Loading level " + mi.getName() + "...", Logger.MESSAGE);
level = new Level("data/levels/" + mi.getName(), mi.getSet(), world, eventQueue, null, true);
createSpawnPoints();
}
private List<SimpleVector> getPositionsOtherTeams(Bot bot) {
int myTeam=TeamAssigner.getTeam(bot);
if (myTeam==0) {
return getPositions();
}
List<SimpleVector> res=new ArrayList<SimpleVector>();
for (LocalPlayerObject player:players) {
if (!player.isDead() && TeamAssigner.getTeam(player)!=myTeam) {
res.add(new SimpleVector(player.getPosition()));
}
}
return res;
}
private List<SimpleVector> getPositions() {
List<SimpleVector> res=new ArrayList<SimpleVector>();
for (LocalPlayerObject player:players) {
if (!player.isDead()) {
res.add(new SimpleVector(player.getPosition()));
}
}
return res;
}
private void updateBombs(long ticks) {
if (speedMode && speedModeTimer.getTicks()>0 && bombMan.getCount()<15) {
level.populateSparse(bombMan, clientImpl, world, eventQueue);
}
bombMan.processBotBombs(players, level, ticks);
}
/**
* Updates the local player. Albeit the local player is no mesh, this method takes care of setting the correct
* animation because that will be transfered to the server and all other clients.
* @param ticks long the number of ticks passed
*/
private void updatePlayer(long ticks) {
if (state.getState() == NetState.STATE_RUNNING && allPlayersHaveSpawned()) {
List<SimpleVector> pPos=getPositions();
coMan.enterCollisionMode();
bombMan.enterCollisionMode();
bombMan.moveBombs(world, ticks);
for (Bot player:players) {
if (!player.isDead()) {
List<SimpleVector> pPosTeam=getPositionsOtherTeams(player);
ClientObject playerView=player.getView();
playerView.setVisibility(false);
boolean moved=false;
moved|= player.nextStep(this, world, ticks, level, coMan, bombMan, pPos, pPosTeam, dummy);
if (player.getPlayerPowers().isSick()==PlayerPowers.DROP_IMMEDIATELY) {
placeBomb(player);
}
playerView.setVisibility(true);
if (moved) {
/*
if (mouse.buttonDown(1)) {
player.setAnimation(Animations.CROUCH_MOVE);
player.setAnimationSpeed(20);
} else {
*/
player.setAnimation(Animations.MOVE);
player.setAnimationSpeed(40);
} else {
/*
if (mouse.buttonDown(1)) {
player.setAnimation(Animations.CROUCH_NONE);
} else {
*/
player.setAnimation(Animations.NONE);
player.setAnimationSpeed(300);
}
} else {
if (Ticker.hasPassed(player.deadSince(), 1000)) {
player.setAnimation(Animations.DEAD);
} else {
player.setAnimation(Animations.DIE);
}
player.setAnimationSpeed(80);
}
}
coMan.leaveCollisionMode();
bombMan.leaveCollisionMode();
}
}
private void updatePlayerView(long ticks) {
if (state.getState() == NetState.STATE_RUNNING) {
for (LocalPlayerObject player:players) {
ClientObject playerView=player.getView();
if (playerView != null) {
playerView.setToLocalObject(player);
playerView.process(ticks, level);
playerView.processSpecial(player);
}
}
}
}
private void reInit() throws Exception {
roundCompleted=false;
speedMode=false;
synchronized (world) {
synchronized (KILL_SYNC) {
toKill.clear();
}
synchronized (SYNC) {
world.removeAllObjects();
world.removeAllLights();
bombMan=null;
level=null;
loadLevel();
initWorld();
initPlayers();
initClient();
initPlayerView();
spawnsUsed.clear();
}
}
}
}