Recast AI - Devlog #2

Hi, everybody,

It was really bad week, so I didn’t have any time to code this week properly (with flooding in Serbia, and declared emergency state). Now everything is messed up. The exams are moved and now my plan to make some available features before midterm has failed.

I have built prototype for Detour module, because as I saw later Recast module doesn’t give you any functionality for showing.

So, new plan has been made. The plan is to code for 12 hours until next Wednesday in hope to make the promised deliverers. I will use @mifth demo game to test it.

I hope this plan will work. :smiley:

@Tihomir said: Hi, everybody,

It was really bad week, so I didn’t have any time to code this week properly (with flooding in Serbia, and declared emergency state). Now everything is messed up. The exams are moved and now my plan to make some available features before midterm has failed.

I have built prototype for Detour module, because as I saw later Recast module doesn’t give you any functionality for showing.

So, new plan has been made. The plan is to code for 12 hours until next Wednesday in hope to make the promised deliverers. I will use @mifth demo game to test it.

I hope this plan will work. :smiley:

Hey!
I hope Serbia will be ok! And you too!

Cool news about your plan. You can always contact me on IRC channel. Here id the IRC client through the browser: http://webchat.freenode.net/ (channel is #jmonkeyengine) . My nick is mifth.
I always glad to help you.

Remember, you ned make all collision checks with physics only. Remember my post here http://hub.jmonkeyengine.org/forum/topic/ai-engine/page/8/#post-287558

About AI implementation. In AICharacterControl:
doRotate, doRun, doShoot, doStrike variables are only for inputs (fro the main character keys). For AI you should use set States. AICharacterState.Run, AICharacterState.Shoot, etc…

Well if you have any troubles - you can contact me in the forum or onthe IRC.

Ok. I will be very happy when I came to the AI implementation problem. Now the problem is JNI implementation problem. :frowning:

Best of luck, very crappy what’s happening in Serbia. I’ve been in a flood 1 time in my life, and everything is really slow to get started again what with the insurance companies not helping because it’s an “act of god” and such.

The JNI implementation… Does JNI support C++ fully? Iirc it doesn’t, which may be awkward.

I think it does support it, because jbullet has been also made with JNI.

JNI doesn’t natively support C++ due to name mangling. You need to create a native C file with proxies to all of the functions taking a pointer as a parameter. It’s pretty confusing. SWIG could be used to produce a fully working proxy class + associated java classes.

Update: Using SWIG, I was successfully able to produce a fully working, object-oriented JNI wrapper for the C++ recast library. I don’t know the SoC rules/restrictions, so I won’t post any help, but I would strongly suggest using SWIG to make the process less tedious.
Also note: rcContext isn’t optional. They (methods involved in generation) will all fail without that as it provides a logging interface.

1 Like

If you would like it, it can be found here:
http://uppit.com/ikqu4y4jfrbd/RecastNavigationJNI.rar

The Detour may need a bit further configuring, but the recast seems to be working just fine.

1 Like
@fabsterpal said: I don't know the SoC rules/restrictions, so I won't post any help, but I would strongly suggest using SWIG to make the process less tedious.
Rules for GSoC are that you can help participants in that what can they use, advice, etc., but help in coding part is not allowed.
Also note: rcContext isn't optional. They (methods involved in generation) will all fail without that as it provides a logging interface.
I know it isn't optional, but because it is only interface, and there is no implementation of it, I thought that I only send it instance as documentation said, if you don't use logging.

I see the code, I don’t understand it fully, but if the framework did all the job, I have to do and lot more, I don’t think I could use it all. I think that is breaking the rules, but thanks anyway.

@sploreg can you check if this is allowed to use? If it is I only need to build wrappers, rename things to be with Java convention, mesh converter etc. Also then it would be possible to include and Crowd module in my GSoC project (it is pathfinding for groups of agents) and adjust it too.

@Tihomir said: Rules for GSoC are that you can help participants in that what can they use, advice, etc., but help in coding part is not allowed.

I know it isn’t optional, but because it is only interface, and there is no implementation of it, I thought that I only send it instance as documentation said, if you don’t use logging.

I see the code, I don’t understand it fully, but if the framework did all the job, I have to do and lot more, I don’t think I could use it all. I think that is breaking the rules, but thanks anyway.

@sploreg can you check if this is allowed to use? If it is I only need to build wrappers, rename things to be with Java convention, mesh converter etc. Also then it would be possible to include and Crowd module in my GSoC project (it is pathfinding for groups of agents) and adjust it too.

Well, Good luck.
If you can use SWIG to build the wrapper, You really should remake the entire .i file as mine was half-assed and sucky.

Yes you can use SWIG to make the wrapper. With this project there is always more work we can find for it, so if SWIG saves a lot of time, don’t worry, we can get extra stuff for you to do for the recast bindings =)
You just shouldn’t use Fabian’s already generated beindings, but feel free to reference them for help or use parts to get it working.
Flooding is a bad experience and out of your control, don’t fret about the deadline and already-stated deliverables, we can adjust them. Just get done what you can. There are definitely provisions for those situations.

@fabsterpal said: If you can use SWIG to build the wrapper, You really should remake the entire .i file as mine was half-assed and sucky.
Can you show me your .i file and maybe some good tutorial for making a good one?
@Tihomir said: Can you show me your .i file and maybe some good tutorial for making a good one?

Detour.i: http://puu.sh/9glIj/c9c6194783.i
Recast.i: http://puu.sh/9glJd/9dbee4ac0e.i

There’s really no good tutorials. Just best to play around with it, add bits you feel are missing. Remember to use the -package [package] option because you can’t refactor it in Java, and remember to rename the classes in the .i file instead of refactoring, else you get UnsatisfiedLinkException.

About wrapping native C++, my last better experience was with javacpp. (nicer than my last work with SWIG). Your write java classes and annotate class and method to bind native method.

my 2c.

@david.bernard.31 said: About wrapping native C++, my last better experience was with javacpp. (nicer than my last work with SWIG). Your write java classes and annotate class and method to bind native method.

my 2c.

This library looks unbelievably better than SWIG. SWIG generates big, messy files with hundreds of methods to fulfil 1 purpose, doesn’t identify arrays automatically and makes a new class for each type of manually defined array. Thanks for sharing.

So, now is the time to learn yet another technology. :slight_smile:

Actually, just checked. I believe with javacpp you still need to write the classes in java yourself with perfectly matching names.

Right, it’s easier to match name but you can override the name (convention over configuration)

It’s a example from my raknet wrapper (where I keep original name):
[java]
package raknet;

import java.nio.ByteBuffer;

import com.googlecode.javacpp.;
import com.googlecode.javacpp.annotation.
;

@Properties({
@Platform(value=“linux-x86_64”, include=“javacpp-code.h”, link = “RakNetDLL”),
@Platform(value=“windows-x86_64”, include=“javacpp-code.h”, link = “RakNet_VS2008_DLL_Release_x64”),
@Platform(value=“macosx-x86_64”, include=“javacpp-code.h”, link = “RakNetDLL”)
})
@Namespace(“RakNet”) // Namespace where all c++ code must reside
// “link” tells javacpp which original library should be linked (if not specified, “Abc” will be used)
public class RakNet {
static { Loader.load(); }

public static class RakPeerInterface extends Pointer {
static { Loader.load(); }
public static native RakPeerInterface GetInstance(); // Method we want to use
public static native void DestroyInstance(RakPeerInterface v); // Method we want to use
public native void Startup(int maxConnections, SocketDescriptor socketDescriptors, int socketDescriptorCount, int threadPriority);
public native void SetMaximumIncomingConnections(int maxConnections);
public native Packet Receive();

//…
[/java]

I include the native lib into the jar following a javacpp convention

src/main/resources
└── raknet
    ├── javacpp-code.h
    ├── linux-x86_64
    │   └── libRakNetDLL.so
    ├── macosx-x86_64
    │   └── libRakNetDLL.dylib
    └── windows-x86_64
        └── RakNet_VS2008_DLL_Release_x64.dll
more src/main/resources/raknet/javacpp-code.h 
#include "RakPeerInterface.h"
#include "MessageIdentifiers.h"
#include "BitStream.h"
#include "RakNetTypes.h"

then I can use it like

[java]
public class RakNetDemo {
static final byte ID_GAME_MESSAGE_1= ID_USER_PACKET_ENUM+1;

public static void main(String[] args) {

System.out.println("BEGIN");
RakPeerInterface peer = RakPeerInterface.GetInstance();
boolean isClient = (System.getProperty("client") != null); 
if (isClient) {
  SocketDescriptor sd = new SocketDescriptor();
  peer.Startup(1, sd, 1, -99999);
  peer.Connect("127.0.0.1", 60000, null, 0);
  System.out.println("Client");

[/java]

${JAVA_HOME}/bin/java \
 -cp $HOME/.m2/repository/com/googlecode/javacpp/javacpp/0.7/javacpp-0.7.jar:target/raknet_java-0.1.0-SNAPSHOT.jar:target/test-classes \
 sandbox.RakNetDemo

Hope, it helps

1 Like

So, the past two days I was studying automatic translators for C++ Java interface. I thought at first that SWIG had big overhead. But it is not that big, it resolves all the problems that I even didn’t thought about.

I was learning directives for SWIG, but they didn’t work as well as I thought they would, so looking closely at the produced code I realized that I could change everything very easily (refactoring in Java didn’t work because the JNI calls, but I know how to change that).

There are going to be some classes that user shouldn’t use because it is for internal framework use, but I think it can be structured that user can’t use them at all.

I will write here what happens next. I hope it happens to be “No bug detected”. :smiley:

@david.bernard.31 said: Right, it's easier to match name but you can override the name (convention over configuration)

It’s a example from my raknet wrapper (where I keep original name):
[java]
package raknet;

import java.nio.ByteBuffer;

import com.googlecode.javacpp.;
import com.googlecode.javacpp.annotation.
;

@Properties({
@Platform(value=“linux-x86_64”, include=“javacpp-code.h”, link = “RakNetDLL”),
@Platform(value=“windows-x86_64”, include=“javacpp-code.h”, link = “RakNet_VS2008_DLL_Release_x64”),
@Platform(value=“macosx-x86_64”, include=“javacpp-code.h”, link = “RakNetDLL”)
})
@Namespace(“RakNet”) // Namespace where all c++ code must reside
// “link” tells javacpp which original library should be linked (if not specified, “Abc” will be used)
public class RakNet {
static { Loader.load(); }

public static class RakPeerInterface extends Pointer {
static { Loader.load(); }
public static native RakPeerInterface GetInstance(); // Method we want to use
public static native void DestroyInstance(RakPeerInterface v); // Method we want to use
public native void Startup(int maxConnections, SocketDescriptor socketDescriptors, int socketDescriptorCount, int threadPriority);
public native void SetMaximumIncomingConnections(int maxConnections);
public native Packet Receive();

//…
[/java]

I include the native lib into the jar following a javacpp convention

src/main/resources
└── raknet
    ├── javacpp-code.h
    ├── linux-x86_64
    │   └── libRakNetDLL.so
    ├── macosx-x86_64
    │   └── libRakNetDLL.dylib
    └── windows-x86_64
        └── RakNet_VS2008_DLL_Release_x64.dll
more src/main/resources/raknet/javacpp-code.h 
#include "RakPeerInterface.h"
#include "MessageIdentifiers.h"
#include "BitStream.h"
#include "RakNetTypes.h"

then I can use it like

[java]
public class RakNetDemo {
static final byte ID_GAME_MESSAGE_1= ID_USER_PACKET_ENUM+1;

public static void main(String args) {

System.out.println("BEGIN");
RakPeerInterface peer = RakPeerInterface.GetInstance();
boolean isClient = (System.getProperty("client") != null); 
if (isClient) {
  SocketDescriptor sd = new SocketDescriptor();
  peer.Startup(1, sd, 1, -99999);
  peer.Connect("127.0.0.1", 60000, null, 0);
  System.out.println("Client");

[/java]

${JAVA_HOME}/bin/java \n -cp $HOME/.m2/repository/com/googlecode/javacpp/javacpp/0.7/javacpp-0.7.jar:target/raknet_java-0.1.0-SNAPSHOT.jar:target/test-classes \n sandbox.RakNetDemo

Hope, it helps

Isn’t Kryonet lightly based off Raknet?

On topic: It should be easy, I’d never used SWIG before and managed to get it working (my demonstration produced a weird output, but the fact everything went as expected means it was likely my hardcoded triangle or configurations that were wrong).