Database Extender

Der Botaniker

Veteran
Veteran
Joined
Mar 18, 2013
Messages
33
Reaction score
13
First Language
French
Primarily Uses
Database Extender

Thanks Hiino for the translation ;)

I think that the RPG Maker database is a bit of a pain since we cannot extend it. Hence, I am obligated to stay in the quite restrictive base system, and, in order to obtain cooler (and more specific) things I have to abuse of the database's commentary/note fields (and why not complete with the Typed Entities script, which isn't adapted to this kind of things... IN MY OPINION!)

So I plagiarized Avygeil who had already been plagiarized by Grim and recoded a database system for RM.

 

Concept

This system is based on the same idea as the one Grim used in his "Expressive Database", except it's a bit better (and more cleverly) coded. So firstly we are going to create tables in a blank script on top of Main. To achieve this, simply write:

 

class Swords < Database::Table # Here we will define our table's fieldsendTo add fields that characterize our table, we have to set their type and their name.

The script accepts the following types: 

  • :string   - Represents text data
  • :integer   - Represents an integer number
  • :float   - Represents a floating point number 
  • :boolean   - Represents either true or false (a switch)
  • :polymorphic   - Represents any RM data type
Here is an example with swords and Pokemon:

 

Code:
class Swords < Database::Table  integer :id  string  :name  string  :description   float   :cost  integer :powerendclass Pokemon < Database::Table  integer :id  string  :name  string  :description  string  :type  integer :powerend
The goal is to describe every attribute of our tables. Of course, these exaples are quite naive and not finished.

How to fill our database

There are two ways of filling our database.

The first one is the most economic: after having defined our fields, we can use the "insert" command and pass it arguments. If said arguments aren't the right type the script will try to convert them, else it will set them a default value according to their type. Here is an example:

 

class Swords < Database::Table # Design of the table integer :id string :name string :description float :cost integer :power # Filling insert 0, "Excalibur", "A rare sword", 150.50, 120 insert 1, "Durendal", "A very rare sword", 200.20, 200 insert 2, "Dard", "Bilbon's, then Frodon's sword", 30.0, 50endclass Pokemon < Database::Table # Design of the table integer :id string :name string :description string :type integer :power # Filling insert 0, "Pikachu", "Ugly green mouse", "Electric", 10 insert 1, "Pichu", "Same as above", "Electric", 5 insert 2, "Doraemon", "thing", "Fire", 100 insert 3, "Sangoku", "Legendary Pokemon", "Rare", 1000 endAlso, it is possible to instantiate objects this way:

Code:
Pokemon.new(id: 4, name: "Mew", description: "Blue monkey", type: "Plant", power: 999)Pokemon.new(id: 5, name: "Magicalichigo", description: "Looks like an Evoli", type: "Psy", power: 1)
Personally, I prefer this way of doing, which allows me to separate my "design" and my filling. But it's possible to mix both techniques.

Access a table

We just have to write:Database.tables[:Table_Name] or Database.Table_Name

For example: Database.Pokemon or Database.tables[:pokemon]

Then Database.Pokemon[0] will return the first record (Pikachu), but since the fields are stored inside an array, it is possible to use all the methods concerning arrays. However this part only addresses scripters, kind of like this whole script actually :D

 

Process the initial RPG Maker database

Since this script is modern and cool, it also allows for handling the RPG Maker database with the same primitives.

For example, to access the Actors table of the database, we will write: Database.VXACE_Actors, which returns the array of all the database's actors.

The accessible tables:


  • VXACE_Actors
  • VXACE_Classes
  • VXACE_Skills
  • VXACE_Items
  • VXACE_Weapons
  • VXACE_Armors
  • VXACE_Enemies
  • VXACE_States
  • VXACE_Animations
  • VXACE_Tilesets
  • VXACE_CommonEvents
  • VXACE_MapInfos
This append allows us to manipulate the initial database in a transparent manner with the script.

Associating with the Event Extender

If the Event Extender is already appended to your project, you have to place this script below it, so that its database overrides the Event Extender's.

The Design/Filling works the ame way as detailed above.

To access the database, it works as usual or as documented in the Event Extender (for example T[:pokemon] or T[:VXACE_Actors]).

Thanks to Hiino for his proofreading and translation!

 

Code

# Extend Database ~ Der Botaniker (Nuki)# http://www.biloucorp.com# Idea : Avygeil, Grim # Thanks to Hiino, Zangther (sexual motivation)# And special thanks to larabdubled#==============================================================================# ** Object#------------------------------------------------------------------------------# Generic behaviour#==============================================================================class Object #-------------------------------------------------------------------------- # * Bool casting #-------------------------------------------------------------------------- if defined?(Command) remove_const:)Database) def to_bool; (self != nil || self != false) end end #-------------------------------------------------------------------------- # * Polymorphic casting #-------------------------------------------------------------------------- def nothing; self; end #-------------------------------------------------------------------------- # * Get Instance values #-------------------------------------------------------------------------- def instance_values instances = Array.new instance_variables.each do |i| instances << instance_variable_get(i) end instances endend#==============================================================================# ** Database#------------------------------------------------------------------------------# Representation of an Abstract Database#==============================================================================module Database #============================================================================== # ** Types #------------------------------------------------------------------------------ # Implements the Type System #============================================================================== RPGDatas = [ "Actors", "Classes", "Skills", "Items", "Weapons", "Armors", "Enemies", "States", "Animations", "Tilesets", "CommonEvents", "MapInfos" ] module Type #-------------------------------------------------------------------------- # * Type Enum #-------------------------------------------------------------------------- Types = { string: [:to_s, ""], integer: [:to_i, 0], float: [:to_f, 0.0], boolean: [:to_bool, true], polymorphic: [:nothing, ""] } #-------------------------------------------------------------------------- # * String representation #-------------------------------------------------------------------------- def string(field_name) handle_field:)string, field_name.to_sym) end alias :text :string #-------------------------------------------------------------------------- # * Integer representation #-------------------------------------------------------------------------- def integer(field_name) handle_field:)integer, field_name.to_sym) end alias :int :integer #-------------------------------------------------------------------------- # * Floating point number representation #-------------------------------------------------------------------------- def float(field_name) handle_field:)float, field_name.to_sym) end #-------------------------------------------------------------------------- # * Boolean representation #-------------------------------------------------------------------------- def boolean(field_name) handle_field:)boolean, field_name.to_sym) end alias :bool :boolean #-------------------------------------------------------------------------- # * Polymorphic type representation #-------------------------------------------------------------------------- def polymorphic(field_name) handle_field:)polymorphic, field_name.to_sym) end alias :free :polymorphic #-------------------------------------------------------------------------- # * Type Coercion #-------------------------------------------------------------------------- def self.coercion(className) return :integer if className == Fixnum return :string if className == String return :float if className == Float return :boolean if className == TrueClass || className == FalseClass :polymorphic end end #============================================================================== # ** Table #------------------------------------------------------------------------------ # Representation of an Abstract Table #============================================================================== class Table #-------------------------------------------------------------------------- # * Appends Type handler #-------------------------------------------------------------------------- extend Type Types = Type::Types #-------------------------------------------------------------------------- # * Singleton of Table #-------------------------------------------------------------------------- class << self #-------------------------------------------------------------------------- # * Public instance variables #-------------------------------------------------------------------------- attr_accessor :fields attr_accessor :classname #-------------------------------------------------------------------------- # * Field handling #-------------------------------------------------------------------------- def handle_field(type, name) @classname ||= self.to_s.to_sym @fields ||= Hash.new @fields[name] = type instance_variable_set("@#{name}".to_sym, Types[type][1]) send:)attr_accessor, name) end #-------------------------------------------------------------------------- # * Inline insertion #-------------------------------------------------------------------------- def insert(*args) keys = @fields.keys hash = Hash[keys.zip(args)] self.new(hash) end end #-------------------------------------------------------------------------- # * Object initialization #-------------------------------------------------------------------------- def initialize(hash) hash.each do |key, value| type = self.class.fields[key] insertion = Types[type][1] insertion = value.send(Types[type][0]) if value.respond_to?(Types[type][0]) instance_variable_set("@#{key}".to_sym, insertion) end Database.tables[self.class.classname] ||= Array.new Database.tables[self.class.classname] << self end end #-------------------------------------------------------------------------- # * Singleton of Database #-------------------------------------------------------------------------- class << self #-------------------------------------------------------------------------- # * Public instance variables #-------------------------------------------------------------------------- attr_accessor :tables #-------------------------------------------------------------------------- # * API for tables #-------------------------------------------------------------------------- Database.tables = Hash.new #-------------------------------------------------------------------------- # * Method Missing #-------------------------------------------------------------------------- def method_missing(method, *args) tables[method] || (raise(NoMethodError)) end endend#==============================================================================# ** Junction with the Event Extender 4#==============================================================================if defined?(Command) #============================================================================== # ** T #------------------------------------------------------------------------------ # Database handling API #============================================================================== module T #-------------------------------------------------------------------------- # * Get a table #-------------------------------------------------------------------------- def [](name); Database.tables[name.to_sym]; end endend#==============================================================================# ** RPG::Module Mapping#------------------------------------------------------------------------------# Initial Database Mapping#==============================================================================Database::RPGDatas.each do |data| rpgStruct = load_data("Data/#{data}.rvdata2") instance = rpgStruct.find{|i| !i.nil?} instance = instance[1] if instance.is_a?(Array) Object.const_set( "VXACE_#{data}".to_sym, Class.new(Database::Table) do self.classname = "VXACE_#{data}".to_sym instance.instance_variables.each do |attr| classData = instance.send:)instance_variable_get, attr).class type = Database::Type.coercion(classData) self.send(type, attr.to_s[1..-1].to_sym) end rpgStruct.each do |rpgData| rpgData = rpgData[1] if rpgData.is_a?(Hash) self.insert(*rpgData.instance_values) end end )end

 

Permalink

If I update the script, it will usually be on this page: https://github.com/Funkywork/Scripts-rm/blob/master/VXAce/Extend-Database.rb

And the official Page : http://www.biloucorp.com/index.php?page=article&id_article=4
 
Last edited by a moderator:

Mr. Bubble

Makes stuff.
Member
Joined
Mar 1, 2012
Messages
853
Reaction score
163
Please put long code boxes within spoiler tags. Thanks.
 

Der Botaniker

Veteran
Veteran
Joined
Mar 18, 2013
Messages
33
Reaction score
13
First Language
French
Primarily Uses
Done.

Sorry for this catastrophe. 
 

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,230
Reaction score
3,071
First Language
English
Looks interesting. How about updating database entries? And what happens if I save the game? Will any newly inserted or updated entries be preserved?
 

Der Botaniker

Veteran
Veteran
Joined
Mar 18, 2013
Messages
33
Reaction score
13
First Language
French
Primarily Uses
This 's a Static Database to extend Statics Data. 

In Game, you can't update RPG::think somtimes. It's for build "object representation".
 

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,230
Reaction score
3,071
First Language
English
That makes sense.


on the topic of databases, suppose I chose to set up my database in mySQL or SQLite or something. Then I set up my tables using your script. What would be an easy way for me to load my data into the game?
 

gpgekko

Nevermind me, I'll just cast shadows on your walls
Veteran
Joined
Jan 23, 2013
Messages
114
Reaction score
7
First Language
Dutch
Primarily Uses
That makes sense.

on the topic of databases, suppose I chose to set up my database in mySQL or SQLite or something. Then I set up my tables using your script. What would be an easy way for me to load my data into the game?
Export/import from sources like a (my)SQL tool or even an Excel sheet (maybe csv?) would actually be pretty awesome. It would make setting up the database easier since I could use an enviroment I know and am comfertable with. It would probably increase my working speed by at least 150%...
 

ディーノス

Make a new destiny!
Veteran
Joined
Jul 3, 2012
Messages
187
Reaction score
19
First Language
Indonesian
Primarily Uses
can u give me a demo???

i don't quite understand
 

psychokill

Warper
Member
Joined
Apr 17, 2013
Messages
2
Reaction score
0
First Language
German
Primarily Uses
Hmm, thanks for the script!

// EDIT

Hmm sry, but it does not seem to work.

both, Database.Test2 or Database.tables[:Test2] does not give any values from the database tables.

I created, like instructions, an simple table:

class Test2 < Database::Table  # Design of the table  integer :id  string  :name  string  :value  # Filling  insert 0, "window_screensize", "800,600"  insert 1, "window_mode", "window"endThan I tried to get the data out of it.

text = Database.Test2[0]raise("test:" << text.to_s)The only thing I will get is:
test: #<Test2:0xa84f9e0>

I tried some various querys like: "Database.Test2[0][1], Database.Test2[0[1]], Database.Test2[1][0]... And the same with the variant of Database.tables[:Test2].

No result.
 
Last edited by a moderator:

Der Botaniker

Veteran
Veteran
Joined
Mar 18, 2013
Messages
33
Reaction score
13
First Language
French
Primarily Uses
Yes... but wich field do you want? 

Database.Test2[0].name => "window_screensize" for example...
 

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

I have tried, several times to understand how Markiplier is popular. You can't deny his popularity. I can only get through a few minutes of his vids, though. He's cringier than ANY cringe comp I've ever watched. When I was a kid, if you acted like that, 0 friends and 100% no dates for you. Times have changed XD
Sometimes you may feel helpless and defeated. But everyone loses from time to time. It's okay to be tired. Take a breather. Have a good cry if you need to. You gotta take breaks from your workout, or you'll collapse before you can get stronger.
So, my roommates wrote a news article in English, translated it into Bengali with google translate and now I'm helping them fix the monstrosity which was the result. Making English the medium of education is fine... but not to an extent that we forget how to write properly in our own language :")
Stream will be live shortly with some more Minecraft spriting! Feel free to drop by~

Forum statistics

Threads
93,542
Messages
913,320
Members
123,067
Latest member
SehoraX
Top