Data Structures in 2D-Games with Multiplayer (Java) - java

I have following problem:
I've programmed a 2D Game with a multiplayer function. Right now i store others Player Data and GameObjects in two ArrayList (The world is stored otherwise). Sometimes the Network-Thread sends Updates, which can not be applied, because the Game draws the Players/Game Objects (java.util.ConcurrentModificationException). Because this drawing process happens every Second around 60 times (because of animations) the problem apeers often (every 2 seconds). This is the code for the players ArrayList:
Draw the Players:
for (Player p : oPlayer) {
if (p != null) {
int x = (int) ((width / 2) + (p.x - getPlayerX()) * BLOCK_SIZE);
int y = (int) ((height / 2) + (p.y - getPlayerY()) * BLOCK_SIZE);
g.drawImage(onlinePlayer, x, y, BLOCK_SIZE, BLOCK_SIZE, null);
FontMetrics fm = g.getFontMetrics();
g.setColor(Color.DARK_GRAY);
g.drawString(p.getName(), x + (BLOCK_SIZE / 2) - (fm.stringWidth(p.getName()) / 2), y - 5);
}
}
Edit Information in Network-Thread:
case "ADP": //add Player
Game.oPlayer.add(new Player(message, id));
sendX();
sendY();
break;
case "SPX": // set X
for (Player p : Game.oPlayer) {
if (p.getId() == id) {
p.setX(Short.parseShort(message));
break;
}
}
break;
case "SPY": // set Y
for (Player p : Game.oPlayer) {
if (p.getId() == id) {
p.setY(Short.parseShort(message));
break;
}
}
break;
case "PDI": // remove Player
for (Player p : Game.oPlayer) {
if (p.getId() == id) {
Game.oPlayer.remove(p);
break;
}
}
break;
Thank you in advance :)

What happens here is, that 2 Threads are working on the same list.
The first one is reading the List (for (Player p : oPlayer) {) and the second one is modifying it (Game.oPlayer.add(new Player(message, id));). This brings the oPlayer list into an (sort of) "inconsistent" state. Java sees that you modified something that you are reading and throws this exception to let you know, that something is not kosher.
More information about ConcurrentModificationExceptions can be found here
To clarify, you dipped into the so called Readers-writer problem. You have an reader (Thread), that reads the Data of Game.oPlayer and a writer (Thread) that writes data to Game.oPlayer.
Solutions
Synchronized-Keyword
The synchronized keyword is explained here. You would use it like this:
private final List<Player> players = ...;
public void addPlayer(Player player) {
synchronized(players) {
players.add(player);
}
}
public void removePlayer(Player player) {
synchronized(players) {
players.remove(player);
}
}
Note that the List has to bee final. Furhter i am using a local attribute instead of your static one. Remove players with Game.oPlayer to get a suited solution.
This allows only 1 thread to access players.add() and players.remove().
Lock
Informations about how to use Locks can be found here.
Easy said, you create a block like this:
try {
lock.lock();
// work ..
} finally {
lock.unlock();
}
so that only one thread can access the work part by saying lock.lock(). If any other thread locked the work part using lock.lock() and not unlocked it, the current thread will wait until lock.unlock() is called. The try-finall block is used, to assure, that the lock is unlocked, even if your work part is throwing an throwable.
Furhter i would recommend itterating over a "copy" of the player-list like this:
List<Player> toIterate;
synchronized(players) {
toIterate = new ArrayList<>(getPlayerList());
}
for(Player player : toIterate) {
// work
}
Or synchronizing this part completly like this:
synchronized(players) {
for(Player player : players) {
// work
}
}
The first one provides you with an copy of that instance, which basically means, it contains the same Objects as the original List, but it isn't the same List. It helps you by letting more threads work on there own "list" and finish theire jobs, regardless of updates at the current time, becaus the second example will block if:
Any thread wants to read the list.
Any thread modifies the list.
So you only have to synchronize the coppy part in the first example.
Even furhter (not particually part of your question, but still something that would make it easyer) i would recommend not using static, as you stated in Game.oPlayer.[...] and taking a look at Dependency Injection.
You could modify your Game-class to provide the methods addPlayer(Player player);, removePlayer(Player player); and getPlayerList(); to realy code in an Object Oriented fashion.
With that design, you could easyly modify your code, to handle the new concurrency issue.

If a list is iterated or modified in one thread and also in another thread you will get a ConcurrentModficationException. In general user interface applications restrict modifying model data to a single thread, usually the user interface thread, such as the event dispatch thread of Swing, or the platform thread in JavaFX.
As an aside, for JavaFX there exists a game library providing out of the box techniques for game development. JavaFX in general is much better suited for graphics intensive work than AWT or Swing.

Have you tried using Vector instead? It is part of Collection and is synchronized.

Related

Can ChronicleQueue tailers for two different queues be interleaved?

I have two separate ChronicleQueues that were created by independent threads that monitor web socket streams in a Java application. When I read each queue independently in a separate single-thread program, I can traverse each entire queue as expected - using the following minimal code:
final ExcerptTailer queue1Tailer = queue1.createTailer();
final ExcerptTailer queue2Tailer = queue2.createTailer();
while (true)
{
try( final DocumentContext context = queue1Tailer.readingDocument() )
{
if ( isNull(context.wire()) )
break;
counter1++;
queue1Data = context.wire()
.bytes()
.readObject(Queue1Data.class);
queue1Writer.write(String.format("%d\t%d\t%d%n", counter1, queue1Data.getEventTime(), queue1Data.getEventContent()));
}
}
while (true)
{
try( final DocumentContext context = queue2Tailer.readingDocument() )
{
if ( isNull(context.wire()) )
break;
counter2++;
queue2Data = context.wire()
.bytes()
.readObject(Queue2Data.class);
queue2Writer.write(String.format("%d\t%d\t%d%n", counter2, queue2Data.getEventTime(), queue2Data.getEventContent()));
}
}
In the above, I am able to read all the Queue1Data objects, then all the Queue2Data objects and access values as expected. However, when I try to interleave reading the queues (read an object from one queue, based on a property of Queue1Data object (a time stamp), read Queue2Data objects until the first object that is after the time stamp (the limit variable below), of the active Queue1Data object is found - then do something with it) after only one object from the queue2Tailer is read, an exception is thrown .DecoratedBufferUnderflowException: readCheckOffset0 failed. The simplified code that fails is below (I have tried putting the outer while(true) loop inside and outside the the queue2Tailer try block):
final ExcerptTailer queue1Tailer = queue1Queue.createTailer("label1");
try( final DocumentContext queue1Context = queue1Tailer.readingDocument() )
{
final ExcerptTailer queue2Tailer = queue2Queue.createTailer("label2");
while (true)
{
try( final DocumentContext queue2Context = queue2Tailer.readingDocument() )
{
if ( isNull(queue2Context.wire()) )
{
terminate = true;
break;
}
queue2Data = queue2Context.wire()
.bytes()
.readObject(Queue2Data.class);
while(true)
{
queue1Data = queue1Context.wire()
.bytes()
.readObject(Queue1Data.class); // first read succeeds
if (queue1Data.getFieldValue() > limit) // if this fails the inner loop continues
{ // but the second read fails
// cache a value
break;
}
}
// continue working with queu2Data object and cached values
} // end try block for queue2 tailer
} // end outer while loop
} // end outer try block for queue1 tailer
I have tried as above, and also with both Tailers created at the beginning of the function which does the processing (a private function executed when a button is clicked in a relatively simple Java application). Basically I took the loop which worked independently, and put it inside another loop in the function, expecting no problems. I thinking I am missing something crucial in how tailers are positioned and used to read objects, but I cannot figure out what it is - since the same basic code works when reading queues independently. The use of isNull(context.wire()) to determine when there are no more objects in a queue I got from one of the examples, though I am not sure this is the proper way to determine when there are no more objects in a queue when processing the queue sequentially.
Any suggestions would be appreciated.
You're not writing it correctly in the first instance.
Now, there's hardcore way of achieving what you are trying to achieve (that is, do everything explicitly, on lower level), and use MethodReader/MethodWriter magic rovided by Chronicle.
Hardcore way
Writing
// write first event type
try (DocumentContext dc = queueAppender.writingDocument()) {
dc.wire().writeEventName("first").text("Hello first");
}
// write second event type
try (DocumentContext dc = queueAppender.writingDocument()) {
dc.wire().writeEventName("second").text("Hello second");
}
This will write different types of messages into the same queue, and you will be able to easily distinguish those when reading.
Reading
StringBuilder reusable = new StringBuilder();
while (true) {
try (DocumentContext dc = tailer.readingDocument()) {
if (!dc.isPresent) {
continue;
}
dc.wire().readEventName(reusable);
if ("first".contentEquals(reusable)) {
// handle first
} else if ("second".contentEquals(reusable)) {
// handle second
}
// optionally handle other events
}
}
The Chronicle Way (aka Peter's magic)
This works with any marshallable types, as well as any primitive types and CharSequence subclasses (i.e. Strings), and Bytes. For more details have a read of MethodReader/MethodWriter documentation.
Suppose you have some data classes:
public class FirstDataType implements Marshallable { // alternatively - extends SelfDescribingMarshallable
// data fields...
}
public class SecondDataType implements Marshallable { // alternatively - extends SelfDescribingMarshallable
// data fields...
}
Then, to write those data classes to the queue, you just need to define the interface, like this:
interface EventHandler {
void first(FirstDataType first);
void second(SecondDataType second);
}
Writing
Then, writing data is as simple as:
final EventHandler writer = appender.methodWriterBuilder(EventHandler).get();
// assuming firstDatum and secondDatum are created earlier
writer.first(firstDatum);
writer.second(secondDatum);
What this does is the same as in the hardcore section - it writes event name (which is taken from the method name in method writer, i.e. "first" or "second" correspondingly), and then the actual data object.
Reading
Now, to read those events from the queue, you need to provide an implementation of the above interface, that will handle corresponding event types, e.g.:
// you implement this to read data from the queue
private class MyEventHandler implements EventHandler {
public void first(FirstDataType first) {
// handle first type of events
}
public void second(SecondDataType second) {
// handle second type of events
}
}
And then you read as follows:
EventHandler handler = new MyEventHandler();
MethodReader reader = tailer.methodReader(handler);
while (true) {
reader.readOne(); // readOne returns boolean value which can be used to determine if there's no more data, and pause if appropriate
}
Misc
You don't have to use the same interface for reading and writing. In case you want to only read events of second type, you can define another interface:
interface OnlySecond {
void second(SecondDataType second);
}
Now, if you create a handler implementing this interface and give it to tailer#methodReader() call, the readOne() calls will only process events of second type while skipping all others.
This also works for MethodWriters, i.e. if you have several processes writing different types of data and one process consuming all that data, it is not uncommon to define multiple interfaces for writing data and then single interface extending all others for reading, e.g.:
interface FirstOut {
void first(String first);
}
interface SecondOut {
void second(long second);
}
interface ThirdOut {
void third(ThirdDataType third);
}
interface AllIn extends FirstOut, SecondOut, ThirdOut {
}
(I deliberately used different data types for method parameters to show how it is possible to use various types)
With further testing, I have found that nested loops to read multiple queues which contain data in different POJO classes is possible. The problem with the code in the above question is that queue1Context is obtained once, OUTSIDE the loop that I expected to read queue1Data objects. My fundamental misconception was that DocumentContext objects managed stepping through objects in a queue, whereas actually ExcerptTailer objects manage stepping (maintaining indices) when reading a queue sequentially.
In case it might help someone else just getting started with ChronicleQueues, the inner loop in the original question should be:
while(true)
{
try (final DocumentContext queue1Context = queue1Tailer() )
{
queue1Data = queue1Context.wire()
.bytes()
.readObject(Queue1Data.class); // first read succeeds
if (queue1Data.getFieldValue() > limit) // if this fails the inner loop continues as expected
{ // and second and subsequent reads now succeed
// cache a value
break;
}
}
}
And of course the outer-most try block containing queue1Context (in the original code) should be removed.

Is it possible to check a condition after every method in a loop? If so, how?

Like I said in the title I have a loop in an RPG I'm making about High School. This is the main loop that sets up your day to act out individual sequences in chronological order. My question is how could I make it so that I check whether the boolean "beat" or the boolean "lost" (referring to the status of the game) has been tripped to true after every method in the loop but still keeping the methods together in a loop. Is nested if statements inside my while loop the only way?
while (!g.getBeat() || g.getLost())
{
g.wakeUp();
g.goToSchool();
g.beforeLunch();
g.lunchActivity();
g.afterLunch();
g.afterSchool();
g.home();
g.sleep();
}
You would have to do it manually. To help you write a little less code, make a method that checks both conditions:
private boolean stopTheLoop() {
return g.getBeat() || g.getLost();
}
Now convert your loop to infinite with checks after each method:
while (true) {
g.wakeUp();
if (stopTheLoop()) break;
g.goToSchool();
if (stopTheLoop()) break;
g.beforeLunch();
if (stopTheLoop()) break;
...
}
You could use a switch statement by introducing a state :
int state = 0;
while (!g.getBeat() || g.getLost())
{
switch (state) {
case 0:
g.wakeUp();
break;
case 1:
g.goToSchool();
break;
case 2:
g.beforeLunch();
break;
case 3:
g.lunchActivity();
break;
case 4:
g.afterLunch();
break;
case 5:
g.afterSchool();
break;
case 6:
g.home();
break;
case 7:
g.sleep();
break;
default:
// some error handling, depending on your logic,
// or perhaps state = -1 to restart
}
state++;
}
There isn't any "built-in" way to do this, but with some coding, anything's possible.
First, regardless if how you handle this, I'd wrap the end condition into a single method, just to make things more convenient:
public class Game {
// method, members, etc...
public boolean isOver() {
return !getBeat() || getLost();
}
}
Now, The first option that comes to mind is to do this manually:
while (!g.isOver()) {
g.wakeUp();
if (g.isOver()) {
break;
}
g.goToSchool();
if (g.isOver()) {
break;
}
// etc...
}
But this involves a lot of code, and isn't too elegant.
A more OO approach, perhaps, would be to warp every such call in a handler class:
public abstract GameStageHandler (Game g) {
protected Game g;
public GameStageHandler (Game g) {
this.g = g;
}
/**
* Play a stage in the game
* #return Whether the game should go on or not after this stage
*/
public boolean play() {
performStage();
return !g.isOver();
}
public abstract void performStage();
}
And implement it for every stage of the game. E.g. for the wakeUp() stage you'd have:
public abstract WakeUpHandler (Game g) {
public WakeUpHandler (Game g) {
super(g);
}
#Override
public void performStage() {
g.wakeUp();
}
}
Then, in the main method, you could have an array of such handlers, and iterate over them:
List<GameStageHandler> handlers = ...;
while (!g.isOver()) {
for (GameStageHandler handler : handlers) {
if (!g.play()) {
break;
}
}
}
This is probably beyond the scope of your assignment, as you noted the class hasn't even covered Runnable yet. This is an interesting question, though, and the challenge is to come up with a concise and elegant way to represent it, while avoiding as much repetition as possible. Here's a solution that uses Java 8 and functional programming techniques.
The first insight is to see that each game action or step can be represented as a lambda expression or method reference. I'll assume that you have a Game class. Each such step takes a Game instance as an argument (or receiver) and thus can be typed as a "consumer" of Game instances. We can thus put them into a data structure:
List<Consumer<Game>> actions = Arrays.asList(
Game::wakeUp,
Game::goToSchool,
Game::beforeLunch,
Game::lunchActivity,
Game::afterLunch,
Game::afterSchool,
Game::home,
Game::sleep);
Now that we have them in a data structure, we can loop over them:
for (Consumer<Game> action : actions) {
action.accept(game);
}
Of course, we want to check if the game is over after each action. Let's assume you have a method isOver on the Game class that checks the right termination conditions. You can then do:
for (Consumer<Game> a : actions) {
a.accept(game);
if (game.isOver()) {
break;
}
}
That only runs through one day of the game. Presumably you want to run the game indefinitely until it reaches its termination condition. For that you need an outer loop, and the termination check has to break out of the outer loop:
outer:
while (true) {
for (Consumer<Game> a : actions) {
a.accept(game);
if (game.isOver()) {
break outer;
}
}
}
This by itself might be sufficient: you have a list of game actions, and a loop that runs indefinitely, checking the termination condition after each action.
But wait, there's more! There's still a fair amount of boilerplate here, which can be eliminated using some of Java 8's stream features. Consider that every element of a stream can be tested against a predicate using the noneMatch method. This method terminates when one of the predicates returns true.
Since each action has type Consumer<Game>, we need a little helper function that turns each action into a predicate:
static Predicate<Consumer<Game>> stepAndCheck(Game game) {
return c -> { c.accept(game); return game.isOver(); };
}
Now we can run all the actions of a day as follows:
actions.stream().noneMatch(stepAndCheck(game))
To run the game indefinitely, we simply wrap this in a while loop. Since noneMatch returns true if, as it says, none of the predicates matches, we make this the loop condition and leave the loop body empty:
while (actions.stream().noneMatch(stepAndCheck(game))) {
// nothing
}
This might seem like it's unnecessarily obscure. Indeed, it might be, for toy examples such as this. However, for more complex problems, techniques like this are quite valuable.
If you want to keep each step in its own method like you do in your example there is little you can do about it...
You can reduce the amount of code if you make all those methods to return "true" if the condition to stop the loop is met... however this might not be possible if you plan to use those methods in order context.
if (!g.getBeat() || g.getLost()) do {
if (g.wakeUp()) break;
if (g.goToSchool()) break;
...
if (g.sleep()) break;
} while (true);
A possible trick is to make those methods to throw an exception if the stop condition is met. Then you would catch that exception in outside the loop. That way you would save the if (...) break statements. However this is not considered a good practice.
if (!g.getBeat() || g.getLost()) {
try {
do {
g.wakeUp();
g.goToSchool();
...
g.sleep();
} while (true);
} catch (ActivityLoopFinished ex) {
// nothing to do here
}
}

Getting an infinite loop while trying to remove from a queue

I'm modeling a fastfood drive-through using a priority queue of Event objects (yep, homework). There are three stations, an order, payment and collection station, each with their own queues. I'm having an issue removing an item from the collection station (the last station visited by a Customer). When the collection queue fills up, the simulation begins to loop indefinitely and the timer no longer increments. I assume it's because of this line:
public void processFoodCollection(Customer c, Event e) {
collection.remove(c);//this is the issue I believe
collection.setServerStatus(false);
However, if I attempt to use my standard remove() method (which just calls queue.poll() in the station class), it returns null. I have no idea why this would happen after having just added to the queue, it's given me zero problems any other time I've used it at the other stations (and I just copy-pasted the methods for each station class, they're all identical). I'd really appreciate any help on identifying what is causing this loop, or, if it is the remove(c), how I can fix this.
Here's my Restaurant class (contains the simulation, lazy I know), but hopefully it's not necessary to look at since my documentation isn't complete yet: http://pastebin.com/cHj3xqJN[1]
Here's the method in particular I'm having issue with (collection is a CollectionStation var composed of a queue field, the remove(Customer c) and remove() methods are just for access to the queue methods):
public void processFoodCollection(Customer c, Event e) {
collection.remove(c);//Customer c should be head of queue
collection.setServerStatus(false);//cashier not helping anyone
if (collection.getQueueSize() < 2) {
//process event if room available in collection queue
collection.add(payment.remove());//remove customer from payment queue, add to collection queue
payment.setServerStatus(false);
if (!collection.getServerStatus())
createFinishCollection(collection.peek());//creates event to be processed in the future
//generate new finish payment event for new head of payment queue
if (payment.getQueueSize()>0) {
double b = this.exponentialPay.next();//minutes until finished paying
while (b == 0.0) {
b = this.exponentialPay.next();//ensure return > 0.0
}
createFinishPayment(b, payment.peek());
}
//check if head of order queue can move up
if (order.getQueueSize() > 0) {
if (order.peek().getTimeFinished() == this.clockTime && order.getServerStatus()) {
processFinishOrder(order.peek(), eventList.peek());
} else if (!order.getServerStatus()) {
double timeToOrder = (order.peek().getOrderSize() * this.timeToOrderItem);
createFinishOrder(timeToOrder, order.peek());
}
}
}
}//end method processFoodCollection
If I try to use the remove() method, I get a null pointer exception at:
Event newE = new Event(Events.FINISHFOODCOLLECTION, this.clockTime + (c.getOrderSize() * this.timeToProcessItem), c);
from the null customer object (c). This traces back to the createFinishCollection() method call in the above code. So this is how I know I get a null from calling remove, but I don't understand why my queue would say it's empty when I just added to it. Is there some trick to look out for when indirectly removing data structure elements?
Here's the remove method I'm calling (in the CollectionStation class):
/**
* Removes and returns object at front of queue.
* #return
*/
public Customer remove() {
return customerQueue.poll();
}//end method remove
I'm honestly pretty stumped why this wouldn't work. Any guidance would be appreciated (not looking for answers, just help).

synchronization, remove from collection

I am working on website with games and I have map of players and their virtual tables.
private final ConcurrentMap<Player, List<Table>> tableOfPlayers = new ConcurrentHashMap<>();
and method to remove table
private void removeTable(Player player,Table table) {
if(tableOfPlayers.get(player).size() == 1) {
tableOfPlayers.remove(player);
} else {
tableOfPlayers.get(player).remove(table);
}
}
Is there any good way to solve this check-then-act idiom, because now it isn't thread-safe.
I know that I can synchronize both add and remove method, but I am wondering if it is possible to make it better. The reason why I check if size is equal to 1 is that if player have only one active table and I decide to remove I no longer need this player in my map.

Swapping position of objects by Polymorphism

I am trying to solve an instance of Blockworld Problem. Basically an NxN Grid contains Blocks A, B, C and an Agent. Only the Agent can move, if on the way it encounter a Block, then their positions will be switched. For example, Agent(1, 0) goes left encounter a Block B(0, 0) then the new positions of the two would be Agent(0, 0) and B(1, 0).
Both my Agent and Block classes are subclass of Entity.
Here is my function swap(). It checks if after a move, the Agent is on the a Block, then the new Position of Block would be the previous position of the Agent.
I tried with (Block block : blockList) and it works, but not with the (Entity en : entityList) when I tried to use Polymorphism.
Can anyone spot the mistake I made please?
public void swap() {
for (Entity en : entityList) {
if (agent.position.equals(block.position) && (en instanceof Block)) {
System.out.print("Agent overlap block: " + en);
en.previousPosition = new Dimension(block.position.width, block.position.height);
en.setPosition(agent.previousPosition);
}
}
}
First Of All, you haven't told where did the "block" in the if statement came from.
What you may need to do, is:
public void swap(){
for(Entity en:entityList){
if((en instanceof Block)&&(en.position.equals(agent.position)){
// ^here is "en" instead of block
System.out.println("Agent overlab block: "+en);
en.previousPosition=new Dimension(
en.position.width,
en.position.height);
en.setPosition(agent.previousPosition);
}
}
}
At last, you may use java.awt.Point instead of Dimension.
Also, you should use setter method for the field "previousPosition".
Your problem is that your code does stuff if agent.position and block.position are equal; but in the example you talk about, agent.position and block.position are different. So your code is never actually making any changes.
Everywhere you use the block variable in the function, you need to change it with en since your for loop no longer creates a variable named block.
When you move entities around in this function, be careful that you don't accidentally try to swap the agent with itself!

Categories

Resources