Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - Mason Wheeler

1
RMXP Script Database / Re: [XP] RMX-OS
July 01, 2017, 09:54:52 am
So what happens if you try to run it directly?  If it's erroring out trying to load it, then running it should give you some sort of error message. (Hopefully!)
2
RMXP Script Database / Re: [XP] RMX-OS
July 01, 2017, 09:43:39 am
OK. Does that file exist?  (It should.  If so, try running that file and see if you get a more detailed output.  If not, you'll want to re-download and reinstall RMX-OS.)
3
RMXP Script Database / Re: [XP] RMX-OS
July 01, 2017, 08:56:44 am
Deucerer, if you want to find out why, try running it from a command-line window.  Then the console will stay open and you'll be able to read whatever it says.

If you don't know how to use the command line (because a bunch of people don't), create a text file named "RMX-OS.cmd" in the same folder.  It should say exactly this:

RMX-OS.rb >output.txt 2>&1

Run that instead of the Ruby file, and it'll create an "output.txt" file containing the output from the server.
4
RMXP Script Database / Re: [XP] RMX-OS
May 08, 2016, 07:47:55 am
QuoteTo be honest, before retiring I did play with the idea to change RMX-OS in such a way to be able to run on multiple servers where the maps would simply be distributed between servers since they are isolated entities. It actually wouldn't be that difficult. All you had to do would be sending messages to the client to reconnect to another server if they are changing to a map that currently resides on another server and you would probably need a login server separate from the map servers. The login server would also handle the list of where each map currently resides and handle server synchronization by handing out and revoking map handles to servers.

Interesting.  Did you ever come up with any code for this?

QuoteThere is another better, but also more complicated solution that I thought of. If you would create a dummy RMXP engine, you could run an instance of the game without graphics on the server for every map so gmaster processing would happen on the server. This approach still allows you to use the gmaster system for processing, but it would be server side.

Possibly, but this would involve running possibly hundreds of instances--I've even seen a few games with over 1000 maps!--and Ruby is not a lightweight scripting engine.  That would require a non-trivial resource commitment to make it work.
5
RMXP Script Database / Re: [XP] RMX-OS
May 07, 2016, 06:39:03 pm
After looking this over, with a bit of help from whitespirits, it seems that the source of the lag has very little to do with the choice of TCP over UDP.  Instead, it seems to stem from a quirk in Blizz-ABS, the "gmaster" system.

A bit of background:

Most MMOs are designed with the canonical game state--the authoritative answers to the questions of where characters and NPCs are located, what they're doing, and what items, stats and abilities they have--living entirely on the server.  The game client is mostly just a terminal that passes input messages to the server, retrieves update messages from the server, and renders the game according to the state the server describes in the update messages.  This has several advantages.  It allows you to centralize all the processing of the game, it makes it easy to implement the well-known security principle of Never Trust User Input (always verify that any outside input is valid before accepting and acting on it,) which makes cheating much more difficult, and it makes reverse-engineering the game harder because the client doesn't have the game logic.  Running a map server can be a difficult, processor-intensive job, and you'll often have one server for each map.  (Or sometimes more than one per map, depending on how big your game is!)  This is generally OK, because you tend to have a small number of large maps.

RMX-OS is the exact opposite in many ways.  It's not designed as an MMO, but rather it's a system for adding MMO logic onto an existing, well-established single-player RPG engine.  Because RPG Maker is a single-player engine, the concept of canonical game state existing somewhere other than on the client doesn't make sense to it.  The RMX-OS server is a pretty lightweight MMO system, which mostly deals with message passing and saving persistent data to the database; it knows nothing about the game itself.  It doesn't have its own copy of the maps or the game logic; these are all located on the client-side, which means that both cheating and reverse-engineering are fairly simple, unfortunately.  (All a player needs to do is open up their copy of the game in RPG Maker and play around with the maps.)

But this runs into a problem with a system like Blizz-ABS, where NPCs are supposed to be moving around on the shared map and interacting with the users as enemies that users can fight together: you can't have the clients move the NPCs.  (What if two of them moved the same NPC in different ways?  The action would get out of sync!)  And you can't have the server move the NPCs, because it doesn't know about the maps or the game logic.  Therefore, Blizz-ABS decided to have one client move the NPCs and handle canonical map data for each map, designating that client as "gmaster" (Game Master, I assume.)  So now this one client does all the processing locally, and coordinates everything (including other users' actions) with the server.

What this means is that if a laggy client is chosen as gmaster for a map, he'll lag up everyone on that map.

Ideally, this could be solved by moving canonical processing of game data to the server, but that would be tricky: a large amount of RGSS and the game engine would have to be recreated on the server-side, while removing the graphics part of it, and the corresponding code would need to be disabled on the client-side and replaced with messaging.  And it would take a bunch of additional reworking due to the way RPG Maker's map engine is designed with the implicit assumption that only one map is running at a time.  And just to further complicate things, unlike standard MMOs, which feature a small number of large maps, RPG Maker's style tends towards a large number of small maps, which makes multi-server solutions trickier.

It could be done, but it would not be an easy task!

The other possible solution would be for the server to assign gmaster more intelligently.  Right now, it simply assigns gmaster on a first-come-first-served basis: the first person to enter a map becomes gmaster for that map and retains the title for as long as they stay connected and on that map.  If the server had a way of detecting ping times for its clients, though, it could check as part of the server_update cycle to see which client on each map has the lowest latency and reassign gmaster status to keep things running smoothly.  Unfortunately, there doesn't seem to be any built-in way to do that.

One thing that might work: Have the server spawn a new Thread that does the following in a loop:

for each client connected:
   record current time
   send a PING message to client, to which it responds "PONG"
   wait for the response. when it comes, check how long it took.
record all client ping times in a hash of client => time
save this hash to a global value
sleep for a few seconds before running the loop again.


Then the server_update would check to see if the hash has been updated.  If it has, run through the list of maps, find the fastest user for each map, and set them as gmaster.

This wouldn't be perfect, but it would help keep lag down without having to rewrite the entire game engine.

Any thoughts?
6
Script Requests / Re: A script to stop force close
April 25, 2016, 07:31:01 am
Wow.  How do you hook window messages in RGSS?
7
Any progress on this?
8
Thanks.  Edited to fit the template.
9
Quote from: KK20 on April 03, 2016, 05:26:54 pm
Should have said the template, but they are pretty much guidelines to get databased.


Oh.  I didn't know that there was a formal template.  I just copied the basic format off another post.

Quote
Pokemon reference: https://youtu.be/cQxITW6VO-A?t=33s


Yeah, you should be able to build something like that with this.  Or build buildings for a sim, in the style of FarmVille or DragonVale.  Or set up a base like in a strategy game, or possibly even a tower defense game.  This script is intended as basic plumbing, and then you build the game logic on top of it.

Quote
The VXA compatibility for RMX-OS is too obscure. For now, you should provide a link to that topic unless you plan on getting that databased as well.

Linked.
10
Quote from: KK20 on April 03, 2016, 04:08:23 pm
You need to follow all the guidelines to have this script be moved into the database.

OK, where would I find them?  Searching on the scripts forum for "guidelines" turns up nothing.

Quote
At first I was confused what this script even did. You used the word "regions" which are actually those colored squares with numbers in them (press F7). I then see that all you're doing is copying tile IDs (and events) from one map to another with the use of a script call. Screenshots (or more preferably a demo) would be appreciated.

Yeah, not capital-R Regions.  It copies the contents of the map.

This is a WIP and I'm still working on a demo.  I'll have something to post soon enough.

Quote
In its current state, this is helpful for games where there's an empty plot of land that the player can build a specific house on top of, something like rebuilding a destroyed town. As for things like making bases, I'd still prefer a system like in the Pokemon games which would require another script en-tandem with this. Other than that, I don't see what else you can do with this. You should state more ideas.


I've never actually played the Pokemon games in question, but the idea here is that you can place premade elements in arbitrary places on a map.  (Actually working out what to place and where is a game-specific piece of logic left to the developer, of course.)

QuoteAlso you mentioned it works with RMX-OS for VXA, but no such thing exists yet. You should probably remove that for now until you release that compatibility version (I'm not sure where your current progress is in that. If it's done and you're gonna post it in a couple days, no worries then).

http://forum.chaos-project.com/index.php/topic,15373.0.html  It's been posted here for a while now.
11
Buildings
Authors: Mason Wheeler
Version: 1.0
Type: Copyable buildings script
Key Term: Environment Add-on



Introduction

This is a script I wrote up to make it possible to create dynamic maps by defining custom regions in one map and copying them to another.  The custom regions are known as "buildings", because the basic idea is to make a customizable town, base, or similar, although the script can of course be used for things other than buildings.

It lets you define maps that contain buildings, and define which regions make up each building, and then copy them to your game maps using scripting.  The copying process will include any events located within the defined region.



Features


  • Create buildings on one map, then copy them dynamically to another

  • Copies events placed on the buildings

  • Built-in hook for registering copied events

  • New Game_Map#events_for_building_id method to conveniently find all events belonging to a certain building

  • RMX-OS compatible




Screenshots

None for the moment.


Demo

None for the moment


Script

Spoiler: ShowHide

#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
# RPG Maker VX Ace Buildings System
#------------------------------------------------------------------------------
# Author: Mason Wheeler
#------------------------------------------------------------------------------
#
# Allows a map to contain custom map elements that can be copied from another map
# and placed dynamically.  These elements are known in this script as "buildings",
# though they may look like any sort of map element.
#
#------------------------------------------------------------------------------
#
# LICENSE
#
# The contents of this script are used with permission, subject to
# the Mozilla Public License Version 1.1 (the "License"); you may
# not use this file except in compliance with the License. You may
# obtain a copy of the License at
# http://www.mozilla.org/MPL/MPL-1.1.html
#
# Software distributed under the License is distributed on an
# "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
#------------------------------------------------------------------------------
#
# SETUP
#
# Any map that contains buildings should be named "Buildings".  You can place as
# many buildings into the map as you want.  You define the coordinates for your
# buildings in the Notes section of the map.  Each line should begin with a
# name, a colon, then 4 numbers separated by commas, denoting the x, y, width,
# and height values of a Rect that encloses the building, like so:
#
# Custom House 1:0,0,16,20
#
# Every building should have a name that is unique throughout the entire project.
# (Duplicate names will throw an error during setup.)
#
# Copying a building will copy any Events within the rect, with a few
# restrictions.  Bear in mind that each copied Event is a *copy*, that will end
# up somewhere other than the original map.  Therefore, nothing in the Rvent's
# script should reference elements of the original map, including other events
# or map coordinates.  If your building contains a Transfer Player command to an
# indoor location which has a door leading back out, this will need to save the
# player's coordinates to variables for the return teleport to use.
#
#------------------------------------------------------------------------------
#
# USAGE
#
# This script defines a global obect named $custom_buildings whose data property
# holds information about building locations.  To place buildings, call the
# add_building method on it.
#
# The method takes 5 arguments: (map, name, x, y, id).  The map value is the ID
# number of the map on which the building should be placed.  The name is a
# string, the name of the building.  It should match a building name as defined
# above.  Next are the X and Y coordinates on the destination map where the
# too-left corner of the building should begin.  The final value is a building
# ID, a custom tag that will be added to any Event copied with the building as
# its "building_id" property, which can be used in scripts to distinguish
# between two copies of the same original Event.  It should be unique within
# each map, and will raise an error if it is not.

# The building id value is also used in the remove_building method, to locate
# the buiding to be removed.
#
# $custom_buildings is scanned for buildings each time a map is setup.
# Therefore, changing the entry for a map while on that map will have no effect
# until the player leaves and returns to it or Buildings.map_refresh is called,
# which causes the map to reload itself.
#
# The Buildings.event_created(event) routine is provided as a convenient hook
# for other scripts to override.  Each time an event is copied as part of
# placing a building, this routine will be called, passing the new Game_Event
# object to it.
#
#------------------------------------------------------------------------------
#
# COMPATIBILITY
#
# This script can be used with RMX-OS.  It should be placed in the Materials
# section below the RMX-OS script, if applicable.
#
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=

class Building_Data
  attr_reader :data
  attr_reader :events
  attr_reader :coords
 
  def initialize(data, events, coords)
      @data = data
      @events = events
      @coords = coords
  end
end

class Scene_Title
  alias title_start start
  def start
    title_start
    Buildings.setup_houses
  end   
end

class Game_Event
  attr_accessor :building_id
  attr_reader :event
 
  alias ge_initialize initialize
  def initialize(map_id, event)
    ge_initialize(map_id, event)
    building_id = -1
  end
end

module DataManager
 
  class << self
    alias DM_save make_save_contents
    alias DM_load extract_save_contents
  end
 
  #--------------------------------------------------------------------------
  # * Create Save Contents
  #--------------------------------------------------------------------------
  def self.make_save_contents
    contents = DM_save
    contents[:custom_buildings] = $custom_buildings
    contents
  end
  #--------------------------------------------------------------------------
  # * Extract Save Contents
  #--------------------------------------------------------------------------
  def self.extract_save_contents(contents)
    DM_load(contents)
    $custom_buildings = contents[:custom_buildings]
  end
 
end

module Buildings

  class Custom_Buildings
    attr_accessor :data
   
    def initialize
      @data = {}
    end
   
    def add_building(map, name, x, y, id)
      mapdata = @data[map]
      if mapdata.nil?
        mapdata = {}
        @data[map] = mapdata
      end
      raise "Duplicate ID #{id} on map # #{map}" if mapdata.has_key?(id)
      mapdata[id] = [name, x, y]
    end
   
    def remove_building(map, id)
      mapdata = @data[map]
      unless mapdata.nil?
        mapdata.delete(id)
        @data.delete(map) if mapdata.empty?
      end
    end
  end
 
  def self.setup_houses
    $houses = {}
    houses = $data_mapinfos.find_all{|id, map| map.name == "Buildings"}.map{|a| a[0]}
    houses.each do |id|
      mapinfo = load_data(sprintf("Data/Map%03d.rvdata2", id))
      mapinfo.note.split('\n').each do |line|
        name, values = line.split(':')
        coords = values.split(',').map{|v| v.to_i}.to_a
        rect = Rect.new(coords[0], coords[1], coords[2], coords[3])
        raise "Duplite building name #{name}" if $houses[name]
        $houses[name] = Building_Data.new(mapinfo.data, mapinfo.events, rect)
      end
    end
  end
 
  def self._blit_house(map, house_id, left, top, building_id)
    house = $houses[house_id]
    data = house.data
    coords = house.coords
    coords.height.times do |y|
      y2 = y + top + coords.y
      coords.width.times do |x|
        x2 = x + left + coords.x
        4.times{|z| map.data[x2, y2, z] = data[x, y, z]}
      end
    end
   
    house.events.each do |i, event|
      if (event.x >= coords.x) && (event.x < coords.x + coords.width) && (event.y >= coords.y) && (event.y < coords.y + coords.height)
        _blit_house_event(map, i, event, left, top, building_id, coords)
      end
    end
  end

  def self._blit_house_event(map, i, event, left, top, building_id, coords)
    event_id = map.events.size + 1
    newEvent = Game_Event.new(map.map_id, event)
    newEvent.moveto(event.x + left - coords.x, event.y + top - coords.y)
    newEvent.id = event_id
    newEvent.building_id = building_id
    map.events[event_id] = newEvent
    event_created(newEvent)
  end

  def self.map_refresh
    $game_map.setup($game_map.map_id)
    $game_player.center($game_player.x, $game_player.y)
    $game_player.make_encounter_count
  end

  def self.event_created(event) #override this as needed
  end
end

class Game_Map
  $custom_buildings = Buildings::Custom_Buildings.new
 
  alias gm_setup setup
  def setup(map_id)
    gm_setup(map_id)
    cust = $custom_buildings.data[map_id]
    if cust
      cust.each do |id, value|
        map, left, top = value
        Buildings._blit_house(self, map, left, top, id)
      end
    end
  end
end

def this_event
  $game_map.events[$game_map.interpreter.event_id]
end

if defined? RMXOS
 
  class Scene_Servers
    alias servers_setup setup_scene
    def setup_scene
      servers_setup
      Buildings.setup_houses
    end   
  end
 
  module RMXOS
    module Options
      SAVE_CONTAINERS.push('$custom_buildings')
      SAVE_DATA[Buildings::Custom_Buildings] = ['@data']
    end
  end
 
end



Instructions

Pretty straightforward, just see the documentation at the top of the script.


Compatibility

This script will work with RMX-OS (VXAce version).  Place it after the RMX-OS script, if applicable.


Credits and Thanks

(This is original work)



Author's Notes

Enjoy and report any bugs or suggestions here. :)



License

This is released under the MPL license, which essentially says that you may freely use this script with any project, including commercial projects.  However, if you modify this script, for example to fix bugs or add new features, you are required to publish your modified version under the same license.  (The rest of your project is not affected by this license, only the script itself.)
12
RPG Maker Scripts / Re: RMX-OS port to VXAce
April 03, 2016, 12:21:39 pm
After some testing, saving seems to work just fine so far.  Just added a fix for teleports between maps, though, which was broken due to a different order of events between XP and VXAce.
13
RPG Maker Scripts / [RMX-OS] Simple instance maps
April 03, 2016, 08:47:04 am
So after looking over a few partial proposals on here, I decided to try and do instance maps myself.  It turned out to be surprisingly easy and not require any new client-side messages or special scripting.  (For ordinary gameplay at least.  Administration and visiting someone else's instance requires scripting to send special messages.)  All it requires is a new database table to hold a list of IDs of maps that should be shared (ie. the RMX-OS default behavior.  This script changes it so all maps are instance maps by default.)  Everything needed for setup and implementation is explained in the header comment block, except the obvious observation that it needs to be added to EXTENSIONS on cfg.ini in order for it to work.

Spoiler: ShowHide
Code: ruby

#======================================================================
# Instance Maps extension.  This script allows the server to have maps
# that aren't shared between players, and in fact makes this the default.
# It requires a new table in the database that holds a list of maps that
# *should* be shared, which can be set up with the following SQL command:
#
# CREATE TABLE `shared_maps` (
# `map_id` int unsigned NOT NULL,
# PRIMARY KEY (`map_id`)
# ) ENGINE = InnoDB;
#
# Any map not on this list will be treated as an instance map.  The
# extension handles this completely transparently by intercepting and
# modifying MEN (Map Enter) messages before they can be processed by
# Client#check_game.  This means that no special scripts or client-side
# code of any kind is needed to enable instance maps.
#
# The shared_maps database table can be safely modified while the server
# is running.  Once it has been modified, the admin will need to send a
# "IMAP" message to the server, with no parameters.  This will cause the
# extension to reload its shared maps data.
#
# It's also possible to visit someone else's instance by sending a MEN
# message with the appropriate ID value, which can be calculated
# client-side from the map ID and user ID.
#
#======================================================================


module RMXOS

#------------------------------------------------------------------
# Passes the extension's main module to RMX-OS on the top
# level so it can handle this extension.
# Returns: Module of this extension for update.
#------------------------------------------------------------------
def self.load_current_extension
return InstanceMaps
end

end

#======================================================================
# module InstanceMaps
#======================================================================

module InstanceMaps

# extension version
VERSION = 1.0
# required RMX-OS version
RMXOS_VERSION = 2.0
# whether the server should update this extension in an individual thread or not
SERVER_THREAD = true
# the extension's name/identifier
IDENTIFIER = 'Instance Maps'

#------------------------------------------------------------------
# Initializes the extension (i.e. instantiation of classes).
#------------------------------------------------------------------
def self.initialize
# create mutex
@mutex = Mutex.new
end

#------------------------------------------------------------------
# Gets the local extension mutex.
#------------------------------------------------------------------
def self.mutex
return @mutex
end

#------------------------------------------------------------------
# Shouldn't need to do this in a thread, but it has to happen after
# the server is created, and extensions are initialized before that
# point
#------------------------------------------------------------------
def self.main
self._load_shared_maps
end

#------------------------------------------------------------------
# Handles updating from a client.
# client - Client instance (from Client.rb)
# Returns: Whether to stop check the message or not.
#------------------------------------------------------------------
def self.client_update(client)
case client.message
when /\AMEN\t(.+)/
mapid = (
#======================================================================
# Instance Maps extension.  This script allows the server to have maps
# that aren't shared between players, and in fact makes this the default.
# It requires a new table in the database that holds a list of maps that
# *should* be shared, which can be set up with the following SQL command:
#
# CREATE TABLE `shared_maps` (
# `map_id` int unsigned NOT NULL,
# PRIMARY KEY (`map_id`)
# ) ENGINE = InnoDB;
#
# Any map not on this list will be treated as an instance map.  The
# extension handles this completely transparently by intercepting and
# modifying MEN (Map Enter) messages before they can be processed by
# Client#check_game.  This means that no special scripts or client-side
# code of any kind is needed to enable instance maps.
#
# The shared_maps database table can be safely modified while the server
# is running.  Once it has been modified, the admin will need to send a
# "IMAP" message to the server, with no parameters.  This will cause the
# extension to reload its shared maps data.
#
# It's also possible to visit someone else's instance by sending a MEN
# message with the appropriate ID value, which can be calculated
# client-side from the map ID and user ID.
#
#======================================================================


module RMXOS

#------------------------------------------------------------------
# Passes the extension's main module to RMX-OS on the top
# level so it can handle this extension.
# Returns: Module of this extension for update.
#------------------------------------------------------------------
def self.load_current_extension
return InstanceMaps
end

end

#======================================================================
# module InstanceMaps
#======================================================================

module InstanceMaps

# extension version
VERSION = 1.0
# required RMX-OS version
RMXOS_VERSION = 2.0
# whether the server should update this extension in an individual thread or not
SERVER_THREAD = true
# the extension's name/identifier
IDENTIFIER = 'Instance Maps'

#------------------------------------------------------------------
# Initializes the extension (i.e. instantiation of classes).
#------------------------------------------------------------------
def self.initialize
# create mutex
@mutex = Mutex.new
end

#------------------------------------------------------------------
# Gets the local extension mutex.
#------------------------------------------------------------------
def self.mutex
return @mutex
end

#------------------------------------------------------------------
# Shouldn't need to do this in a thread, but it has to happen after
# the server is created, and extensions are initialized before that
# point
#------------------------------------------------------------------
def self.main
self._load_shared_maps
end

#------------------------------------------------------------------
# Handles updating from a client.
# client - Client instance (from Client.rb)
# Returns: Whether to stop check the message or not.
#------------------------------------------------------------------
def self.client_update(client)
case client.message
when /\AMEN\t(.+)/
mapid = ($1.to_i)
return false if mapid > 1000
is_shared = @sharedmaps[mapid]
unless is_shared
mapid += client.player.user_id * 1000
client.message = "MEN\t#{mapid}"
end
when /\AIMAP\Z/
self._load_shared_maps
return true
end
return false
end

def self._load_shared_maps
@sharedmaps = {}
sql = RMXOS::SQL.new(RMXOS.server.options)
dataset = sql.query('select map_id from shared_maps')
dataset.num_rows.times {
hash = dataset.fetch_hash
@sharedmaps[hash['map_id']] = true
}
end

end
.to_i)
return false if mapid > 1000
is_shared = @sharedmaps[mapid]
unless is_shared
mapid += client.player.user_id * 1000
client.message = "MEN\t#{mapid}"
end
when /\AIMAP\Z/
self._load_shared_maps
return true
end
return false
end

def self._load_shared_maps
@sharedmaps = {}
sql = RMXOS::SQL.new(RMXOS.server.options)
dataset = sql.query('select map_id from shared_maps')
dataset.num_rows.times {
hash = dataset.fetch_hash
@sharedmaps[hash['map_id']] = true
}
end

end


Any feedback is welcome, of course.

Edit: Fixed an error with recursive mutex locking.  Also added support for visiting someone else's instance.
14
RMXP Script Database / Re: [XP] RMX-OS
April 03, 2016, 05:19:45 am
Yes, in theory, assuming everyone remembers to use it every time and the escaping routine works perfectly, that is the case.

In practice, neither of those assumptions is valid.  People forget the escaping when concatenating a string into the query, and escaping routines are notoriously difficult to get right.  (Just look at how many different "mysql_escape_strings_for_real_we_swear_we_got_it_right_this_time" routines there are in PHP!)  This is why any developer with experience in database security will tell you it's not worth the risk: you should always use parameterized queries and never use escaping and concatenation instead.

But don't take my word for it; just ask on StackOverflow (or the more specialized security.stackexchange.com) if escaping is a valid substitute for parameters.  They'll say what I just said.  They might also point out that if you use parameters, the DBMS is able to cache the query plan, leading to improved performance on long-running processes such as servers.
15
RMXP Script Database / Re: [XP] RMX-OS
April 02, 2016, 09:32:37 pm
I just looked at SQL.rb in the server, and saw something worrisome: it's not set up for proper security.  It has a method for escaping strings--a bad idea which should never be done--and no support for parameterized queries, which is the right way to handle the problem that escaping strings is supposed to solve.  That means that the server's database architecture is essentially a SQL injection attack waiting to happen.

If I had an API specification for mysql_api.so I'd fix this myself, but since it's custom-built, I need to ask for Blizzard to update this to support parameterized queries.  Can you do that?
16
RMXP Script Database / Re: [XP] RMX-OS
April 01, 2016, 05:59:48 pm
Ack, my mistake.  I looked at the wrong thing.  Regardless, the current version is Ruby 2.2.

So this was something you had to build yourself?
17
RMXP Script Database / Re: [XP] RMX-OS
April 01, 2016, 02:13:20 pm
One other quick question: where does mysql_api.so come from?  It would be very nice to be able to run this on the latest version of Ruby instead of one that's 9 years old, but for that I need an updated mysql_api.so binary, and casual Googling doesn't actually turn up anything useful.
18
Thanks, Zexion!

Having it happen within events is infeasible without being able to change the event editor.  Basically what I need is a script command, a function that inputs an integer (ID of a Class in the database) and returns a newly-created party member, and oh-by-the-way ensures that everything will save and load correctly.
19
Yeah, I suppose $data_actors wouldn't get saved automatically, because it's part of the database.

Does such a script exist, that you know of?
20
Does anyone have a script that will let you create a new Actor from a Class, who's not predefined in the Database?  Anyone who's recruited new random party members in a Disgaea game will understand what I'm looking for and why it's useful.