I recently returned to face a problem I had with a game client of mine, i.e. the client's thread responsible for input & painting becomes unable to run after some while.
I suspect that it has something to do with server sent massages. Possibly client is unable to handle old ones before new ones are arriving. But when I am printing inQueue size after dequeue it always reaches 0.
What else could possibly be the reason of this block?
I was debugging using NetBeans and it says there is no deadlocks?
Are there other tools which I should/might use to find the reason.
I have tried lots of things and I think the code of my client is now in a state of disaster :)
I am using the engine coded by Bret Barker which I got from the book by David Brackeen titled "Developing Games in Java".
If you guys would need some code I can paste some snippets of bits which you would suspect the problem is since the whole code is big & fat. Plus the last thing all wants to do here is read and debug someone's code, right? :) Thus I think we can do it by need basic.
I am stuck and all your help/suggestions of stuff I should look after, even an article about similar issues, etc. is much appreciated.
EDIT1: Here is presented a test class which combines client for server communication and GUI/frame for display & user input.
public class NetworkingTest2 extends GameCore implements IGameFrame
{
private static final long serialVersionUID = 1L;
private float _scrollSpeed = 0.35f;
private InputManager inputManager;
//mouse Actions
protected GameAction leftMouseClick;
protected GameAction rightMouseClick;
//keyboard Actions
protected GameAction scrollMapUpKey;
protected GameAction scrollMapDownKey;
protected GameAction scrollMapLeftKey;
protected GameAction scrollMapRightKey;
//robot moves
protected GameAction moveForwardKey;
protected GameAction moveBackwardKey;
protected GameAction moveLeftKey;
protected GameAction moveRightKey;
private RoboClient client;
//your/client's bot
private IUnit unit;
private RoboGame game = null;
public NetworkingTest2(String playerName, String password)
{
addWindowListener(new WindowAdapter()
{
@Override
public void windowClosing(WindowEvent e)
{
System.out.println("NetworkingTest2 windowClosing");
//used to call disconect once and then wait for it to finish
Runnable doWork = new Runnable()
{
public void run()
{
System.out.println("Stops client if it is still running.");
if(client.isRunning())
client.disconnect();
}
};
SwingUtilities.invokeLater(doWork);
}
});
initializeInput();
this.client = new RoboClient(this)
{
@Override
public void onSuccessfulLogin()
{
System.out.println("././././onSuccessfulLogin././././");
// 0 becaue we assume that there is only one game
client.createAndEnqueueJoinGameEvent(0);
}
};
boolean isConnected = client.connectToServer(GameConstants.SERVER_IP, playerName, password);
System.out.println("isConnected with server (doesn't mean the player is logged)=" + isConnected);
}
private void initializeInput()
{
this.inputManager = new InputManager(this);
// mouse
this.leftMouseClick = new GameAction("left mouse click");//, GameAction.DETECT_INITIAL_PRESS_ONLY);
this.rightMouseClick = new GameAction("righ mouse click", GameAction.DETECT_INITIAL_PRESS_ONLY);
// key
this.scrollMapDownKey = new GameAction("scrollDown", GameAction.NORMAL);
this.scrollMapUpKey = new GameAction("scrollUp", GameAction.NORMAL);
this.scrollMapLeftKey = new GameAction("scrollLeft", GameAction.NORMAL);
this.scrollMapRightKey = new GameAction("scrollRight", GameAction.NORMAL);
this.moveForwardKey = new GameAction("Move yout robot Forawrd/North");
this.moveBackwardKey = new GameAction("Move yout robot Back/South");
this.moveLeftKey = new GameAction("Move yout robot Left/West");
this.moveRightKey = new GameAction("Move yout robot Right/East");
// key mouse assigment
inputManager.mapToMouse(leftMouseClick, InputManager.MOUSE_BUTTON_1);
inputManager.mapToMouse(rightMouseClick, InputManager.MOUSE_BUTTON_3);
// keybard assignment
inputManager.mapToKey(scrollMapDownKey, KeyEvent.VK_DOWN);
inputManager.mapToKey(scrollMapUpKey, KeyEvent.VK_UP);
inputManager.mapToKey(scrollMapLeftKey, KeyEvent.VK_LEFT);
inputManager.mapToKey(scrollMapRightKey, KeyEvent.VK_RIGHT);
inputManager.mapToKey(moveForwardKey, KeyEvent.VK_W);
inputManager.mapToKey(moveBackwardKey, KeyEvent.VK_S);
inputManager.mapToKey(moveLeftKey, KeyEvent.VK_A);
inputManager.mapToKey(moveRightKey, KeyEvent.VK_D);
}
public void setUnit(IUnit robot)
{
setTitle(getTitle() + " for playerName=" + robot.getPlayer().getPlayerId());
this.unit = robot;
//center view on the player's robot
System.out.println("screenWidth=" + screenWidth + ";;screenHeight=" + screenHeight);
int initialOffsetX = (int) ((robot.getCenterPoint().getX() - getFrameWidth() / 2));
int initialOffsetY = (int) ((robot.getCenterPoint().getY() - getFrameHeight() / 2));
game = client.getGame();
game.getGameLevel().getMap().setMapOffsetX(-initialOffsetX);
game.getGameLevel().getMap().setMapOffsetY(-initialOffsetY);
}
@Override
public void update(long elapsedTime)
{
System.out.println("NetworkingTest2 public void update(long elapsedTime)");
checkInput(elapsedTime);
if(game != null)
{
GameLevel gameLevel = game.getGameLevel();
if(gameLevel != null)
{
List<IShot> shotList = gameLevel.getShotList();
//update all animated projectiles -- thus user sees their animation
for(int i = 0; i < shotList.size(); i++)
if(shotList.get(i).getProjectile() instanceof IAnimatedProjectile)
{
IAnimatedProjectile ap = (IAnimatedProjectile) shotList.get(i).getProjectile();
ap.update(elapsedTime);
}
}
}
}
// for debug purpose
private String _clickedObjectName = "None";
private String _clickedObjectToughness = "None";
private long drawCounter = 0;
@Override
public void draw(Graphics2D g2)
{
g2.setColor(Color.BLACK);
g2.fillRect(0, 0, this.getWidth(), this.getHeight());
if(game != null)
{
GameLevel gameLevel = game.getGameLevel();
if(gameLevel != null)
{
WorldMap map = gameLevel.getMap();
//center view on the unit -- this way arrow key are not working as map offset is set again here
int initialOffsetX = (int) ((unit.getCenterPoint().getX() - getFrameWidth() / 2));
int initialOffsetY = (int) ((unit.getCenterPoint().getY() - getFrameHeight() / 2));
map.setMapOffsetX(-initialOffsetX);
map.setMapOffsetY(-initialOffsetY);
gameLevel.draw(g2);//, offsetX, offsetY);//(g2, map.getMapOffsetX(), map.getMapOffsetY());
g2.setColor(Color.YELLOW);
g2.drawString("MapOffset X: " + map.getMapOffsetX(), 10, 100);
g2.drawString("MapOffset Y: " + map.getMapOffsetY(), 10, 120);
g2.drawString("Mouse X: " + inputManager.getMouseX(), 10, 160);
g2.drawString("Mouse Y: " + inputManager.getMouseY(), 10, 180);
g2.drawString("Mouse on Map X: " + (inputManager.getMouseX() + map.getMapOffsetX()), 10, 220);
g2.drawString("Mouse on Map Y:" + (inputManager.getMouseY() + map.getMapOffsetY()), 10, 240);
}
//unit display update
g2.setColor(Color.RED);
IShootingClipWeapon head = (IShootingClipWeapon) unit.getEquipmentAtLocation(Robot.EQUIPMENT_ON_HEAD);
g2.drawString("Ammo on head: "
+ head.getClip().getCurrentAmmoAmount() + "/" + head.getClip().getMaximumAmmoCapacity(), 10, 450);
g2.drawString("Money: " + unit.getPlayer().getMoney(), 10, 480);
g2.drawString("Hp: " + unit.getHpCurrent() + "/" + unit.getHpMax(), 10, 510);
g2.drawString("Speed: " + unit.getSpeed(), 10, 540);
}
g2.setColor(Color.YELLOW);
g2.drawString("ClickedObjectName: " + _clickedObjectName, 10, 260);
g2.drawString("ClickedObjectToughness: " + _clickedObjectToughness, 10, 290);
g2.drawString("drawCounter= " + (drawCounter++), 10, 320);
}
@Override
public void clean()
{
}
private void checkInput(long elapsedTime)
{
int step = Math.round(_scrollSpeed * elapsedTime);
if(game != null)
{
GameLevel gameLevel = game.getGameLevel();
if(gameLevel != null)
{
WorldMap map = gameLevel.getMap();
if(scrollMapRightKey.isPressed())
{
map.scroll(WorldMapDirection.EAST, step);
System.out.println("Pressed:" + scrollMapRightKey.getName());
}
if(scrollMapLeftKey.isPressed())
{
map.scroll(WorldMapDirection.WEST, step);
System.out.println("Pressed:" + scrollMapLeftKey.getName());
}
if(scrollMapUpKey.isPressed())
{
map.scroll(WorldMapDirection.NORTH, step);
System.out.println("Pressed:" + scrollMapRightKey.getName());
}
if(scrollMapDownKey.isPressed())
{
map.scroll(WorldMapDirection.SOUTH, step);
System.out.println("Pressed:" + scrollMapLeftKey.getName());
}
if(client.isInGame() && unit != null)
{
Point2D mousePoint = new Point2D.Double(
inputManager.getMouseX() - map.getMapOffsetX(),
inputManager.getMouseY() - map.getMapOffsetY());
double angleBetweenDirectionAndAxisX =
GeometricOperations.calculateAngleOfRotation(
unit.getCenterPoint(), mousePoint, 0.0);
if(unit.isAlive() && Math.abs(unit.getFaceAngle() - angleBetweenDirectionAndAxisX) >= 5.0)
client.createAndEnqueueTurnActionEvent(unit, mousePoint);
boolean isMoving = false;
double modX = 0;
double modY = 0;
boolean isForwardMove = false;
boolean isBackwardMove = false;
boolean isLeftMove = false;
boolean isRightMove = false;
if(moveLeftKey.isPressed())
{
isLeftMove = true;
isMoving = true;
modX = modX - 100 - unit.getSpeed();
}
if(moveRightKey.isPressed())
{
isRightMove = true;
isMoving = true;
modX = modX + 100 + unit.getSpeed();
}
if(moveForwardKey.isPressed())
{
isForwardMove = true;
isMoving = true;
modY = modY - 100 - unit.getSpeed();
}
if(moveBackwardKey.isPressed())
{
isBackwardMove = true;
isMoving = true;
modY = modY + 100 + unit.getSpeed();
}
if(isMoving && unit.isAlive())
{
if(unit.isMoving() == false || unit.isMoveFlagsStateChanged(
isForwardMove, isBackwardMove, isLeftMove, isRightMove))
{
unit.startMoving();
unit.setMoveFlags(isForwardMove, isBackwardMove, isLeftMove, isRightMove);
client.createAndEnqueueMoveMessageEvent(unit,
isForwardMove, isBackwardMove, isLeftMove, isRightMove);
}
}//start and stop move/shoot are controlled by server
else if(unit.isMoving())
{
unit.stopMoving();
client.createAndEnqueueMoveStopEvent(unit);
}
if(leftMouseClick.isPressed())
{
if(unit.isFiring() == false && unit.isAlive())
{
Iterator<String> it = unit.getEquipmentLocationMap().keySet().iterator();
while(it.hasNext())
{
String key = it.next();
IEquipment eq = unit.getEquipmentAtLocation(key);
if(eq instanceof IClipWeapon)
{
IClipWeapon cw = ((IClipWeapon) eq);
if(cw.isEnoughAmmoToAttack() == true)
((IWeaponMR) cw.getMapRepresentation()).attack();
}
}
unit.startFiring();
client.createAndEnqueueFireActionEvent(unit, IUnit.EQUIPMENT_ON_ALL_SLOTS);
}
}
else if(unit.isFiring())
{
System.out.println("stop firing");
unit.stopFiring();
client.createAndEnqueueFireStopEvent(unit);
}
}
}
}
}
public static void main(String[] args)
{
BasicConfigurator.configure();
NetworkingTest2 nft = new NetworkingTest2("Alegroth2", "ElBoro");
nft.setCoreFrameSize(600, 600);
nft.run();
}
}