rgss_db 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/COPYING.md +674 -0
  4. data/README.md +347 -0
  5. data/bin/rgss-db +4 -0
  6. data/bin/rgssdb +4 -0
  7. data/lib/rgss_db/app.rb +928 -0
  8. data/lib/rgss_db/controller/data_manager.rb +557 -0
  9. data/lib/rgss_db/model/data_file.rb +516 -0
  10. data/lib/rgss_db/model/data_file_factory.rb +94 -0
  11. data/lib/rgss_db/model/debug.rb +199 -0
  12. data/lib/rgss_db/model/errors.rb +17 -0
  13. data/lib/rgss_db/model/mixins/jsonable.rb +35 -0
  14. data/lib/rgss_db/model/mixins/jsonable_constructor.rb +40 -0
  15. data/lib/rgss_db/model/rpg_maker_data/vx/rgss/color.rb +72 -0
  16. data/lib/rgss_db/model/rpg_maker_data/vx/rgss/rect.rb +70 -0
  17. data/lib/rgss_db/model/rpg_maker_data/vx/rgss/table.rb +99 -0
  18. data/lib/rgss_db/model/rpg_maker_data/vx/rgss/tone.rb +72 -0
  19. data/lib/rgss_db/model/rpg_maker_data/vx/rgss.rb +11 -0
  20. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/actor.rb +44 -0
  21. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/animation.rb +31 -0
  22. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/animation_frame.rb +20 -0
  23. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/animation_timing.rb +23 -0
  24. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/area.rb +26 -0
  25. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/armor.rb +31 -0
  26. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/audio_file.rb +23 -0
  27. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/base_item.rb +25 -0
  28. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/bgm.rb +36 -0
  29. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/bgs.rb +36 -0
  30. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/class.rb +31 -0
  31. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/class_learning.rb +20 -0
  32. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/common_event.rb +25 -0
  33. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/enemy.rb +44 -0
  34. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/enemy_action.rb +29 -0
  35. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/enemy_drop_item.rb +23 -0
  36. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/event.rb +36 -0
  37. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/event_command.rb +19 -0
  38. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/event_page.rb +32 -0
  39. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/event_page_condition.rb +34 -0
  40. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/event_page_graphic.rb +25 -0
  41. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/item.rb +27 -0
  42. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/map.rb +47 -0
  43. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/map_info.rb +26 -0
  44. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/me.rb +27 -0
  45. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/move_command.rb +18 -0
  46. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/move_route.rb +20 -0
  47. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/se.rb +21 -0
  48. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/skill.rb +22 -0
  49. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/state.rb +47 -0
  50. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/system.rb +43 -0
  51. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/system_terms.rb +53 -0
  52. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/system_test_battler.rb +25 -0
  53. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/system_vehicle.rb +24 -0
  54. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/troop.rb +24 -0
  55. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/troop_member.rb +23 -0
  56. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/troop_page.rb +21 -0
  57. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/troop_page_condition.rb +33 -0
  58. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/usable_item.rb +87 -0
  59. data/lib/rgss_db/model/rpg_maker_data/vx/rpg/weapon.rb +31 -0
  60. data/lib/rgss_db/model/rpg_maker_data/vx/rpg.rb +59 -0
  61. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rgss/color.rb +72 -0
  62. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rgss/rect.rb +70 -0
  63. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rgss/table.rb +99 -0
  64. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rgss/tone.rb +72 -0
  65. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rgss.rb +11 -0
  66. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/actor.rb +27 -0
  67. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/animation.rb +31 -0
  68. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/animation_frame.rb +23 -0
  69. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/animation_timing.rb +26 -0
  70. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/armor.rb +20 -0
  71. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/audio_file.rb +23 -0
  72. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/base_item.rb +31 -0
  73. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/base_item_feature.rb +29 -0
  74. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/bgm.rb +43 -0
  75. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/bgs.rb +43 -0
  76. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/class.rb +37 -0
  77. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/class_learning.rb +24 -0
  78. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/common_event.rb +33 -0
  79. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/enemy.rb +27 -0
  80. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/enemy_action.rb +26 -0
  81. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/enemy_drop_item.rb +24 -0
  82. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/equip_item.rb +19 -0
  83. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/event.rb +36 -0
  84. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/event_command.rb +19 -0
  85. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/event_page.rb +35 -0
  86. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/event_page_condition.rb +40 -0
  87. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/event_page_graphic.rb +31 -0
  88. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/item.rb +25 -0
  89. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/map.rb +58 -0
  90. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/map_encounter.rb +23 -0
  91. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/map_info.rb +26 -0
  92. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/me.rb +27 -0
  93. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/move_command.rb +17 -0
  94. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/move_route.rb +19 -0
  95. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/se.rb +21 -0
  96. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/skill.rb +25 -0
  97. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/state.rb +34 -0
  98. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/system.rb +62 -0
  99. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/system_terms.rb +25 -0
  100. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/system_test_battler.rb +24 -0
  101. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/system_vehicle.rb +27 -0
  102. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/tileset.rb +26 -0
  103. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/troop.rb +24 -0
  104. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/troop_member.rb +25 -0
  105. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/troop_page.rb +24 -0
  106. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/troop_page_condition.rb +39 -0
  107. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/usable_item.rb +84 -0
  108. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/usable_item_damage.rb +56 -0
  109. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/usable_item_effect.rb +25 -0
  110. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg/weapon.rb +25 -0
  111. data/lib/rgss_db/model/rpg_maker_data/vx_ace/rpg.rb +66 -0
  112. data/lib/rgss_db/model/rpg_maker_data/xp/rgss/color.rb +72 -0
  113. data/lib/rgss_db/model/rpg_maker_data/xp/rgss/rect.rb +70 -0
  114. data/lib/rgss_db/model/rpg_maker_data/xp/rgss/table.rb +99 -0
  115. data/lib/rgss_db/model/rpg_maker_data/xp/rgss/tone.rb +72 -0
  116. data/lib/rgss_db/model/rpg_maker_data/xp/rgss.rb +11 -0
  117. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/actor.rb +44 -0
  118. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/animation.rb +28 -0
  119. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/animation_frame.rb +20 -0
  120. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/animation_timing.rb +24 -0
  121. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/armor.rb +37 -0
  122. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/audio_file.rb +23 -0
  123. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/class.rb +28 -0
  124. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/class_learning.rb +20 -0
  125. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/common_event.rb +25 -0
  126. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/enemy.rb +47 -0
  127. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/enemy_action.rb +28 -0
  128. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/event.rb +36 -0
  129. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/event_command.rb +19 -0
  130. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/event_page.rb +32 -0
  131. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/event_page_condition.rb +30 -0
  132. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/event_page_graphic.rb +27 -0
  133. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/item.rb +48 -0
  134. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/map.rb +39 -0
  135. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/map_info.rb +26 -0
  136. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/move_command.rb +18 -0
  137. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/move_route.rb +19 -0
  138. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/skill.rb +47 -0
  139. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/state.rb +51 -0
  140. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/system.rb +56 -0
  141. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/system_test_battler.rb +25 -0
  142. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/system_words.rb +39 -0
  143. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/tileset.rb +39 -0
  144. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/troop.rb +24 -0
  145. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/troop_member.rb +23 -0
  146. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/troop_page.rb +21 -0
  147. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/troop_page_condition.rb +32 -0
  148. data/lib/rgss_db/model/rpg_maker_data/xp/rpg/weapon.rb +38 -0
  149. data/lib/rgss_db/model/rpg_maker_data/xp/rpg.rb +52 -0
  150. data/lib/rgss_db/model/strings.rb +607 -0
  151. data/lib/rgss_db/model/utilities.rb +90 -0
  152. data/lib/rgss_db/version.rb +7 -0
  153. data/lib/rgss_db/view/app_cli.rb +449 -0
  154. data/lib/rgss_db.rb +41 -0
  155. data/sig/rgss_db.rbs +5221 -0
  156. metadata +496 -0
@@ -0,0 +1,557 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "psych"
5
+ require "fileutils"
6
+ require_relative "../model/errors"
7
+ require_relative "../model/data_file_factory"
8
+
9
+ module RgssDb
10
+ # Relative path within the working directory to store back ups
11
+ # @return [String]
12
+ RGSS_BACK_UP_RELATIVE_PATH = "./Back Ups"
13
+
14
+ # RPG Maker XP RGSS version symbol
15
+ # @return [Symbol]
16
+ RGSS_VERSION_XP = :rpg_maker_xp
17
+
18
+ # RPG Maker VX RGSS version symbol
19
+ # @return [Symbol]
20
+ RGSS_VERSION_VX = :rpg_maker_vx
21
+
22
+ # RPG Maker VX Ace RGSS version symbol
23
+ # @return [Symbol]
24
+ RGSS_VERSION_VX_ACE = :rpg_maker_vx_ace
25
+
26
+ # Binary file format type
27
+ # @return [Symbol]
28
+ RGSS_FORMAT_TYPE_BINARY = :binary
29
+
30
+ # JSON file format type
31
+ # @return [Symbol]
32
+ RGSS_FORMAT_TYPE_JSON = :json
33
+
34
+ # YAML file format type
35
+ # @return [Symbol]
36
+ RGSS_FORMAT_TYPE_YAML = :yaml
37
+
38
+ # JSON file format extension
39
+ # @return [String]
40
+ RGSS_FILE_EXT_JSON = ".json"
41
+
42
+ # Exported YAML data file extension
43
+ # @return [String]
44
+ RGSS_FILE_EXT_YAML = ".yml"
45
+
46
+ # RPG Maker XP binary data file extension
47
+ # @return [String]
48
+ RGSS_FILE_EXT_XP = ".rxdata"
49
+
50
+ # RPG Maker VX binary data file extension
51
+ # @return [String]
52
+ RGSS_FILE_EXT_VX = ".rvdata"
53
+
54
+ # RPG Maker VX Ace binary data file extension
55
+ # @return [String]
56
+ RGSS_FILE_EXT_VX_ACE = ".rvdata2"
57
+
58
+ # Hash of all extracted file extensions
59
+ #
60
+ # The type of external file is used as the key, the value is the file extension string
61
+ # @return [Hash<Symbol, String>]
62
+ RGSS_EXTRACTED_FILE_EXTENSIONS = {
63
+ RGSS_FORMAT_TYPE_JSON => RGSS_FILE_EXT_JSON,
64
+ RGSS_FORMAT_TYPE_YAML => RGSS_FILE_EXT_YAML
65
+ }.freeze
66
+
67
+ # Hash of all database file extensions for each RPG Maker (RGSS) version
68
+ #
69
+ # The RPG Maker version is used as the key, the value is the file extension string
70
+ #
71
+ # This hash is used to detect the RPG Maker database version based on the file extension
72
+ # @return [Hash<Symbol, String>]
73
+ RGSS_DB_FILE_EXTENSIONS = {
74
+ RGSS_VERSION_XP => RGSS_FILE_EXT_XP,
75
+ RGSS_VERSION_VX => RGSS_FILE_EXT_VX,
76
+ RGSS_VERSION_VX_ACE => RGSS_FILE_EXT_VX_ACE
77
+ }.freeze
78
+
79
+ # Hash that contains the appropiate database model (data classes) for each RPG Maker (RGSS) version
80
+ #
81
+ # The RPG Maker version is used as the key, the value is an array of file paths
82
+ # @return [Hash<Symbol, Array<String>>]
83
+ RGSS_DB_MODELS = {
84
+ RGSS_VERSION_XP => [
85
+ "../model/rpg_maker_data/xp/rgss",
86
+ "../model/rpg_maker_data/xp/rpg"
87
+ ],
88
+ RGSS_VERSION_VX => [
89
+ "../model/rpg_maker_data/vx/rgss",
90
+ "../model/rpg_maker_data/vx/rpg"
91
+ ],
92
+ RGSS_VERSION_VX_ACE => [
93
+ "../model/rpg_maker_data/vx_ace/rgss",
94
+ "../model/rpg_maker_data/vx_ace/rpg"
95
+ ]
96
+ }.freeze
97
+
98
+ # Hash of all supported database glob patterns files for each RPG Maker (RGSS) version
99
+ #
100
+ # The RPG Maker version is used as the key, the value is an array of glob patterns file names
101
+ # @return [Hash<Symbol, Array<String>>]
102
+ RGSS_DB_FILES = {
103
+ RGSS_VERSION_XP => [
104
+ DATA_FILE_ACTORS,
105
+ DATA_FILE_ANIMATIONS,
106
+ DATA_FILE_ARMORS,
107
+ DATA_FILE_CLASSES,
108
+ DATA_FILE_COMMON_EVENTS,
109
+ DATA_FILE_ENEMIES,
110
+ DATA_FILE_ITEMS,
111
+ DATA_FILE_MAPS,
112
+ DATA_FILE_MAP_INFOS,
113
+ DATA_FILE_SKILLS,
114
+ DATA_FILE_STATES,
115
+ DATA_FILE_SYSTEM,
116
+ DATA_FILE_TILESETS,
117
+ DATA_FILE_TROOPS,
118
+ DATA_FILE_WEAPONS
119
+ ],
120
+ RGSS_VERSION_VX => [
121
+ DATA_FILE_ACTORS,
122
+ DATA_FILE_ANIMATIONS,
123
+ DATA_FILE_AREAS,
124
+ DATA_FILE_ARMORS,
125
+ DATA_FILE_CLASSES,
126
+ DATA_FILE_COMMON_EVENTS,
127
+ DATA_FILE_ENEMIES,
128
+ DATA_FILE_ITEMS,
129
+ DATA_FILE_MAPS,
130
+ DATA_FILE_MAP_INFOS,
131
+ DATA_FILE_SKILLS,
132
+ DATA_FILE_STATES,
133
+ DATA_FILE_SYSTEM,
134
+ DATA_FILE_TROOPS,
135
+ DATA_FILE_WEAPONS
136
+ ],
137
+ RGSS_VERSION_VX_ACE => [
138
+ DATA_FILE_ACTORS,
139
+ DATA_FILE_ANIMATIONS,
140
+ DATA_FILE_ARMORS,
141
+ DATA_FILE_CLASSES,
142
+ DATA_FILE_COMMON_EVENTS,
143
+ DATA_FILE_ENEMIES,
144
+ DATA_FILE_ITEMS,
145
+ DATA_FILE_MAPS,
146
+ DATA_FILE_MAP_INFOS,
147
+ DATA_FILE_SKILLS,
148
+ DATA_FILE_STATES,
149
+ DATA_FILE_SYSTEM,
150
+ DATA_FILE_TILESETS,
151
+ DATA_FILE_TROOPS,
152
+ DATA_FILE_WEAPONS
153
+ ]
154
+ }.freeze
155
+
156
+ #
157
+ # Data manager class
158
+ #
159
+ class DataManager
160
+ # Data folder path
161
+ # @return [String]
162
+ attr_reader :path
163
+
164
+ # RGSS Version
165
+ #
166
+ # Returns ``nil`` if no version was detected
167
+ # @return [Symbol]
168
+ attr_reader :rgss_version
169
+
170
+ #
171
+ # Creates a data manager instance
172
+ #
173
+ # @param data_folder [String] RPG Maker database folder
174
+ #
175
+ def initialize(data_folder)
176
+ @path = File.expand_path(data_folder)
177
+ database_detect_version
178
+ database_load_model
179
+ end
180
+
181
+ #
182
+ # Checks if a valid RPG Maker version was detected or not
183
+ #
184
+ # @return [Boolean]
185
+ #
186
+ def version?
187
+ !@rgss_version.nil?
188
+ end
189
+
190
+ #
191
+ # Checks if the current RPG Maker version detected matches the given one
192
+ #
193
+ # The argument is automatically casted into a Symbol instance
194
+ #
195
+ # @param version [Symbol] RPG Maker version
196
+ #
197
+ # @return [Boolean]
198
+ #
199
+ def version_is?(version)
200
+ @rgss_version == version.to_s.to_sym
201
+ end
202
+
203
+ #
204
+ # Returns ``true`` if ``file_path`` is a RPG Maker binary data file
205
+ #
206
+ # Returns ``false`` if ``file_path`` is not a binary data file
207
+ #
208
+ # Returns ``false`` if the RGSS version could not be determined
209
+ #
210
+ # @param file_path [String] File path
211
+ #
212
+ # @return [Boolean]
213
+ #
214
+ def database_file?(file_path)
215
+ File.extname(file_path).casecmp?(database_file_extension)
216
+ end
217
+
218
+ #
219
+ # Returns ``true`` if the file path is a JSON file
220
+ #
221
+ # @param file_path [String] File path
222
+ #
223
+ # @return [Boolean]
224
+ #
225
+ def json_file?(file_path)
226
+ File.extname(file_path).casecmp?(RGSS_FILE_EXT_JSON)
227
+ end
228
+
229
+ #
230
+ # Returns ``true`` if the file path is a YAML file
231
+ #
232
+ # @param file_path [String] File path
233
+ #
234
+ # @return [Boolean]
235
+ #
236
+ def yaml_file?(file_path)
237
+ File.extname(file_path).casecmp?(RGSS_FILE_EXT_YAML)
238
+ end
239
+
240
+ #
241
+ # Loads a single database data file based on the given type
242
+ #
243
+ # @param [String] database_file_type
244
+ #
245
+ # @return [DataFile]
246
+ #
247
+ def load_database_file(database_file_type)
248
+ # Formats the database file path
249
+ database_file_path = File.join(@path, database_file_type + database_file_extension)
250
+
251
+ # Creates a data file instance for this database file
252
+ DataFileFactory.create_data_file(database_file_path, load_file(database_file_path))
253
+ end
254
+
255
+ #
256
+ # Gets a list of ``DataFile`` instances based on the current path and detected version
257
+ #
258
+ # This method should be used to read all RPG Maker binary data files
259
+ #
260
+ # Returns an empty array if the operation is not possible
261
+ #
262
+ # @return [Array<DataFile>]
263
+ #
264
+ def load_database_files
265
+ return [] unless version?
266
+
267
+ # Formats the database file names adding the proper file extension
268
+ database_files = database_file_names.map { |file_name| file_name + database_file_extension }
269
+
270
+ # Scans the data folder for files
271
+ detected_files = Dir.glob(database_files, File::FNM_CASEFOLD, base: @path)
272
+
273
+ # Creates an array of data file instances with the detected database files
274
+ detected_files.map do |data_file|
275
+ data_file_path = File.expand_path(data_file, @path)
276
+ DataFileFactory.create_data_file(data_file_path, load_file(data_file_path))
277
+ end
278
+ end
279
+
280
+ #
281
+ # Gets a list of ``DataFile`` instances based on the given directory
282
+ #
283
+ # All extracted files should be inside the given directory
284
+ #
285
+ # This method reads extracted files and returns it as data files (RPG maker data)
286
+ #
287
+ # Returns an empty array if the operation is not possible
288
+ #
289
+ # @param app_directory [String] Application working directory
290
+ #
291
+ # @return [Array<DataFile>]
292
+ #
293
+ def load_extracted_files(app_directory)
294
+ return [] unless version?
295
+
296
+ # Determines the application working folder directory
297
+ base_path = File.expand_path(app_directory, @path)
298
+
299
+ # Creates a glob pattern to detect extracted data files using file extensions
300
+ file_extensions_glob = "{#{RGSS_EXTRACTED_FILE_EXTENSIONS.values.join(",")}}"
301
+
302
+ # Formats all supported database files adding the file extensions glob pattern
303
+ extracted_files = database_file_names.map do |file_name|
304
+ file_name + file_extensions_glob
305
+ end
306
+
307
+ # Scans the extracted folder for complete extracted files
308
+ detected_files = Dir.glob(extracted_files, File::FNM_CASEFOLD, base: base_path)
309
+
310
+ # Creates an array of data file instances with the detected database files
311
+ detected_files.map do |data_file|
312
+ data_file_path = File.expand_path(data_file, base_path)
313
+ DataFileFactory.create_data_file(data_file_path, load_file(data_file_path))
314
+ end
315
+ end
316
+
317
+ #
318
+ # Gets a list of ``DataFile`` instances based on the given directory
319
+ #
320
+ # All custom extracted files should be inside the given directory
321
+ #
322
+ # This method reads extracted files and returns it as data files (RPG maker data)
323
+ #
324
+ # Returns an empty array if the operation is not possible
325
+ #
326
+ # @param app_directory [String] Application working directory
327
+ #
328
+ # @return [Array<DataFile>]
329
+ #
330
+ def load_extracted_files_custom(app_directory)
331
+ return [] unless version?
332
+
333
+ # Determines the application working folder directory
334
+ base_path = File.expand_path(app_directory, @path)
335
+
336
+ # Creates a glob pattern to detect extracted data files using file extensions
337
+ file_extensions_glob = "{#{RGSS_EXTRACTED_FILE_EXTENSIONS.values.join(",")}}"
338
+
339
+ # Formats all supported database files adding the file extensions glob pattern
340
+ extracted_files = database_file_names.map do |file_name|
341
+ file_name + DATA_FILE_CUSTOM_LABEL + file_extensions_glob
342
+ end
343
+
344
+ # Scans the extracted folder for complete extracted files
345
+ detected_files = Dir.glob(extracted_files, File::FNM_CASEFOLD, base: base_path)
346
+
347
+ # Creates an array of data file instances with the detected files
348
+ detected_files.map do |data_file|
349
+ data_file_path = File.expand_path(data_file, base_path)
350
+ DataFileFactory.create_data_file(data_file_path, load_file(data_file_path))
351
+ end
352
+ end
353
+
354
+ #
355
+ # Saves the given data file instance
356
+ #
357
+ # @param data_file [DataFile] Data file instance
358
+ # @param app_directory [String] Application working directory
359
+ # @param output_format_type [String] Output file format type
360
+ #
361
+ # @raise [StandardError] RPG Maker version is not valid
362
+ #
363
+ def save_data_file(data_file, app_directory, output_format_type)
364
+ raise "cannot save data file because rpg maker version is unknown: #{@rgss_version}" unless version?
365
+
366
+ data_file_path = File.join(
367
+ File.expand_path(app_directory, @path),
368
+ data_file.serialize_file_name + determine_file_extension(output_format_type)
369
+ )
370
+ save_file(data_file_path, data_file.serialize)
371
+ end
372
+
373
+ #
374
+ # Saves a back up of the given file
375
+ #
376
+ # If ``file_path`` is a path, the file's base name is auto. extracted
377
+ #
378
+ # If the database file does not exist back up creation is skipped
379
+ #
380
+ # @param [String] file_path File path
381
+ # @param [String] app_directory Application working directory
382
+ #
383
+ # @raise [StandardError] RPG Maker version is not valid
384
+ #
385
+ def save_database_back_up(file_path, app_directory)
386
+ raise "cannot save file backup because rpg maker version is unknown: #{@rgss_version}" unless version?
387
+
388
+ # Gets the file's base name
389
+ database_file = File.basename(file_path, ".*")
390
+
391
+ # Determines the absolute path to the (possible) database file
392
+ database_file_path = File.join(@path, database_file + database_file_extension)
393
+
394
+ # Creates a back up file if the database file exists
395
+ save_back_up(database_file_path, app_directory) if File.file?(database_file_path)
396
+ end
397
+
398
+ private
399
+
400
+ #
401
+ # Detects the RGSS engine version on the current opened data folder
402
+ #
403
+ def database_detect_version
404
+ # Gets all supported RPG Maker data file extensions
405
+ file_extensions = RGSS_DB_FILE_EXTENSIONS.values
406
+
407
+ # Gets all files that matches any data file extension (glob pattern)
408
+ data_files = Dir.glob("*{#{file_extensions.join(",")}}", File::FNM_CASEFOLD, base: @path)
409
+
410
+ # All data files within the data folder must be of the same type (aka the same RGSS version)
411
+ file_extension = file_extensions.find do |file_ext|
412
+ !data_files.empty? && data_files.all? { |data_file| File.extname(data_file).casecmp?(file_ext) }
413
+ end
414
+ @rgss_version = RGSS_DB_FILE_EXTENSIONS.key(file_extension)
415
+
416
+ # Freeze attributes to avoid modifications
417
+ @path.freeze
418
+ @rgss_version.freeze
419
+ end
420
+
421
+ #
422
+ # Loads the appropriate RPG Maker database classes based on the detected RPG Maker version
423
+ #
424
+ # Only one RPG Maker version should be loaded at a time to avoid data corruption
425
+ #
426
+ def database_load_model
427
+ models = RGSS_DB_MODELS[@rgss_version]
428
+ return if models.nil?
429
+
430
+ models.each { |model| require_relative model }
431
+ end
432
+
433
+ #
434
+ # Gets the appropiate file extension based on the detected RGSS version
435
+ #
436
+ # Returns ``nil`` if the RGSS version is invalid
437
+ #
438
+ # @return [String]
439
+ #
440
+ def database_file_extension
441
+ RGSS_DB_FILE_EXTENSIONS[@rgss_version]
442
+ end
443
+
444
+ #
445
+ # Gets a list of all supported database file names based on the detected RGSS version
446
+ #
447
+ # The list of file names has glob patterns
448
+ #
449
+ # Returns ``nil`` if the RGSS version is invalid
450
+ #
451
+ # @return [Array<String>]
452
+ #
453
+ def database_file_names
454
+ RGSS_DB_FILES[@rgss_version]
455
+ end
456
+
457
+ #
458
+ # Determines the file extension based on the file format type
459
+ #
460
+ # Returns ``nil`` if the format type is unknown
461
+ #
462
+ # @param format_type [Symbol]
463
+ #
464
+ # @return [String]
465
+ #
466
+ def determine_file_extension(format_type)
467
+ case format_type
468
+ when RGSS_FORMAT_TYPE_BINARY
469
+ database_file_extension
470
+ when RGSS_FORMAT_TYPE_JSON
471
+ RGSS_FILE_EXT_JSON
472
+ when RGSS_FORMAT_TYPE_YAML
473
+ RGSS_FILE_EXT_YAML
474
+ end
475
+ end
476
+
477
+ #
478
+ # Loads the given file contents
479
+ #
480
+ # Returns ``nil`` if the operation is not possible
481
+ #
482
+ # @param file_path [String] File entry
483
+ #
484
+ # @return [Object]
485
+ #
486
+ def load_file(file_path)
487
+ if database_file?(file_path)
488
+ file_contents = File.read(file_path, mode: "rb")
489
+ Marshal.load(file_contents)
490
+ elsif json_file?(file_path)
491
+ file_contents = File.read(file_path, mode: "r")
492
+ JSON.parse(file_contents, create_additions: true)
493
+ elsif yaml_file?(file_path)
494
+ file_contents = File.read(file_path, mode: "r")
495
+ Psych.unsafe_load(file_contents)
496
+ end
497
+ end
498
+
499
+ #
500
+ # Saves the data file instance
501
+ #
502
+ # The file path will be created if it does not exists
503
+ #
504
+ # @param file_path [String] File path
505
+ # @param object [Object] object
506
+ #
507
+ def save_file(file_path, object)
508
+ # Creates the directory if it does not exists
509
+ FileUtils.mkdir_p(File.dirname(file_path))
510
+
511
+ # Perform the write operation
512
+ if database_file?(file_path)
513
+ File.open(file_path, "wb") do |file|
514
+ file << Marshal.dump(object)
515
+ end
516
+ elsif json_file?(file_path)
517
+ File.open(file_path, "w") do |file|
518
+ file << JSON.pretty_generate(object)
519
+ end
520
+ elsif yaml_file?(file_path)
521
+ File.open(file_path, "w") do |file|
522
+ file << Psych.dump(object)
523
+ end
524
+ end
525
+ end
526
+
527
+ #
528
+ # Saves a back up of the given file
529
+ #
530
+ # @param file_path [String] File path
531
+ # @param app_directory [String] Application working directory
532
+ #
533
+ # @raise [StandardError] File path does not exists
534
+ #
535
+ def save_back_up(file_path, app_directory)
536
+ # Determine back up paths
537
+ dest_folder = File.join(File.expand_path(app_directory, @path), RGSS_BACK_UP_RELATIVE_PATH)
538
+ dest_file_name = "#{File.basename(file_path)} - #{current_date}.bak"
539
+ dest_path = File.join(dest_folder, dest_file_name)
540
+
541
+ # Creates (recursively) the back ups folder if it does not exists
542
+ FileUtils.mkdir_p(dest_folder) unless File.directory?(dest_folder)
543
+
544
+ # Creates a copy of the file (throws an error if it does not exists)
545
+ FileUtils.copy_file(file_path, dest_path)
546
+ end
547
+
548
+ #
549
+ # Gets the current date and time as a string
550
+ #
551
+ # @return [String]
552
+ #
553
+ def current_date
554
+ Time.now.strftime("%Y.%m.%d - %H.%M.%S")
555
+ end
556
+ end
557
+ end