Skip to content

Commit

Permalink
Merge pull request #217 from floralvikings/v0.7.0-alpha-release
Browse files Browse the repository at this point in the history
V0.7.0 alpha release
  • Loading branch information
floralvikings committed Nov 3, 2014
2 parents d992f3e + ad37175 commit 99c070d
Show file tree
Hide file tree
Showing 170 changed files with 4,077 additions and 3,253 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Jenjin ![Build Status](https://travis-ci.org/floralvikings/jenjin.svg?branch=jenjin-184)
Jenjin ![Build Status](https://travis-ci.org/floralvikings/jenjin.svg?branch=master)
=====

The Jenjin is a flexible server architecture designed for use in MMORPGs.
Expand Down Expand Up @@ -46,7 +46,7 @@ the Travis automated building is helping with that a great deal.

Special thanks go out to:

* [This blog](http://seamless-pixels.blogspot.co.uk/), which supplied all the textures used in the demo application. These
* [This blog](http://seamless-pixels.blogspot.co.uk/), which supplied all the textures used in early testing versions of the demo application. These
textures are high-resolution, tileable, and very, very nice. They are completely free but there is an option to download the entire
archive for as little as $1.99 should you desire to support an open-source artist. (You should.)

Expand All @@ -58,3 +58,4 @@ The Jenjin itself does not use any third party dependencies; however, the tests

* The Jenjin uses [TestNG](http://testng.org/doc/index.html) for unit tests. ([License](http://testng.org/license/))
* For database integration tests, [H2Database](http://h2database.com/html/main.html) is used. ([License](http://h2database.com/html/license.html))
* The Jenjin World modules make use of [Gson](https://code.google.com/p/google-gson/). ([License](http://www.apache.org/licenses/LICENSE-2.0))
3 changes: 1 addition & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ allprojects {
apply plugin: 'maven'

group = 'com.jenjinstudios'
version = '0.6.0-alpha'
version = '0.7.0-alpha'
}

subprojects {
apply plugin: 'java'
//apply plugin: 'jacoco'

repositories {
mavenLocal()
Expand Down
2 changes: 1 addition & 1 deletion jenjin-core-client/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
description = ''
description = 'Jenjin Core Client'

dependencies {
compile project(':jenjin-core')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package com.jenjinstudios.client.message;

import com.jenjinstudios.core.message.ExecutableMessage;
import com.jenjinstudios.core.io.Message;
import com.jenjinstudios.client.net.Client;
import com.jenjinstudios.core.io.Message;
import com.jenjinstudios.core.message.ExecutableMessage;

/**
* Superclass of ExecutableMessages used by the client.
* @author Caleb Brinkman
*/
// TODO This class can probably be refactored away; should the subclasses just cast the constructor arguments?
public abstract class ClientExecutableMessage extends ExecutableMessage
{
/** The client invoking this ExecutableMessage. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,31 @@

import com.jenjinstudios.client.net.ClientUser;
import com.jenjinstudios.core.io.Message;
import com.jenjinstudios.core.io.MessageRegistry;
import com.jenjinstudios.core.util.MessageFactory;

/**
* Used to generate messages for the Jenjin core client.
*
* @author Caleb Brinkman
*/
public class ClientMessageFactory extends MessageFactory
{

/**
* Generate a LogoutRequest message.
*
* @return The LogoutRequestMessage.
*/
public Message generateLogoutRequest() {return getMessageRegistry().createMessage("LogoutRequest");}
public Message generateLogoutRequest() { return MessageRegistry.getInstance().createMessage("LogoutRequest");}

/**
* Generate a LoginRequest message. This message will be encrypted if possible.
*
* @return The LoginRequest message.
*/
public Message generateLoginRequest(ClientUser user) {// Create the login request.
Message loginRequest = getMessageRegistry().createMessage("LoginRequest");
Message loginRequest = MessageRegistry.getInstance().createMessage("LoginRequest");
loginRequest.setArgument("username", user.getUsername());
loginRequest.setArgument("password", user.getPassword());
return loginRequest;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
import com.jenjinstudios.client.message.ClientMessageFactory;
import com.jenjinstudios.core.Connection;
import com.jenjinstudios.core.MessageIO;
import com.jenjinstudios.core.util.MessageFactory;

import java.util.LinkedList;
import java.util.List;
import java.util.Timer;

/**
* The base class for any client. This class uses a similar system to the JGSA.
*
* @author Caleb Brinkman
*/
public class Client extends Connection
Expand All @@ -20,6 +22,7 @@ public class Client extends Connection
private final ClientMessageFactory messageFactory;
/** The timer that manages the update loop. */
private Timer sendMessagesTimer;
private ClientLoop clientLoop = new ClientLoop(this);

/**
* Construct a new client and attempt to connect to the server over the specified port.
Expand All @@ -32,6 +35,7 @@ protected Client(MessageIO messageIO) {

/**
* Add a task to the repeated queue of this client. Should be called to extend client functionality.
*
* @param r The task to be performed.
*/
public void addRepeatedTask(Runnable r) {
Expand All @@ -52,16 +56,15 @@ public void shutdown() {
}

@Override
public void run() {
public void start() {
int period = 1000 / 60;

// Finally, send a ping request to establish latency.
queueOutgoingMessage(messageFactory.generatePingRequest());
getMessageIO().queueOutgoingMessage(MessageFactory.generatePingRequest());

sendMessagesTimer = new Timer("Client Update Loop", false);
sendMessagesTimer.scheduleAtFixedRate(new ClientLoop(this), 0, period);
sendMessagesTimer.scheduleAtFixedRate(clientLoop, 0, period);

super.run();
super.start();
}

/** Run the repeated synchronized tasks. */
Expand All @@ -72,4 +75,6 @@ protected void runRepeatedTasks() {
r.run();
}
}

public double getAverageUPS() { return 1d / clientLoop.getAverageRunTime(); }
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
package com.jenjinstudios.client.net;

import java.io.IOException;
import java.util.TimerTask;

/**
* The ClientLoop class is essentially what amounts to the output thread.
*
* @author Caleb Brinkman
*/

class ClientLoop extends TimerTask
{
/** The Client for this loop. */
private final Client client;
private int updateCount = 0;
private long lastStart = System.nanoTime();
private final long[] updateTimesNanos = new long[50];

/**
* Construct a ClientLoop for the given client.
*
* @param client The client for this ClientLoop
*/
public ClientLoop(Client client) {
Expand All @@ -22,9 +28,34 @@ public ClientLoop(Client client) {

@Override
public void run() {
updateCount++;
saveUpdateTime();
client.runRepeatedTasks();
client.runQueuedExecutableMessages();
client.writeAllMessages();
client.getExecutableMessageQueue().runQueuedExecutableMessages();
try
{
client.getMessageIO().writeAllMessages();
} catch (IOException e)
{
client.shutdown();
}
}

private void saveUpdateTime() {
long newStart = System.nanoTime();
long timeElapsed = newStart - lastStart;
lastStart = newStart;
updateTimesNanos[updateCount % updateTimesNanos.length] = timeElapsed;
}

public double getAverageRunTime() {
double maxIndex = Math.min(updateCount, updateTimesNanos.length);
double total = 0;
for (int i = 0; i < maxIndex; i++)
{
total += updateTimesNanos[i];
}
return (total / maxIndex) / 1000000000;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public void setLoggedIn(boolean loggedIn) {
protected void sendLoginRequest() {
waitingForResponse = true;
Message message = ((ClientMessageFactory) client.getMessageFactory()).generateLoginRequest(client.getUser());
client.queueOutgoingMessage(message);
client.getMessageIO().queueOutgoingMessage(message);
}

public boolean sendLoginRequestAndWaitForResponse() {
Expand All @@ -59,7 +59,7 @@ public void sendLogoutRequestAndWaitForResponse() {
private void sendLogoutRequest() {
waitingForResponse = true;
Message message = ((ClientMessageFactory) client.getMessageFactory()).generateLogoutRequest();
client.queueOutgoingMessage(message);
client.getMessageIO().queueOutgoingMessage(message);
}

private void waitTenMillis() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
<?xml version="1.0" ?>

<messages>
<messages xmlns="https://www.jenjinstudios.com">

<message name="LoginRequest" id="101">
<message name="LoginRequest" id="101">
<argument type="String" name="username" encrypt="true" />
<argument type="String" name="password" encrypt="true" />
<executable language="java">com.jenjinstudios.server.message.ExecutableLoginRequest</executable>
<executable>com.jenjinstudios.server.message.ExecutableLoginRequest</executable>
</message>

<message name="LoginResponse" id="102">
<argument type="boolean" name="success" />
<argument type="long" name="loginTime" />
<executable language="java">com.jenjinstudios.client.message.ExecutableLoginResponse</executable>
<executable>com.jenjinstudios.client.message.ExecutableLoginResponse</executable>
</message>

<message name="LogoutRequest" id="103">
<executable language="java">com.jenjinstudios.server.message.ExecutableLogoutRequest</executable>
<executable>com.jenjinstudios.server.message.ExecutableLogoutRequest</executable>
</message>

<message name="LogoutResponse" id="104">
<argument type="boolean" name="success" />
<executable language="java">com.jenjinstudios.client.message.ExecutableLogoutResponse</executable>
<executable>com.jenjinstudios.client.message.ExecutableLogoutResponse</executable>
</message>

</messages>
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import org.testng.annotations.Test;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/**
* @author Caleb Brinkman
Expand All @@ -16,11 +15,9 @@ public class AuthClientTest
{
@Test
public void testIsLoggedIn() {
MessageIO messageIO = mock(MessageIO.class);
MessageInputStream mis = mock(MessageInputStream.class);
MessageOutputStream mos = mock(MessageOutputStream.class);
when(messageIO.getIn()).thenReturn(mis);
when(messageIO.getOut()).thenReturn(mos);
MessageIO messageIO = new MessageIO(mis, mos);
ClientUser clientUser = mock(ClientUser.class);
boolean random = Math.random() * 10 % 2 == 0;
AuthClient authClient = new AuthClient(messageIO, clientUser);
Expand All @@ -31,11 +28,9 @@ public void testIsLoggedIn() {

@Test
public void testLoggedInTime() {
MessageIO messageIO = mock(MessageIO.class);
MessageInputStream mis = mock(MessageInputStream.class);
MessageOutputStream mos = mock(MessageOutputStream.class);
when(messageIO.getIn()).thenReturn(mis);
when(messageIO.getOut()).thenReturn(mos);
MessageIO messageIO = new MessageIO(mis, mos);
ClientUser clientUser = mock(ClientUser.class);
long random = (long) (Math.random() * 1000);
AuthClient authClient = new AuthClient(messageIO, clientUser);
Expand All @@ -46,11 +41,9 @@ public void testLoggedInTime() {

@Test
public void testGetUser() {
MessageIO messageIO = mock(MessageIO.class);
MessageInputStream mis = mock(MessageInputStream.class);
MessageOutputStream mos = mock(MessageOutputStream.class);
when(messageIO.getIn()).thenReturn(mis);
when(messageIO.getOut()).thenReturn(mos);
MessageIO messageIO = new MessageIO(mis, mos);
ClientUser clientUser = mock(ClientUser.class);
AuthClient authClient = new AuthClient(messageIO, clientUser);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import com.jenjinstudios.core.io.MessageOutputStream;
import org.testng.annotations.Test;

import static org.mockito.Mockito.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

/**
* @author Caleb Brinkman
Expand All @@ -14,11 +15,9 @@ public class ClientTest
{
@Test
public void testAddRepeatedTask() {
MessageIO messageIO = mock(MessageIO.class);
MessageInputStream mis = mock(MessageInputStream.class);
MessageOutputStream mos = mock(MessageOutputStream.class);
when(messageIO.getIn()).thenReturn(mis);
when(messageIO.getOut()).thenReturn(mos);
MessageIO messageIO = new MessageIO(mis, mos);
Runnable r = mock(Runnable.class);
Client client = new Client(messageIO);
client.addRepeatedTask(r);
Expand Down
2 changes: 1 addition & 1 deletion jenjin-core-server/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
description = ''
description = 'Jenjin Core Server'


dependencies {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

/**
* Executes the necessary actions to deal with a login response.
*
* @author Caleb Brinkman
*/
@SuppressWarnings("unused")
Expand All @@ -22,6 +23,7 @@ public class ExecutableLoginRequest extends ServerExecutableMessage

/**
* Construct a new ExecutableLoginRequest.
*
* @param clientHandler The handler which created this executable message.
* @param loginRequest The request sent by the client.
*/
Expand Down Expand Up @@ -55,14 +57,14 @@ public void runImmediate() {

private void queueLoginSuccessResponse(long loggedInTime) {
Message loginResponse = getClientHandler().getMessageFactory().generateLoginResponse(true, loggedInTime);
getClientHandler().queueOutgoingMessage(loginResponse);
getClientHandler().getMessageIO().queueOutgoingMessage(loginResponse);
}

private void queueLoginFailureResponse() {
ClientHandler clientHandler = getClientHandler();
ServerMessageFactory messageFactory = clientHandler.getMessageFactory();
Message loginResponse = messageFactory.generateLoginResponse(false, 0);
clientHandler.queueOutgoingMessage(loginResponse);
clientHandler.getMessageIO().queueOutgoingMessage(loginResponse);
}

}
Loading

0 comments on commit 99c070d

Please sign in to comment.