the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "JavaMath.h"
3#include "BasicTypeContainers.h"
4#if 0
5// 4J - not required anymore
6#include "Matcher.h"
7#endif
8#include "ProgressListener.h"
9#include "net.minecraft.world.level.chunk.storage.h"
10#include "net.minecraft.world.level.chunk.h"
11#include "LevelSummary.h"
12#include "McRegionLevelStorage.h"
13#include "File.h"
14#include "LevelData.h"
15#include "McRegionLevelStorageSource.h"
16
17#include "ConsoleSaveFileIO.h"
18
19#if 0
20// 4J - not required anymore
21// These were Pattern class objects, using the c++0x regex class instead
22const std::tr1::wregex McRegionLevelStorageSource::FolderFilter::chunkFolderPattern = std::tr1::wregex(L"[0-9a-z]|([0-9a-z][0-9a-z])");
23const std::tr1::wregex McRegionLevelStorageSource::ChunkFilter::chunkFilePattern = std::tr1::wregex(L"c\\.(-?[0-9a-z]+)\\.(-?[0-9a-z]+)\\.dat");
24#endif
25
26McRegionLevelStorageSource::McRegionLevelStorageSource(File dir) : DirectoryLevelStorageSource(dir)
27{
28}
29
30wstring McRegionLevelStorageSource::getName()
31{
32 return L"Scaevolus' McRegion";
33}
34
35vector<LevelSummary *> *McRegionLevelStorageSource::getLevelList()
36{
37 // 4J Stu - We don't need to do directory lookups with the xbox save files
38 vector<LevelSummary *> *levels = new vector<LevelSummary *>;
39#if 0
40 vector<File *> *subFolders = baseDir.listFiles();
41 File *file;
42 AUTO_VAR(itEnd, subFolders->end());
43 for (AUTO_VAR(it, subFolders->begin()); it != itEnd; it++)
44 {
45 file = *it; //subFolders->at(i);
46
47 if (file->isDirectory())
48 {
49 continue;
50 }
51
52 wstring levelId = file->getName();
53
54 LevelData *levelData = getDataTagFor(levelId);
55 if (levelData != NULL)
56 {
57 bool requiresConversion = levelData->getVersion() != McRegionLevelStorage::MCREGION_VERSION_ID;
58 wstring levelName = levelData->getLevelName();
59
60 if (levelName.empty()) // 4J Jev TODO: levelName can't be NULL? if (levelName == NULL || isEmpty(levelName))
61 {
62 levelName = levelId;
63 }
64 // long size = getLevelSize(folder);
65 long size = 0;
66 levels->push_back(new LevelSummary(levelId, levelName, levelData->getLastPlayed(), size, requiresConversion, levelData->isHardcore()));
67 }
68 }
69#endif
70 return levels;
71}
72
73void McRegionLevelStorageSource::clearAll()
74{
75}
76
77shared_ptr<LevelStorage> McRegionLevelStorageSource::selectLevel(ConsoleSaveFile *saveFile, const wstring& levelId, bool createPlayerDir)
78{
79 // return new LevelStorageProfilerDecorator(new McRegionLevelStorage(baseDir, levelId, createPlayerDir));
80 return shared_ptr<LevelStorage>(new McRegionLevelStorage(saveFile, baseDir, levelId, createPlayerDir));
81}
82
83bool McRegionLevelStorageSource::isConvertible(ConsoleSaveFile *saveFile, const wstring& levelId)
84{
85 // check if there is old file format level data
86 LevelData *levelData = getDataTagFor(saveFile, levelId);
87 if (levelData == NULL || levelData->getVersion() != 0)
88 {
89 delete levelData;
90 return false;
91 }
92 delete levelData;
93
94 return true;
95}
96
97bool McRegionLevelStorageSource::requiresConversion(ConsoleSaveFile *saveFile, const wstring& levelId)
98{
99 LevelData *levelData = getDataTagFor(saveFile, levelId);
100 if (levelData == NULL || levelData->getVersion() != 0)
101 {
102 delete levelData;
103 return false;
104 }
105 delete levelData;
106
107 return true;
108}
109
110bool McRegionLevelStorageSource::convertLevel(ConsoleSaveFile *saveFile, const wstring& levelId, ProgressListener *progress)
111{
112 assert(false);
113 // I removed this while updating the saves to use the single save file
114 // Will we ever use this convertLevel function anyway? The main issue is the check
115 // for the hellFolder.exists() which would require a slight change to the way our
116 // save files are structured
117#if 0
118 progress->progressStagePercentage(0);
119
120 vector<ChunkFile *> *normalRegions = new vector<ChunkFile *>;
121 vector<File *> *normalBaseFolders = new vector<File *>;
122 vector<ChunkFile *> *netherRegions = new vector<ChunkFile *>;
123 vector<File *> *netherBaseFolders = new vector<File *>;
124 ArrayList<ChunkFile> enderRegions = new ArrayList<ChunkFile>();
125 ArrayList<File> enderBaseFolders = new ArrayList<File>();
126
127 //File baseFolder = File(baseDir, levelId);
128 //File netherFolder = File(baseFolder, LevelStorage::HELL_FOLDER);
129 //File enderFolder = new File(baseFolder, LevelStorage.ENDER_FOLDER);
130 ConsoleSaveFile saveFile = ConsoleSaveFile( levelId );
131
132 // System.out.println("Scanning folders..."); 4J Jev, TODO how do we println ?
133
134 // find normal world
135 addRegions(baseFolder, normalRegions, normalBaseFolders);
136
137 // find hell world
138 if (netherFolder.exists())
139 {
140 addRegions(netherFolder, netherRegions, netherBaseFolders);
141 }
142 if (enderFolder.exists())
143 {
144 addRegions(enderFolder, enderRegions, enderBaseFolders);
145 }
146
147 int totalCount = normalRegions->size() + netherRegions->size() + enderRegions.size() + normalBaseFolders->size() + netherBaseFolders->size() + enderBaseFolders.size();
148
149 // System.out.println("Total conversion count is " + totalCount); 4J Jev, TODO
150
151 // convert normal world
152 convertRegions(baseFolder, normalRegions, 0, totalCount, progress);
153 // convert hell world
154 convertRegions(netherFolder, netherRegions, normalRegions->size(), totalCount, progress);
155 // convert hell world
156 convertRegions(enderFolder, enderRegions, normalRegions.size() + netherRegions.size(), totalCount, progress);
157
158 LevelData *levelData = getDataTagFor(levelId);
159 levelData->setVersion(McRegionLevelStorage::MCREGION_VERSION_ID);
160
161 LevelStorage *levelStorage = selectLevel(levelId, false);
162 levelStorage->saveLevelData(levelData);
163
164 // erase old files
165 eraseFolders(normalBaseFolders, normalRegions->size() + netherRegions->size(), totalCount, progress);
166 if (netherFolder.exists())
167 {
168 eraseFolders(netherBaseFolders, normalRegions->size() + netherRegions->size() + normalBaseFolders->size(), totalCount, progress);
169 }
170#endif
171 return true;
172}
173
174#if 0
175// 4J - not required anymore
176void McRegionLevelStorageSource::addRegions(File &baseFolder, vector<ChunkFile *> *dest, vector<File *> *firstLevelFolders)
177{
178 FolderFilter folderFilter;
179 ChunkFilter chunkFilter;
180
181 File *folder1;
182 vector<File *> *folderLevel1 = baseFolder.listFiles((FileFilter *) &folderFilter);
183 AUTO_VAR(itEnd, folderLevel1->end());
184 for (AUTO_VAR(it, folderLevel1->begin()); it != itEnd; it++)
185 {
186 folder1 = *it; //folderLevel1->at(i1);
187
188 // keep this for the clean-up process later on
189 firstLevelFolders->push_back(folder1);
190
191 File *folder2;
192 vector<File *> *folderLevel2 = folder1->listFiles(&folderFilter);
193 AUTO_VAR(itEnd2, folderLevel2->end());
194 for (AUTO_VAR(it2, folderLevel2->begin()); it2 != itEnd; it2++)
195 {
196 folder2 = *it2; //folderLevel2->at(i2);
197
198 vector<File *> *chunkFiles = folder2->listFiles((FileFilter *) &chunkFilter);
199
200 File *chunk;
201 AUTO_VAR(itEndFile, chunkFiles->end());
202 for (AUTO_VAR(itFile, chunkFiles->begin()); itFile != itEndFile; itFile++)
203 {
204 chunk = *itFile; //chunkFiles->at(i3);
205
206 dest->push_back(new ChunkFile(chunk));
207 }
208 }
209 }
210}
211#endif
212
213void McRegionLevelStorageSource::convertRegions(File &baseFolder, vector<ChunkFile *> *chunkFiles, int currentCount, int totalCount, ProgressListener *progress)
214{
215 assert( false );
216
217 // 4J Stu - Removed, see comment in convertLevel above
218#if 0
219 //Collections::sort(chunkFiles);
220 std::sort( chunkFiles->begin(), chunkFiles->end() );
221
222 byteArray buffer = byteArray(4096);
223
224 ChunkFile *chunkFile;
225 AUTO_VAR(itEnd, chunkFiles->end());
226 for (AUTO_VAR(it, chunkFiles->begin()); it != itEnd; it++)
227 {
228 chunkFile = *it; //chunkFiles->at(i1);
229
230 // Matcher matcher = ChunkFilter.chunkFilePattern.matcher(chunkFile.getName());
231 // if (!matcher.matches()) {
232 // continue;
233 // }
234 // int x = Integer.parseInt(matcher.group(1), 36);
235 // int z = Integer.parseInt(matcher.group(2), 36);
236
237 int x = chunkFile->getX();
238 int z = chunkFile->getZ();
239
240 RegionFile *region = RegionFileCache::getRegionFile(baseFolder, x, z);
241 if (!region->hasChunk(x & 31, z & 31))
242 {
243 FileInputStream fis = new BufferedInputStream(FileInputStream(*chunkFile->getFile()));
244 DataInputStream istream = DataInputStream(&fis); // 4J - was new GZIPInputStream as well
245
246 DataOutputStream *out = region->getChunkDataOutputStream(x & 31, z & 31);
247
248 int length = 0;
249 while ( (length = istream.read(buffer)) != -1 )
250 {
251 out->write(buffer, 0, length);
252 }
253
254 out->close();
255 istream.close();
256
257 // 4J Stu - getChunkDataOutputStream makes a new DataOutputStream that points to a new ChunkBuffer( ByteArrayOutputStream )
258 // We should clean these up when we are done
259 out->deleteChildStream();
260 delete out;
261 }
262
263 currentCount++;
264 int percent = (int) Math::round(100.0 * (double) currentCount / (double) totalCount);
265 progress->progressStagePercentage(percent);
266 }
267 RegionFileCache::clear();
268#endif
269
270}
271
272void McRegionLevelStorageSource::eraseFolders(vector<File *> *folders, int currentCount, int totalCount, ProgressListener *progress)
273{
274 File *folder;
275 AUTO_VAR(itEnd, folders->end());
276 for (AUTO_VAR(it, folders->begin()); it != itEnd; it++)
277 {
278 folder = *it; //folders->at(i);
279
280 vector<File *> *files = folder->listFiles();
281 deleteRecursive(files);
282 folder->_delete();
283
284 currentCount++;
285 int percent = (int) Math::round(100.0 * (double) currentCount / (double) totalCount);
286 progress->progressStagePercentage(percent);
287 }
288}
289
290#if 0
291// 4J - not required anymore
292bool McRegionLevelStorageSource::FolderFilter::accept(File *file)
293{
294 if (file->isDirectory())
295 {
296 Matcher matcher( chunkFolderPattern, file->getName() );
297 return matcher.matches();
298 }
299 return false;
300}
301
302
303bool McRegionLevelStorageSource::ChunkFilter::accept(File *dir, const wstring& name)
304{
305 Matcher matcher( chunkFilePattern, name );
306 return matcher.matches();
307}
308
309
310McRegionLevelStorageSource::ChunkFile::ChunkFile(File *file)
311{
312 this->file = file;
313
314 Matcher matcher( ChunkFilter::chunkFilePattern, file->getName() );
315 if (matcher.matches())
316 {
317 x = Integer::parseInt(matcher.group(1), 36);
318 z = Integer::parseInt(matcher.group(2), 36);
319 }
320 else
321 {
322 x = 0;
323 z = 0;
324 }
325}
326
327//Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
328int McRegionLevelStorageSource::ChunkFile::compareTo(ChunkFile *rhs)
329{
330 // sort chunk files so that they are placed according to their
331 // region position
332 int rx = x >> 5;
333 int rhsrx = rhs->x >> 5;
334 if (rx == rhsrx)
335 {
336 int rz = z >> 5;
337 int rhsrz = rhs->z >> 5;
338 return rz - rhsrz;
339 }
340
341 return rx - rhsrx;
342}
343
344// 4J Stu Added so we can use std::sort instead of the java Collections::sort
345// a < b
346bool McRegionLevelStorageSource::ChunkFile::operator<( ChunkFile *b )
347{
348 return compareTo( b ) < 0;
349}
350
351File *McRegionLevelStorageSource::ChunkFile::getFile()
352{
353 return (File *) file;
354}
355
356int McRegionLevelStorageSource::ChunkFile::getX()
357{
358 return x;
359}
360
361int McRegionLevelStorageSource::ChunkFile::getZ()
362{
363 return z;
364}
365#endif