[Development] Java Conquer Server

03/25/2014 16:02 jackpotsvr#1
Hi elitepvpers,

Lately we've been working on a conquer online 5017 source programmed in Java, cause we had to learn Java for university. We will gladly continue this project, and work on some exciting features, and this is the development thread.

Java-Conquer-Server

[Only registered and activated users can see links. Click Here To Register...] will be about an Conquer Online server emulator programmed in Java. The repository is maintained by Thomas and Jan-Willem Gmelig Meyling, but is open for public contributions and a ElitePVPers thread has been opened since March 2014.

[Only registered and activated users can see links. Click Here To Register...]

Our goal is to hold on to the native Java libraries as much as possible, currently only leaning on Simple XML for configuration persistency and a PostgreSQL JDBC-connector. The Java Archives for these libraries and other project files are included in this repository. Furthermore, we document our code with Javadoc and Github Wiki's. This is to improve the overall code quality as well as to keep contribution to the repository easy accessible and informative.

The current version of the server has the following features:
  1. Login and account creation
  2. Character information and other start up packets
  3. Spawn me to other players, retrieve surrounding entities when walking or jumping around
  4. Monster spawning
  5. Magic skill proficiency and animation

We're currently working on the attack skills, damage calculation and investigating on how we will implement the AI for NPC's and Monsters. We're thinking about languages like LISP or LUA to take care of the AI.

Our goal is to keep as close as possible to the original Conquer. We intend to implement all varities of item upgrades, stay to the original skills and their damage calculation / chances. We see a view improvements though:
  • Better balance between the various professions
  • Higher loot chances; higher item qualities and socketed items
  • Higher gem mining chance
  • More quests / kill quests
  • More interaction with NPC's (for example quest teaming or a more interactive tutorial)

Building and contribution

Fork the Github repository, load the project into you're Java IDE. We are using Eclipse with EGit. A tutorial on EGit can be found here: [Only registered and activated users can see links. Click Here To Register...] . Commited changes can be merged in to the main repository by requesting a merge commit.

For more documentation on how several functions could be implemented, you can go to the following places:

ConquerWiki.com - A site containing all Packet Structures
spirited-fang - A site which may be useful for enumerations
ElitePVPers.com - A forum with a lot of useful posts
Epvp form thread with some useful notes

Running the server


The client first connects to the Authentication Server. There it retrieves the server IP and port number. Then the client connects to the Game Server. The Game Server creates a thread for every active player. This thread then handles all incoming packets from the client, and sends responses and other outgoing packets. Before reading and writing packets, they are decrypted and encrypted in the cipher.

All data for the entities is stored in a so called Model. There are currently two implementations for the model interface: one using Mock data (the Mock model) and one using data stored in a database (the PostgreSQL model). The Mock model allows to develop and test new functionality, without having to alter the database model first. For "production" a database model should be a better fit instead, because compared to the Mock model, the database model is persistent. Other implementations for the Model interface, like a SQLite or Java serialization based model are not planned, but contributors are free to implement them.

A model can be bound in the config.xml file which is loaded at initialization:

Code:
<server gameport="5816" authport="9958">
   <model class="net.co.java.model.Mock"/>
</server>
The database model can be initialized with only a few changes:

Code:
<server gameport="5816" authport="9958">
   <model class="net.co.java.model.PostgreSQL" host="jdbc:postgresql://host:port/database" username="username" password="password"/>
</server>
Currently we only support a one-to-one binding of Authentication server and Game server. We're intending to make the configuration such that additional Game Servers listening on different IP addresses and/or port numbers can be initialized on this instance and/or bound to the Authentication server.

Getting the client

This version uses the Conquer Online 5017 client. Binaries for that version can be downloaded [Only registered and activated users can see links. Click Here To Register...] Do not forget to run the client with the blacknull parameter and that local IP adresses can only be accessed after a HEX edit. Or you can just simply download the Conquer Loader from the thread linked above.
03/25/2014 16:13 xSeZaRx#2
oh great work !
03/25/2014 16:16 KraHen#3
Seems really nice. :) I would advise against using LISP for AI though, and opt for LUA. :)
03/25/2014 19:23 Spirited#4
The socket system is very weak. If you are open to suggestions, I would recommend the use of asynchronous sockets using Java's NIO channel classes. Example:

Code:
public class AsynchronousSocket {
    
    // Composition of networking classes for the asynchronous socket class:
    AsynchronousServerSocketChannel socket;
    CompletionHandler<AsynchronousSocketChannel, Void> acceptHandler;
    
    public AsynchronousSocket() {
        try { socket = AsynchronousServerSocketChannel.open(); }
        catch (Exception e) { System.out.println(e); return; }
        acceptHandler = new CompletionHandler<AsynchronousSocketChannel, Void>() {

            @Override // Invoked when the client is accepted from the backlog.
            public void completed(AsynchronousSocketChannel result, Void attachment) {
                try {
                    System.out.println("Accepting connection from " 
                        + result.getRemoteAddress().toString());
                }
                catch (Exception e) { System.out.println(e); }
                finally { socket.accept(null, this); }
            }

            @Override // Invoked when the client is rejected from the backlog.
            public void failed(Throwable exc, Void attachment) {
                System.out.println("Asynchronous Connection Event Failed");
            }
        };
    }
    
    public boolean Bind(int port, int backlog) {
        try {
            socket = socket.bind(new InetSocketAddress(port), backlog); 
            return true;
        }
        catch (IOException e) { System.out.println(e); }
        return false;
    }
    
    public void Listen()
    {
        socket.accept(null, acceptHandler);        
        System.out.println("Ready for incoming connections.");
    }
}
03/25/2014 20:20 jackpotsvr#5
Quote:
Originally Posted by Spirited View Post
The socket system is very weak. If you are open to suggestions, I would recommend the use of asynchronous sockets using Java's NIO channel classes. Example:

Code:
public class AsynchronousSocket {
    
    // Composition of networking classes for the asynchronous socket class:
    AsynchronousServerSocketChannel socket;
    CompletionHandler<AsynchronousSocketChannel, Void> acceptHandler;
    
    public AsynchronousSocket() {
        try { socket = AsynchronousServerSocketChannel.open(); }
        catch (Exception e) { System.out.println(e); return; }
        acceptHandler = new CompletionHandler<AsynchronousSocketChannel, Void>() {

            @Override // Invoked when the client is accepted from the backlog.
            public void completed(AsynchronousSocketChannel result, Void attachment) {
                try {
                    System.out.println("Accepting connection from " 
                        + result.getRemoteAddress().toString());
                }
                catch (Exception e) { System.out.println(e); }
                finally { socket.accept(null, this); }
            }

            @Override // Invoked when the client is rejected from the backlog.
            public void failed(Throwable exc, Void attachment) {
                System.out.println("Asynchronous Connection Event Failed");
            }
        };
    }
    
    public boolean Bind(int port, int backlog) {
        try {
            socket = socket.bind(new InetSocketAddress(port), backlog); 
            return true;
        }
        catch (IOException e) { System.out.println(e); }
        return false;
    }
    
    public void Listen()
    {
        socket.accept(null, acceptHandler);        
        System.out.println("Ready for incoming connections.");
    }
}
Thanks for the feedback.
Of course we're open to suggestions, else there would be no point of making it open source. :)

We'll investigate on how to implement Asynchronous Sockets and implement it anytime soon.
03/27/2014 10:07 Korvacs#6
Nice to see something different around here though personally not a fan of Java, or its associated IDEs. Thanks for the wiki mention also, did you find most of the packet structures to be accurate?
03/27/2014 10:59 ganndlas#7
Quote:
Originally Posted by Korvacs View Post
Nice to see something different around here though personally not a fan of Java, or its associated IDEs. Thanks for the wiki mention also, did you find most of the packet structures to be accurate?
Hi, they are pretty accurate for 5017 :) We've found several differences so far:
  • Different offsets for the Message packet, there seems to go something wrong in the 5017 table. To-length starts at 26 + fromLength, toStr at 27 + fromLength, immediately followed by msgLength at 28 + fromLength + toLength and message at 29 +... .
  • Interact packet required a bit of shifting with the identity, we've rewritten one of the solutions from a C# source. Offset 24 seems to be SkillID instead of damage, but we've might not have implemented most uses for this packet yet.
03/27/2014 17:06 Super Aids#8
Good luck with your little project (Unless it turns big.) XD
04/01/2014 21:09 ganndlas#9
Quote:
Originally Posted by Spirited View Post
The socket system is very weak. If you are open to suggestions, I would recommend the use of asynchronous sockets using Java's NIO channel classes.
We have switched to Java NIO now :) Hopefully the socket system improved significantly now. The implementation is based on the [Only registered and activated users can see links. Click Here To Register...] example. Further suggestions will always be appreciated.
04/03/2014 04:17 L1nk1n*P4rK#10
Oh Java! Nice, glad to see that someone here is not bound to C# and/or tries (and fails) to make a solid C++ source. I should not be the one to talk, but still, good job guys! Keep it up.
04/03/2014 04:21 CptSky#11
Quote:
Originally Posted by L1nk1n*P4rK View Post
Oh Java! Nice, glad to see that someone here is not bound to C# and/or tries (and fails) to make a solid C++ source. I should not be the one to talk, but still, good job guys! Keep it up.
Mhm. My C++ source is not a big fail ;)
04/11/2014 19:56 Spirited#12
No, he has a very valuable point. The point might be from the advice we gave him in his thread asking about programming languages and why we don't use Java, but it's still a good point. Java's socket layer is much slower than C#. There are uses for Java, and making a massive multiplayer server isn't one of them. Is it a useless project though? Well, the original programmer didn't know about NIO before posting here, and now he has something to research into and learn from. He learned Java in class and now he's going above and beyond what was taught by studying on his own, and I have no problem with that. Will the server be stable? Probably. Will the server be efficient? Probably not. Does that make the project useless? Not in my opinion.
04/11/2014 23:48 Super Aids#13
Quote:
Originally Posted by CptSky View Post
Mhm. My C++ source is not a big fail ;)
Neither is my D source. :D
04/12/2014 11:11 turk55#14
Quote:
Originally Posted by Spirited View Post
No, he has a very valuable point. The point might be from the advice we gave him in his thread asking about programming languages and why we don't use Java, but it's still a good point. Java's socket layer is much slower than C#. There are uses for Java, and making a massive multiplayer server isn't one of them. Is it a useless project though? Well, the original programmer didn't know about NIO before posting here, and now he has something to research into and learn from. He learned Java in class and now he's going above and beyond what was taught by studying on his own, and I have no problem with that. Will the server be stable? Probably. Will the server be efficient? Probably not. Does that make the project useless? Not in my opinion.
It shouldn't matter if the source is one of the greatest around or not, it is about the fact that he programming and learning new things which will increase his knowledge and experience. I am pretty sure your first C# source wasn't great either, what I am simply trying to say is: one will only learn by doing and experiencing.
04/12/2014 12:57 jackpotsvr#15
Development continues on full power as soon as exams are finished.