I am designing a multiplayer online game for the sake of learning.
Several clients connect to a server that contains the true representation of the game world. Every client keeps track of a subset of that representation. I store the representations in a Context. The clients and the server change the state of the global context by passing various action classes around. One example is the MoveEntityAction, another is the TalkAction, and they all implement an interface called Action. In principle, the game is played by a flow of Action instances.
However, passing actions back and forth requires some fiddling. First, provide a definition of how they are read and written to the network. Second, protocol to translate them back and forth between the global and local contexts (different coordinate systems, etc). Third, let the server determine which actions need to preceed another action (I hope that is made clear by the pseudo-code below).
Right now, this process relies on several helper classes, each implementing an interface called Writer, Reader, ContextSwitcher and PrerequisiteFinder.
This has made me do the following:
Create a lookup table, ActionLibrary, that defines methods such as getReader(int actionId), getWriter(<Class <? extends Action> a), etc.
The classes that implement the helper interfaces are highly dependent on their associated Action class.
My game will have quite many classes implementing the Action interface, which means that every such class would require the implementation of 3 additional helper classes, each containing the protocol for dealing with a specific action. For example, MoveEntityReader, MoveEntityWriter, MoveEntityContextSwitcher, MoveEntityPrerequisiteFinder.
In spite of trying to adhere to the single responsibility principle, this approach does not feel very flexible. In fact, it feels quite awkward to distribute small pieces of protocol over several classes like this. And the ActionLibrary class does not feel like the best practice to associate these classes with each other.
Below is some example code of how an action might "flow" back and forth between the client and the server. Please note that this is pseudo-code written for this example, but hopefully it captures the essentials of what my real code does. In the below code, each Entity can be regarded as a client.
Human input (dragging and dropping an item on the screen) generates an instance of moveEntityAction. It is passed to the network stream as follows
writer = ActionLibrary.getWriter(moveEntityAction);
writer.writeTo(outputStream, moveEntityAction);
Server receives a packet with an ID and translates it to the global context, the servers representation of the game world:
reader = ActionLibrary.getReader(Id);
localAction = reader.readFrom(inputStream);
globalAction = ActionLibrary.getContextSwitcher(localAction.getClass(), playerContext, globalContext).apply(localAction);
After verifying that the action is OK, the server decides to broadcast the action to all the other clients. However, before it can do that it must broadcast the "prerequisites" of that action to every client. For example, if a MoveEntityAction moves an entity into the screen of a second entity, a PlaceEntityAction must be sent to the second entity first, so that it has an object to move. That happens as follows:
List<Entity> spectators = globalContext.getActionSpectators(globalAction);
for (Entity spectator : spectators) {
List<Action> prerequisiteActions = ActionLibrary.getPrerequisiteFinder(globalAction.getClass()).get(spectator, globalAction, globalContext);
spectatorContext = globalContext.getContextOf(spectator);
// Broadcast prerequisite actions (if any)
for (Action globalPreAction : prerequisiteActions) {
localPreAction = ActionLibrary.getContextSwitcher(globalPreAction.getClass(), globalContext, spectatorContext).apply(globalPreAction);
writer = ActionLibrary.getWriter(localPreAction);
writer.writeTo(outputStream);
}
// Finally, send the instigating action:
localAction = ActionLibrary.getContextSwitcher(globalAction.getClass(), globalContext, spectatorContext).apply(globalAction);
writer = ActionLibrary.getWriter(localAction);
writer.writeTo(outputStream);
}
// Execute the action on the globalContext
globalContext = globalAction.execute(globalAction);
then, the client receives each packet and its id, finds the corresponding reader and applies that to its local Context:
reader = ActionLibrary.getReader(Id);
localAction = reader.readFrom(inputStream);
context = localAction.execute(context);
I am basically looking for some thoughts and advice on the matter. How would you clean this mess up? Maybe there is a design pattern for situations like mine where I risk entangling myself with a bunch of helper classes.
Thank you in advance!
Edit: I would like to avoid Serializable for several reasons. One being that the client might not be written in Java. Another being that I want to pick up a general best practice here because in time I might turn this into a private server for another game that I do not own the network protocol for.
Related
I am reading the headfirst design patterns book.
I observe that the client is shown analogous to a hotel customer, who creates an order(command) object, the waitress(invoker) picks it and calls its execute() method which in turn calls the chef's cook() method(chef=receiver)
In the command pattern class diagram, I can see client is associated with Receiver as well as the ConcreteCommand class. I am unable to get the example because in real world, a customer is not supposed to know about the cook and set the instructions for him. Other concern is that in the command pattern class diagram, I observe that Client is not shown associated with Invoker, but in the attached java program I can see the Invoker reference in the Client class.
Totally confused about what Client module does in the command pattern. Clear about the rest 4 modules.
Read this: http://www.oodesign.com/command-pattern.html
Client creates a ConcreteCommand object and sets its receiver [...] The Client asks for a command to be executed.
It even has sample code that show what the client does:
The client creates some orders for buying and selling stocks (ConcreteCommands). Then the orders are sent to the agent (Invoker). [...]
public class Client {
public static void main(String[] args) {
StockTrade stock = new StockTrade();
BuyStockOrder bsc = new BuyStockOrder (stock);
SellStockOrder ssc = new SellStockOrder (stock);
Agent agent = new Agent();
agent.placeOrder(bsc); // Buy Shares
agent.placeOrder(ssc); // Sell Shares
}
}
You've stumbled upon the challenge with demonstrating design patterns with analogy, by a single concrete example, or with object diagrams. Except for very simple patterns, the concepts and examples usually don't map perfectly to all useful instances of the pattern.
I highly recommend that you pick several sources to learn any of the more complex design patterns. Every explanation is going to have strengths and weaknesses, and you'll probably get a more accurate picture if you take several viewpoints into account. There are plenty of free sources available on the Internet, so you probably don't need to buy additional books (except, eventually, the original Design Patterns book, for reference purposes).
What isn't clear in the diagram is that the Client, the Invoker, and the Receiver are abstract concepts, and don't have a single form that always applies in every case. In any particular implementation of the command pattern, most of these roles are going to be present (except maybe the Receiver - it is possible that the command is self-contained). You may even be able to point out a specific bit of code that maps to each of these roles, but it's going to map differently in every application. It may even map differently in separate parts of the same application.
There are parts of the diagram you shared that I have problems with, because they are not always true. The Client might not directly access or even know about the Receiver. The Client might also not know about specific ConcreteCommand objects. The Client might know how to ask for an instance of a command, and it might know some information that helps pick the right command. However, the client might in some cases be oblivious to which ConcreteCommand object was executed, especially if you combine the command pattern with the AbstractFactory pattern.
in real world, a customer is not supposed to know about the cook and set the instructions for him
Analogies and models tend to break down or become confusing when you compare them strictly to reality. It is best to try to figure out what the model is trying to accomplish, and which possible interpretation of reality that the model is trying to account for.
Also, not all models/analogies are any good :) Sometimes they don't actually get the job done.
I observe that Client is not shown associated with Invoker
This is perfectly valid in some implementations of the pattern. The code that eventually calls execute() may not be the same code that is capable of accepting actions.
The diagram may show a single box, but in the restaurant analogy, the waiter, the cooks, the busboys, the host, the cashier, etc, are all a part of that Invoker role.
The problem with the diagram is that the client eventually has to pass the command off to the invoker. The invoker itself might have a way to accomplish this, or there may be some sort of system in between (like a command queue). Either way, in their explanation, the invoker role handles both things, and the client must therefore know about the invoker.
Finally:
What does the client do in Command Pattern?
The Client is responsible for knowing that it wants a command to be done
The Client is responsible for knowing how to pick which command gets done, and get an instance of it (even if the client delegates the actual construction of that ConcreteCommand to some other part of the system)
The Client is responsible for knowing how to pass off a command so that it will eventually be invoked (passing it to some object in the Invoker role, even if that command eventually gets passed off to some other object that actually calls execute())
The Client is responsible for actually handing off the command to the Invoker (whether it is directly handed off, or passed off to some intermediate part of the system first)
So the idea of a client is in opposition to the idea of a server. (for get the restaurant metaphor for a minute). The server is the centralized application, the client is the interface presented on a users machine. The client machine or GUI signals wither a receiver (middle man) or your program directly to make things happen.
I hope this makes things a little clearer.
Within Java you can create an Observer-Observable set of classes in which the Observable can call the Observer. You can also in java explicitly reference an owning class instance in a child instance of another class and call the owning class instance's public functions.
Which is the better approach to take? Which is more beneficial in different scenarios, one example being Multi-Threading?
The Observer Pattern should be used whenever you don't know or don't care who is observing you. This is the key-concept in event-driven programming. You don't have any control of who is observing or what they do when you broadcast your events. Like you already mentioned in your comments, this is great for decoupling classes.
An example of a usage could be in a plugin-architecture:
You write a basic mail-server that broadcasts whenever a mail is received. You could then have a spam-plugin that validates the incoming mail, an auto-reply service that sends a reply, a forward service that redirects the mail and so on. Your plain mail server (the observable) doesn't know anything about spam, replies or forwarding. It just shouts out "Hey, a new mail is here" not knowing if anyone is listening. Then each of the plugins (the observers) does their own special thing, not knowing anything about each other. This system is very flexible and could easily be extended.
But the flexibility provided by the Observer Pattern is a two-edged sword. In the mail-server example, each plugin handles the incoming mail in total isolation from each other. This makes it impossible to setup rules like "don't reply or forward spam" because the observers doesn't know about each other - and even if they did, they wouldn't know in what order they are executed or has completed. So for the basic mail-server to solve this problem, It'll need to have references to the instances that does the spam/reply/forward actions.
So the Observer Pattern provides flexibility. You could easily add a new anti-virus plugin later, without having to modify your plain mail server code. The cost of this flexibility is loss of control of the flow of actions.
The reference approach gives you total control of the flow of actions. However you would need to modify your plain mail server code if you ever need to add support for an anti-virus plugin.
I hope this example gives you some ideas of the pros and cons of each approach.
In regards to multi-threading, one approach isn't favorable over the other.
We have an application that is composed of a number of independent components and sub-systems. We are looking at implementing a simple event logging mechanism where these components & sub-systems can log some events of interest. Events could be something like
New account created
Flight arrived
Weekly report dispatched to management etc.
As you can see, the event types are heterogeneous in nature and the attributes that needs to be logged differs based on the event types. New account created event, for example, will also log the account-id, the name of the user who created the new account etc. Whereas, the flight arrived event will be logging the flight number, arrived at, arrived from etc.
I'm wondering what is the good way of modelling the event types and the attributes.
One option is to do it object oriented way - to have an AbstractEvent that will have some common attributes (timestamp, message etc) and then create a full hierarchy of classes underneath. The flight events, for example, can look like
abstract class AbstractEvent;
abstract class FlightEvent extends AbstractEvent;
class FlightArrivedEvent extends FlightEvent;
class FlightCancelledEvent extends FlightEvent;
The problem I see with this approch is that we have hundreds of events which will result in class explosion. Also, whenever we add a new event (very likely), we have to create a class and distribute the new package to all the components and sub-systems.
The second option I can think of is on the other end of the spectrum. Have a simple Event class that contains the basic attributes and wrap a map inside it so that the clients can populate any data they want. The code in that case will look something like this.
class Event {
private timestamp;
private eventType;
private Map attributes;
public Event ( String eventType ) {
timestamp = System.nanoTime();
this.eventType = eventType;
attributes = new HashMap();
}
public Event add ( String key, String value ) {
attributes.put ( key, value );
return this;
}
}
//Client code.
Event e = new Event("FlightEvent:FlightArrived")
.add("FLIGHT_NUMBER", "ABC123")
.add("ARRIVED_AT", "12:34");
While this is flexible, it suffers from inconsitency. Two components can log the FLIGHT_NUMBER key in two different formats (FLIGHT_NUMBER & FLGT_NO) and I can't think of a good way to enforce some convention.
Any one have some suggestions that can provide a nice compromise between these two extreme options?
There is a Java event framework (see java.util.EventObject and the Beans framework) but the fundamental question you are asking is not connected with events. It is a design question, and it is this: do I use Java classes in my application to represent classes in my business domain?
It is clear that the different types of event are different "classes" of thing, but for maintainability reasons you are considering representing your business data in a map so that you don't have to write and distribute an actual class. If you take this to a logical extreme, you could design your whole application with no classes and just use maps and name-value pairs for everything - not just events. It would be a mess and you would be debugging it forever because you would have no type-safety whatsoever. The only way of finding what was in map would be to look up in some documentation somewhere what someone might have added to it and what type that object might be.
So, here is the thing - you would not have actually have gotten rid of your class definition.
You will have moved it into a Word document somewhere that people will have to refer to in order to understand what is in your map. The Word document will need to be maintained, verified and distributed but unlike the Java class, it won't be checked by the compiler and there is no guarantee that the programmers will interpret it correctly.
So I would say, if there is a class, put it in your code and then focus on solving the problems of distributing and versioning the Java classes instead of distributing and versioning Word documents.
I will mention versioning again as this is an issue if you might serialise the objects and restore them, so you need to think about that.
Some caveats:
If you are writing a piece of middleware software that routes events from one system to another system, it might be you don't need to know are care what the data is, and it might make sense to use a generic holder in this case. If you don't need to look at the data, you don't need a class for it.
You might get complaints from high-level designers and architects about the number of classes and the work they have to do in defining them compared with a map and name/value stuff. This is because putting classes (i.e., the real design) in Java is harder than putting them in a Word document. Easier, if you are high-level hand-waving type guy, to write something wishy-washy in Word that doesn't need to run or even compile and then give the real design work to the programmers to get working.
Can [someone] provide a nice compromise between these two extreme options?
No. There is no generic one-size-fits-all answer to this problem. You will have to find yourself a balance which fits the general design of your product. If you nail everything down, you will need thousands of classes. If you give a lot of leeway, you can get away with a few but you're paying your freedom with precision. See my blog post "Designing a Garbage Bin"
Do you have shared attributes? As in: Do you expect to define attributes of events like you define classes right now with very tight-fitting semantics?
That would mean you have a simple event and typed attributes (i.e. String value simply isn't sufficient). You need formatting and validation for attributes or ... attributes themselves need to be classes.
If this is the case, you can use my type-safe map pattern: http://blog.pdark.de/2010/05/28/type-safe-object-map/
Event type "explosion" is not a problem. In fact it is a desirable approach as it allows the components to be independent of one another. I wouldn't necessarily make all events inherit from a single superclass unless it gives you a lot of reusable code because it can cause dependencies to start proliferating.
I would put the event types in a separate project that will be a dependency of both the publisher and consumer.
What is your communication mechanism for these events between components? JMS? If so you could also consider making your messages XML and using JAXB.
I would definitely discount the map approach as it destroys any hope of polymorphism or any other oo niceties.
Hey guys,
I'm using GWT to code a simple multiplayer board game.
And while I was coding the question came up to my mind:
At first I though my client could simply communicate with the server via RemoteServices calls, so if a client wanted to connect to a game he could do as follows:
joinGame (String playerName, String gameName)
And the server implementation would do the necessary processing with the argument's data.
In other words, I would have lots of RemoteService methods, one for each type of message in the worst case.
I thought of another way, which would be creating a Message class and sub-classing it as needed.
This way, a single remoteService method would be enough:
sendMessage (Message m)
The messages building and interpreting processing too would be done by specialized classes.
Specially the building class could even be put in the gwt-app shared package.
That said,
I can't see the benefits of one or another. Thus I'm not sure if I should do one way or another or even another completely different way.
One vs other, who do you think it is better (has more benefits in the given situation)?
EDIT: A thing I forgot to mention is that one of the factors that made me think of the second (sendMessage) option was that in my application there is a CometServlet that queries game instances to see if there is not sent messages to the client in its own message queue (each client has a message queue).
I prefer the command pattern in this case (something like your sendMessage() concept).
If you have one remote service method that accepts a Command, caching becomes very simple. Batching is also easier to implement in this case. You can also add undo functionality, if that's something you think you may need.
The gwt-dispatch project is a great framework that brings this pattern to GWT.
Messaging takes more programmer time and creates a more obfuscated interface. Using remote service methods is cleaner and faster. If you think there are too many then you can split your service into multiple services. You could have a service for high scores, a service for player records, and a service for the actual game.
The only advantage I can see with messaging is that it could be slightly more portable if you were to move away from a Java RPC environment but that would be a fairly drastic shift.
I'm part of a team designing the server for a client/server model naval warfare video game (University course). We have a fairly concrete (well, I think) system design, but there is one aspect that bothers me.
The basic layout of the system is:
Server [thread] (handles incoming connections)
|
Game [thread] (deals with game events in it's work queue and sending messages to clients)
|--Environment (holds environment variables, deals with collision)
|--Client(s) [thread] (handles incoming messages from client sockets and adds events to the Game's work queue)
|--Ship (holds game data, eg: hit points, fire power, etc)
|--Parser (parses client messages and creates game event objects)
|--GameEvent (event objects held in a queue that can preform appropriate work and send appropriate responses to clients)
Now, my issue is that both Client and GameEvent (and probably Environment, once we get to it) need a reference to the Game object that they belong to.
Clients need to add GameEvent's to the Game's work queue.
GameEvent's need to access other game data (other Client's Ships, Environment).
Is there a better/more conventional method instead of having these objects store a local reference to their Game? What about declaring all of Game's methods as static? We only need to handle one game at a time, so there wouldn't ever be more than one instance of Game...
I'm sure there is a convention for a system with one central object that has many helper objects that need to reference it.
Did you consider using a Dependency Injection framework like Guice? There you have config classes called "modules", where you bind your interface Game to an implementation (you can decide if you want a singleton or new instances). A Client class would look like
public class Client {
private final Game game;
#Inject
public Client(Game game) {
this.game = game;
}
...
}
You can construct this class as usual, providing a Game instance (e.g. for testing, using a mock Game class). But if you let Guice create this instance for you (which doesn't need to be directly, it works as well if another class injects Client), you get automatically the instance specified in your Guice module.
I know it takes some time to wrap your head around that concept, but I can confirm that this leads to cleaner, more flexible code.
If there's really only logically ever one instance, you can use a singleton. The canonical form of a singleton is:
public enum Singleton {
INSTANCE;
// fields and methods here
}
That way, you don't have to shoehorn everything into static methods (though, if you want to write static methods that reference INSTANCE, that's fine too). Any code that wants to access the singleton just uses Singleton.INSTANCE, and you don't have to pass it around if you don't want to.
Passing the reference around will keep your options open, it can still be a reference to an actual static object. Also the concept of a request context might be useful, an object that holds all references needed to process a single request, and you pass that around.
Check out Inversion of Control (IOC) and containers.
That way, in your Client and GameEvent classes, whenever you need access to the Game, you just do something like:
var game = IoC.Resolve<Game>();
And then use the game instance methods...
I would strongly advise not using a singleton or a static class in your design. There are lots of reasons for this, but the one that will probably affect you most immediately is that it makes things very hard to test. At testing time, there will probably be more than one instance of Game.
A common convention to ameliorate having one big central object with lots of helper objects is to try to avoid one big central object. You note that there are different clients of 'Game' with different needs. Maybe your interface on Game is too wide.
There's nothing wrong with passing references to a constructor and storing them. You should also introduce an interface that will mediate access between your Game and your client and environment objects.