rgss_db 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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