fix: panorama

This commit is contained in:
Fireblade
2026-07-02 21:09:39 -04:00
parent c1f2096ea6
commit e92a063e63
37 changed files with 625 additions and 285 deletions
+22 -9
View File
@@ -416,15 +416,28 @@ bool DLCPack::hasPurchasedFile(DLCManager::EDLCType type, const wstring &path)
void DLCPack::UpdateLanguage()
{
// find the language file
DLCManager::e_DLCType_LocalisationData;
DLCFile *file = nullptr;
if(m_files[DLCManager::e_DLCType_LocalisationData].size() > 0)
if (m_files[DLCManager::e_DLCType_LocalisationData].empty())
{
file = m_files[DLCManager::e_DLCType_LocalisationData][0];
DLCLocalisationFile *localisationFile = static_cast<DLCLocalisationFile *>(getFile(DLCManager::e_DLCType_LocalisationData, L"languages.loc"));
StringTable *strTable = localisationFile->getStringTable();
strTable->ReloadStringTable();
return;
}
}
DLCFile *file = getFile(DLCManager::e_DLCType_LocalisationData, L"languages.loc");
if (!file)
{
file = m_files[DLCManager::e_DLCType_LocalisationData][0];
}
DLCLocalisationFile *localisationFile = static_cast<DLCLocalisationFile *>(file);
if (!localisationFile)
{
return;
}
StringTable *strTable = localisationFile->getStringTable();
if (!strTable)
{
return;
}
strTable->ReloadStringTable();
}
@@ -13,6 +13,7 @@ class ConsoleSchematicFile;
class LevelRuleset;
class BiomeOverride;
class StartFeature;
class DLCPack;
class GrSource
{
@@ -135,6 +136,7 @@ public:
void setBaseSavePath(const wstring &x);
bool ready();
DLCPack *getParentDLCPack() { return m_parentDLCPack; }
void setBaseSaveData(PBYTE pbData, DWORD dwSize);
PBYTE getBaseSaveData(DWORD &size);
Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

@@ -5,45 +5,237 @@
#include "MultiPlayerLevel.h"
#include "../../../Minecraft.World/net.minecraft.world.level.dimension.h"
#include "../../../Minecraft.World/net.minecraft.world.level.storage.h"
#include "Tesselator.h"
#include "Textures.h"
#include "BufferedImage.h"
#include "../GameRules/LevelGenerationOptions.h"
#include <fstream>
#include <direct.h>
#include <cmath>
static const wchar_t *PANORAMA_TEXTURE_RELPATH = L"Graphics/ControlType/Panorama/";
static wstring GetPanoramaTexturePath()
{
const wchar_t *envOverride = _wgetenv(L"PANORAMA_TEXTURE_PATH");
if(envOverride && envOverride[0] != L'\0')
{
wstring path(envOverride);
if(!path.empty() && path.back() != L'/' && path.back() != L'\\')
path += L'/';
return path;
}
if(app.getLevelGenerationOptions() != nullptr)
{
LevelGenerationOptions *levelGen = app.getLevelGenerationOptions();
DLCPack *parentPack = levelGen->getParentDLCPack();
if(parentPack != nullptr)
{
wstring packName = parentPack->getName();
if(!packName.empty())
{
wchar_t buf[MAX_PATH];
if(_wgetcwd(buf, MAX_PATH))
{
wstring path(buf);
path += L"\\Windows64Media\\DLC\\";
path += packName;
path += L"\\Data\\Panorama\\";
wstring sampleDay = path + L"Panorama_S.png";
wstring sampleNight = path + L"Panorama_N.png";
if(GetFileAttributesW(sampleDay.c_str()) != INVALID_FILE_ATTRIBUTES ||
GetFileAttributesW(sampleNight.c_str()) != INVALID_FILE_ATTRIBUTES)
{
return path;
}
}
}
}
}
const char *mountedPanoramaRoots[] =
{
"TPACK:Data/Panorama/",
"WPACK:Data/Panorama/",
};
for(const char *mountedRoot : mountedPanoramaRoots)
{
wstring mountedPath = convStringToWstring(StorageManager.GetMountedPath(mountedRoot));
if(mountedPath.empty()) continue;
wstring sampleDay = mountedPath + L"Panorama_S.png";
wstring sampleNight = mountedPath + L"Panorama_N.png";
if(GetFileAttributesW(sampleDay.c_str()) != INVALID_FILE_ATTRIBUTES ||
GetFileAttributesW(sampleNight.c_str()) != INVALID_FILE_ATTRIBUTES)
{
if(!mountedPath.empty() && mountedPath.back() != L'/' && mountedPath.back() != L'\\')
mountedPath += L'/';
return mountedPath;
}
}
wchar_t buf[MAX_PATH];
if(_wgetcwd(buf, MAX_PATH))
{
wstring path(buf);
path += L"\\Common\\Media\\MediaWindows64\\Graphics\\ControlType\\Panorama\\";
return path;
}
// fallback
return PANORAMA_TEXTURE_RELPATH;
}
// opengl time :v
static int LoadPanoramaQuadTexture(const wstring &fileName, int &outWidth, int &outHeight)
{
wstring filePath = GetPanoramaTexturePath() + fileName;
const char *nativePath = wstringtofilename(filePath);
std::ifstream stream(nativePath, std::ios::binary);
if(!stream)
{
printf("Failed to open panorama quad texture %ls\n", filePath.c_str());
return -1;
}
stream.seekg(0, std::ios::end);
std::streamoff size = stream.tellg();
if(size <= 0)
{
printf("Empty panorama quad texture %ls\n", filePath.c_str());
return -1;
}
stream.seekg(0, std::ios::beg);
BYTE *data = new BYTE[static_cast<size_t>(size)];
if(!stream.read(reinterpret_cast<char *>(data), size))
{
delete [] data;
printf("Failed to read panorama quad texture %ls\n", filePath.c_str());
return -1;
}
BufferedImage image(data, static_cast<DWORD>(size));
delete [] data;
if(image.getData() == nullptr)
{
printf("Failed to decode panorama quad texture %ls\n", filePath.c_str());
return -1;
}
// gaussian blur
const float sigma = 0.5f;
const int width = image.getWidth();
const int height = image.getHeight();
const int radius = static_cast<int>(ceilf(3.0f * sigma));
const int ksize = radius * 2 + 1;
vector<float> kernel(ksize);
float sum = 0.0f;
for(int i = -radius; i <= radius; ++i)
{
float v = expf(-(i*i) / (2.0f * sigma * sigma));
kernel[i + radius] = v;
sum += v;
}
for(int i = 0; i < ksize; ++i) kernel[i] /= sum;
float *tmpA = new float[width * height];
float *tmpR = new float[width * height];
float *tmpG = new float[width * height];
float *tmpB = new float[width * height];
int *sourcePixels = image.getData();
for(int y = 0; y < height; ++y)
{
for(int x = 0; x < width; ++x)
{
float a = 0, r = 0, g = 0, b = 0;
for(int k = -radius; k <= radius; ++k)
{
// horizontal wrap
int sx = x + k;
while(sx < 0) sx += width;
while(sx >= width) sx -= width;
int p = sourcePixels[sx + y * width];
float w = kernel[k + radius];
a += w * static_cast<float>((p >> 24) & 0xff);
r += w * static_cast<float>((p >> 16) & 0xff);
g += w * static_cast<float>((p >> 8) & 0xff);
b += w * static_cast<float>(p & 0xff);
}
int idx = x + y * width;
tmpA[idx] = a;
tmpR[idx] = r;
tmpG[idx] = g;
tmpB[idx] = b;
}
}
// vertical clamp
BufferedImage blurredImage(width, height, BufferedImage::TYPE_INT_ARGB);
int *targetPixels = blurredImage.getData();
for(int y = 0; y < height; ++y)
{
for(int x = 0; x < width; ++x)
{
float a = 0, r = 0, g = 0, b = 0;
for(int k = -radius; k <= radius; ++k)
{
int sy = y + k;
if(sy < 0) sy = 0;
if(sy >= height) sy = height - 1;
int idx = x + sy * width;
float w = kernel[k + radius];
a += w * tmpA[idx];
r += w * tmpR[idx];
g += w * tmpG[idx];
b += w * tmpB[idx];
}
int ia = static_cast<int>(a + 0.5f);
int ir = static_cast<int>(r + 0.5f);
int ig = static_cast<int>(g + 0.5f);
int ib = static_cast<int>(b + 0.5f);
if(ia < 0) ia = 0; if(ia > 255) ia = 255;
if(ir < 0) ir = 0; if(ir > 255) ir = 255;
if(ig < 0) ig = 0; if(ig > 255) ig = 255;
if(ib < 0) ib = 0; if(ib > 255) ib = 255;
targetPixels[x + y * width] = (ia << 24) | (ir << 16) | (ig << 8) | ib;
}
}
delete [] tmpA;
delete [] tmpR;
delete [] tmpG;
delete [] tmpB;
outWidth = image.getWidth();
outHeight = image.getHeight();
int id = Minecraft::GetInstance()->textures->getTexture(&blurredImage, C4JRender::TEXTURE_FORMAT_RxGyBzAw, false);
printf("Loaded panorama background quad '%ls' -> texture id %d\n", filePath.c_str(), id);
return id;
}
UIComponent_Panorama::UIComponent_Panorama(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer)
{
// Setup all the Iggy references we need for this scene
initialiseMovie();
m_bShowingDay = true;
while(!m_hasTickedOnce) tick();
tick();
}
wstring UIComponent_Panorama::getMoviePath()
{
switch( m_parentLayer->getViewport() )
{
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
m_bSplitscreen = true;
return L"PanoramaSplit";
break;
case C4JRender::VIEWPORT_TYPE_FULLSCREEN:
default:
m_bSplitscreen = false;
return L"Panorama";
break;
}
return L"";
}
void UIComponent_Panorama::tick()
{
if(!hasMovie()) return;
Minecraft *pMinecraft = Minecraft::GetInstance();
bool isDay = true;
EnterCriticalSection(&pMinecraft->m_setLevelCS);
if(pMinecraft->level!=nullptr)
{
@@ -52,24 +244,111 @@ void UIComponent_Panorama::tick()
if(pMinecraft->level->dimension->id==0)
{
i64TimeOfDay = pMinecraft->level->getLevelData()->getGameTime() % 24000;
isDay = (i64TimeOfDay <= 14000);
}
if(i64TimeOfDay>14000)
{
setPanorama(false);
}
else
{
setPanorama(true);
}
setPanorama(isDay);
}
else
{
setPanorama(true);
}
// scroll forever
m_panoramaScroll += 0.000035f;
LeaveCriticalSection(&pMinecraft->m_setLevelCS);
UIScene::tick();
m_hasTickedOnce = true;
}
void UIComponent_Panorama::EnsurePanoramaTexturesLoaded()
{
wstring currentRoot = GetPanoramaTexturePath();
if(m_bPanoramaTexturesLoaded && currentRoot == m_panoramaTextureRoot) return;
if(m_texPanoramaDay >= 0)
{
Minecraft::GetInstance()->textures->releaseTexture(m_texPanoramaDay);
m_texPanoramaDay = -1;
}
if(m_texPanoramaNight >= 0)
{
Minecraft::GetInstance()->textures->releaseTexture(m_texPanoramaNight);
m_texPanoramaNight = -1;
}
m_panoramaTextureRoot = currentRoot;
m_bPanoramaTexturesLoaded = false;
int dayWidth = 0;
int dayHeight = 0;
m_texPanoramaDay = LoadPanoramaQuadTexture(L"Panorama_S.png", dayWidth, dayHeight);
int nightWidth = 0;
int nightHeight = 0;
m_texPanoramaNight = LoadPanoramaQuadTexture(L"Panorama_N.png", nightWidth, nightHeight);
if(dayWidth > 0 && dayHeight > 0)
{
m_panoramaAspect = static_cast<float>(dayWidth) / static_cast<float>(dayHeight);
}
else if(nightWidth > 0 && nightHeight > 0)
{
m_panoramaAspect = static_cast<float>(nightWidth) / static_cast<float>(nightHeight);
}
m_bPanoramaTexturesLoaded = (m_texPanoramaDay >= 0 || m_texPanoramaNight >= 0);
}
void UIComponent_Panorama::DrawPanoramaBackgroundQuad(S32 width, S32 height)
{
EnsurePanoramaTexturesLoaded();
int texId = m_bShowingDay ? m_texPanoramaDay : m_texPanoramaNight;
if(texId < 0) return; // failed
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, width, height, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glDisable(GL_ALPHA_TEST);
glDisable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
Minecraft::GetInstance()->textures->bind(texId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
float sourceWidth = static_cast<float>(height) * m_panoramaAspect;
float scroll = m_panoramaScroll - floorf(m_panoramaScroll);
float scrollPx = scroll * sourceWidth;
float startX = -scrollPx;
float startY = 0.0f;
const float overscanY = (static_cast<float>(height) * 0.03f > 8.0f) ? (static_cast<float>(height) * 0.03f) : 8.0f;
const float drawTop = -overscanY;
const float drawBottom = static_cast<float>(height) + overscanY;
Tesselator *t = Tesselator::getInstance();
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
t->begin();
for(float x = startX - sourceWidth; x < static_cast<float>(width) + sourceWidth; x += sourceWidth)
{
float left = x;
float right = x + sourceWidth;
t->vertexUV(left, drawBottom, 0.0f, 0.0f, 1.0f);
t->vertexUV(right, drawBottom, 0.0f, 1.0f, 1.0f);
t->vertexUV(right, drawTop, 0.0f, 1.0f, 0.0f);
t->vertexUV(left, drawTop, 0.0f, 0.0f, 0.0f);
}
t->end();
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glDisable(GL_BLEND);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
void UIComponent_Panorama::render(S32 width, S32 height, C4JRender::eViewportType viewport)
@@ -78,7 +357,7 @@ void UIComponent_Panorama::render(S32 width, S32 height, C4JRender::eViewportTyp
(viewport == C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM) ||
(viewport == C4JRender::VIEWPORT_TYPE_SPLIT_LEFT) ||
(viewport == C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT);
if(m_bSplitscreen && specialViewport)
if(specialViewport)
{
S32 xPos = 0;
S32 yPos = 0;
@@ -108,32 +387,17 @@ void UIComponent_Panorama::render(S32 width, S32 height, C4JRender::eViewportTyp
tileYStart = static_cast<S32>(ui.getScreenHeight() / 2);
}
F32 scaleW = static_cast<F32>(tileXStart + tileWidth) / static_cast<F32>(m_movieWidth);
F32 scaleH = static_cast<F32>(tileYStart + tileHeight) / static_cast<F32>(m_movieHeight);
F32 scale = (scaleW > scaleH) ? scaleW : scaleH;
if(scale < 1.0f) scale = 1.0f;
IggyPlayerSetDisplaySize( getMovie(), static_cast<S32>(m_movieWidth * scale), static_cast<S32>(m_movieHeight * scale) );
IggyPlayerDrawTilesStart ( getMovie() );
m_renderWidth = tileWidth;
m_renderHeight = tileHeight;
IggyPlayerDrawTile ( getMovie() ,
tileXStart ,
tileYStart ,
tileXStart + tileWidth ,
tileYStart + tileHeight ,
0 );
IggyPlayerDrawTilesEnd ( getMovie() );
DrawPanoramaBackgroundQuad(tileWidth, tileHeight);
}
else
{
if(m_bIsReloading) return;
if(!m_hasTickedOnce || !getMovie()) return;
ui.setupRenderPosition(0, 0);
IggyPlayerSetDisplaySize( getMovie(), static_cast<S32>(ui.getScreenWidth()), static_cast<S32>(ui.getScreenHeight()) );
IggyPlayerDraw( getMovie() );
m_renderWidth = static_cast<S32>(ui.getScreenWidth());
m_renderHeight = static_cast<S32>(ui.getScreenHeight());
DrawPanoramaBackgroundQuad(static_cast<S32>(ui.getScreenWidth()), static_cast<S32>(ui.getScreenHeight()));
}
}
@@ -142,12 +406,5 @@ void UIComponent_Panorama::setPanorama(bool isDay)
if(isDay != m_bShowingDay)
{
m_bShowingDay = isDay;
IggyDataValue result;
IggyDataValue value[1];
value[0].type = IGGY_DATATYPE_boolean;
value[0].boolval = isDay;
IggyResult out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcShowPanoramaDay , 1 , value );
}
}
}
@@ -5,14 +5,15 @@
class UIComponent_Panorama : public UIScene
{
private:
bool m_bSplitscreen;
bool m_bShowingDay;
protected:
IggyName m_funcShowPanoramaDay;
UI_BEGIN_MAP_ELEMENTS_AND_NAMES(UIScene)
UI_MAP_NAME(m_funcShowPanoramaDay, L"ShowPanoramaDay");
UI_END_MAP_ELEMENTS_AND_NAMES()
void EnsurePanoramaTexturesLoaded();
void DrawPanoramaBackgroundQuad(S32 width, S32 height);
int m_texPanoramaDay = -1;
int m_texPanoramaNight = -1;
bool m_bPanoramaTexturesLoaded = false;
wstring m_panoramaTextureRoot;
float m_panoramaAspect = 1.0f;
float m_panoramaScroll = 0.0f;
public:
UIComponent_Panorama(int iPad, void *initData, UILayer *parentLayer);
@@ -23,6 +24,8 @@ protected:
public:
virtual EUIScene getSceneType() { return eUIComponent_Panorama;}
virtual bool isPanoramaOverrideScene() { return true; }
virtual bool isPanoramaDayOverride() { return m_bShowingDay; }
// Returns true if this scene handles input
virtual bool stealsFocus() { return false; }
+12 -3
View File
@@ -123,7 +123,10 @@ void UIScene::reloadMovie(bool force)
value[0].type = IGGY_DATATYPE_number;
value[0].number = m_iFocusControl;
IggyResult out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcSetFocus , 1 , value );
if(swf && m_funcSetFocus)
{
IggyResult out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcSetFocus , 1 , value );
}
m_needsCacheRendered = true;
m_bIsReloading = false;
@@ -238,6 +241,8 @@ void UIScene::updateSafeZone()
void UIScene::setSafeZone(S32 safeTop, S32 safeBottom, S32 safeLeft, S32 safeRight)
{
if(!swf) return;
IggyDataValue result;
IggyDataValue value[4];
@@ -254,8 +259,12 @@ void UIScene::setSafeZone(S32 safeTop, S32 safeBottom, S32 safeLeft, S32 safeRig
void UIScene::initialiseMovie()
{
loadMovie();
mapElementsAndNames();
wstring moviePath = getMoviePath();
if(!moviePath.empty())
{
loadMovie();
mapElementsAndNames();
}
updateSafeZone();
@@ -765,7 +765,7 @@ UIScene_LoadCreateJoinMenu::UIScene_LoadCreateJoinMenu(int iPad, void *initData,
m_controlSavesTimer.setVisible( true );
m_controlNewGameTimer.setVisible( true );
m_controlNewGameTimer.setVisible( false );
m_controlJoinTimer.setVisible( false );
@@ -2256,23 +2256,7 @@ void UIScene_LoadCreateJoinMenu::tick()
HANDLE hFile = CreateFileW(filePath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, nullptr);
DWORD fileSize = 0;
if (hFile != INVALID_HANDLE_VALUE) {
fileSize = GetFileSize(hFile, nullptr);
if (fileSize < 12 || fileSize == INVALID_FILE_SIZE) fileSize = 0;
CloseHandle(hFile);
}
m_spaceIndicatorSaves.addSave(fileSize);
m_spaceIndicatorSaves.addSave(m_pSaveDetails->SaveInfoA[origIdx].metaData.dataSize);
#elif defined(__ORBIS__)
@@ -3143,11 +3127,12 @@ void UIScene_LoadCreateJoinMenu::handleInput(int iPad, int key, bool repeat, boo
if(StorageManager.EnoughSpaceForAMinSaveGame() && !StorageManager.GetSaveDisabled())
{
UINT uiIDA[3];
UINT uiIDA[4];
uiIDA[0]=IDS_CONFIRM_CANCEL;
uiIDA[1]=IDS_TITLE_RENAMESAVE;
uiIDA[2]=IDS_TOOLTIPS_DELETESAVE;
ui.RequestAlertMessage(IDS_TOOLTIPS_SAVEOPTIONS, IDS_TEXT_SAVEOPTIONS, uiIDA, 3, iPad,&UIScene_LoadCreateJoinMenu::SaveOptionsDialogReturned,this);
uiIDA[3]=IDS_COPYSAVE;
ui.RequestAlertMessage(IDS_TOOLTIPS_SAVEOPTIONS, IDS_TEXT_SAVEOPTIONS, uiIDA, 4, iPad,&UIScene_LoadCreateJoinMenu::SaveOptionsDialogReturned,this);
}
else
{
@@ -5825,30 +5810,6 @@ int UIScene_LoadCreateJoinMenu::SaveOptionsDialogReturned(void *pParam,int iPad,
#ifdef SONY_REMOTE_STORAGE_UPLOAD
case C4JStorage::EMessage_ResultFourthOption: // upload to cloud
{
UINT uiIDA[2];
uiIDA[0]=IDS_CONFIRM_OK;
uiIDA[1]=IDS_CONFIRM_CANCEL;
ui.RequestAlertMessage(IDS_TOOLTIPS_SAVETRANSFER_UPLOAD, IDS_SAVE_TRANSFER_TEXT, uiIDA, 2, iPad,&UIScene_LoadCreateJoinMenu::SaveTransferDialogReturned,pClass);
}
break;
#endif // SONY_REMOTE_STORAGE_UPLOAD
#if defined _XBOX_ONE || defined __ORBIS__
case C4JStorage::EMessage_ResultFourthOption: // copy save
{
@@ -5867,7 +5828,6 @@ int UIScene_LoadCreateJoinMenu::SaveOptionsDialogReturned(void *pParam,int iPad,
break;
#endif
@@ -8691,7 +8651,7 @@ void UIScene_LoadCreateJoinMenu::HandleDLCLicenseChange()
#if defined _XBOX_ONE || defined __ORBIS__
#if defined _XBOX_ONE || defined __ORBIS__ || defined(_WINDOWS64)
int UIScene_LoadCreateJoinMenu::CopySaveDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result)
@@ -8875,54 +8835,10 @@ int UIScene_LoadCreateJoinMenu::CopySaveDataReturned(LPVOID lpParam, bool succes
{
#ifdef __ORBIS__
UINT uiIDA[1];
// you cancelled the save on exit after choosing exit and save? You go back to the Exit choices then.
uiIDA[0]=IDS_OK;
if( stat == C4JStorage::ESaveGame_CopyCompleteFailLocalStorage )
{
ui.LeaveCallbackIdCriticalSection();
ui.RequestErrorMessage(IDS_COPYSAVE_FAILED_TITLE, IDS_COPYSAVE_FAILED_LOCAL, uiIDA, 1, ProfileManager.GetPrimaryPad(), CopySaveErrorDialogFinishedCallback, lpParam);
}
else if( stat == C4JStorage::ESaveGame_CopyCompleteFailQuota )
{
ui.LeaveCallbackIdCriticalSection();
ui.RequestErrorMessage(IDS_COPYSAVE_FAILED_TITLE, IDS_COPYSAVE_FAILED_QUOTA, uiIDA, 1, ProfileManager.GetPrimaryPad(), CopySaveErrorDialogFinishedCallback, lpParam);
}
else
{
pClass->m_bCopying = false;
ui.LeaveCallbackIdCriticalSection();
}
#else
pClass->m_bCopying = false;
ui.LeaveCallbackIdCriticalSection();
#endif
}
}
@@ -396,7 +396,7 @@ private:
static int CrossSaveUploadFinishedCallback(void *pParam,int iPad,C4JStorage::EMessageResult result);
#endif
#if defined _XBOX_ONE || defined __ORBIS__
#if defined _XBOX_ONE || defined __ORBIS__ || defined(_WINDOWS64)
static int CopySaveDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result);
static int CopySaveThreadProc( LPVOID lpParameter );
static int CopySaveDataReturned( LPVOID lpParameter, bool success, C4JStorage::ESaveGameState state );
Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

@@ -9634,4 +9634,16 @@ All Ender Chests in a world are linked. Items placed into an Ender Chest are acc
<data name="IDS_SWAP">
<value>Swap</value>
</data>
<data name="IDS_COPYSAVE">
<value>Copy Save</value>
</data>
<data name="IDS_TEXT_COPY_SAVE">
<value>Are you sure you want to copy this save game?</value>
</data>
<data name="IDS_PROGRESS_COPYING_SAVE">
<value>Copying Save</value>
</data>
</root>
+1
View File
@@ -112,6 +112,7 @@ void Biome::staticCtor()
Biome::jungleEdge = (new JungleBiome(23, true))->setColor(0x628b17)->setName(L"Jungle Edge")->setLeafColor(0x537b09)->setTemperatureAndDownfall(0.95F, 0.8F)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_Jungle, eMinecraftColour_Foliage_Jungle, eMinecraftColour_Water_JungleEdge,eMinecraftColour_Sky_JungleEdge);
Biome::deepOcean= (new OceanBiome(24))->setName(L"Deep Ocean")->setDepthAndScale(-1.8,0.1f)->setColor(0x000070)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_Ocean, eMinecraftColour_Foliage_Ocean, eMinecraftColour_Water_Ocean,eMinecraftColour_Sky_Ocean);;
//public static final BiomeGenBase stoneBeach = (new BiomeGenStoneBeach(25)).setColor(10658436).setBiomeName("Stone Beach").setTemperatureRainfall(0.2F, 0.3F).setHeight(height_RockyWaters);
Biome::stoneBeach = (new StoneBeachBiome(25))->setColor(0xa2a284)->setName(L"Stone Beach")->setTemperatureAndDownfall(0.2f, 0.3f)->setDepthAndScale(0.1f, 0.8f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_Beach, eMinecraftColour_Foliage_Beach, eMinecraftColour_Water_Beach, eMinecraftColour_Sky_Beach);
Biome::coldBeach = (new BeachBiome(26))->setColor(0xFAF0C0)->setName(L"Cold Beach")->setTemperatureAndDownfall(0.05F, 0.3F)->setDepthAndScale(0.0F, 0.025F)->setSnowCovered()->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_IcePlains, eMinecraftColour_Foliage_IcePlains, eMinecraftColour_Water_IcePlains, eMinecraftColour_Sky_IcePlains);
Biome::birchForest=(new ForestBiome(27, 2))->setColor(0x307444)->setName(L"Birch Forest")->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_Forest, eMinecraftColour_Foliage_Birch, eMinecraftColour_Water_Forest, eMinecraftColour_Sky_Forest);
Biome::birchForestHills=(new ForestBiome(28, 2))->setColor(0x1f5f32)->setName(L"Birch Forest Hills")->setDepthAndScale(0.45f, 0.3f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_ForestHills, eMinecraftColour_Foliage_Birch, eMinecraftColour_Water_Forest, eMinecraftColour_Sky_ForestHills);
+76 -30
View File
@@ -1,3 +1,4 @@
// TODO: fix cold-swampland edge-case scenario
#include "stdafx.h"
#include "BiomeEdgeLayer.h"
#include "net.minecraft.world.level.biome.h"
@@ -21,47 +22,92 @@ intArray BiomeEdgeLayer::getArea(int xo, int yo, int w, int h)
initRandom(ix + xo, iy + yo);
int center = b[(ix + 1) + (iy + 1) * stride];
if (!checkEdge(b, result, ix, iy, stride, Biome::extremeHills->id, Biome::smallerExtremeHills->id, center) &&
!checkEdge(b, result, ix, iy, stride, Biome::mesaPlateauF->id, Biome::mesaPlateau->id, center) &&
!checkEdge(b, result, ix, iy, stride, Biome::mesaPlateau->id, Biome::mesaPlateau->id, center) &&
!checkEdge(b, result, ix, iy, stride, Biome::megaTaiga->id, Biome::megaTaiga->id, center))
if (checkEdge(b, result, ix, iy, stride, Biome::extremeHills->id, Biome::smallerExtremeHills->id, center))
continue;
if (checkEdgeStrict(b, result, ix, iy, stride, Biome::mesaPlateauF->id, Biome::mesa->id, center))
continue;
if (checkEdgeStrict(b, result, ix, iy, stride, Biome::mesaPlateau->id, Biome::mesa->id, center))
continue;
if (checkEdgeStrict(b, result, ix, iy, stride, Biome::megaTaiga->id, Biome::taiga->id, center))
continue;
int n = b[(ix + 1) + (iy + 0) * stride];
int e = b[(ix + 2) + (iy + 1) * stride];
int w1 = b[(ix + 0) + (iy + 1) * stride];
int s = b[(ix + 1) + (iy + 2) * stride];
if (center == Biome::desert->id)
{
if (center == Biome::desert->id) {
int n = b[(ix + 1) + (iy + 0) * stride];
int e = b[(ix + 2) + (iy + 1) * stride];
int w1 = b[(ix + 0) + (iy + 1) * stride];
int s = b[(ix + 1) + (iy + 2) * stride];
if (n == Biome::iceFlats->id || e == Biome::iceFlats->id || w1 == Biome::iceFlats->id || s == Biome::iceFlats->id) {
center = Biome::extremeHills->id;
}
}
result[ix + iy * w] = center;
bool nearIce = (n == Biome::iceFlats->id || e == Biome::iceFlats->id ||
w1 == Biome::iceFlats->id || s == Biome::iceFlats->id);
result[ix + iy * w] = nearIce ? Biome::extremeHills_plus->id : center;
}
else if (center == Biome::swampland->id)
{
bool nearDesert = (n == Biome::desert->id || e == Biome::desert->id || w1 == Biome::desert->id || s == Biome::desert->id);
bool nearColdTaiga = (n == Biome::coldTaiga->id || e == Biome::coldTaiga->id || w1 == Biome::coldTaiga->id || s == Biome::coldTaiga->id);
bool nearIceFlats = (n == Biome::iceFlats->id || e == Biome::iceFlats->id || w1 == Biome::iceFlats->id || s == Biome::iceFlats->id);
if (nearDesert || nearColdTaiga || nearIceFlats)
{
result[ix + iy * w] = Biome::plains->id;
}
else
{
bool nearJungle = (n == Biome::jungle->id || e == Biome::jungle->id || w1 == Biome::jungle->id || s == Biome::jungle->id);
result[ix + iy * w] = nearJungle ? Biome::jungleEdge->id : center;
}
}
else
{
result[ix + iy * w] = center;
}
}
}
return result;
}
bool BiomeEdgeLayer::checkEdge(intArray& b, intArray& result, int x, int y, int w, int biome, int target, int center)
bool BiomeEdgeLayer::checkEdge(intArray& b, intArray& result, int x, int y, int stride, int biome, int target, int center)
{
if (!isSame(center, biome)) return false;
int n = b[(x + 1) + (y + 0) * stride];
int e = b[(x + 2) + (y + 1) * stride];
int w1 = b[(x + 0) + (y + 1) * stride];
int s = b[(x + 1) + (y + 2) * stride];
bool interior = isValidTemperatureEdge(n, biome) && isValidTemperatureEdge(e, biome) &&
isValidTemperatureEdge(w1, biome) && isValidTemperatureEdge(s, biome);
result[x + y * (stride - 2)] = interior ? center : target;
return true;
}
bool BiomeEdgeLayer::checkEdgeStrict(intArray& b, intArray& result, int x, int y, int stride, int biome, int target, int center)
{
if (center != biome) return false;
int n = b[(x + 1) + (y + 0) * w];
int e = b[(x + 2) + (y + 1) * w];
int w1 = b[(x + 0) + (y + 1) * w];
int s = b[(x + 1) + (y + 2) * w];
int n = b[(x + 1) + (y + 0) * stride];
int e = b[(x + 2) + (y + 1) * stride];
int w1 = b[(x + 0) + (y + 1) * stride];
int s = b[(x + 1) + (y + 2) * stride];
if (n != biome || e != biome || w1 != biome || s != biome)
bool interior = isSame(n, biome) && isSame(e, biome) && isSame(w1, biome) && isSame(s, biome);
result[x + y * (stride - 2)] = interior ? center : target;
return true;
}
bool BiomeEdgeLayer::isValidTemperatureEdge(int neighbor, int target)
{
if (isSame(neighbor, target)) return true;
Biome* a = Biome::getBiome(neighbor);
Biome* b = Biome::getBiome(target);
if (a != nullptr && b != nullptr)
{
result[x + y * (w-2)] = target;
return true;
int catA = a->getTemperatureCategory();
int catB = b->getTemperatureCategory();
return catA == catB || catA == 2 || catB == 2;
}
return false;
}
bool BiomeEdgeLayer::isValidTemperatureEdge(int a1biome, int a2biome)
{
if (a1biome == a2biome) return true;
return true;
}
}
+1 -1
View File
@@ -9,7 +9,7 @@ public:
virtual intArray getArea(int xo, int yo, int w, int h) override;
private:
static bool isValidTemperatureEdge(int a1biome, int a2biome);
bool isValidTemperatureEdge(int a1biome, int a2biome);
bool checkEdge(intArray& b, intArray& result, int x, int y, int w, int biome, int target, int replacement);
bool checkEdgeStrict(intArray& b, intArray& result, int x, int y, int w, int biome, int target, int replacement);
};
+1 -8
View File
@@ -453,15 +453,8 @@ void BiomeSource::getFracs(intArray indices, float *fracs, float *groupFracs)
bool BiomeSource::getIsMatch(float *fracs, float *groupFracs)
{
if (fracs[0] + fracs[24] > 0.15f) return false;
int varietyCount = 0;
for (int i = 0; i < 8; i++)
{
if (groupFracs[i] > 0.0f)
{
varietyCount++;
}
}
if (groupFracs[i] > 0.0f) varietyCount++;
return varietyCount >= 5;
}
+2 -1
View File
@@ -61,7 +61,8 @@ LayerArray Layer::getDefaultLayers(int64_t seed, LevelType* levelType, void* sup
zoomLevel = 6;
shared_ptr<Layer> riverInit = make_shared<RiverInitLayer>(seed, baseLayer, 0x64);
shared_ptr<Layer> riverBase = ZoomLayer::zoom(seed, baseLayer, 0x3E8, 0);
shared_ptr<Layer> riverInit = make_shared<RiverInitLayer>(seed, riverBase, 0x64);
shared_ptr<Layer> hillsNoise = ZoomLayer::zoom(seed, riverInit, 0x3E8, 2);
+2 -2
View File
@@ -26,8 +26,8 @@ public:
Layer(int64_t seedMixup);
virtual void init(int64_t seed);
bool isOcean(int biomeId);
bool isSame(int biomeIdA, int biomeIdB);
static bool isOcean(int biomeId);
static bool isSame(int biomeIdA, int biomeIdB);
virtual void initRandom(int64_t x, int64_t y);
protected:
+6 -4
View File
@@ -3,8 +3,6 @@
#include "IntCache.h"
#include "RegionHillsLayer.h"
RegionHillsLayer::RegionHillsLayer(int64_t seed, shared_ptr<Layer> parent) : Layer(seed)
{
this->parent = parent;
@@ -27,7 +25,7 @@ void RegionHillsLayer::init(int64_t seed)
bool RegionHillsLayer::biomesEqualOrMesaPlateau(int a, int b)
{
return a == b;
return isSame(a, b); // was: a == b
}
@@ -125,7 +123,7 @@ intArray RegionHillsLayer::getArea(int xo, int yo, int w, int h)
}
else if (k == Biome::extremeHills->id)
{
i1 = Biome::smallerExtremeHills->id;
i1 = Biome::extremeHills_plus->id; // NOT smallerExtremeHills
}
else if (k == Biome::savanna->id)
{
@@ -133,6 +131,10 @@ intArray RegionHillsLayer::getArea(int xo, int yo, int w, int h)
i1 = Biome::savannaPlateau->id;
}
else if (Layer::isSame(k, Biome::mesaPlateauF->id))
{
i1 = Biome::mesa->id;
}
else if (k == Biome::deepOcean->id && nextRandom(3) == 0)
{
+110 -61
View File
@@ -4,78 +4,127 @@
ShoreLayer::ShoreLayer(int64_t seed, shared_ptr<Layer> parent, int64_t seedMixup) : Layer(seedMixup)
{
this->parent = parent;
this->parent = parent;
}
bool ShoreLayer::isJungleCompatible(int id)
{
if (id == Biome::jungle->id || id == Biome::jungleHills->id || id == Biome::jungleEdge->id ||
id == Biome::jungleM->id || id == Biome::jungleEdgeM->id)
return true;
if (id == Biome::forest->id || id == Biome::taiga->id)
return true;
if (isOcean(id))
return true;
return false;
}
bool ShoreLayer::isMesaBiome(int id)
{
return id == Biome::mesa->id || id == Biome::mesaPlateauF->id || id == Biome::mesaPlateau->id ||
id == Biome::mesaBryce->id || id == Biome::mesaPlateauFM->id || id == Biome::mesaPlateauM->id;
}
void ShoreLayer::replaceIfNeighborOcean(intArray& b, intArray& result, int x, int y, int w, int stride, int center, int target)
{
if (!isOcean(center))
{
int n = b[(x + 1) + (y + 0) * stride];
int e = b[(x + 2) + (y + 1) * stride];
int w1 = b[(x + 0) + (y + 1) * stride];
int s = b[(x + 1) + (y + 2) * stride];
if (isOcean(n) || isOcean(e) || isOcean(w1) || isOcean(s))
{
result[x + y * w] = target;
return;
}
}
result[x + y * w] = center;
}
intArray ShoreLayer::getArea(int xo, int yo, int w, int h)
{
intArray b = parent->getArea(xo - 1, yo - 1, w + 2, h + 2);
intArray result = IntCache::allocate(w * h);
int stride = w + 2;
for (int y = 0; y < h; y++)
{
{
for (int x = 0; x < w; x++)
{
{
initRandom(x + xo, y + yo);
int old = b[(x + 1) + (y + 1) * (w + 2)];
int old = b[(x + 1) + (y + 1) * stride];
int n = b[(x + 1) + (y + 0) * stride];
int e = b[(x + 2) + (y + 1) * stride];
int w1 = b[(x + 0) + (y + 1) * stride];
int s = b[(x + 1) + (y + 2) * stride];
if (old == Biome::mushroomIsland->id)
{
int _n = b[(x + 1) + (y + 1 - 1) * (w + 2)];
int _e = b[(x + 1 + 1) + (y + 1) * (w + 2)];
int _w = b[(x + 1 - 1) + (y + 1) * (w + 2)];
int _s = b[(x + 1) + (y + 1 + 1) * (w + 2)];
if (_n == Biome::ocean->id || _e == Biome::ocean->id || _w == Biome::ocean->id || _s == Biome::ocean->id || _n == Biome::deepOcean->id || _e == Biome::deepOcean->id || _w == Biome::deepOcean->id || _s == Biome::deepOcean->id)
{
result[x + y * w] = Biome::mushroomIslandShore->id;
}
else
{
result[x + y * w] = old;
}
}
else if (old != Biome::ocean->id && old != Biome::deepOcean->id && old != Biome::river->id && old != Biome::swampland->id && old != Biome::extremeHills->id)
{
int _n = b[(x + 1) + (y + 1 - 1) * (w + 2)];
int _e = b[(x + 1 + 1) + (y + 1) * (w + 2)];
int _w = b[(x + 1 - 1) + (y + 1) * (w + 2)];
int _s = b[(x + 1) + (y + 1 + 1) * (w + 2)];
if (_n == Biome::ocean->id || _e == Biome::ocean->id || _w == Biome::ocean->id || _s == Biome::ocean->id || _n == Biome::deepOcean->id || _e == Biome::deepOcean->id || _w == Biome::deepOcean->id || _s == Biome::deepOcean->id)
{
if (old == Biome::taiga->id || old == Biome::taigaHills->id || old == Biome::megaTaiga->id || old == Biome::megaTaigaHills->id || old == Biome::coldTaiga->id || old == Biome::coldTaigaHills->id)
{
result[x + y * w] = Biome::coldBeach->id;
}
else
{
result[x + y * w] = Biome::beaches->id;
}
}
else
{
result[x + y * w] = old;
}
}
else if (old == Biome::extremeHills->id)
{
int _n = b[(x + 1) + (y + 1 - 1) * (w + 2)];
int _e = b[(x + 1 + 1) + (y + 1) * (w + 2)];
int _w = b[(x + 1 - 1) + (y + 1) * (w + 2)];
int _s = b[(x + 1) + (y + 1 + 1) * (w + 2)];
if (_n != Biome::extremeHills->id || _e != Biome::extremeHills->id || _w != Biome::extremeHills->id || _s != Biome::extremeHills->id)
{
result[x + y * w] = Biome::smallerExtremeHills->id;
}
else
{
result[x + y * w] = old;
}
}
else
{
result[x + y * w] = old;
{
// decompile checks plain ocean only, NOT deepOcean, for this branch
bool nearOcean = (n == Biome::ocean->id || e == Biome::ocean->id ||
w1 == Biome::ocean->id || s == Biome::ocean->id);
result[x + y * w] = nearOcean ? Biome::mushroomIslandShore->id : old;
continue;
}
if (old == Biome::jungle->id || old == Biome::jungleHills->id ||
old == Biome::jungleM->id)
{
bool allCompatible = isJungleCompatible(n) && isJungleCompatible(e) &&
isJungleCompatible(w1) && isJungleCompatible(s);
if (!allCompatible)
{
result[x + y * w] = Biome::jungleEdge->id;
}
else
{
bool nearOcean = (isOcean(n) || isOcean(e) || isOcean(w1) || isOcean(s));
result[x + y * w] = nearOcean ? Biome::beaches->id : old;
}
continue;
}
if (old == Biome::extremeHills->id || old == Biome::extremeHills_plus->id ||
old == Biome::smallerExtremeHills->id)
{
replaceIfNeighborOcean(b, result, x, y, w, stride, old, Biome::stoneBeach->id);
continue;
}
Biome* biome = Biome::getBiome(old);
if (biome != nullptr && biome->hasSnow())
{
replaceIfNeighborOcean(b, result, x, y, w, stride, old, Biome::coldBeach->id);
continue;
}
if (old == Biome::mesa->id || old == Biome::mesaPlateauF->id)
{
bool nearOcean = (isOcean(n) || isOcean(e) || isOcean(w1) || isOcean(s));
if (nearOcean)
{
result[x + y * w] = Biome::beaches->id;
}
else
{
bool allMesa = isMesaBiome(n) && isMesaBiome(e) && isMesaBiome(w1) && isMesaBiome(s);
result[x + y * w] = allMesa ? old : Biome::desert->id;
}
continue;
}
if (old != Biome::ocean->id && old != Biome::deepOcean->id &&
old != Biome::river->id && old != Biome::swampland->id)
{
bool nearOcean = (isOcean(n) || isOcean(e) || isOcean(w1) || isOcean(s));
result[x + y * w] = nearOcean ? Biome::beaches->id : old;
continue;
}
result[x + y * w] = old;
}
}
return result;
}
}
+4
View File
@@ -3,6 +3,10 @@
class ShoreLayer : public Layer
{
private:
static bool isJungleCompatible(int id);
static bool isMesaBiome(int id);
void replaceIfNeighborOcean(intArray& b, intArray& result, int x, int y, int w, int stride, int center, int target);
public:
ShoreLayer(int64_t seed, shared_ptr<Layer> parent, int64_t seedMixup);
virtual intArray getArea(int xo, int yo, int w, int h);
+19
View File
@@ -0,0 +1,19 @@
#include "stdafx.h"
#include "StoneBeachBiome.h"
#include "net.minecraft.world.level.tile.h"
#include "BiomeDecorator.h"
StoneBeachBiome::StoneBeachBiome(int id) : Biome(id)
{
this->topMaterial = static_cast<byte>(Tile::stone_Id);
this->topMaterialData = 0;
this->material = static_cast<byte>(Tile::stone_Id);
this->materialData = 0;
if (decorator != nullptr)
{
decorator->treeCount = 0;
decorator->grassCount = 0;
decorator->flowerCount = 0;
}
}
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include "Biome.h"
class StoneBeachBiome : public Biome
{
public:
StoneBeachBiome(int id);
virtual bool isFoggy() const { return false; }
virtual bool isNatural() const { return true; }
};
+2 -2
View File
@@ -11,8 +11,8 @@ intArray ZoomLayer::getArea(int xo, int yo, int w, int h)
{
int px = xo >> 1;
int py = yo >> 1;
int pw = (w >> 1) + 3;
int ph = (h >> 1) + 3;
int pw = (w >> 1) + 2;
int ph = (h >> 1) + 2;
intArray p = parent->getArea(px, py, pw, ph);
intArray tmp = IntCache::allocate((pw * 2) * (ph * 2));
@@ -1367,6 +1367,8 @@ set(_MINECRAFT_WORLD_COMMON_NET_MINECRAFT_WORLD_LEVEL_BIOME
"${CMAKE_CURRENT_SOURCE_DIR}/RainforestBiome.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/RainforestBiome.h"
"${CMAKE_CURRENT_SOURCE_DIR}/RiverBiome.h"
"${CMAKE_CURRENT_SOURCE_DIR}/StoneBeachBiome.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/StoneBeachBiome.h"
"${CMAKE_CURRENT_SOURCE_DIR}/SwampBiome.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/SwampBiome.h"
"${CMAKE_CURRENT_SOURCE_DIR}/TaigaBiome.cpp"
@@ -34,4 +34,5 @@
//TU31
#include "SavannaBiome.h"
#include "MesaBiome.h"
#include "MesaBiome.h"
#include "StoneBeachBiome.h"