Debugging guide for L2J server

Have you created a useful tool? or Do you want to get help building one? This is the right place!
Forum rules
READ NOW: L2j Forums Rules of Conduct
Post Reply
User avatar
JIV
L2j Veteran
L2j Veteran
Posts: 1882
Joined: Sun Jan 06, 2008 8:17 pm
Location: Slovakia
Contact:

Debugging guide for L2J server

Post by JIV »

Debugging guide for L2J server

First of all, I am not native English speaker so try to take my grammar lightly :)

1. Intro

Every developer sooner or later need test his code more deeply and require info about object state and variable values. Most of you would probably use System.out.print() method to print desired data to console, then restart server or reload script. Its archaic solution without any flexibility. In this tutorial I will show you how to use modern java debugging techniques, mostly from eclipse.

2. Basic debugging in eclipse
Eclipse contains one of the best debugger I ever saw, not mention only java IDEs. Debugging simple application in eclipse is for two mouse clicks. You take java file with main() method, right click on file and in menu select Debug As -> Java Application. Eclipse will start program in debug mode.
In Debug view you can see active threads of your application. You can pause them and resume again anytime. While thread is paused you can inspect variables values and use steps. Steps allow you to continue executing paused thread but all is now under your control. Basic steps in code are step into, over and return. First, Step Into, will always follow inside calling method. Second, Step Over, will executed one line of code. Last, Step Return, will move debug cursor back to line from which actual method was called from. I recommend to test this on some small application.
Ok, pausing threads is cool but how to pause thread in my code? Answer is breakpoints - section 4.
So hurray we know how to debug, lets debug l2j gameserver! Wrong.. L2J is much more complex piece of software and require datapack, configs, libs, etc. Best way to start GS in debug mode is use launcher - section 3.

3. Launchers
Launcher is simple XML file which eclipse can parse and start program with additional parameters and configurations. L2J GS already contains pre-made launchers almost ready to use. Since I think none of l2j developers use them, I take over and put there mine own configurations. So open L2 GameServer.launch as normal text file and search for line:

Code: Select all

<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="D:/_l2j/gameserver/"/>
Yes, "D:/_l2j/gameserver/" is my own path on my HDD. Install on your HDD l2j distribution and put your path over mine. Note: This directory will be used to load everything expect code and libs. It means configs, datapack, xml, csv, etc. Save file, right click on launcher, Debug as -> L2_GameServer.
Now if you did everything right, you should see in console loading GS.

4. Breakpoints
Now since you are in debug mode you can start adding breakpoints to your code wherever you want start debugging. Just find a desired lines of code and on free space on left make double click. If you did it right, small blue dot should appear. Now if any application thread reach this breakpoint, debugger pause thread and you can start using steps and check variables values.
This is nice but L2J is multithreaded and more threads can pause on my breakpoints and cause server lag. To prevent this you can use Conditional breakpoint. It means thread will pause only if condition is met. Right click on breakpoint - breakpoint properties. Check condition and you can write code. It can be for example:

Code: Select all

this.getNpc().getNpcId() == 16064
. This require some java knowledge.
More info about debugging can be found at http://www.vogella.de/articles/EclipseD ... ticle.html (they have some nice pictures :) )
Next part is much more interesting and for sure will save you some time.

5. Hot code replace
While JVM running application in debugging mode it allows you transfer through debugging channel new class files. HUH?!?? YES, it means you can modify core java files and changes will directly apply to running GameServer. No more restarting GS if you made small typo, big mistake or just forget call method. This apply to DataPack java scripts as well. Everything which sound perfect must have some catch :) . In this case it is Hot code replace fail. One big ugly message box which I hate most. Basically it means you made such change which cannot be transferred. Some of them are Class signature changed (remove, add, rename method), modify method variables and some others. You can no more modify this class and options which you have are Continue with old class, terminate app or restart. Hit restart and go gather some food to refrigerator :) . Of course sometimes you must make these changes to code, but make sure you don't start debugging until you are done.
More info: http://wiki.eclipse.org/FAQ_What_is_hot_code_replace%3F

6. Java Profilers
<TODO>

This is the end and I am sure I forgot mention something. I hope you like it and hopefully it will help you with l2j gs debugging.
mgbhard
Posts: 228
Joined: Mon May 05, 2008 10:34 pm

Re: Debugging guide for L2J server

Post by mgbhard »

Great work JIV very easy to understund.
Thx!
Image
halski103
Posts: 2
Joined: Thu May 26, 2011 4:43 am

Re: Debugging guide for L2J server

Post by halski103 »

pls some update. There is no Launchers in repo any more
Ghurdyl
Posts: 55
Joined: Tue Jun 03, 2008 4:52 pm
Location: Hannut, Belgium

Re: Debugging guide for L2J server

Post by Ghurdyl »

I am definitely not a specialist but here's how I succeeded to debug the gameserver :

You'll probably need to be a java developer and familiar with the Eclipse and L2J environment to understand me here. The objective of this post is not to teach you everything but give you the main hints I found.

I used Eclipse Juno under windows 7 64bit

1. The running environment
- First, build the gameserver and datapack with build.xml's Ant files.
- unzip both resulting zip's in a directory of your choice (e.g: E:\_WORKSPACE\L2J\LiveGS for me)
- ensure the server is properly configured and can be run.

2. The basic properties
- then go back to Eclipse
- Click the debug button (with the icon of a Bug) to expand the sub-menu and select "Debug Configurations..."
- A window opens
- in the left column, select "Java Application" and clic "new" to create a new run configuration
- in the "Name" field enter a name of your choice
- in "Project" field, select the L2J_Server project
- in the "Main class" field, select "GameServer - com.l2j.gameserver"

3. The run arguments
- select then the "Arguments" tab
- in VM argument, add the following :

Code: Select all

-XX:-UseSplitVerifier
(I had to add this due to an eclipse bug, server startup blocked without)
- in the "Working directory" section check the "other" radio button and as path, enter the path of the directory where you've deployed the server (in 1.) followed by "\game" ( e.g. E:\_WORKSPACE\L2J\LiveGS\game for me)

4. the class path
- select then the "Classpath" tab to add some dependencies
- click "user-entries" and then "Add JARs..."
- in the opening window browse the L2J_Server project > dist/libs and add the following libraries :

Code: Select all

mysql-connector-java[version]-bin.jarbsh-[version].jarbsh-engine-[version].jarecj-[version].jarjava-engine-[version].jar
(actually, all the libraries that are in dist/libs but not in the project's build path)
for the [version] see 7.

5. the sources
- select then the "Source" tab to add the 2 java projects L2J_Server and L2J_DataPack

6. the launch file
- optionally, you can save the configuration as a "launch file" through the "Common" tab
Here's mine :
SPOILER:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/L2J_Server/java/com/l2jserver/gameserver/GameServer.java"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="1"/>
</listAttribute>
<stringAttribute key="org.eclipse.debug.core.source_locator_id" value="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"/>
<stringAttribute key="org.eclipse.debug.core.source_locator_memento" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?>&#13;&#10;<sourceLookupDirector>&#13;&#10;<sourceContainers duplicates="false">&#13;&#10;<container memento="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;javaProject name=&quot;L2J_DataPack&quot;/&gt;&#13;&#10;" typeId="org.eclipse.jdt.launching.sourceContainer.javaProject"/>&#13;&#10;<container memento="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;javaProject name=&quot;L2J_Server&quot;/&gt;&#13;&#10;" typeId="org.eclipse.jdt.launching.sourceContainer.javaProject"/>&#13;&#10;<container memento="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;default/&gt;&#13;&#10;" typeId="org.eclipse.debug.core.containerType.default"/>&#13;&#10;</sourceContainers>&#13;&#10;</sourceLookupDirector>&#13;&#10;"/>
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?>&#13;&#10;<runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER" javaProject="L2J_Server" path="1" type="4"/>&#13;&#10;"/>
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?>&#13;&#10;<runtimeClasspathEntry internalArchive="/L2J_Server/dist/libs/mysql-connector-java-5.1.20-bin.jar" path="3" type="2"/>&#13;&#10;"/>
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?>&#13;&#10;<runtimeClasspathEntry internalArchive="/L2J_Server/dist/libs/bsh-2.0b5.jar" path="3" type="2"/>&#13;&#10;"/>
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?>&#13;&#10;<runtimeClasspathEntry internalArchive="/L2J_Server/dist/libs/bsh-engine-2.0b5.jar" path="3" type="2"/>&#13;&#10;"/>
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?>&#13;&#10;<runtimeClasspathEntry internalArchive="/L2J_Server/dist/libs/ecj-4.2.jar" path="3" type="2"/>&#13;&#10;"/>
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?>&#13;&#10;<runtimeClasspathEntry internalArchive="/L2J_Server/dist/libs/java-engine-1.7.jar" path="3" type="2"/>&#13;&#10;"/>
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?>&#13;&#10;<runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath">&#13;&#10;<memento exportedEntriesOnly="false" project="L2J_Server"/>&#13;&#10;</runtimeClasspathEntry>&#13;&#10;"/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.l2jserver.gameserver.GameServer"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="L2J_Server"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-XX:-UseSplitVerifier"/>
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="E:\_WORKSPACE\L2J\LiveGS\game"/>
</launchConfiguration>
 
7. maintenance
Note that whenever the dependency libraries will be updated, you'll have to adapt the classpath to include all the necessary libraries or at least change their [version] number
~Ghurdyl~
"If you give a man a fire, he'll be warm for a day. If you set a man on fire, he'll be warm for the rest of his life" :)
User avatar
xvendettax
Posts: 10
Joined: Fri Apr 22, 2011 1:28 pm
Location: Bulgaria

Re: Debugging guide for L2J server

Post by xvendettax »

halski103 wrote:pls some update. There is no Launchers in repo any more
Yeah, pls some update.
User avatar
MELERIX
L2j Veteran
L2j Veteran
Posts: 6667
Joined: Sat Sep 23, 2006 11:31 pm
Location: Chile
Contact:

Re: Debugging guide for L2J server

Post by MELERIX »

xvendettax wrote:Yeah, pls some update.
these are the old launchers...

http://trac.l2jserver.com/export/4551/b ... ger.launch
http://trac.l2jserver.com/export/4551/b ... ver.launch
http://trac.l2jserver.com/export/4551/b ... ver.launch

but require update (2 years old atm), so better you should create new ones in an updated Eclipse ;)

more info about this here: http://help.eclipse.org/juno/index.jsp? ... uncher.htm

or read the steps above: viewtopic.php?f=94&t=19326#p151649
Post Reply