Preserved forum archive. This topic stores the original first post and locally mirrored RPG Maker Web attachments when available. It is posted by the BMMPlay archive account, not by the original creator.
Original Source
- Original title: Combine RGSS with ruby-c dll and speed up the game like a boss
- Original author: ken1882
- Original date: March 19, 2019
- Source thread: https://forums.rpgmakerweb.com/threads/combine-rgss-with-ruby-c-dll-and-speed-up-the-game-like-a-boss.107006/
- Source forum path: Game Development Engines > RPG Maker Tutorials > RMVXAce Tutorials
Summary
WARNING: This post is not suitable for newbies, perhaps also not applied to the game that doesn't have a performance issue. It's suggested to know the following knowledge to fully understand how it works: RMVA Scripting experience(most important one, required)
Archived First Post
WARNING:
This post is not suitable for newbies, perhaps also not applied to the game that doesn't have a performance issue.
It's suggested to know the following knowledge to fully understand how it works:
A very basic thing that you should know is the datatype of all ruby object in C level is 'VALUE', a pointer to the object except some very basic object, like Fixnum, and you can see this part in ruby.c:
in this line, SIGNED_VALUE generally is LONG(aka int) and FIXNUM_FLAG is 1, so you can think Fixnum is encoded by (n * 2 + 1) instead of the pointer. However, the VALUE of String and Float are both pointers. And you can get the object's address by:
(as known as multiply the object_id by 2)
we'll need that to pass the object from Game.exe to our dll later
------------------------I'm a random split line------------------------
Currently, I'm making a unique engine for my game, and as larger as it gets, the performance issue comes up...(duh)
Just like Python, one of the popular way to resolve this problem in interpreter language is mixing it with C-level code to speed up and improve the calculation significantly.
Before getting started, you will need:
- Ruby 1.9.2-p0 source code (download here), this is the ruby version that rgss using
- A C/C++ IDE, Visual Studio is a common option, but I also using Code::Blocks, VS is using for debugging DLL
- (optional) A debugger (I use VS), because the game will crash silently if something wrong with the dll
Once got the software running and prepared the DLL project, the next step is telling the compiler to know what's Ruby object, notice that we don't have to compile the ruby source code itself. Since RubyVM is running inside RGSS301.dll so we only need to declare necessary functions and datatypes and call RGSS301.dll while building up the dynamic link library. But if you're as silly as I am...managed to include the whole ruby to the dll and using the ruby function... Congratulations! You'll get ruby_vm_current_ptr is nullptr and the game crashes! (I f*cking even compile the whole ruby natively and it took me ages to build successfully...)
If you don't want to copy, edit and post the ruby source code, you can go download header files here and put them in the project folder, then include "ruby.h", this way you should have no trouble using VALUE in your C/CPP file. So the .hpp or .h file should like:
Next, we're heading to the example, and what I gonna show here is how to improve the projectile collide detection, here're also some extra tips you should know while writing c code:
- Access VALUE as less as possible, the dll is slower than getting VALUE in RGSS
- Don't wrap the functions that frequently calling other methods into dll, the reason is above
- From 2 above, things needed to write into C-level are calculation-heavy functions
- Since Float are pointers, so using Fixnum if you can, and convert them to int and store in your C code
- avoid using std::vector, using new int [] if need to deal with fixed-length array
since the time complexity of simplest collide detection is O(n^2), only need O(n) time to access VALUE data, also not affect gameplay much if the projectile colliding effect is delayed by 1 frame so it's good to put that into C.
Before jump into the demo and explain the code, here's the result of my little experiment, I also used Theo's Anti-Lag to make the result better due to the fact that tons of projectiles also means tons of active sprites(unfortunately RMVA is not good at graphics processing), and the measurement is making a constantly updated event run from A point to B point 10 times, since the lag will slow the entire game down, so the one take less time is the better result.
Experiment Info:
> Using collision box as collide detection
> Distance of A to B: 10 tiles
> Measurement Event: x4 Faster Speed, Highest Frequency, through
> 5 projectiles are generated per frame update
> Maximum visible sprites number is 100/1000000000 (over will become invisible projectile lol)
> Total events: 277
> Total battler event: 65
※The result will vary on different hardware, tested using I5-6200U/4GB laptop
Download the source code of DLL project: https://github.com/ken1882/RGSS-Ext
Download the Demo: https://mega.nz/#!AlZiAK6A!cCybazZERTQmkT0TELzZpAu6I2AnUZTf1nCRAnDsPPA (Google Drive tends to think executable is infected virus for some reason)
<next: building dll>
This post is not suitable for newbies, perhaps also not applied to the game that doesn't have a performance issue.
It's suggested to know the following knowledge to fully understand how it works:
- RMVA Scripting experience(most important one, required)
- Basic C/C++ knowledge
- Familiar with Ruby and C/C++
- PE(portable executable) and DLL(Dynamic Link Library)
A very basic thing that you should know is the datatype of all ruby object in C level is 'VALUE', a pointer to the object except some very basic object, like Fixnum, and you can see this part in ruby.c:
Code:
#define INT2FIX(i) ((VALUE)(((SIGNED_VALUE)(i))<<1 | FIXNUM_FLAG))
Code:
obj.object_id << 1
we'll need that to pass the object from Game.exe to our dll later
------------------------I'm a random split line------------------------
Currently, I'm making a unique engine for my game, and as larger as it gets, the performance issue comes up...(duh)
Just like Python, one of the popular way to resolve this problem in interpreter language is mixing it with C-level code to speed up and improve the calculation significantly.
Before getting started, you will need:
- Ruby 1.9.2-p0 source code (download here), this is the ruby version that rgss using
- A C/C++ IDE, Visual Studio is a common option, but I also using Code::Blocks, VS is using for debugging DLL
- (optional) A debugger (I use VS), because the game will crash silently if something wrong with the dll
Once got the software running and prepared the DLL project, the next step is telling the compiler to know what's Ruby object, notice that we don't have to compile the ruby source code itself. Since RubyVM is running inside RGSS301.dll so we only need to declare necessary functions and datatypes and call RGSS301.dll while building up the dynamic link library. But if you're as silly as I am...managed to include the whole ruby to the dll and using the ruby function... Congratulations! You'll get ruby_vm_current_ptr is nullptr and the game crashes! (I f*cking even compile the whole ruby natively and it took me ages to build successfully...)
If you don't want to copy, edit and post the ruby source code, you can go download header files here and put them in the project folder, then include "ruby.h", this way you should have no trouble using VALUE in your C/CPP file. So the .hpp or .h file should like:
Code:
#include <windows.h>
#include "ruby.h"
Next, we're heading to the example, and what I gonna show here is how to improve the projectile collide detection, here're also some extra tips you should know while writing c code:
- Access VALUE as less as possible, the dll is slower than getting VALUE in RGSS
- Don't wrap the functions that frequently calling other methods into dll, the reason is above
- From 2 above, things needed to write into C-level are calculation-heavy functions
- Since Float are pointers, so using Fixnum if you can, and convert them to int and store in your C code
- avoid using std::vector, using new int [] if need to deal with fixed-length array
since the time complexity of simplest collide detection is O(n^2), only need O(n) time to access VALUE data, also not affect gameplay much if the projectile colliding effect is delayed by 1 frame so it's good to put that into C.
Before jump into the demo and explain the code, here's the result of my little experiment, I also used Theo's Anti-Lag to make the result better due to the fact that tons of projectiles also means tons of active sprites(unfortunately RMVA is not good at graphics processing), and the measurement is making a constantly updated event run from A point to B point 10 times, since the lag will slow the entire game down, so the one take less time is the better result.
Experiment Info:
> Using collision box as collide detection
> Distance of A to B: 10 tiles
> Measurement Event: x4 Faster Speed, Highest Frequency, through
> 5 projectiles are generated per frame update
> Maximum visible sprites number is 100/1000000000 (over will become invisible projectile lol)
> Total events: 277
> Total battler event: 65
※The result will vary on different hardware, tested using I5-6200U/4GB laptop
No projectile:
Average 1.0149 seconds in 10 runs
100 sprite limit, no dll nor anti-lag script:
Average 5.4282 seconds in 10 runs; lim -> 5.98 seconds with around 620 projectiles
100 sprite limit, with dll only:
Average 3.1801 seconds in 10 runs; lim -> 3.38 seconds with around 620 projectiles
100 sprite limit, with ATL only:
Average 3.3929 seconds in 10 runs; lim -> 3.92 seconds with around 676 projectiles
100 sprite limit, with both dll and ATL:
Average 1.3161 seconds in 10 runs; lim -> 1.39 seconds with around 676 projectiles
1,000,000,000 sprite limit, with dll only:
Average 4.3676 seconds in 10 runs; lim -> 5.11 seconds with around 650 projectiles
1,000,000,000 sprite limit, with ATL only:
Average 4.0854 seconds in 10 runs; lim -> 4.92 seconds with around 693 projectiles
1,000,000,000 sprite limit, with both dll and ATL:]
Average 2.3111 seconds in 10 runs; lim -> 3.09 seconds with around 693 projectiles
Average 1.0149 seconds in 10 runs
100 sprite limit, no dll nor anti-lag script:
Average 5.4282 seconds in 10 runs; lim -> 5.98 seconds with around 620 projectiles
100 sprite limit, with dll only:
Average 3.1801 seconds in 10 runs; lim -> 3.38 seconds with around 620 projectiles
100 sprite limit, with ATL only:
Average 3.3929 seconds in 10 runs; lim -> 3.92 seconds with around 676 projectiles
100 sprite limit, with both dll and ATL:
Average 1.3161 seconds in 10 runs; lim -> 1.39 seconds with around 676 projectiles
1,000,000,000 sprite limit, with dll only:
Average 4.3676 seconds in 10 runs; lim -> 5.11 seconds with around 650 projectiles
1,000,000,000 sprite limit, with ATL only:
Average 4.0854 seconds in 10 runs; lim -> 4.92 seconds with around 693 projectiles
1,000,000,000 sprite limit, with both dll and ATL:]
Average 2.3111 seconds in 10 runs; lim -> 3.09 seconds with around 693 projectiles
No projectile:
No anti-lag, native ruby collision detection, 100 sprite limit
with anti-lag, native ruby code, 100 sprite limit
1000000000 limit:
no anti-lag, C-level collide detection code, 100 sprite limit
1000000000 limit:
with anti-lag and C-level code, 100 sprite limit
1000000000 limit:
No anti-lag, native ruby collision detection, 100 sprite limit
with anti-lag, native ruby code, 100 sprite limit
1000000000 limit:
no anti-lag, C-level collide detection code, 100 sprite limit
1000000000 limit:
with anti-lag and C-level code, 100 sprite limit
1000000000 limit:
Download the source code of DLL project: https://github.com/ken1882/RGSS-Ext
Download the Demo: https://mega.nz/#!AlZiAK6A!cCybazZERTQmkT0TELzZpAu6I2AnUZTf1nCRAnDsPPA (Google Drive tends to think executable is infected virus for some reason)
<next: building dll>
Downloads / Referenced Files
Log in to download
Log in, then follow the RPG Maker Developers Group to see these download links.
Log in to downloadCreator Claims / Removal
If you are the original creator and want this listing reassigned, edited, or removed, join BMMPlay and contact the moderators with proof that matches the original RPG Maker Web profile, linked GitHub, itch.io page, or another public creator identity.
Replies (0)
No replies yet.
0
replies
1
view
Topic Summary
Loading summary...