Home Tutorials Download Beta Store Forum Documentation KnowledgeBase Wiki Blog
Main Page About Help FAQ Special pages Log in

Hooks and Callbacks

From ShiVa Wiki

Contents

Introduction

What are Hooks/Callbacks? How do I connect handlers in ShiVa to external code? (ANDROID EDITION - HOOKS TUTORIAL)

This tutorial is actually for those who are more intermediate, HOWEVER keep in mind that once you know this, you will be able to move onto the tutorial after this that will teach you how to integrate Share options in Android such as Email, Facebook, etc. This will open you up to the world of true customization with ShiVa!

So grab a coffee and a snack and let's get down to it!

What are hooks and callbacks?

A Hook/Callback is external code that connects up to ShiVa LUA code outside of ShiVa to complete additional functions that are not possible in ShiVa. These custom functions could be things such as In App Purchase, Sending Email with Attachments (My Next Tutorial will be on this topic), Posting to Facebook/Twitter and Many other neat functions that are more advanced or outside the scope of ShiVa. This current tutorial is for the ANDROID version of Hooks/Callbacks. I have yet to setup and create a tutorial for the iOS version of Hooks/Callbacks which I will do later when I figure that out.

ShiVa Steps

ASSUMPTION: I am assuming you are capable of creating HUD elements and connecting them to your ShiVa code and are able to do basic ShiVa programming.

user.sendEvent ( this.getUser ( ), "MainAI", "onMyTestCall" )
user.sendEvent ( this.getUser ( ), "MainAI", "onMyTestCallWithVar", "Test" )
log.message ( "Button Pressed" )

UAT (ShiVa Authoring Tool) Steps

You are now done with the UAT steps and can now move onto Eclipse steps.

Eclipse Steps

ASSUMPTION: We assume this is a new app and has not been made in Eclipse yet. If it has you'll have to do these steps from a fresh copy to understand it. We also assume that you have Eclipse setup already with ANT. If not, go to the wiki to learn how to set up Eclipse properly with ANT.

C++ and JAVA Hook/Callback

C++ file

#include "S3DXAIVariable.h"
S3DClient_InstallCurrentUserEventHook ( "MainAI", "onMyTestCall", fun_CallCPP, NULL );		
S3DClient_InstallCurrentUserEventHook ( "MainAI", "onMyTestCallWithVar", fun_CallWithVarCPP, NULL );		

The above code basically says: WHEN "onMyTestCall" in the "MainAI" AI is called, re-route the call to the C++ function called "fun_CallCPP".

Same idea for the second line in the code above: WHEN "onMyTestCallWithVar" in the "MainAI" AI is called, re-route the call to the C++ function called "fun_CallWithVarCPP"

void fun_CallCPP ( unsigned char _iArgumentCount, const void *_pArguments, void *_pUserData )
{
    if ( pJavaVM )
        {
        JNIEnv *pEnv ;
        if    ( pJavaVM->GetEnv ( (void**) &pEnv, JNI_VERSION_1_4 ) >= 0 )
            {
            //USE REVERSE DOMAIN USING '/' instead of '.' ex. com/gamescorpion/intimatefireplace/IntimateFireplace
            //NOTE: THIS IS CASE SENSITIVE SO MAKE SURE YOU DO IT RIGHT!
            jclass pClass  = pEnv->FindClass ( "com/yourapp/yourapp/YourApp" );
            if   ( pClass != 0 )
                 {
                //(ARGS)ReturnType -> (Z)I = (boolean)Function_Returns_Int
                //(ARGS)ReturnType -> (I)V = (Int)Function_Returns_Void
                //Google GetStaticMethodID for more return type examples
                jmethodID pMethod = pEnv->GetStaticMethodID ( pClass, "MyTestCallJAVA", "()I");
                if      ( pMethod )
                    {
                    int dummy = pEnv->CallStaticIntMethod ( pClass, pMethod ) ;
                    }
                }
            }
        }
       
}

Ok, so right now that is a SINGLE function, we still have one more to write which takes in arguments, but I wanted to break it down because many may be lost as to what this is.

Keep in mind when doing this that there is C++ code and JAVA code you are mixing. DONT MAKE THE MISTAKE OF USING JAVA CODE IN THE C++ FILE AND VICE VERSA! Your program will end up compiling perfectly and will even run, but when you come to that specific function hook/callback in your app, your app will CRASH!

How does it work?

void fun_CallCPP ( unsigned char _iArgumentCount, const void *_pArguments, void *_pUserData )	{ }

This function basically is taking 3 arguments in. EVERY SINGLE CALLBACK FUNCTION YOU MAKE MUST HAVE THESE 3 ARGUMENTS OR IT WILL NOT WORK! The first one, _iArgumentCount gets the TOTAL number of arguments in the function. In this first case however we do not have any arguments we are passing from ShiVa, so this should return a 0 value.

Second is the *_pArguments that holds the actual value in the arguments.

Third is the *_pUserData which I honestly have no clue what its used for at this time however it is required and must be placed here for the function to work.

if ( pJavaVM )
    {
    JNIEnv *pEnv ;
    if    ( pJavaVM->GetEnv ( (void**) &pEnv, JNI_VERSION_1_4 ) >= 0 )
        {

//USE REVERSE DOMAIN USING '/' instead of '.' ex. com/gamescorpion/intimatefireplace/IntimateFireplace //NOTE: THIS IS CASE SENSITIVE SO MAKE SURE YOU DO IT RIGHT!

        jclass pClass  = pEnv->FindClass ( "com/yourapp/yourapp/YourApp" );
        if   ( pClass != 0 )
            {
            //(ARGS)ReturnType -> (Z)I = (boolean)Function_Returns_Int
            //(ARGS)ReturnType -> (I)V = (Int)Function_Returns_Void
            //Google GetStaticMethodID for more return type examples
            jmethodID pMethod = pEnv->GetStaticMethodID ( pClass, "MyTestCallJAVA", "()I");
            if      ( pMethod )
                {
                    int dummy = pEnv->CallStaticIntMethod ( pClass, pMethod ) ;
                }
            }
        }
    }

Ok so now we define the above which is important:

We can skip down to the actual points which you will be editing any time you create a callback which I have bolded and underlined in the code. The first bolded and underlined line shows you the location of the Java file you will be referring to. This is where the function will LOOK for the JAVA version of the function we are going to call. Basically its saying, "WHERE DO I FIND THE JAVA FUNCTION THAT RELATES TO THIS CALLBACK?".

In this case its the REVERSE DOMAIN notation followed by the Java filename (ReverseDomain.Filename), however the delimiter is no longer a period (.) but a forward slash (/). EXAMPLE: com.gamescorpion.intimatefireplace.IntimateFireplace => com/gamescorpion/intimatefireplace/IntimateFireplace

Please take note that this is CASE SENSITIVE. If you are unsure of the filename for the java file, then simply find it in the Project Explorer window on your left under the src->com.yourcompany.yourapp folder.

The next bolded and underlined part is a bit tricky but it is a C++ method call. It is basically connecting and calling the JAVA function to pass variables to and receive any final input from. In this case we use Static methods to access the items, but there is a very important part at the end of the line and that is HOW the JAVA function is defined.

jmethodID pMethod = pEnv->GetStaticMethodID ( pClass, "MyTestCallJAVA", "()I");

The last part there which is highlighted is basically saying that the JAVA function takes NO arguments and RETURNS an integer type. Based on what you want you can customize this for your needs. EX. ( ) I = No arguments and Returns Integer Type. ( Z ) V = JAVA Function Takes in a BOOLEAN and returns VOID ( I ) I = JAVA Function Takes in an integer and returns an integer ( ZI ) I = JAVA Function Takes in a BOOLEAN and an integer and returns an integer ( Ljava/lang/String; ) I = JAVA Function Takes in a String (MAKE SURE IT STARTS WITH "L" AND ENDS WITH SEMI-COLON, THIS IS NOT A TYPO!) and returns an integer

NOTE: For more on this function please google GetStaticMethodID or you can also look at this link which I found helpful -> [url]http://journals.ecs.soton.ac.uk/java/tutorial/native1.1/implementing/method.html[/url]

OK So the last highlighted part that you will usually edit is the CallStaticIntMethod which basically is the code that executes the call to the JAVA function. This can be edited based on the input types you have specified earlier such as Z, I or any of the other input arguments.

Currently there is NO arguments going in, but if for example we had a string variable going in it would look like this:

int dummy = pEnv->CallStaticIntMethod ( pClass, pMethod, pEnv->NewStringUTF ( YOURSTRING ) ) ;

And if you were taking in a boolean for example it would look like this:

int dummy = pEnv->CallStaticIntMethod ( pClass, pMethod, true ) ;

void fun_CallWithVarCPP ( unsigned char _iArgumentCount, const void *_pArguments, void *_pUserData )
    {
    if ( _pArguments && ( _iArgumentCount == 1 ) )
        {
        const S3DX::AIVariable *pVariables = (const S3DX::AIVariable *)_pArguments ;
        
        if ( pVariables[0].GetType ( ) == S3DX::AIVariable::eTypeString )
            {
                strncpy ( YOURSTRING, pVariables[0].GetStringValue ( ), 254 ) ;
            }
        }
    if ( pJavaVM )
        {
        JNIEnv *pEnv ;
        if ( pJavaVM->GetEnv ( (void**) &pEnv, JNI_VERSION_1_4 ) >= 0 )
            {
            jclass pClass  = pEnv->FindClass ( "com/gamescorpion/funtime3dedesignereaster/FunTime3DeDesignerEaster" );
               
            if ( pClass != 0 )
                {
                jmethodID pMethod = pEnv->GetStaticMethodID ( pClass, "MyTestCallWithVarJAVA", "(Ljava/lang/String;)I");
                if ( pMethod )
                    {
                    int dummy = pEnv->CallStaticIntMethod ( pClass, pMethod, pEnv->NewStringUTF ( YOURSTRING ) ) ;
                    }
               }
           }
       }
       
}


Ok so in this second version you will notice a NEW set of code that is added (when compared to the other function above) which I have outlined here with bold.

This time we are taking in an argument and so now the _iArgumentCount comes into play and it is used to figure out the argument number in this case and then obtain the actual data which we then place into a variable (Assuming you have DEFINED THE GLOBAL VARIABLE CALLED "YOURSTRING" IN THE EARLIER SECTION in step 2 above: 2. If you have any CUSTOM GLOBAL variables you would like to use in the app you can add them to the "// @@BEGIN_JNI_GLOBALS@@" section on line 20. (Ex. static char YOURSTRING [255] = "" ;))

We then using the same method can now pass the variable over to the JAVA function in the next step.

YAAY WE ARE DONE WITH THE C++ STEPS, NOW WE GO TO OUR JAVA FILE TO CREATE THE JAVA FUNCTIONS WHICH CONNECT AND COMPLETE THE CODE.

Java Code

Open the JAVA FILE now in the main view and now we must go down to line 496 approx. where we see the code:

   @Override
   public void onLowMemory ( ) { }

Before this line we need to now add our new functions which we created in the cpp file earlier.

Copy and paste the two functions below into the lines above the override for onLowMemory:

   public static int MyTestCallJAVA( ) 
   {

// JAVA CODE HERE

   	return 0;
   }
   public static int MyTestCallWithVarJAVA( String sBody ) 
   {

// JAVA CODE HERE

   	return 0;
   }

So there you can now start coding your java commands that you want to take place every time the function is called. This now allows you FULL customization such as being able to do special things like sending an email with an attachment, posting to facebook/twitter or even other cool advanced things.

NOTE: in the java code you may require certain function calls. These can only happen with the oThis object which is defined. Here is an example of calling an Intent for email (which I will go into detail in the next tutorial on creating Email with Attachments and sending a screenshot via email).

EX.

       // Where sBody is the location of an image file
   	final Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
   	emailIntent.setType("image/jpg");
   	emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse( sBody ) );
   	oThis.startActivity(Intent.createChooser(emailIntent, "Share:"));

CONGRATULATIONS, you now know how to create Event Hooks and Callbacks!

Credits and Further Reading

created by Nav (gamescorpion)
Link to the original forum thread

Retrieved from "http://www.stonetrip.com/developer/wiki/index.php?title=Hooks_and_Callbacks"

This page has been accessed 4,666 times. This page was last modified on 30 March 2012, at 22:25.