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 ^_^
Thank you for the ‘Heads up’ on the info “Extending RGSS / C”.
Can’t wait to try this out….very intresting. This could open up Ruby with
many more possibilities!
Keep up the good work.
No worries ^_^
I’m actually gonna write up a better tutorial when i get the time, learned quite a bit in the short time since I wrote this 😀
This is fascinating. I was not able to read the whole article for the first time but I as I am rereading it, I have been fascinated how this works. This is what amazes me of Ruby, it can be of anything.