Langage : Ruby
Posté le 13 juillet 2016
Télécharger | Reposter
# -*- coding: utf-8 -*- #============================================================================== # ** RME Database #------------------------------------------------------------------------------ # With : # Nuki #------------------------------------------------------------------------------ # Provide two customs databases #============================================================================== #============================================================================== # ** Object #------------------------------------------------------------------------------ # Add coersion stuff #============================================================================== class Object #-------------------------------------------------------------------------- # * identity #-------------------------------------------------------------------------- def nothing; self; end alias_method :noth, :nothing alias_method :to_poly, :nothing #-------------------------------------------------------------------------- # * Magic coersion #-------------------------------------------------------------------------- def db_cast_boolean return self if self.is_a?(TrueClass) || self.is_a?(FalseClass) return false unless self.respond_to?(:to_s) value = begin !!eval(self.to_s) rescue Exception => exc false end end alias_method :ptbo, :db_cast_boolean alias_method :magic_to_bool, :ptbo end #============================================================================== # ** String #------------------------------------------------------------------------------ # Coersion stuff #============================================================================== class String #-------------------------------------------------------------------------- # * Polymorphism cast #-------------------------------------------------------------------------- def to_poly begin eval(self) rescue Exception => exc nil end end #-------------------------------------------------------------------------- # * bool cast #-------------------------------------------------------------------------- def magic_to_bool !!to_poly end end #============================================================================== # ** Types #------------------------------------------------------------------------------ # Minimalist types #============================================================================== module Types #-------------------------------------------------------------------------- # * Singleton #-------------------------------------------------------------------------- class << self #-------------------------------------------------------------------------- # * Build a type #-------------------------------------------------------------------------- def make(type) return CommonDB::TYPES.find{|t|t.match(type)} if type.is_a?(Symbol) if type.is_a?(Array) return Types::Complex.new(:list, (make(type[1]))) end end #-------------------------------------------------------------------------- # * Infer a type #-------------------------------------------------------------------------- def inference(value) return :integer if value.is_a?(Fixnum) return :float if value.is_a?(Float) return :string if value.is_a?(String) return :boolean if value.is_a?(FalseClass) || value.is_a?(TrueClass) if value.is_a?(Array) v = value.compact return [:list, :poly] if v.length == 0 t = inference(v.first) return [:list, t] if v.all?{|x| inference(x) == t} return [:list, :poly] end return :poly end end #============================================================================== # ** Abstract #------------------------------------------------------------------------------ # Abstract type representation #============================================================================== class Abstract #-------------------------------------------------------------------------- # * Public instance variable #-------------------------------------------------------------------------- attr_accessor :coersion attr_accessor :name attr_accessor :names #-------------------------------------------------------------------------- # * Constructor #-------------------------------------------------------------------------- def initialize(name, names, coer) @name = name @names = names coersion = coer if coer.is_a?(Symbol) coersion = Proc.new {|x| x.send(coer)} end @coersion = coersion end #-------------------------------------------------------------------------- # * Produce coersion #-------------------------------------------------------------------------- def cast(x) self.coersion.call(x) end #-------------------------------------------------------------------------- # * Check type name #-------------------------------------------------------------------------- def match(label) return true if label.to_sym == @name.to_sym return @names.include?(label) end end #============================================================================== # ** Simple #------------------------------------------------------------------------------ # Simple type representation #============================================================================== class Simple < Abstract #-------------------------------------------------------------------------- # * Public instance variables #-------------------------------------------------------------------------- attr_accessor :is_rgss #-------------------------------------------------------------------------- # * Constructor #-------------------------------------------------------------------------- def initialize(name, names, coer, rgss = false) super(name, names, coer) @is_rgss = rgss end alias_method :rgss?, :is_rgss end #============================================================================== # ** Complex #------------------------------------------------------------------------------ # Complex type representation #============================================================================== class Complex < Abstract #-------------------------------------------------------------------------- # * Instances variables #-------------------------------------------------------------------------- attr_accessor :subtype #-------------------------------------------------------------------------- # * Constructor #-------------------------------------------------------------------------- def initialize(name, subtype) @subtype = subtype coersion = ->(subtype,x){x.collect{|y|subtype.cast(y)}} super(name, [], coersion.curry.call(@subtype)) end end end #============================================================================== # ** CommonDB #------------------------------------------------------------------------------ # Common Database utils #============================================================================== module CommonDB #-------------------------------------------------------------------------- # * Configuration #-------------------------------------------------------------------------- RGSS_PREFIX = "VXACE_" #-------------------------------------------------------------------------- # * Micro Structures #-------------------------------------------------------------------------- EmbedData = Struct.new(:name, :const, :container) #-------------------------------------------------------------------------- # * Types infos #-------------------------------------------------------------------------- TYPES = [ Types::Simple.new(:integer, [:int, :integer, :natural, :fixnum], :to_i), Types::Simple.new(:float, [:float, :double, :real, :numeric], :to_f), Types::Simple.new(:string, [:string, :text, :raw], :to_s), Types::Simple.new(:boolean, [:bool, :boolean, :switch], :magic_to_bool), Types::Simple.new(:poly, [:poly, :polymorphic, :script, :rgss], :to_poly), # Types spéciaux (issu du RGSS) Types::Simple.new(:actor, [:actor, :actors, :heroes, :people], :to_i, true), Types::Simple.new(:map, [:map, :maps, :game_map, :gamemap], :to_i, true), Types::Simple.new(:klass, [:klass, :actor_type, :classes, :klasses],:to_i, true), Types::Simple.new(:skill, [:kill, :skills, :jutsu], :to_i, true), Types::Simple.new(:item, [:item, :items, :usable_item], :to_i, true), Types::Simple.new(:weapon, [:weapon, :weapons], :to_i, true), Types::Simple.new(:armor, [:armor, :armors], :to_i, true), Types::Simple.new(:enemy, [:enemy, :enemies, :opposant], :to_i, true), Types::Simple.new(:troop, [:troop, :group, :troops], :to_i, true), Types::Simple.new(:state, [:state, :statement, :states], :to_i, true), Types::Simple.new(:animation, [:animation, :anim], :to_i, true), Types::Simple.new(:tileset, [:tileset, :tilesets, :tile, :tiles], :to_i, true), Types::Simple.new(:mapinfo, [:mapinfo, :mapinfos, :infomap], :to_i, true) ] #-------------------------------------------------------------------------- # * Embeded structs #-------------------------------------------------------------------------- RGSS_EMBEDABLE = [ EmbedData.new(:actor, RPG::Actor, load_data("Data/Actors.rvdata2")), EmbedData.new(:klass, RPG::Class, load_data("Data/Classes.rvdata2")), EmbedData.new(:skill, RPG::Skill, load_data("Data/Skills.rvdata2")), EmbedData.new(:item, RPG::Item, load_data("Data/Items.rvdata2")), EmbedData.new(:weapon, RPG::Weapon, load_data("Data/Weapons.rvdata2")), EmbedData.new(:armor, RPG::Armor, load_data("Data/Armors.rvdata2")), EmbedData.new(:enemy, RPG::Enemy, load_data("Data/Enemies.rvdata2")), EmbedData.new(:troop, RPG::Troop, load_data("Data/Troops.rvdata2")), EmbedData.new(:state, RPG::State, load_data("Data/States.rvdata2")), EmbedData.new(:animation, RPG::Animation, load_data("Data/Animations.rvdata2")), EmbedData.new(:tileset, RPG::Tileset, load_data("Data/Tilesets.rvdata2")), EmbedData.new(:mapinfo, RPG::MapInfo, load_data("Data/MapInfos.rvdata2")), ] RGSS_TYPES = [ :actor, :map, :klass, :item, :weapon, :armor, :enemy, :troop, :state, :animtation, :tileset, :mapinfo, :skills ] #-------------------------------------------------------------------------- # * Singleton #-------------------------------------------------------------------------- class << self #-------------------------------------------------------------------------- # * Get table path #-------------------------------------------------------------------------- def path "Database" end #-------------------------------------------------------------------------- # * Get a RGSS ressource #-------------------------------------------------------------------------- def rgss_access(data, id) return load_data(sprintf("Data/Map%03d.rvdata2", id)) if data == :map ctn = RGSS_EMBEDABLE.find{|d|d.name == data} raise(RuntimeError, "Invalid container") unless ctn ctn.container[id] end end #============================================================================== # ** Table #------------------------------------------------------------------------------ # Generic Table representation #============================================================================== class Table #-------------------------------------------------------------------------- # * Singleton #-------------------------------------------------------------------------- class << self #-------------------------------------------------------------------------- # * Public instance variable #-------------------------------------------------------------------------- attr_accessor :fields attr_accessor :classname attr_accessor :records attr_reader :primary_key alias :schema :fields #-------------------------------------------------------------------------- # * Inherit views #-------------------------------------------------------------------------- def inherit(klass) unless klass.respond_to?(:schema) raise(ArgumentError, "Class isn't a Table") end klass.schema.each do |field, type| if type.is_a?(Symbol) self.send(type, field) else self.send(type[0], type[1], field) end end define_primary_key (klass.primary_key) end #-------------------------------------------------------------------------- # * Insertion #-------------------------------------------------------------------------- def insert(*args); self.new(*args); end #-------------------------------------------------------------------------- # * Build a typed field #-------------------------------------------------------------------------- def handle_field(type, name) @records ||= Hash.new @classname ||= self.to_s.to_sym @fields ||= Hash.new @fields[name] = type self.instance_variable_set("@#{name}".to_sym, nil) if RGSS_TYPES.include?(type) accessor = Proc.new do instance_var = self.instance_variable_get("@#{name}".to_sym) CommonDB.rgss_access(type, instance_var) if instance_var end self.send(:define_method, name.to_sym, &accessor) else self.send(:attr_reader, name.to_sym) end self.send(:attr_writer, name.to_sym) return name end #-------------------------------------------------------------------------- # * Embed list #-------------------------------------------------------------------------- def list(subtype, name) return self.handle_field([:list, subtype], name) if subtype.is_a?(Symbol) return self.handle_field(subtype, name) end #-------------------------------------------------------------------------- # * Define primary key #-------------------------------------------------------------------------- def define_primary_key(key) if !@fields.has_key?(key) raise(ArgumentError, "Unknown field") elsif RGSS_TYPES.include?(@fields[key]) raise(ArgumentError, "RGSS fields couldnt be Primary Key") else @primary_key = key end end alias :pk :define_primary_key alias :define_pk :define_primary_key #-------------------------------------------------------------------------- # * Enumerable #-------------------------------------------------------------------------- def length; @records.length; end def [](prk); @records[prk]; end def each(&block); @records.each(&block); end alias :count :length alias :size :length alias :all :records include Enumerable #-------------------------------------------------------------------------- # * Construct types by field #-------------------------------------------------------------------------- TYPES.each do |type| self.send(:define_method, type.name, &->(x){handle_field(type.name, x)}) type.names.select{|u|u != type.name}.each do |name| self.send(:alias_method, name, type.name) end end end #-------------------------------------------------------------------------- # * Initialize a data #-------------------------------------------------------------------------- def initialize(*args) self.class.records ||= hash.new if args.length != self.class.fields.length msg = "#{self.class.classname}: #{args.length} donnés, #{self.class.fields.length} requis" raise(ArgumentError, msg) end arr_fields = self.class.fields.to_a (0...args.length).each do |i| current = args[i] name, typen = *arr_fields[i] type = Types.make(typen) current = eval(current) if type.is_a?(Types::Complex) && current.is_a?(String) value = type.cast(current) self.instance_variable_set("@#{name}".to_sym, value) index = self.send(self.class.primary_key) self.class.records[index] = self end end end end #============================================================================== # ** Static #------------------------------------------------------------------------------ # Static Database #============================================================================== module Static #-------------------------------------------------------------------------- # * Singleton #-------------------------------------------------------------------------- class << self #-------------------------------------------------------------------------- # * Public instance variables #-------------------------------------------------------------------------- attr_accessor :tables Static.tables ||= Hash.new #-------------------------------------------------------------------------- # * Easy table access #-------------------------------------------------------------------------- def method_missing(*args) name = args[0] return Static.tables[name] if Static.tables[name] super(*args) end #-------------------------------------------------------------------------- # * Get user tables #-------------------------------------------------------------------------- def user_tables Static.tables.select do |k, o| !(k.to_s =~ /^VXACE_/) end end end #============================================================================== # ** Table #------------------------------------------------------------------------------ # Static Table #============================================================================== class Table < CommonDB::Table #-------------------------------------------------------------------------- # * Singleton #-------------------------------------------------------------------------- class << self #-------------------------------------------------------------------------- # * Build a field from an instance variable #-------------------------------------------------------------------------- def dynamic_from_ivar(name, value) sym_name = name[1 .. -1].to_sym subtype = Types.inference(value) return handle_field(subtype, sym_name) if subtype.is_a?(Symbol) return list(subtype, sym_name) if subtype.is_a?(Array) && subtype.length == 2 return (poly sym_name) end #-------------------------------------------------------------------------- # * define primary key #-------------------------------------------------------------------------- def define_primary_key(key) super(key) Static.tables[self.classname] ||= self end alias :pk :define_primary_key alias :define_pk :define_primary_key end end # == Fin de Table == #-------------------------------------------------------------------------- # * Map original Database #-------------------------------------------------------------------------- CommonDB::RGSS_EMBEDABLE.select{|g|![:map,:mapinfo].include?(g.name)}.each do |rgss_struct| # mappingb const = rgss_struct.const datas = rgss_struct.container datas = datas.compact if datas.respond_to?(:compact) datas ||= [] prefix = CommonDB::RGSS_PREFIX name = "#{prefix}#{rgss_struct.name.upcase}".to_sym if datas.length > 0 elt = datas.max{|e| e.instance_variables.length} temp_class = Class.new(Static::Table) do @classname = name elt.instance_variables.each do |value| ivar = elt.instance_variable_get(value) dynamic_from_ivar(value, ivar) end define_pk :id end storage = Object.const_set(name, temp_class) # remplissage datas.each do |r| entries = Array.new storage.fields.each do |iv, t| val = r.instance_variable_get("@#{iv}") entries << val end storage.insert(*entries) end end end #-------------------------------------------------------------------------- # * Map case #-------------------------------------------------------------------------- rgss_mapinfo = RPG::MapInfo.new rgss_map = RPG::Map.new(100, 100) name = "#{CommonDB::RGSS_PREFIX}MAP".to_sym temp_class = Class.new(Static::Table) do @classname = name define_pk integer :id [rgss_mapinfo,rgss_map].each do |elt| elt.instance_variables.each do |value| ivar = elt.instance_variable_get(value) dynamic_from_ivar(value, ivar) end end end storage = Object.const_set(name, temp_class) # Fill mapinfos = CommonDB::RGSS_EMBEDABLE.find{|d|d.name == :mapinfo} mapinfos.container.each do |i, v| entries = [i] [v, load_data(sprintf("Data/Map%03d.rvdata2", i))].each do |r| r.instance_variables.each do |iv| entries << r.instance_variable_get(iv) end end storage.insert(*entries) end end #============================================================================== # ** Dynamic #------------------------------------------------------------------------------ # Dynamic DB #============================================================================== module Dynamic #-------------------------------------------------------------------------- # * Singleton #-------------------------------------------------------------------------- class << self #-------------------------------------------------------------------------- # * Public instance variables #-------------------------------------------------------------------------- attr_accessor :tables Dynamic.tables ||= Hash.new #-------------------------------------------------------------------------- # * Cast Table to Hash #-------------------------------------------------------------------------- def to_hash data = Hash.new Dynamic.tables.each do |name, value| data[name] = Hash.new value.all.each do |primary, instance| data[name][primary] = instance.to_array end end data end #-------------------------------------------------------------------------- # * Convienent Table access #-------------------------------------------------------------------------- def method_missing(*args) name = args[0] return Dynamic.tables[name] if Dynamic.tables[name] super(*args) end end #============================================================================== # ** Table #------------------------------------------------------------------------------ # Dynamic table #============================================================================== class Table < CommonDB::Table #-------------------------------------------------------------------------- # * Singleton #-------------------------------------------------------------------------- class << self #-------------------------------------------------------------------------- # * Erease a field #-------------------------------------------------------------------------- def delete(pkvalue) self.records.delete(pkvalue) end #-------------------------------------------------------------------------- # * Erease by a predicat #-------------------------------------------------------------------------- def delete_if(&block) self.records.delete_if(&block) end #-------------------------------------------------------------------------- # * Drop the table #-------------------------------------------------------------------------- def drop self.records = Hash.new end #-------------------------------------------------------------------------- # * Define primary key #-------------------------------------------------------------------------- def define_primary_key(key) super(key) Dynamic.tables[self.classname] ||= self end alias :pk :define_primary_key alias :define_pk :define_primary_key end #-------------------------------------------------------------------------- # * Cast to array #-------------------------------------------------------------------------- def to_array data = Array.new self.class.fields.each do |name, type| data << self.instance_variable_get("@#{name}".to_sym) end data end end end #============================================================================== # ** DataManager #------------------------------------------------------------------------------ # Save data #============================================================================== module DataManager #-------------------------------------------------------------------------- # * Singleton #-------------------------------------------------------------------------- class << self #-------------------------------------------------------------------------- # * Alias #-------------------------------------------------------------------------- alias :db_make_save_contents :make_save_contents alias :db_extract_save_contents :extract_save_contents alias :db_create_game_objects :create_game_objects #-------------------------------------------------------------------------- # * Init #-------------------------------------------------------------------------- def init_cst_db create_cst_views purge_database set_db_rvdata end #-------------------------------------------------------------------------- # * Get persistent layout #-------------------------------------------------------------------------- def set_db_rvdata t = load_data("Data/StaticDB.rvdata2") t.each do |table_sym, v| v.each do |fields| Object.const_get(table_sym).insert(*fields) end end end #-------------------------------------------------------------------------- # * Purge Database #-------------------------------------------------------------------------- def purge_database return unless $TEST Dir["#{CommonDB.path}/tables/*.csv"].each do |f| fname = File.basename(f, File.extname(f)).to_sym unless Static.user_tables.include?(fname) FileTools.move(f, "#{CommonDB.path}/backups/#{fname}_#{Time.now.to_i}.csv") end end Dir["#{CommonDB.path}/views/*.rvdata2"].each do |f| fname = File.basename(f, File.extname(f)).to_sym File.delete(f) unless Static.user_tables.include?(fname) end end #-------------------------------------------------------------------------- # * Create views #-------------------------------------------------------------------------- def create_cst_views return unless $TEST hashed = {} Static.user_tables.each do |table_sym, const| hashed[table_sym] = [] ref = CommonDB.path+"/views/#{table_sym.to_s}.rvdata2" schema = const.schema old_schema = (File.exists?(ref)) ? load_data(ref) : {} if schema != old_schema save_data(schema, ref) clone_table_to_backup(table_sym) end unless File.exists?(CommonDB.path+"/tables/#{table_sym.to_s}.csv") create_table_layout(table_sym, schema, const) else # retreive datas content = FileTools.read(CommonDB.path+"/tables/#{table_sym.to_s}.csv") content = content.split("\n")[1..-1] content.each do |line| fields = line.split(";") hashed[table_sym] << fields end end end save_data(hashed, "Data/StaticDB.rvdata2") end #-------------------------------------------------------------------------- # * Create table layout #-------------------------------------------------------------------------- def create_table_layout(t, schema, const) return unless $TEST fname = CommonDB.path+"/tables/#{t.to_s}.csv" contn = schema.keys.join(";") if const.count > 0 const.each do |pk, r| ll = schema.keys.collect {|mth| r.send(mth)} contn += "\n" + ll.join(";") end end FileTools.write(fname, contn) end #-------------------------------------------------------------------------- # * Create backup #-------------------------------------------------------------------------- def clone_table_to_backup(t) return unless $TEST fname = CommonDB.path+"/tables/#{t.to_s}.csv" bname = CommonDB.path+"/backups/#{t.to_s}_#{Time.now.to_i}.csv" return unless File.exists?(fname) FileTools.move(fname, bname) end #-------------------------------------------------------------------------- # * Create Game Objects #-------------------------------------------------------------------------- def create_game_objects db_create_game_objects Dynamic.tables.each do |k, t| t.drop end end #-------------------------------------------------------------------------- # * Ajout de sauvegarde de la base de données #-------------------------------------------------------------------------- def make_save_contents contents = db_make_save_contents contents[:database] = Dynamic.to_hash contents end #-------------------------------------------------------------------------- # * Ajout du chargement de la base de données #-------------------------------------------------------------------------- def extract_save_contents(contents) db_extract_save_contents(contents) contents[:database].each do |k, f| f.each do |key, a| Object.const_get(k).insert(*a) end end end end end #============================================================================== # ** Create Base #------------------------------------------------------------------------------ # Create folders #============================================================================== if $TEST path = CommonDB.path Dir.mkdir(path, 0777) unless Dir.exists?(path+"/") Dir.mkdir(path+"/views/", 0777) unless Dir.exists?(path+"/views/") Dir.mkdir(path+"/backups/", 0777) unless Dir.exists?(path+"/backups/") Dir.mkdir(path+"/tables/", 0777) unless Dir.exists?(path+"/tables/") end
x
Éditer le texte

Merci d'entrer le mot de passe que vous avez indiqué à la création du texte.

x
Télécharger le texte

Merci de choisir le format du fichier à télécharger.