RGSS3 tutorials

Extending RGSS (ruby) with C

So, thanks to the wonderfull work of Wannabe && FenixFyreX, the RPG Maker Community is  now able to benefit from loading .so files into the maker directly.

Alot (perhaps most) of you may be thinking “what the hell is a .so file?”, so here is a short explanation from my understanding.

A .so file is essentially the same as a .dll file, with one major exception… Rather than being called each time its required via some API call, the .so is able to implant new methods into the ruby (RGSS) environment directly.

Consider the following…

# Ruby Code
def some_method(value)
return value >= 100 ? true : false
end
# End Ruby Code

This simple method checks if the value passed as argument 1 is greater or equal to the value of 100. if yes, it returns true and false otherwise.

Now what if we wanted to write this method in C?  There are many reasons for why you may wish to do such a thing, performance
being the most common, but I’m not really going into that…

Normally, we would have had to do something like this..

  # Ruby Code
  def some_method(value)
    @method_api ||= Win32API.new('DllName','FunctionName','i','i')
    return @method_api.call(value) != 0 ? true : false
  end
  # End Ruby Code
// C Code
int FunctionName(int value)
{
if (value >= 100)
{
return 1;
}
return 0;
}
// End C Code

As you can see, this is fairly pointless. Its likely that performance would actually be lost in such a transition; however, if we where able to perform even more of the code on the C side of things (ideally all of it), it could potentially become far superior..

In order to do this, we are going to venture into unfamiliar territory (at least it was for me) and make ourself a Ruby-C Extension.

This may seem rather daunting at first but let me assure you, it is much easier than you would imagine.

First of all, there are a few things we are going to need.
1 – Ruby Code Writing Knowledge,
2 – C Code Writing Knowledge,
3 – Ruby 1.9.3 (download from http://rubyinstaller.org/) Recommended install folder – C:\Ruby193
4 – DevKit (downloaded from http://rubyinstaller.org/downloads/) Recommended install folder – C:\DevKit  (no spaces)
5 – A folder to house your shiny new .so projects. Recommended to create a new folder within your user profile rather than inside the ‘DevKit’ folder. I called mine ‘RPG-Extensions’ and plan to create a new (sub)folder within for each .so project that I create.
My folder is located at  C:\Users\Dekita\RPG-Extensions\
6 – The LoadSo project written by Wannabe && enhanced by FenixFyreX Found HERE

NOTE ::
This will not work without the LoadSo script and dll. ie – they are both 100% required.

Now, assuming you have all of that prepared, we can begin.

First, lets make a folder for this project. I shall call mine ‘Tutorial’. Within this folder I am going to create two files.
1 – extconf.rb file. This is a ruby file that generates the MAKEFILE that is used during compilation of your ruby extension. extconf.rb is not the required name, but it is general practice to use this name.
2 – Tutorial.c file.  This is a C source code file that contains your code to connect ruby with C.
Currently, both of these files are empty and my folder looks like this.. (click image to see it properly)

Now, we configure the extconf.rb file. As mentioned, this is used to generate the MAKEFILE that will be used during the creation of our extension. As you may notice for the extension, this is a ruby file and therefor, uses ruby code. So here is what I put in mine.

# Ruby Code
require 'mkmf'
create_makefile('Tutorial')
# End Ruby Code

When ran, this code simply requires the make file module, which is required to make MAKEFILE’s (surprisingly…) and then creates said MAKEFILE with the name ‘Tutorial’.

Ok, so thats that done. Now we have to setup our C source code.

# C Code

#include "ruby.h"

VALUE FunctionName(VALUE self,VALUE ruby_value)
{
return NUM2INT(ruby_value) >= 100 ? Qtrue : Qfalse;
}

VALUE rb_DEKModule = Qnil;

void Init_Tutorial()
{
rb_DEKModule = rb_define_module("DEK");
rb_define_singleton_method(rb_DEKModule, "function_name", FunctionName, 1);
}

# End C Code

Ok, I will take this part step by step.
First, we include the ruby.h file. This is a ruby header that will be included within all ruby extensions that you make. ‘ruby.h’ also contains all the required functions we will be using to connect our C code with ruby.

Secondly, we define a function. ‘FunctionName’. Notice, this function is of the type ‘VALUE’, all methods that are called from within ruby should return this type. Also notice, the function NUM2INT() is called from within this function. This is one of the aforementioned functions that ‘ruby.h’ gives us. This function converts a ruby numeric value into a C integer value.
NOTE: Qnil, Qfalse, Qtrue are equivalents to ruby’s nil, true and false. These are also of the VALUE type.

Third, we create a VALUE variables called ‘rb_DEKModule’ – this variable is going to store the handle to our new module that will house our new method.

Fourth, the Init_Tutorial() function is defined. All ruby extensions (.so’s) invoke the Init_(ExtensionName)() function upon being initialized.
Within this function you will notice we allocate a new value to the rb_DEKModule variable, this now holds the handle to our newly created module. For the purposes of this tutorial I have named this new module ‘DEK’. Now, we define a new method for the rb_DEKModule object, this method has been named “function_name” (for when it is being called from ruby), and it calls the function ‘FunctionName’ (C Code) when called. The ‘1’ signifies how many arguments will be passed to FunctionName when called.

Now you may be thinking, but ‘FunctionName’ had more than one argument and yes, you are completely correct! Lets go back and look at that function definition…

# C Code
VALUE FunctionName(VALUE self,VALUE ruby_value)
...
# End C Code

As you can see this function actually has two arguments, one is the VALUE object ‘self’ and the other is an int variable I have named ‘ruby_value’. All functions that are called from ruby directly (such as this one) have a few things you should remember:
1 – they are always the VALUE type
2 – their first argument is always VALUE self. – this is equivalent to ruby’s self and simply references the current instance of the object in question.
So with this in mind, we are only actually passing one unique argument – the functions we are calling to attach our C onto ruby (such as rb_define_singleton_method) already know that the first argument will be a VALUE type referencing self.

Anyway..

Now that we have our extconf.rb file and our Tutorial.c file containing the required code, we can begin to compile it into our extension.

Personally, I had a lot of trouble finding helpful information on this topic and unfortunately, had to piece together bits from various sources…

So lets take this step by step..

1 – open your command promt (search windows for CMD if you dont know how)
2 – ‘cd’ to your Dev Kit folder. What this means is you must use the cd command to navigate to the folder your dev kit was installed to. – Type the following into your cmd promt

cd C:\DevKit\

3 – once here, run the ruby dk.rb file. (Type the following into your cmd promt)

ruby dk.rb

– Messages appear

ruby dk.rb init

– More Messages appear

ruby dk.rb install

– Messages again…

4 – now the dev kit is ready for us to direct it towards our extension directory. We do this by ‘cd’-ing to our extension folder. This is what I typed into my cmd promt, yours will likely be a little different – unless you copied my folder names exactly.

cd C:\Users\Dekita\RPG-Extensions\Tutorial\

5 – You should now be within your extension folder. Type the following into your cmd promt

"C:\DevKit\devkitvars"

NOTE: the quotation marks seem to be required for this step.

If done correctly, you should be informed that the DevKit has been added to path. This is what we want.

6 – Now we can call our extconf.rb file. This will generate the MAKEFILE that is about to be required. – Type the following into your cmd promt

ruby extconf.rb

You should be informed with the message ‘Creating Makefile’. Additionally, if you check your extension project folder, it should now contain a regular file called ‘Makefile’.

7 – This is it, the final step. Take a moment and breath.. If you have come this far without any hiccups then I take my hat off to you. This took much trial and error on my part to finally get it all working.  Type the following into your cmd promt;

make

Upon hitting enter, you should be informed of a successful compilation via
the message ‘linking shared-object Tutorial.so’.

And that’s it. You have successfully created a ruby C extension.

Now comes the hardest part… Loading your .so into RPG Maker VX Ace…

Step1 – Add the msvcrt-ruby191.dll into your RPG Maker project folder. I personally place it within the System folder.  You should have this downloaded from earlier.
Step2 – Add the LoadSo script into your RPG Maker script editor in a new project, under materials is fine.
Step3 – Run the code below in your script editor

# Ruby Code Within RPG Maker VX ACe
require 'System/Tutorial.so'
puts "Dek::Tutorial = #{DEK.function_name(101)} !!"
# End Ruby Code Within RPG Maker VX ACe

Obviously, the code DEK.function_name(101) will return true, as its above the
value of 100. Equally, DEK.function_name(50) would return false.

And that’s it. Not as hard as you expected huh?

Not only did we write up our own ruby-C extension, we also applied its logic into the RPG Maker engine with ease.
Obviously the examples in this tutorial are very basic, but the logic used is likely to be highly useful in a huge array of situations.

Finally, I would like to thank a few people who helped me out during this process:
– FenixFyreX for huge help in figuring out my compilation issues.
– Zalerinian for getting me more interested in the working of C.
– Peter Cooper for the article (http://www.rubyinside.com/how-to-create-a-ruby-extension-in-c-in-under-5-minutes-100.html)
– You, for reading this huge wall of text :p

Annnnddddd…..
Here are some helpful website links 🙂
http://blog.jacius.info/ruby-c-extension-cheat-sheet/
https://people.apache.org/~rooneg/talks/ruby-extensions/ruby-extensions.html

And Here is an RPG Maker demo containing a working Tutorial.so along with the first draft of this tutorial and some other helpful information. LINK.

Any questions ??
I’m still fairly new at this myself, but I will try to assist you in any way I can and hopefully, someone else with more knowledge may chime in with a few random bits of helpful information ^_^

Advertisements

Basic HUD/GUI

#===============================================================================
# HotFireLegend recently requested I make a small example of a HUD and explain 
# the workings behind my example. Here it is. 
# 
# NOTES: 
# - This example CAN (and should) be placed in your script editor. It 
# increases readability AND allows you to test the script and see it in action.
# - This 'tutorial' assumes you understand the basics of writing ruby code.
#===============================================================================

#===============================================================================
# 
# First, I need to make a class for my HUD. 
# I have opted to make a very simple sprite class for this example. 
# Of course, a class that makes multiple sprites would be avantageous depending
# on the type of hud you are trying to create. 
# 
# Sprites are the basic concept used to display Bitmap images on the game screen.
# 
#===============================================================================
class Time_HUD < Sprite
#===============================================================================
  #-----------------------------------------------------------------------------
  # creates sprite and bitmap.
  # super calls the initialize method from parent class 'Sprite'
  # this MUST be done before attempting to add a bitmap to the sprite.
  # Calls update method after creating bitmap to ensure data is printed 
  # immediately - it is somewhat noticeable if this is not done.
  #-----------------------------------------------------------------------------
  def initialize(viewport)
    super(viewport)
    self.bitmap = Bitmap.new(100,24) # Creates a new Bitmap object. 100x24
    update
  end
  #-----------------------------------------------------------------------------
  # updates sprite and bitmap. 
  # super calls update method of sprite class - not really necessary unless
  # you are creating a flash effect on the sprite.
  # self.bitmap.clear simply wipes the bitmap to ensure that it is 'blank'
  # prior to adding the new text.
  # self.bitmap.draw_text(x,y,width,height,text,alignment)
  # ^ this line draws the text onto the bitmap.
  # $game_system.playtime_s is defined within Game_System class and simply
  # returns a string (string of text) showing the time the game has been played
  #-----------------------------------------------------------------------------
  def update
    super
    self.bitmap.clear  # clears bitmap
    self.bitmap.draw_text(0,0,100,24, $game_system.playtime_s, 1)
  end
  #-----------------------------------------------------------------------------
  # calls dispose method on bitmap and then (due to super) on the sprite. 
  #-----------------------------------------------------------------------------
  def dispose
    self.bitmap.dispose if self.bitmap
    super
  end
  #-----------------------------------------------------------------------------
  # 
  #-----------------------------------------------------------------------------
end
#===============================================================================
# Now, we are adding our new class into 'Spriteset_Map' 
# This is a class that is included in Vx Ace default scripts and shows many
# various sprites (such as tileset and characters) on the map.
#===============================================================================
class Spriteset_Map
#===============================================================================
  #-----------------------------------------------------------------------------
  # Aliased Methods
  #-----------------------------------------------------------------------------
  alias :init_hud :initialize
  alias :disp_hud :dispose
  alias :updt_hud :update
  #-----------------------------------------------------------------------------
  # Creates new instance of Time_HUD class and passes the argument of class
  # variable '@viewport2' (defined within default spriteset map)
  #-----------------------------------------------------------------------------
  def initialize
    init_hud # Calls alias data
    @time_hud = Time_HUD.new(@viewport2)
  end
  #-----------------------------------------------------------------------------
  # Disposes time hud BEFORE other dispose methods are carried out. 
  # This simply ensures that the sprite will be disposed correctly and does
  # not create any memory leaks. 
  #-----------------------------------------------------------------------------
  def dispose
    @time_hud.dispose if @time_hud
    disp_hud # Calls alias data
  end
  #-----------------------------------------------------------------------------
  # Updates time hud. This can be done before or after alias data is called, 
  # Personally, i prefer before :)
  #-----------------------------------------------------------------------------
  def update
    @time_hud.update if @time_hud
    updt_hud # Calls alias data
  end
  #-----------------------------------------------------------------------------
  # 
  #-----------------------------------------------------------------------------
end

Class Inheritance

Neok of http://forums.rpgmakerweb.com recently asked the question:

[quote]

Just a quick question. If say in the original script, a class is defined as follows:
class Window_ChoiceList < Window_Command
and later under Materials, I define it as follows:
class Window_ChoiceList
What changes inside it, now that I’ve removed the ‘Window_Command’ inheritance?

[/quote]

To which my answer was…

[quote]

If the normal code (ie, class Window_ChoiceList < Window_Command) is still there, it will not ‘affect’ anything.  If you have removed the original code, there would be no inheritance when the code is initialized. For example :

class Game_Actor
  def example_method
    p "Just showing text"
  end
end

Will simply add a new method into the game actor class, providing the Game_Actor class has been previously defined, it does not remove Game_Actors inheritance from Game_Battler.

[/quote]

DRS of http://forums.rpgmakerweb.com then stated:

[quote]

That’s interesting! I thought it would be over written since it wasn’t making the original inheritance call.

[/quote]

This prompted me to write a short explanation of inheritance and how to include new inheritance within your classes. So here it is…

 

As long the inheritance is being applied at ‘some point’ along the line of code it will work. For example…

I have defined this code within my projects script editor…

class Person
  def intialize
    @name = "Newborn"
    @age  = 1
  end
  def name
    @name
  end
  def age
    @age
  end
end

class Dekita < Person
  def intialize
    @name = "Dekita"
    @age  = 24
  end
end

This creates and defines the ‘Dekita’ class. Which inherits from ‘Person’ class. Now, I want to add a new method into ‘Dekita’ class called ‘gender’.

class Dekita
  alias :init_alias :initialize
  def initialize
    init_alias
    @gender = "??"
  end
  def gender
    @gender
  end
end

As you can see, I have removed the class inheritance from my new methods code, but because its already defined prior to my new modification, it does not affect any inheritance already included. This can be tested by calling the code below (when the code from above is also there);

dekita = Dekita.new
p dekita.name
p dekita.age
p dekita.gender

Also – lets say we wanted to include a new ‘inheritance’. We can do this by creating a new module and including it in any class we choose, for this example, I am placing it within the ‘Person’ class.. This will mean even descendants of ‘Person’ will be entitled to access the methods.

module Person_New
  def new_stuff
    return "New Stuff"
  end
end
class Person
  include Person_New
end

Can be tested by calling.

p dekita.new_stuff

For convenience, I have included all the code from above in one handy script – ready to put in your script editor and mess around with to your hearts content. If can be found HERE 🙂

 


Simple Custom Menu Command

This tutorial assumes you understand at least the basics of RGSS coding. Such as aliasing methods, classes, variables, etc..
It is also slightly different to my simple param mod tutorial in the sense that I have simply coded the method and explained why I have done each piece of code in an easy to understand guide. You can also copy/paste the tutorial into your script editor for increased readability and an adequate testing environment. I think I will be continuing this style of tutorial…

If anyone has any issues, let me know.
Would be happy to answer any queries on THIS scenario you may have 🙂

 

#===============================================================================
# Info [ 1 ] = Creates aliased method. used to recall previous method data.
# Info [ 2 ] = Calls alias data, ie - old method data. 
# Info [ 3 ] = Adds new visible command to menu command window.
# Info [ 4 ] = Creates local variable 'handle_name' 
# Info [ 5 ] = Creates local variable 'method_name'
# Info [ 6 ] = Tells the command window to call 'method_name' when 'handle_name'
#              has been selected and activated (pressed)
# Info [ 7 ] = Creates new method. Has the name name as 'method_name' defined in
#              Info [ 5 ]. This method is what is called when the command is 
#              activated.
# Info [ 8 ] = Calls a scene. In this example, I have called 'Scene_Item'.
#              You could call any scene you wanted - usually not Scene_Item :p
#===============================================================================
class Window_MenuCommand < Window_Command
#===============================================================================
  #-----------------------------------------------------------------------------
  # 
  #-----------------------------------------------------------------------------
  alias :aoc_menu_command_tutorial_alias :add_original_commands # See Info [ 1 ]
  #-----------------------------------------------------------------------------
  # 
  #-----------------------------------------------------------------------------
  def add_original_commands
    aoc_menu_command_tutorial_alias                             # See Info [ 2 ]
    add_command("Menu Command Name", :custom_command_handler)   # See Info [ 3 ]
  end
end
#===============================================================================
class Scene_Menu < Scene_MenuBase
#===============================================================================
  #-----------------------------------------------------------------------------
  # 
  #-----------------------------------------------------------------------------
  alias :ccw_menu_command_tutorial_alias :create_command_window # See Info [ 1 ]
  #-----------------------------------------------------------------------------
  # 
  #-----------------------------------------------------------------------------
  def create_command_window
    ccw_menu_command_tutorial_alias                             # See Info [ 2 ]
    handle_name = :custom_command_handler                       # See Info [ 4 ]
    method_name = :custom_command_method_name                   # See Info [ 5 ]
    @command_window.set_handler(handle_name,method(method_name))# See Info [ 6 ]
  end
  #-----------------------------------------------------------------------------
  # 
  #-----------------------------------------------------------------------------
  def custom_command_method_name                                # See Info [ 7 ]
    SceneManager.call( Scene_Item )                             # See Info [ 8 ]
  end
  #-----------------------------------------------------------------------------
  # 
  #-----------------------------------------------------------------------------
end

Simple Param Mod Tutorial

This tutorial assumes you understand at least the basics of RGSS coding. Such as aliasing methods, classes, variables, etc..

Step 1 ::

Grab the class and any methods you need to modify. In this case, that would be Game_Actor and the method ‘param’ – which determines the param value. So, we would write this code… (or something highly similar)

#===============================================================================
class Game_Actor
#===============================================================================
  #-----------------------------------------------------------------------------
  # List Of Aliased Methods
  #-----------------------------------------------------------------------------
  alias :dekita_param_mod_tutorial :param
  #-----------------------------------------------------------------------------
  # Method to determine value of actors params
  #-----------------------------------------------------------------------------
  def param(param_id)
    dekita_param_mod_tutorial(param_id)
  end   
end

All this code does it alias the current ‘param’ method and then calls the aliased method whenever param is called. This is the most basic way of ensuring that the old method is not fully overwritten.

Step 2 ::

Now, we can add a way for the param value to be modified by a variable…

  #-----------------------------------------------------------------------------
  #
  #-----------------------------------------------------------------------------
  def param(param_id)
    ( dekita_param_mod_tutorial(param_id) * $game_variables[VARIABLE_ID] ).to_i
  end

See what I did there?

Because I know that the old method for ‘param’ will return an integer value all I have to do is multiply that value by the value stored in my variable. Lets say in this case the variable is equal to ‘1.5’, this means all stats will be multiplied by 1.5.

Then, because we dont want float numbers for our params (numbers with a decimal point such as 1.234), instead we want nice round integers (such as 1,2,3,4..) I enclosed the formula (old method * variable value) within brackets ‘( )’ and then added an additional method onto the end. ‘.to_i’  will ensure that the code is going to return an integer value.

 

And thats it done.

Obviously, you can start getting ‘more creative’ and maybe create a class or module to determine how the param is going to be modified. Hell, you could end up doing what I did and create about 30 scripts that modify the ‘param’ method to determine the value.