lfdversluis / fddg Goto Github PK
View Code? Open in Web Editor NEWFault-tolerant Distributed Dragon Game - distributed computing systems lab
License: MIT License
Fault-tolerant Distributed Dragon Game - distributed computing systems lab
License: MIT License
Since one of the requirements of the game is to implement a realistic pattern of connecting/disconnection actions from clients and crashing of servers, we should come up with a model for this. The assignment has two pointers to existing literature:
http://ieeexplore.ieee.org/xpl/articleDetails.jsp?arnumber=6404027
http://www.pds.ewi.tudelft.nl/~iosup/game-trace-archive12netgames.pdf
We should dedicate a section in the report about the client simulation. I think this is a good opportunity to actually make some references.
Currently, requests from a server of which not all acks are received are never removed from the buffer. We should probably implement this using a timer for each request (of for instance 5s). When all acks are received, the timer should be stopped. When it expires, the request should be removed
Now, all clients simple try to connect to the first server in the setup/servers.txt
file. However, they should randomly pick one of them and try to connect to it. When this fails, it should randomly select another server.
Here are some comments I have on the current codebase:
nl.tud
) are not really unique. Something like nl.tud.dcs.fddg
will be much better. (fixed in #29)ServerProcess.run()
? This is an example of where a comment should clarify this ;) (fixed in 2082fd7)ServerProcess.connect()
) is not going to work when the clients run on different machines: ClientInterface ci = (ClientInterface) Naming.lookup("rmi://localhost:" + Main.SERVER_PORT + "/FDDGClient/" + playerId);
(fixed in #47)ServerProcess.broadcastFieldToConnectedPlayers()
does not meet our design as the entire field is only sent once to each client (when he connects), so it will never be broadcast. This is probably related to issue #24XAction
classes do not really represent game objects, so I would put them in another package. (fixed in #29)Field.getDirectionToNearestDragon()
you can better use the copy constructor of ArrayList (so new ArrayList<>(path)
) instead of: ArrayList<Integer> updatedPath = new ArrayList<Integer>(path.size()); for(int pos : path){ updatedPath.add(pos); }
(fixed in #29)Field.dragonRage()
function should be replaced because this function only works when there is only one server. With multiple servers, the game state will become inconsistent. Perhaps only perform the rage on the players that have connected to the particular server. Then there is no need for sending messages to other servers. (fixed in #47)With two hosts of which at least one does not run Windows when you start one client, you get the following exception:
INFO: Starting client
mrt 22, 2015 4:55:38 PM nl.tud.dcs.fddg.client.ClientProcess selectServer
INFO: Client 0 trying to connect to //localhost:1099/FDDGServer/0
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.ConnectException: Connection refused to host: 127.0.1.1; nested exception is:
java.net.ConnectException: Connection refused: connect
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:354)
at sun.rmi.transport.Transport$1.run(Transport.java:200)
at sun.rmi.transport.Transport$1.run(Transport.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$240(TCPTransport.java:683)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$17/1664698779.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source)
at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)
at sun.rmi.server.UnicastRef.invoke(Unknown Source)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source)
at com.sun.proxy.$Proxy1.connect(Unknown Source)
at nl.tud.dcs.fddg.client.ClientProcess.run(ClientProcess.java:112)
at java.lang.Thread.run(Unknown Source)
Caused by: java.rmi.ConnectException: Connection refused to host: 127.0.1.1; nested exception is:
java.net.ConnectException: Connection refused: connect
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:619)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:216)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:202)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:130)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:194)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:148)
at com.sun.proxy.$Proxy0.performAction(Unknown Source)
at nl.tud.dcs.fddg.server.ServerProcess.broadcastActionToServers(ServerProcess.java:363)
at nl.tud.dcs.fddg.server.ServerProcess.connect(ServerProcess.java:234)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:323)
at sun.rmi.transport.Transport$1.run(Transport.java:200)
at sun.rmi.transport.Transport$1.run(Transport.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$240(TCPTransport.java:683)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$17/1664698779.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:345)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at java.net.Socket.connect(Socket.java:538)
at java.net.Socket.<init>(Socket.java:434)
at java.net.Socket.<init>(Socket.java:211)
at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:40)
at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:148)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:613)
... 26 more
If a server pings a peer server and it fails two times, what do you do?
Following the discussion in #47, we should remove the checks for multiple heal or actions and see what happens
Now the dragonRage function looks as follows:
Set<Action> actionSet = new HashSet<Action>();
for (int dragonId : dragonMap.keySet()) {
Dragon d = dragonMap.get(dragonId);
int dragonX = d.getxPos();
int dragonY = d.getyPos();
for (int i = 0; i < 4; i++) {
int unitX = dragonX + dx[i];
int unitY = dragonY + dy[i];
if (isInBoard(unitX, unitY) && entities[unitY][unitX] instanceof Player && connectedPlayers.contains(entities[unitY][unitX].getUnitId())) {
Player p = (Player) entities[unitY][unitX];
p.setCurHitPoints(p.getCurHitPoints() - d.getAttackPower());
if (p.getCurHitPoints() <= 0) {
DeleteUnitAction dua = new DeleteUnitAction(p.getUnitId());
actionSet.add(dua);
removePlayer(p.getUnitId());
}
DamageAction da = new DamageAction(p.getUnitId(), d.getAttackPower());
actionSet.add(da);
}
}
}
return actionSet;
Dragon can attack players when the distance between them is at most 2. However, in the code above the for-loop doesn't do this correctly, as it only seems to search for players that are to right and above the dragon (and not also below or to the left). Also the range for searching these players is to big, as it can only be 2 at most (so horizontalDistance+vertDistance <= 2)
After a while (with 100 clients), I get the following exception in multiple client processes:
Exception in thread "Thread-43" java.lang.NullPointerException
at nl.tud.dcs.fddg.game.Field.isInRange(Field.java:108)
at nl.tud.dcs.fddg.server.ServerProcess.attack(ServerProcess.java:128)
at nl.tud.dcs.fddg.server.ServerProcess.performAction(ServerProcess.java:91)
at sun.reflect.GeneratedMethodAccessor9.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
at sun.rmi.transport.Transport$1.run(Unknown Source)
at sun.rmi.transport.Transport$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$240(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$17/833442319.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source)
at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)
at sun.rmi.server.UnicastRef.invoke(Unknown Source)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source)
at com.sun.proxy.$Proxy1.performAction(Unknown Source)
at nl.tud.dcs.fddg.client.ClientProcess.run(ClientProcess.java:82)
at java.lang.Thread.run(Unknown Source)
Now, when two clients connect to two different servers, both can receive the same ID which leads to a field with two players with the same ID.
Now, when you start only one client, it also sends requests for a HealAction to the server. However, this should not be possible with one client (as there is no other player to heal).
java.rmi.NotBoundException: FDDGClient/0
at sun.rmi.registry.RegistryImpl.lookup(RegistryImpl.java:136)
at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:409)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:267)
at sun.rmi.transport.Transport$1.run(Transport.java:177)
at sun.rmi.transport.Transport$1.run(Transport.java:174)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:173)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:556)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:811)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:670)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:275)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:252)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:378)
at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
at java.rmi.Naming.lookup(Naming.java:101)
at nl.tud.dcs.fddg.server.ServerProcess.reconnect(ServerProcess.java:326)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:322)
at sun.rmi.transport.Transport$1.run(Transport.java:177)
at sun.rmi.transport.Transport$1.run(Transport.java:174)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:173)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:556)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:811)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:670)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
It could be a GUI issue maybe?
Now, clients can only be run on the same host as the server they connect to. However, clients should be able to connect to servers that run on other hosts
The servers are stopping if one of the clients disconnect.
We should dedicate a short section of our report discussing the pros and cons of the decisions we made about:
-replication
-fault tolerance
-consistency
I am perfectly fine with keeping the repository on my account until you want to open source it, but if anyone else has a slot for a private repository and wants to take ownership, let me know ๐
In the current code, when the server a client was connected to crashes, it selects another server. However, this client is never added to the connectedPlayers map in the new server (as connect() is not called). In this way it is never attacked by dragons anymore
When one of the servers decides to finish the game, it should broadcast this to all other servers and clients. The other servers and clients can then also finish the game (and exit the program).
Now we can generate files for simulation, the simulation file should be read and executed. This can for example be done in Java or Bash.
a player can hit a dragon (or vice versa) from a distance of at most 2 squares.
We implemented 1 :(
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.