first commit
This commit is contained in:
525
Minecraft.Client/Options.cpp
Normal file
525
Minecraft.Client/Options.cpp
Normal file
@@ -0,0 +1,525 @@
|
||||
#include "stdafx.h"
|
||||
#include "Options.h"
|
||||
#include "KeyMapping.h"
|
||||
#include "LevelRenderer.h"
|
||||
#include "Textures.h"
|
||||
#include "..\Minecraft.World\net.minecraft.locale.h"
|
||||
#include "..\Minecraft.World\Language.h"
|
||||
#include "..\Minecraft.World\File.h"
|
||||
#include "..\Minecraft.World\BufferedReader.h"
|
||||
#include "..\Minecraft.World\DataInputStream.h"
|
||||
#include "..\Minecraft.World\InputStreamReader.h"
|
||||
#include "..\Minecraft.World\FileInputStream.h"
|
||||
#include "..\Minecraft.World\FileOutputStream.h"
|
||||
#include "..\Minecraft.World\DataOutputStream.h"
|
||||
#include "..\Minecraft.World\StringHelpers.h"
|
||||
|
||||
// 4J - the Option sub-class used to be an java enumerated type, trying to emulate that functionality here
|
||||
const Options::Option Options::Option::options[17] =
|
||||
{
|
||||
Options::Option(L"options.music", true, false),
|
||||
Options::Option(L"options.sound", true, false),
|
||||
Options::Option(L"options.invertMouse", false, true),
|
||||
Options::Option(L"options.sensitivity", true, false),
|
||||
Options::Option(L"options.renderDistance", false, false),
|
||||
Options::Option(L"options.viewBobbing", false, true),
|
||||
Options::Option(L"options.anaglyph", false, true),
|
||||
Options::Option(L"options.advancedOpengl", false, true),
|
||||
Options::Option(L"options.framerateLimit", false, false),
|
||||
Options::Option(L"options.difficulty", false, false),
|
||||
Options::Option(L"options.graphics", false, false),
|
||||
Options::Option(L"options.ao", false, true),
|
||||
Options::Option(L"options.guiScale", false, false),
|
||||
Options::Option(L"options.fov", true, false),
|
||||
Options::Option(L"options.gamma", true, false),
|
||||
Options::Option(L"options.renderClouds",false, true),
|
||||
Options::Option(L"options.particles", false, false),
|
||||
};
|
||||
|
||||
const Options::Option *Options::Option::MUSIC = &Options::Option::options[0];
|
||||
const Options::Option *Options::Option::SOUND = &Options::Option::options[1];
|
||||
const Options::Option *Options::Option::INVERT_MOUSE = &Options::Option::options[2];
|
||||
const Options::Option *Options::Option::SENSITIVITY = &Options::Option::options[3];
|
||||
const Options::Option *Options::Option::RENDER_DISTANCE = &Options::Option::options[4];
|
||||
const Options::Option *Options::Option::VIEW_BOBBING = &Options::Option::options[5];
|
||||
const Options::Option *Options::Option::ANAGLYPH = &Options::Option::options[6];
|
||||
const Options::Option *Options::Option::ADVANCED_OPENGL = &Options::Option::options[7];
|
||||
const Options::Option *Options::Option::FRAMERATE_LIMIT = &Options::Option::options[8];
|
||||
const Options::Option *Options::Option::DIFFICULTY = &Options::Option::options[9];
|
||||
const Options::Option *Options::Option::GRAPHICS = &Options::Option::options[10];
|
||||
const Options::Option *Options::Option::AMBIENT_OCCLUSION = &Options::Option::options[11];
|
||||
const Options::Option *Options::Option::GUI_SCALE = &Options::Option::options[12];
|
||||
const Options::Option *Options::Option::FOV = &Options::Option::options[13];
|
||||
const Options::Option *Options::Option::GAMMA = &Options::Option::options[14];
|
||||
const Options::Option *Options::Option::RENDER_CLOUDS = &Options::Option::options[15];
|
||||
const Options::Option *Options::Option::PARTICLES = &Options::Option::options[16];
|
||||
|
||||
|
||||
const Options::Option *Options::Option::getItem(int id)
|
||||
{
|
||||
return &options[id];
|
||||
}
|
||||
|
||||
Options::Option::Option(const wstring& captionId, bool hasProgress, bool isBoolean) : _isProgress(hasProgress), _isBoolean(isBoolean), captionId(captionId)
|
||||
{
|
||||
}
|
||||
|
||||
bool Options::Option::isProgress() const
|
||||
{
|
||||
return _isProgress;
|
||||
}
|
||||
|
||||
bool Options::Option::isBoolean() const
|
||||
{
|
||||
return _isBoolean;
|
||||
}
|
||||
|
||||
int Options::Option::getId() const
|
||||
{
|
||||
return (int)(this-options);
|
||||
}
|
||||
|
||||
wstring Options::Option::getCaptionId() const
|
||||
{
|
||||
return captionId;
|
||||
}
|
||||
|
||||
const wstring Options::RENDER_DISTANCE_NAMES[] =
|
||||
{
|
||||
L"options.renderDistance.far", L"options.renderDistance.normal", L"options.renderDistance.short", L"options.renderDistance.tiny"
|
||||
};
|
||||
const wstring Options::DIFFICULTY_NAMES[] =
|
||||
{
|
||||
L"options.difficulty.peaceful", L"options.difficulty.easy", L"options.difficulty.normal", L"options.difficulty.hard"
|
||||
};
|
||||
const wstring Options::GUI_SCALE[] =
|
||||
{
|
||||
L"options.guiScale.auto", L"options.guiScale.small", L"options.guiScale.normal", L"options.guiScale.large"
|
||||
};
|
||||
const wstring Options::FRAMERATE_LIMITS[] =
|
||||
{
|
||||
L"performance.max", L"performance.balanced", L"performance.powersaver"
|
||||
};
|
||||
|
||||
const wstring Options::PARTICLES[] = {
|
||||
L"options.particles.all", L"options.particles.decreased", L"options.particles.minimal"
|
||||
};
|
||||
|
||||
// 4J added
|
||||
void Options::init()
|
||||
{
|
||||
music = 1;
|
||||
sound = 1;
|
||||
sensitivity = 0.5f;
|
||||
invertYMouse = false;
|
||||
viewDistance = 0;
|
||||
bobView = true;
|
||||
anaglyph3d = false;
|
||||
advancedOpengl = false;
|
||||
framerateLimit = 2;
|
||||
fancyGraphics = true;
|
||||
ambientOcclusion = true;
|
||||
renderClouds = true;
|
||||
skin = L"Default";
|
||||
|
||||
keyUp = new KeyMapping(L"key.forward", Keyboard::KEY_W);
|
||||
keyLeft = new KeyMapping(L"key.left", Keyboard::KEY_A);
|
||||
keyDown = new KeyMapping(L"key.back", Keyboard::KEY_S);
|
||||
keyRight = new KeyMapping(L"key.right", Keyboard::KEY_D);
|
||||
keyJump = new KeyMapping(L"key.jump", Keyboard::KEY_SPACE);
|
||||
keyBuild = new KeyMapping(L"key.inventory", Keyboard::KEY_E);
|
||||
keyDrop = new KeyMapping(L"key.drop", Keyboard::KEY_Q);
|
||||
keyChat = new KeyMapping(L"key.chat", Keyboard::KEY_T);
|
||||
keySneak = new KeyMapping(L"key.sneak", Keyboard::KEY_LSHIFT);
|
||||
keyAttack = new KeyMapping(L"key.attack", -100 + 0);
|
||||
keyUse = new KeyMapping(L"key.use", -100 + 1);
|
||||
keyPlayerList = new KeyMapping(L"key.playerlist", Keyboard::KEY_TAB);
|
||||
keyPickItem = new KeyMapping(L"key.pickItem", -100 + 2);
|
||||
keyToggleFog = new KeyMapping(L"key.fog", Keyboard::KEY_F);
|
||||
|
||||
keyMappings[0] = keyAttack;
|
||||
keyMappings[1] = keyUse;
|
||||
keyMappings[2] = keyUp;
|
||||
keyMappings[3] = keyLeft;
|
||||
keyMappings[4] = keyDown;
|
||||
keyMappings[5] = keyRight;
|
||||
keyMappings[6] = keyJump;
|
||||
keyMappings[7] = keySneak;
|
||||
keyMappings[8] = keyDrop;
|
||||
keyMappings[9] = keyBuild;
|
||||
keyMappings[10] = keyChat;
|
||||
keyMappings[11] = keyPlayerList;
|
||||
keyMappings[12] = keyPickItem;
|
||||
keyMappings[13] = keyToggleFog;
|
||||
|
||||
minecraft = NULL;
|
||||
//optionsFile = NULL;
|
||||
|
||||
difficulty = 2;
|
||||
hideGui = false;
|
||||
thirdPersonView = false;
|
||||
renderDebug = false;
|
||||
lastMpIp = L"";
|
||||
|
||||
isFlying = false;
|
||||
smoothCamera = false;
|
||||
fixedCamera = false;
|
||||
flySpeed = 1;
|
||||
cameraSpeed = 1;
|
||||
guiScale = 0;
|
||||
particles = 0;
|
||||
fov = 0;
|
||||
gamma = 0;
|
||||
}
|
||||
|
||||
Options::Options(Minecraft *minecraft, File workingDirectory)
|
||||
{
|
||||
init();
|
||||
this->minecraft = minecraft;
|
||||
optionsFile = File(workingDirectory, L"options.txt");
|
||||
}
|
||||
|
||||
Options::Options()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
wstring Options::getKeyDescription(int i)
|
||||
{
|
||||
Language *language = Language::getInstance();
|
||||
return language->getElement(keyMappings[i]->name);
|
||||
}
|
||||
|
||||
wstring Options::getKeyMessage(int i)
|
||||
{
|
||||
int key = keyMappings[i]->key;
|
||||
if (key < 0) {
|
||||
return I18n::get(L"key.mouseButton", key + 101);
|
||||
} else {
|
||||
return Keyboard::getKeyName(keyMappings[i]->key);
|
||||
}
|
||||
}
|
||||
|
||||
void Options::setKey(int i, int key)
|
||||
{
|
||||
keyMappings[i]->key = key;
|
||||
save();
|
||||
}
|
||||
|
||||
void Options::set(const Options::Option *item, float fVal)
|
||||
{
|
||||
if (item == Option::MUSIC)
|
||||
{
|
||||
music = fVal;
|
||||
#ifdef _XBOX
|
||||
minecraft->soundEngine->updateMusicVolume(fVal*2.0f);
|
||||
#else
|
||||
minecraft->soundEngine->updateMusicVolume(fVal);
|
||||
#endif
|
||||
}
|
||||
if (item == Option::SOUND)
|
||||
{
|
||||
sound = fVal;
|
||||
#ifdef _XBOX
|
||||
minecraft->soundEngine->updateSoundEffectVolume(fVal*2.0f);
|
||||
#else
|
||||
minecraft->soundEngine->updateSoundEffectVolume(fVal);
|
||||
#endif
|
||||
}
|
||||
if (item == Option::SENSITIVITY)
|
||||
{
|
||||
sensitivity = fVal;
|
||||
}
|
||||
if (item == Option::FOV)
|
||||
{
|
||||
fov = fVal;
|
||||
}
|
||||
if (item == Option::GAMMA)
|
||||
{
|
||||
gamma = fVal;
|
||||
}
|
||||
}
|
||||
|
||||
void Options::toggle(const Options::Option *option, int dir)
|
||||
{
|
||||
if (option == Option::INVERT_MOUSE) invertYMouse = !invertYMouse;
|
||||
if (option == Option::RENDER_DISTANCE) viewDistance = (viewDistance + dir) & 3;
|
||||
if (option == Option::GUI_SCALE) guiScale = (guiScale + dir) & 3;
|
||||
if (option == Option::PARTICLES) particles = (particles + dir) % 3;
|
||||
|
||||
// 4J-PB - changing
|
||||
//if (option == Option::VIEW_BOBBING) bobView = !bobView;
|
||||
if (option == Option::VIEW_BOBBING) ((dir==0)?bobView=false: bobView=true);
|
||||
if (option == Option::RENDER_CLOUDS) renderClouds = !renderClouds;
|
||||
if (option == Option::ADVANCED_OPENGL)
|
||||
{
|
||||
advancedOpengl = !advancedOpengl;
|
||||
minecraft->levelRenderer->allChanged();
|
||||
}
|
||||
if (option == Option::ANAGLYPH)
|
||||
{
|
||||
anaglyph3d = !anaglyph3d;
|
||||
minecraft->textures->reloadAll();
|
||||
}
|
||||
if (option == Option::FRAMERATE_LIMIT) framerateLimit = (framerateLimit + dir + 3) % 3;
|
||||
|
||||
// 4J-PB - Change for Xbox
|
||||
//if (option == Option::DIFFICULTY) difficulty = (difficulty + dir) & 3;
|
||||
if (option == Option::DIFFICULTY) difficulty = (dir) & 3;
|
||||
|
||||
app.DebugPrintf("Option::DIFFICULTY = %d",difficulty);
|
||||
|
||||
if (option == Option::GRAPHICS)
|
||||
{
|
||||
fancyGraphics = !fancyGraphics;
|
||||
minecraft->levelRenderer->allChanged();
|
||||
}
|
||||
if (option == Option::AMBIENT_OCCLUSION)
|
||||
{
|
||||
ambientOcclusion = !ambientOcclusion;
|
||||
minecraft->levelRenderer->allChanged();
|
||||
}
|
||||
|
||||
// 4J-PB - don't do the file save on the xbox
|
||||
// save();
|
||||
|
||||
}
|
||||
|
||||
float Options::getProgressValue(const Options::Option *item)
|
||||
{
|
||||
if (item == Option::FOV) return fov;
|
||||
if (item == Option::GAMMA) return gamma;
|
||||
if (item == Option::MUSIC) return music;
|
||||
if (item == Option::SOUND) return sound;
|
||||
if (item == Option::SENSITIVITY) return sensitivity;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Options::getBooleanValue(const Options::Option *item)
|
||||
{
|
||||
// 4J - was a switch statement which we can't do with our Option:: pointer types
|
||||
if( item == Option::INVERT_MOUSE) return invertYMouse;
|
||||
if( item == Option::VIEW_BOBBING) return bobView;
|
||||
if( item == Option::ANAGLYPH) return anaglyph3d;
|
||||
if( item == Option::ADVANCED_OPENGL) return advancedOpengl;
|
||||
if( item == Option::AMBIENT_OCCLUSION) return ambientOcclusion;
|
||||
if( item == Option::RENDER_CLOUDS) return renderClouds;
|
||||
return false;
|
||||
}
|
||||
|
||||
wstring Options::getMessage(const Options::Option *item)
|
||||
{
|
||||
// 4J TODO, should these wstrings append rather than add?
|
||||
|
||||
Language *language = Language::getInstance();
|
||||
wstring caption = language->getElement(item->getCaptionId()) + L": ";
|
||||
|
||||
if (item->isProgress())
|
||||
{
|
||||
float progressValue = getProgressValue(item);
|
||||
|
||||
if (item == Option::SENSITIVITY)
|
||||
{
|
||||
if (progressValue == 0)
|
||||
{
|
||||
return caption + language->getElement(L"options.sensitivity.min");
|
||||
}
|
||||
if (progressValue == 1)
|
||||
{
|
||||
return caption + language->getElement(L"options.sensitivity.max");
|
||||
}
|
||||
return caption + _toString<int>((int) (progressValue * 200)) + L"%";
|
||||
} else if (item == Option::FOV)
|
||||
{
|
||||
if (progressValue == 0)
|
||||
{
|
||||
return caption + language->getElement(L"options.fov.min");
|
||||
}
|
||||
if (progressValue == 1)
|
||||
{
|
||||
return caption + language->getElement(L"options.fov.max");
|
||||
}
|
||||
return caption + _toString<int>((int) (70 + progressValue * 40));
|
||||
} else if (item == Option::GAMMA)
|
||||
{
|
||||
if (progressValue == 0)
|
||||
{
|
||||
return caption + language->getElement(L"options.gamma.min");
|
||||
}
|
||||
if (progressValue == 1)
|
||||
{
|
||||
return caption + language->getElement(L"options.gamma.max");
|
||||
}
|
||||
return caption + L"+" + _toString<int>((int) (progressValue * 100)) + L"%";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (progressValue == 0)
|
||||
{
|
||||
return caption + language->getElement(L"options.off");
|
||||
}
|
||||
return caption + _toString<int>((int) (progressValue * 100)) + L"%";
|
||||
}
|
||||
} else if (item->isBoolean())
|
||||
{
|
||||
|
||||
bool booleanValue = getBooleanValue(item);
|
||||
if (booleanValue)
|
||||
{
|
||||
return caption + language->getElement(L"options.on");
|
||||
}
|
||||
return caption + language->getElement(L"options.off");
|
||||
}
|
||||
else if (item == Option::RENDER_DISTANCE)
|
||||
{
|
||||
return caption + language->getElement(RENDER_DISTANCE_NAMES[viewDistance]);
|
||||
}
|
||||
else if (item == Option::DIFFICULTY)
|
||||
{
|
||||
return caption + language->getElement(DIFFICULTY_NAMES[difficulty]);
|
||||
}
|
||||
else if (item == Option::GUI_SCALE)
|
||||
{
|
||||
return caption + language->getElement(GUI_SCALE[guiScale]);
|
||||
}
|
||||
else if (item == Option::PARTICLES)
|
||||
{
|
||||
return caption + language->getElement(PARTICLES[particles]);
|
||||
}
|
||||
else if (item == Option::FRAMERATE_LIMIT)
|
||||
{
|
||||
return caption + I18n::get(FRAMERATE_LIMITS[framerateLimit]);
|
||||
}
|
||||
else if (item == Option::GRAPHICS)
|
||||
{
|
||||
if (fancyGraphics)
|
||||
{
|
||||
return caption + language->getElement(L"options.graphics.fancy");
|
||||
}
|
||||
return caption + language->getElement(L"options.graphics.fast");
|
||||
}
|
||||
|
||||
return caption;
|
||||
|
||||
}
|
||||
|
||||
void Options::load()
|
||||
{
|
||||
// 4J - removed try/catch
|
||||
// try {
|
||||
if (!optionsFile.exists()) return;
|
||||
// 4J - was new BufferedReader(new FileReader(optionsFile));
|
||||
BufferedReader *br = new BufferedReader(new InputStreamReader( new FileInputStream( optionsFile ) ) );
|
||||
|
||||
wstring line = L"";
|
||||
while ((line = br->readLine()) != L"") // 4J - was check against NULL - do we need to distinguish between empty lines and a fail here?
|
||||
{
|
||||
// 4J - removed try/catch
|
||||
// try {
|
||||
wstring cmds[2];
|
||||
int splitpos = (int)line.find(L":");
|
||||
if( splitpos == wstring::npos )
|
||||
{
|
||||
cmds[0] = line;
|
||||
cmds[1] = L"";
|
||||
}
|
||||
else
|
||||
{
|
||||
cmds[0] = line.substr(0,splitpos);
|
||||
cmds[1] = line.substr(splitpos,line.length()-splitpos);
|
||||
}
|
||||
|
||||
if (cmds[0] == L"music") music = readFloat(cmds[1]);
|
||||
if (cmds[0] == L"sound") sound = readFloat(cmds[1]);
|
||||
if (cmds[0] == L"mouseSensitivity") sensitivity = readFloat(cmds[1]);
|
||||
if (cmds[0] == L"fov") fov = readFloat(cmds[1]);
|
||||
if (cmds[0] == L"gamma") gamma = readFloat(cmds[1]);
|
||||
if (cmds[0] == L"invertYMouse") invertYMouse = cmds[1]==L"true";
|
||||
if (cmds[0] == L"viewDistance") viewDistance = _fromString<int>(cmds[1]);
|
||||
if (cmds[0] == L"guiScale") guiScale =_fromString<int>(cmds[1]);
|
||||
if (cmds[0] == L"particles") particles = _fromString<int>(cmds[1]);
|
||||
if (cmds[0] == L"bobView") bobView = cmds[1]==L"true";
|
||||
if (cmds[0] == L"anaglyph3d") anaglyph3d = cmds[1]==L"true";
|
||||
if (cmds[0] == L"advancedOpengl") advancedOpengl = cmds[1]==L"true";
|
||||
if (cmds[0] == L"fpsLimit") framerateLimit = _fromString<int>(cmds[1]);
|
||||
if (cmds[0] == L"difficulty") difficulty = _fromString<int>(cmds[1]);
|
||||
if (cmds[0] == L"fancyGraphics") fancyGraphics = cmds[1]==L"true";
|
||||
if (cmds[0] == L"ao") ambientOcclusion = cmds[1]==L"true";
|
||||
if (cmds[0] == L"clouds") renderClouds = cmds[1]==L"true";
|
||||
if (cmds[0] == L"skin") skin = cmds[1];
|
||||
if (cmds[0] == L"lastServer") lastMpIp = cmds[1];
|
||||
|
||||
for (int i = 0; i < keyMappings_length; i++)
|
||||
{
|
||||
if (cmds[0] == (L"key_" + keyMappings[i]->name))
|
||||
{
|
||||
keyMappings[i]->key = _fromString<int>(cmds[1]);
|
||||
}
|
||||
}
|
||||
// } catch (Exception e) {
|
||||
// System.out.println("Skipping bad option: " + line);
|
||||
// }
|
||||
}
|
||||
//KeyMapping.resetMapping(); // 4J Not implemented
|
||||
br->close();
|
||||
// } catch (Exception e) {
|
||||
// System.out.println("Failed to load options");
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
float Options::readFloat(wstring string)
|
||||
{
|
||||
if (string == L"true") return 1;
|
||||
if (string == L"false") return 0;
|
||||
return _fromString<float>(string);
|
||||
}
|
||||
|
||||
void Options::save()
|
||||
{
|
||||
// 4J - try/catch removed
|
||||
// try {
|
||||
|
||||
// 4J - original used a PrintWriter & FileWriter, but seems a bit much implementing these just to do this
|
||||
FileOutputStream fos = FileOutputStream(optionsFile);
|
||||
DataOutputStream dos = DataOutputStream(&fos);
|
||||
// PrintWriter pw = new PrintWriter(new FileWriter(optionsFile));
|
||||
|
||||
dos.writeChars(L"music:" + _toString<float>(music) + L"\n");
|
||||
dos.writeChars(L"sound:" + _toString<float>(sound) + L"\n");
|
||||
dos.writeChars(L"invertYMouse:" + wstring(invertYMouse ? L"true" : L"false") + L"\n");
|
||||
dos.writeChars(L"mouseSensitivity:" + _toString<float>(sensitivity));
|
||||
dos.writeChars(L"fov:" + _toString<float>(fov));
|
||||
dos.writeChars(L"gamma:" + _toString<float>(gamma));
|
||||
dos.writeChars(L"viewDistance:" + _toString<int>(viewDistance));
|
||||
dos.writeChars(L"guiScale:" + _toString<int>(guiScale));
|
||||
dos.writeChars(L"particles:" + _toString<int>(particles));
|
||||
dos.writeChars(L"bobView:" + wstring(bobView ? L"true" : L"false"));
|
||||
dos.writeChars(L"anaglyph3d:" + wstring(anaglyph3d ? L"true" : L"false"));
|
||||
dos.writeChars(L"advancedOpengl:" + wstring(advancedOpengl ? L"true" : L"false"));
|
||||
dos.writeChars(L"fpsLimit:" + _toString<int>(framerateLimit));
|
||||
dos.writeChars(L"difficulty:" + _toString<int>(difficulty));
|
||||
dos.writeChars(L"fancyGraphics:" + wstring(fancyGraphics ? L"true" : L"false"));
|
||||
dos.writeChars(L"ao:" + wstring(ambientOcclusion ? L"true" : L"false"));
|
||||
dos.writeChars(L"clouds:" + _toString<bool>(renderClouds));
|
||||
dos.writeChars(L"skin:" + skin);
|
||||
dos.writeChars(L"lastServer:" + lastMpIp);
|
||||
|
||||
for (int i = 0; i < keyMappings_length; i++)
|
||||
{
|
||||
dos.writeChars(L"key_" + keyMappings[i]->name + L":" + _toString<int>(keyMappings[i]->key));
|
||||
}
|
||||
|
||||
dos.close();
|
||||
// } catch (Exception e) {
|
||||
// System.out.println("Failed to save options");
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
bool Options::isCloudsOn()
|
||||
{
|
||||
return viewDistance < 2 && renderClouds;
|
||||
}
|
||||
Reference in New Issue
Block a user