1 /*
2  * This file is part of EasyRPG Player.
3  *
4  * EasyRPG Player is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * EasyRPG Player is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 // Headers
19 #include <cstdlib>
20 #include "main_data.h"
21 #include "filefinder.h"
22 #include "filefinder_rtp.h"
23 #include "filesystem.h"
24 #include "game_system.h"
25 #include "game_actors.h"
26 #include "game_party.h"
27 #include "game_enemyparty.h"
28 #include "game_ineluki.h"
29 #include "game_player.h"
30 #include "game_screen.h"
31 #include "game_pictures.h"
32 #include "game_map.h"
33 #include "game_variables.h"
34 #include "game_switches.h"
35 #include "game_targets.h"
36 #include "game_quit.h"
37 #include "font.h"
38 #include "player.h"
39 #include "system.h"
40 #include "output.h"
41 
42 #ifndef _WIN32
43 #  include <unistd.h>
44 #endif
45 #if defined(USE_SDL) && defined(__ANDROID__)
46 #  include <jni.h>
47 #  include <SDL_system.h>
48 #elif defined(_3DS)
49 #  include <3ds.h>
50 #  include <cstdio>
51 #elif defined(PSP2)
52 #  include <cstdio>
53 #  include <psp2/io/stat.h>
54 #elif defined(__APPLE__) && TARGET_OS_OSX
55 #  include <sys/syslimits.h>
56 #  include "platform/macos/utils.h"
57 #endif
58 
59 // Global variables.
60 std::string project_path;
61 
62 namespace Main_Data {
63 	// Dynamic Game lcf::Data
64 	std::unique_ptr<Game_System> game_system;
65 	std::unique_ptr<Game_Switches> game_switches;
66 	std::unique_ptr<Game_Variables> game_variables;
67 	std::unique_ptr<Game_Screen> game_screen;
68 	std::unique_ptr<Game_Pictures> game_pictures;
69 	std::unique_ptr<Game_Actors> game_actors;
70 	std::unique_ptr<Game_Player> game_player;
71 	std::unique_ptr<Game_Party> game_party;
72 	std::unique_ptr<Game_EnemyParty> game_enemyparty;
73 	std::unique_ptr<Game_Targets> game_targets;
74 	std::unique_ptr<Game_Quit> game_quit;
75 	std::unique_ptr<Game_Ineluki> game_ineluki;
76 	std::unique_ptr<FileFinder_RTP> filefinder_rtp;
77 }
78 
Init()79 void Main_Data::Init() {
80 	if (project_path.empty()) {
81 		project_path =
82 			getenv("RPG_TEST_GAME_PATH") ? getenv("RPG_TEST_GAME_PATH") :
83 			getenv("RPG_GAME_PATH") ? getenv("RPG_GAME_PATH") :
84 			"";
85 
86 		if (project_path.empty()) {
87 			// first set to current directory for all platforms
88 			project_path = "";
89 
90 #if defined(GEKKO) || defined(__SWITCH__) || defined(__MORPHOS__) || defined(__amigaos4__) || defined(__AROS__)
91 			// Working directory not correctly handled
92 			char working_dir[256];
93 			getcwd(working_dir, 255);
94 			project_path = std::string(working_dir);
95 #elif defined(PSP2)
96 			// Check if app0 filesystem contains the title id reference file
97 			FILE* f = fopen("app0:/titleid.txt","r");
98 			if (f == NULL)
99 				project_path = "ux0:/data/easyrpg-player";
100 			else {
101 				char titleID[10];
102 				char psp2_dir[256];
103 				fread(titleID, 1, 9, f);
104 				titleID[9] = 0;
105 				sprintf(psp2_dir, "ux0:/data/%s",titleID);
106 				fclose(f);
107 				project_path = "app0:";
108 				// Creating saves dir if it doesn't exist
109 				sceIoMkdir(psp2_dir, 0777);
110 				auto savefs = FileFinder::Root().Create(psp2_dir);
111 				if (!savefs) {
112 					Output::Error("PSP2: Invalid save path {}", psp2_dir);
113 				}
114 				FileFinder::SetSaveFilesystem(savefs);
115 			}
116 #elif defined(_3DS)
117 			// Check if romFs has some files inside or not
118 			FILE* testfile = fopen("romfs:/RPG_RT.lmt","r");
119 			if (testfile != NULL) {
120 				Output::Debug("Detected a project on romFs filesystem...");
121 				fclose(testfile);
122 				project_path = "romfs:";
123 
124 				if (!Player::is_3dsx) {
125 					// Create savepath for CIA - unique for any ID
126 
127 					// Generating save_path
128 					u64 titleID;
129 					APT_GetProgramID(&titleID);
130 					char mainDir[64];
131 					sprintf(mainDir,"sdmc:/easyrpg-player/%016llX",titleID);
132 
133 					// Creating dirs if they don't exist
134 					FS_Archive archive;
135 					FSUSER_OpenArchive(&archive, ARCHIVE_SDMC, {PATH_EMPTY, 1, (u8*)""});
136 					FS_Path filePath=fsMakePath(PATH_ASCII, "/easyrpg-player");
137 					FSUSER_CreateDirectory(archive,filePath, FS_ATTRIBUTE_DIRECTORY);
138 					FS_Path filePath2=fsMakePath(PATH_ASCII, &mainDir[5]);
139 					FSUSER_CreateDirectory(archive,filePath2, FS_ATTRIBUTE_DIRECTORY);
140 					FSUSER_CloseArchive(archive);
141 
142 					auto savefs = FileFinder::Root().Create(mainDir);
143 					if (!savefs) {
144 						Output::Error("3DS: Invalid save path {}", mainDir);
145 					}
146 					FileFinder::SetSaveFilesystem(savefs);
147 				}
148 			} else if (!Player::is_3dsx) {
149 				// No RomFS -> load games from hardcoded path
150 				project_path = "sdmc:/3ds/easyrpg-player";
151 			}
152 #elif defined(__APPLE__) && TARGET_OS_OSX
153 			// Apple Finder does not set the working directory
154 			// It points to HOME instead. When it is HOME change it to
155 			// the application directory instead
156 
157 			char* home = getenv("HOME");
158 			char current_dir[PATH_MAX] = { 0 };
159 			getcwd(current_dir, sizeof(current_dir));
160 			if (strcmp(current_dir, "/") == 0 || strcmp(current_dir, home) == 0) {
161 				project_path = MacOSUtils::GetBundleDir();
162 			}
163 #endif
164 		}
165 	}
166 }
167 
168 
Cleanup()169 void Main_Data::Cleanup() {
170 	Game_Map::Quit();
171 
172 	game_switches.reset();
173 	game_screen.reset();
174 	game_pictures.reset();
175 	game_player.reset();
176 	game_party.reset();
177 	game_enemyparty.reset();
178 	game_actors.reset();
179 	game_targets.reset();
180 	game_quit.reset();
181 	game_system.reset();
182 	game_ineluki.reset();
183 }
184 
GetDefaultProjectPath()185 const std::string& Main_Data::GetDefaultProjectPath() {
186 	return project_path;
187 }
188